diff --git a/README.md b/README.md index 8b9be4c5..4eeeae71 100644 --- a/README.md +++ b/README.md @@ -3,54 +3,57 @@ [Join the Discord Here!](https://discord.gg/k3wtdG5fRZ) -DisplayEntityUtils is a extensive plugin designed to make the usage of Display/Interaction entities simplier. It also supports BDEngine, a modeling/animation engine designed for display entities without the need for resource packs or mods. +DisplayEntityUtils makes handling customizable display entities simpler. -## What you'll need -### Dependencies: + +### Supported Entities +- **Block Displays** +- **Text Displays** +- **Item Displays** +- **Interactions** +- **Mannequins** + +### Dependencies - **[PacketEvents](https://modrinth.com/plugin/packetevents)** - - **_This dependency allows for usage of packet-based display entities and animations, and is used throughout the plugin_** -### BDEngine (Recommended) -BDEngine is what you'll use to create models and animations that can be transferred into your game world. Info on BDEngine and the Block Display Place, the collection of BDEngine models and animations, can be found [HERE](block-display.com) -> DISCLAIMER: I DO NOT OWN BDModels/BDEngine! ALL ISSUES AND SUGGESTIONS RELATED TO THAT PROJECT SHOULD BE BROUGHT TO THE OWNER, [ILLYSTRAY](https://illystray.com), IN THE BDENGINE DISCORD FOUND [HERE](https://discord.com/invite/VCeHfSd6Xa) +### Supports BDEngine (Recommended) +- **[BDEngine](block-display.com)** is a modeling and animation engine designed for display entities, + without the need for resource packs or mods +- The created models and animations can be transferred into your game world and reused with **DisplayEntityUtils**. +> DISCLAIMER: I DO NOT OWN **BDEngine**! ALL ISSUES AND SUGGESTIONS RELATED TO THAT PROJECT SHOULD BE BROUGHT TO THE OWNER, [ILLYSTRAY](https://illystray.com), IN THE BDENGINE DISCORD FOUND [HERE](https://discord.com/invite/VCeHfSd6Xa) ## What can DisplayEntityUtils do? -- Manipulate Individual Display/Interaction entities -- Manipulate Groups (BDEngine Models) -- Manipulate every part (Display Entity) within a model +- Manipulate Display Entities - Manipulate Interaction Entities +- Manipulate Mannequin Entities +- Save and load BDEngine models +- Manipulate entities in a model/group - Integration with [Skript](https://github.com/SkriptLang/Skript) [![SkriptHubViewTheDocs](http://skripthub.net/static/addon/ViewTheDocsButton.png)](http://skripthub.net/docs/?addon=DisplayEntityUtils) -- Create and Play Animations through the plugin -- Convert Datapack Animations from BDEngine (preferred over creating in-game) -- Include Interaction Entities as part of groups/models -- Execute commands through Interaction Entities -- Retrieve models from BDEngine and spawn them in-game +- Save/Load/Play BDEngine Animations +- Interaction entity click commands - Intergration with **MythicMobs** - Create Animation State Machines - Save groups and animations through Local Storage, MySQL, or MongoDB - And so much more! ## What more can it do for API/Skript users? -- Tools to manipulate Display and Interaction entity as individual entities -- Show/Hide groups to/from certain players +- Manipulate Display/Interaction/Mannequin entities +- Manage group visibility for players - Mount groups on entities (or vice-versa) - Request models from BDEngine's website -- Create packets based groups/entities -- Play packet-based animations -- Theres too many things to list! +- Play animations ## Showcases -- Display Controllers (Using Models as cosmetic equipment) - With(out) MythicMobs +- ### Display Controllers (Using Models as cosmetic equipment) - With(out) MythicMobs > ![ezgif-1-873ca90c95 (1)](https://github.com/user-attachments/assets/ee189856-3459-49b8-b75c-4c18d1b43818) -- Display Controllers (Creating Animation State Machines) - With(out) MythicMobs *(Credit goes to [Yegor_Mechanic](https://block-display.com/author/yegor_mechanic/) for all Dodo Bird Models/Animations)* +- ### Display Controllers (Creating Animation State Machines) - With(out) MythicMobs > ![](https://github.com/user-attachments/assets/594a4ffe-89cf-4e49-aff5-2f8c43ea21ad) - -- API: Display Entities rotating smoothly with yaw changes, and Interaction entities pivoting around the center -> ![](https://github.com/user-attachments/assets/5c333cd4-71ba-4ad1-a631-f8ec648651f0) + > + > *Dodo Bird Model and Animations by [Yegor_Mechanic](https://block-display.com/author/yegor_mechanic/)* ## WIKI ### Access the wiki [HERE](https://github.com/PZDonny/DisplayEntityUtils/wiki) diff --git a/api/pom.xml b/api/pom.xml index 294e8694..51976498 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.3.8 + 3.4.0 api @@ -45,6 +45,13 @@ 7.3.5 provided + + + com.jeff-media + custom-block-data + 2.2.4 + compile + \ No newline at end of file diff --git a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java index ecee2a1f..ae4cc008 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java +++ b/api/src/main/java/net/donnypz/displayentityutils/DisplayAPI.java @@ -27,6 +27,17 @@ public final class DisplayAPI { static NamespacedKey spawnAnimationTypeKey; static NamespacedKey spawnAnimationLoadMethodKey; static NamespacedKey chunkPacketGroupsKey; + static NamespacedKey placeableGroupKey; + static NamespacedKey placeableGroupPermissionKey; + static NamespacedKey placeableGroupRespectFacingKey; + static NamespacedKey placeableGroupRespectBlockFace; + static NamespacedKey placeableGroupPlaceSounds; + static NamespacedKey placeableGroupBreakSounds; + static NamespacedKey placeableGroupDropItem; + static NamespacedKey placeableGroupPlacerBreaksOnly; + static NamespacedKey placeableGroupItemStack; + static NamespacedKey placeableGroupPlacer; + static NamespacedKey placeableGroupId; static boolean isMythicMobsInstalled; static boolean isLibsDisguisesInstalled; @@ -85,10 +96,54 @@ private DisplayAPI(){} return chunkPacketGroupsKey; } - /** - * Used for older versions of DisplayEntityUtils Plugin - * This will NEVER have to be called manually - */ + public static @NotNull NamespacedKey getPlaceableGroupKey(){ + return placeableGroupKey; + } + + + public static @NotNull NamespacedKey getPlaceableGroupPermissionKey(){ + return placeableGroupPermissionKey; + } + + public static @NotNull NamespacedKey getPlaceableGroupRespectPlayerFacing(){ + return placeableGroupRespectFacingKey; + } + + public static @NotNull NamespacedKey getPlaceableGroupRespectBlockFace(){ + return placeableGroupRespectBlockFace; + } + + public static @NotNull NamespacedKey getPlaceableGroupPlaceSounds(){ + return placeableGroupPlaceSounds; + } + + public static @NotNull NamespacedKey getPlaceableGroupBreakSounds(){ + return placeableGroupBreakSounds; + } + + public static @NotNull NamespacedKey getPlaceableGroupPlacerBreaksOnly() { + return placeableGroupPlacerBreaksOnly; + } + + public static @NotNull NamespacedKey getPlaceableGroupDropItem() { + return placeableGroupDropItem; + } + + + public static @NotNull NamespacedKey getPlaceableGroupItemStack(){ + return placeableGroupItemStack; + } + + public static @NotNull NamespacedKey getPlaceableGroupId(){ + return placeableGroupId; + } + + public static @NotNull NamespacedKey getPlaceableGroupPlacer() { + return placeableGroupPlacer; + } + + + @ApiStatus.Internal public static String getLegacyPartTagPrefix(){ return legacyPartTagPrefix; @@ -104,7 +159,7 @@ public static boolean isMythicMobsInstalled() { /** * Get whether LibsDisguises is installed on this server - * @return true if MythicMobs is present + * @return true if LibsDisguises is present */ public static boolean isLibsDisguisesInstalled() { return isLibsDisguisesInstalled; diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/ChunkAddGroupInteractionsEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/ChunkAddGroupEntitiesEvent.java similarity index 50% rename from api/src/main/java/net/donnypz/displayentityutils/events/ChunkAddGroupInteractionsEvent.java rename to api/src/main/java/net/donnypz/displayentityutils/events/ChunkAddGroupEntitiesEvent.java index d1761d47..0a6c9bd7 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/ChunkAddGroupInteractionsEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/ChunkAddGroupEntitiesEvent.java @@ -3,28 +3,29 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; import org.bukkit.Chunk; -import org.bukkit.entity.Interaction; +import org.bukkit.entity.Entity; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.HashSet; /** - * Called when a Chunk adds a {@link SpawnedDisplayEntityPart} of the type {@link SpawnedDisplayEntityPart.PartType#INTERACTION} to an already registered {@link SpawnedDisplayEntityGroup}. + * Called when a Chunk adds a non-display {@link SpawnedDisplayEntityPart} to an already registered {@link SpawnedDisplayEntityGroup}. *

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

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

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

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

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

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

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

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

*/ public class ChunkRegisterGroupEvent extends Event { private static final HandlerList handlers = new HandlerList(); @@ -38,8 +39,6 @@ public Chunk getChunk() { return chunk; } - - @Override public HandlerList getHandlers() { return handlers; diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/GroupSpawnedEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/GroupSpawnedEvent.java index 95de4314..2fa33c7a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/GroupSpawnedEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/GroupSpawnedEvent.java @@ -1,9 +1,15 @@ package net.donnypz.displayentityutils.events; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; +import org.bukkit.Location; +import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; /** @@ -54,7 +60,18 @@ public enum SpawnReason{ */ PLAYER_SENT_CHUNK, PLAYER_SENT_PASSENGER_GROUP, + /** + * This is only applicable to the {@link PacketDisplayEntityGroup} placed by an item, through {@link PlaceableGroupManager#spawnGroup(ItemStack, Location, Player)} or similar + */ + @ApiStatus.Internal + ITEMSTACK, + /** + * This is only applicable to the {@link PacketDisplayEntityGroup} placed by an item, through {@link PlaceableGroupManager#spawnGroup(ItemStack, Location, Player)} or similar + */ + @ApiStatus.Internal + CHUNK_LOAD_PLACED, SKRIPT, + @ApiStatus.Internal INTERNAL; } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/ItemPlaceGroupEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/ItemPlaceGroupEvent.java new file mode 100644 index 00000000..61ffd54e --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/events/ItemPlaceGroupEvent.java @@ -0,0 +1,62 @@ +package net.donnypz.displayentityutils.events; + +import net.donnypz.displayentityutils.managers.PlaceableGroupData; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Called when a player places an {@link ActiveGroup} using an item that + * has an assigned group with {@link PlaceableGroupData}. + */ +public class ItemPlaceGroupEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + ActiveGroup activeGroup; + ItemStack itemStack; + Player player; + + public ItemPlaceGroupEvent(@NotNull ActiveGroup group, @NotNull ItemStack itemStack, @Nullable Player player){ + super(!Bukkit.isPrimaryThread()); + this.activeGroup = group; + this.itemStack = itemStack; + this.player = player; + } + + /** + * Get the {@link ActiveGroup} involved in this event. + * @return a {@link ActiveGroup} + */ + public @NotNull ActiveGroup getGroup() { + return activeGroup; + } + + /** + * Get the {@link ItemStack} invovled in this event. + * @return an item + */ + public @NotNull ItemStack getItemStack() { + return itemStack; + } + + /** + * Get the player involved in this event + * @return a player + */ + public @Nullable Player getPlayer() { + return player; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/PartTranslateEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/PartTranslateEvent.java index 80f4484c..d0aac4fa 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/PartTranslateEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/PartTranslateEvent.java @@ -11,12 +11,13 @@ import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.util.Transformation; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * Called when a {@link Display} or {@link Interaction} changes its translation using methods within the {@link DisplayGroupManager}. - * Can be cancelled + * Called when an entity changes its translation through the {@link DisplayUtils#translate(Display, Vector, double, int, int)} or similar methods. + *
Can be cancelled */ public final class PartTranslateEvent extends Event implements Cancellable { @@ -28,10 +29,6 @@ public final class PartTranslateEvent extends Event implements Cancellable { Transformation oldTransformation; Transformation newTransformation; - /** - * Called when a Display Entity or Interaction Entity changes its translation through the DisplayGroupManager. - * Can be cancelled - */ public PartTranslateEvent(@NotNull Entity entity, Location destination, Transformation oldTransformation, Transformation newTransformation){ this.entity = entity; this.destination = destination; @@ -61,12 +58,7 @@ public boolean isDisplay(){ * @return a {@link SpawnedDisplayEntityPart}, null if this entity is not a part */ public @Nullable SpawnedDisplayEntityPart getEntityAsSpawnedDisplayEntityPart(){ - if (entity instanceof Interaction i){ - return SpawnedDisplayEntityPart.getPart(i); - } - else{ - return SpawnedDisplayEntityPart.getPart((Display) entity); - } + return SpawnedDisplayEntityPart.getPart(entity); } /** @@ -93,19 +85,12 @@ public Location getDestination() { return newTransformation; } - - /** * Get the tag of this entity's group. * @return group tag, null if not grouped */ public String getGroupTag(){ - if (entity instanceof Interaction i){ - return DisplayUtils.getGroupTag(i); - } - else{ - return DisplayUtils.getGroupTag((Display) entity); - } + return DisplayUtils.getGroupTag(entity); } @Override diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/PlacedGroupBreakEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/PlacedGroupBreakEvent.java new file mode 100644 index 00000000..71fb9732 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/events/PlacedGroupBreakEvent.java @@ -0,0 +1,68 @@ +package net.donnypz.displayentityutils.events; + +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +/** + * Called when a group placed by an item is broken by a player. Cancellable + */ +public class PlacedGroupBreakEvent extends Event implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + boolean cancelled = false; + + Block block; + PacketDisplayEntityGroup packetDisplayEntityGroup; + Player player; + + public PlacedGroupBreakEvent(Block block, PacketDisplayEntityGroup packetDisplayEntityGroup, Player player){ + this.block = block; + this.packetDisplayEntityGroup = packetDisplayEntityGroup; + this.player = player; + } + + + /** + * Get the block involved in this event + * @return a block + */ + public Block getBlock() { + return block; + } + + /** + * Get the {@link PacketDisplayEntityGroup} involved in this event + * @return a packet-based group + */ + public PacketDisplayEntityGroup getGroup() { + return packetDisplayEntityGroup; + } + + /** + * Get the player involved in this event + * @return the player + */ + public Player getPlayer() { + return player; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return handlers; + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java new file mode 100644 index 00000000..d454c1db --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/events/PreItemPlaceGroupEvent.java @@ -0,0 +1,72 @@ +package net.donnypz.displayentityutils.events; + +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Called before the stored {@link DisplayEntityGroup} on an item can be spawned when a player places the item's block + */ +public class PreItemPlaceGroupEvent extends Event implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + ItemStack itemStack; + Player player; + + private boolean isCancelled = false; + + public PreItemPlaceGroupEvent(@NotNull ItemStack itemStack, @Nullable Player player){ + super(!Bukkit.isPrimaryThread()); + this.itemStack = itemStack; + this.player = player; + } + + /** + * Get the group tag of the group involved in this event. + * @return the group tag or null + */ + public @Nullable String getGroupTag() { + return PlaceableGroupManager.getGroupTag(itemStack); + } + + /** + * Get the {@link ItemStack} involved in this event. + * @return an {@link ItemStack} + */ + public @NotNull ItemStack getItemStack() { + return itemStack; + } + + /** + * Get the player involved in this event + * @return a player + */ + public @Nullable Player getPlayer() { + return player; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + @Override + public boolean isCancelled() { + return isCancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.isCancelled = cancel; + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/events/PrePacketGroupCreateEvent.java b/api/src/main/java/net/donnypz/displayentityutils/events/PrePacketGroupCreateEvent.java index a542f3b6..80d51c29 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/events/PrePacketGroupCreateEvent.java +++ b/api/src/main/java/net/donnypz/displayentityutils/events/PrePacketGroupCreateEvent.java @@ -3,6 +3,7 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.GroupSpawnSettings; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; @@ -23,6 +24,7 @@ public class PrePacketGroupCreateEvent extends Event implements Cancellable { private boolean isCancelled = false; public PrePacketGroupCreateEvent(DisplayEntityGroup group, GroupSpawnedEvent.SpawnReason spawnReason){ + super(!Bukkit.isPrimaryThread()); this.displayEntityGroup = group; this.spawnReason = spawnReason; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java index dcba35bc..ae3ac37e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DEUUser.java @@ -36,12 +36,13 @@ public class DEUUser { private AnimationParticleBuilder particleBuilder; private final Location[] pointPositions = new Location[3]; private final Set trackedPacketEntities = Collections.newSetFromMap(new ConcurrentHashMap<>()); + private Integer armorEditMannequinEntityId; private PreAnimationCameraData preAnimationCameraData; private final Object animationCameraLock = new Object(); private UUID cameraPlayerUUID; - + private boolean placedGroupBreakMode = false; private DEUUser(UUID userUUID){ @@ -88,6 +89,21 @@ public boolean unsuppressIfEqual(int entityId, @NotNull Vector3f vector3f) { return false; } + @ApiStatus.Internal + public boolean isEditingMannequinArmor(){ + return armorEditMannequinEntityId != null; + } + + @ApiStatus.Internal + public int getEditingMannequin(){ + return armorEditMannequinEntityId; + } + + @ApiStatus.Internal + public void setEditingMannequinArmor(Integer armorEditMannequinEntityId){ + this.armorEditMannequinEntityId = armorEditMannequinEntityId; + } + /** * Set the selected {@link ActiveGroup} of a user * @param activeGroup the group @@ -306,6 +322,22 @@ public boolean isInAnimationCamera(@NotNull UUID cameraPlayerUUID){ } } + /** + * Set whether this user should be able to break any placed group, regardless of who placed it + * @param breakMode whether the break mode should be enabled + */ + public void setPlacedGroupBreakMode(boolean breakMode){ + this.placedGroupBreakMode = breakMode; + } + + /** + * Get whether this user can break any placed group, regardless of who placed it + * @return a boolean + */ + public boolean isInPlacedGroupBreakMode(){ + return this.placedGroupBreakMode; + } + /** * Check if this user is tracking a {@link PacketDisplayEntityPart} * @param part the {@link PacketDisplayEntityPart} @@ -320,6 +352,7 @@ public int getTrackedPacketEntityCount(){ } public @Nullable ActiveGroup getSelectedGroup(){ + if (selectedGroup != null && !selectedGroup.isRegistered()) selectedGroup = null; return selectedGroup; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationInputStream.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationInputStream.java deleted file mode 100644 index 43547b59..00000000 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationInputStream.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.donnypz.displayentityutils.managers; - -import net.donnypz.displayentityutils.utils.DisplayEntities.saved.OldSound; - -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectStreamClass; - -class DisplayAnimationInputStream extends DisplayObjectInputStream{ - DisplayAnimationInputStream(InputStream in) throws IOException { - super(in); - } - - @Override - protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { - ObjectStreamClass desc = super.readClassDescriptor(); - if (desc.getName().equals("org.bukkit.Sound")){ //Because of old sound HashMaps using an enum - //if (VersionUtils.is_1_21_2){ - return ObjectStreamClass.lookup(OldSound.class); - //} - } - return desc; - } -} diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java index c2e92657..28675070 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayAnimationManager.java @@ -252,7 +252,7 @@ private static void attemptCacheAnimation(String tag, SpawnedDisplayAnimation an } try(ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes); GZIPInputStream gzipInputStream = new GZIPInputStream(byteStream); - ObjectInputStream objIn = new DisplayAnimationInputStream(gzipInputStream) + ObjectInputStream objIn = new DisplayObjectInputStream(gzipInputStream) ){ DisplayAnimation anim = (DisplayAnimation) objIn.readObject(); @@ -277,7 +277,7 @@ private static void attemptCacheAnimation(String tag, SpawnedDisplayAnimation an //Not Compressed (Will be an older file version, before gzip compression) catch (ZipException z){ try(ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes); - ObjectInputStream objIn = new DisplayAnimationInputStream(byteStream) + ObjectInputStream objIn = new DisplayObjectInputStream(byteStream) ){ DisplayAnimation anim = (DisplayAnimation) objIn.readObject(); anim.adaptOldSounds(); @@ -384,7 +384,7 @@ private static DisplayAnimation getAnimationFromJson(JsonObject jsonObject){ DisplayGroupManager.deserializeJsonElement(jsonObject); jsonObject.remove(DisplayGroupManager.PLUGIN_VERSION_FIELD); - return DEGJSONAdapter + return DEUJSONAdapter .GSON .fromJson(jsonObject, DisplayAnimation.class); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java index b995b99d..dc6671d7 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayGroupManager.java @@ -136,7 +136,7 @@ public static void removeSpawnedGroup(SpawnedDisplayEntityGroup spawnedGroup, bo Chunk mainChunk = spawnedGroup.getLocation().getChunk(); ticketChunk(mainChunk, chunks); for (SpawnedDisplayEntityPart part : spawnedGroup.getParts()) { - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ //Chunk may be different from main chunk + if (!part.isDisplay()){ //Chunk may be different from main chunk Entity e = part.getEntity(); Chunk c = e.getChunk(); if (c != mainChunk){ @@ -208,7 +208,7 @@ public static boolean saveDisplayEntityGroupJson(@NotNull DisplayEntityGroup dis saveFile.createNewFile(); FileWriter fileWriter = new FileWriter(saveFile); - Gson gson = DEGJSONAdapter.GSON; + Gson gson = DEUJSONAdapter.GSON; JsonElement jsonEl = gson.toJsonTree(displayEntityGroup); JsonObject jsonObj = jsonEl.getAsJsonObject(); @@ -252,22 +252,6 @@ static void serializeJsonElement(JsonElement el) { } } -// if (obj.has(PART_TAG_FIELD)){ -// JsonArray arr = obj.getAsJsonArray(PDC_FIELD); -// if (arr != null){ -// byte[] bytes = new byte[arr.size()]; -// ItemStack stick = new ItemStack(Material.STICK); -// PersistentDataContainer pdc = stick.getItemMeta().getPersistentDataContainer(); -// try{ -// pdc.readFromBytes(bytes); -// List tags = pdc.get(DisplayAPI.getPartPDCTagKey(), PersistentDataType.LIST.strings()); -// obj.add(PART_TAG_FIELD, gson.toJsonTree(tags)); -// } -// catch(IOException e){} -// } -// } - - for (Map.Entry entry : obj.entrySet()) { serializeJsonElement(entry.getValue()); } @@ -488,7 +472,7 @@ private static DisplayEntityGroup getGroupFromJson(JsonObject jsonObject){ deserializeJsonElement(jsonObject); jsonObject.remove(PLUGIN_VERSION_FIELD); - return DEGJSONAdapter + return DEUJSONAdapter .GSON .fromJson(jsonObject, DisplayEntityGroup.class); } @@ -507,8 +491,8 @@ private static DisplayEntityGroup getGroupFromJson(JsonObject jsonObject){ * Get the {@link GroupResult} of a display entity containing its {@link SpawnedDisplayEntityGroup}, if applicable. *
* If a group is created as a result of this, {@link GroupRegisteredEvent} will be called - * - * @param displayEntity The display entity within a group + * @param displayEntity The display entity that's in a group + * @return a {@link GroupResult} or null */ public static @Nullable GroupResult getSpawnedGroup(@NotNull Display displayEntity) { //Check for already registered group @@ -548,26 +532,38 @@ else if (displayEntity.getPassengers().isEmpty()) { /** - * Get a Spawned Display Entity Group through an interaction entity - * - * @param interaction The interaction entity part of a display entity group - * @param radius The radius to check for a spawned display entity group - * @return SpawnedDisplayEntityGroup containing the interaction entity. Null if not found. + * Get a {@link SpawnedDisplayEntityGroup} through an Interaction entity + * @param interaction The interaction + * @param radius The radius to search for the group + * @return a {@link SpawnedDisplayEntityGroup} containing the interaction. Null if not found. */ - public static SpawnedDisplayEntityGroup getSpawnedGroup(@NotNull Interaction interaction, double radius) { + public static @Nullable SpawnedDisplayEntityGroup getSpawnedGroup(@NotNull Interaction interaction, double radius){ //Keep this just to prevent breakage + return getSpawnedGroup((Entity) interaction, radius); + } + + + /** + * Get a {@link SpawnedDisplayEntityGroup} through an eligible part entity + * @param entity The entity that's in a group + * @param radius The radius to search for the group + * @return a {@link SpawnedDisplayEntityGroup} containing the entity. Null if not found. + */ + public static @Nullable SpawnedDisplayEntityGroup getSpawnedGroup(@NotNull Entity entity, double radius) { + if (!DisplayUtils.isPartEntity(entity)) return null; + //Check for existing group - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(interaction); + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); if (part != null && part.getGroup() != null) { return part.getGroup(); } //Get Nearby Groups - List results = getSpawnedGroupsNearLocation(interaction.getLocation(), radius); + List results = getSpawnedGroupsNearLocation(entity.getLocation(), radius); if (results.isEmpty()){ return null; } //Check if Interaction is part of group - part = SpawnedDisplayEntityPart.getPart(interaction); + part = SpawnedDisplayEntityPart.getPart(entity); return part == null ? null : part.getGroup(); } @@ -635,7 +631,7 @@ public static SpawnedDisplayEntityGroup getSpawnedGroup(@NotNull Interaction int continue; } if (addInteractions){ - result.group().addMissingInteractionEntities(DisplayConfig.getMaximumInteractionSearchRange()); + result.group().addMissingEntities(DisplayConfig.getMaximumInteractionSearchRange()); } results.add(result); } @@ -709,9 +705,15 @@ static void addPersistentPacketGroupSilent(@NotNull PacketDisplayEntityGroup gro id = 1; } else{ - id = gson.fromJson(list.getLast(), PersistentPacketGroup.class).id+1; + PersistentPacketGroup ppg = gson.fromJson(list.getLast(), PersistentPacketGroup.class); + if (ppg == null){ + id = list.size()+1; + } + else{ + id = gson.fromJson(list.getLast(), PersistentPacketGroup.class).id+1; + } } - PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, group.isAutoShow()); + PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, group.isAutoShow(), group.isPlaced()); if (cpg == null) return; String json = gson.toJson(cpg); @@ -735,7 +737,7 @@ public static PacketDisplayEntityGroup addPersistentPacketGroup(@NotNull Locatio else{ id = gson.fromJson(list.getLast(), PersistentPacketGroup.class).id+1; } - PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, autoShow); + PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, autoShow, false); if (cpg == null) return null; String json = gson.toJson(cpg); @@ -764,7 +766,7 @@ public static PacketDisplayEntityGroup addPersistentPacketGroup(@NotNull Locatio PacketDisplayEntityGroup pdeg = displayEntityGroup.createPacketGroup(location, spawnReason, true, settings); displayEntityGroup = pdeg.toDisplayEntityGroup(); - PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, pdeg.isAutoShow()); + PersistentPacketGroup cpg = PersistentPacketGroup.create(id, location, displayEntityGroup, pdeg.isAutoShow(), false); if (cpg != null){ String json = gson.toJson(cpg); list.add(json); @@ -864,9 +866,17 @@ public static void removePersistentPacketGroups(@NotNull Chunk chunk){ @ApiStatus.Internal public static void spawnPersistentPacketGroups(@NotNull Chunk chunk){ List list = getChunkList(chunk.getPersistentDataContainer()); - for (String json : list){ + Iterator i = list.iterator(); + + while (i.hasNext()){ + String json = i.next(); PersistentPacketGroup cpg = gson.fromJson(json, PersistentPacketGroup.class); - cpg.spawn(chunk).setPersistentIds(cpg.id, chunk); + if (cpg == null){ + i.remove(); + } + else{ + cpg.spawn(chunk).setPersistentIds(cpg.id, chunk); + } } } @@ -899,10 +909,11 @@ static class PersistentPacketGroup { String groupBase64; String groupTag; boolean autoShow = true; //Don't change + boolean isPlaced = false; private PersistentPacketGroup(){} - static PersistentPacketGroup create(int id, Location location, DisplayEntityGroup group, boolean autoShow){ + static PersistentPacketGroup create(int id, Location location, DisplayEntityGroup group, boolean autoShow, boolean isPlaced){ PersistentPacketGroup cpg = new PersistentPacketGroup(); cpg.id = id; cpg.x = location.x(); @@ -912,6 +923,7 @@ static PersistentPacketGroup create(int id, Location location, DisplayEntityGrou cpg.pitch = location.getPitch(); cpg.groupTag = group.getTag(); cpg.autoShow = autoShow; + cpg.isPlaced = isPlaced; cpg.setGroup(group); return (cpg.groupBase64 == null) ? null : cpg; } @@ -961,7 +973,12 @@ public PacketDisplayEntityGroup spawn(Chunk chunk){ Location spawnLoc = getLocation(chunk); DisplayEntityGroup g = getGroup(); if (spawnLoc == null || g == null) return null; - return g.createPacketGroup(spawnLoc, GroupSpawnedEvent.SpawnReason.INTERNAL, true, autoShow); + if (isPlaced){ + return g.createPacketGroup(spawnLoc, GroupSpawnedEvent.SpawnReason.CHUNK_LOAD_PLACED, true, autoShow); + } + else{ + return g.createPacketGroup(spawnLoc, GroupSpawnedEvent.SpawnReason.INTERNAL, true, autoShow); + } } } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayObjectInputStream.java b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayObjectInputStream.java index 86fa2287..c3921046 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayObjectInputStream.java +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/DisplayObjectInputStream.java @@ -1,5 +1,8 @@ package net.donnypz.displayentityutils.managers; +import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; +import net.donnypz.displayentityutils.utils.DisplayEntities.saved.OldSound; + import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; @@ -7,7 +10,10 @@ class DisplayObjectInputStream extends ObjectInputStream { - private static final String oldPackage = "com.pzdonny"; + private static final String OLD_PACKAGE = "com.pzdonny"; + private static final String NEW_PACKAGE = "net.donnypz"; + private static final String BUKKIT_SOUND_ENUM = "org.bukkit.Sound"; + private static final String ANIMATION_SOUND = "AnimationSound"; DisplayObjectInputStream(InputStream in) throws IOException { super(in); } @@ -17,10 +23,22 @@ protected Class resolveClass(ObjectStreamClass desc) throws ClassNotFoundExce //Convert Old Serialized Objects with new package name String name = desc.getName(); - if (name.startsWith(oldPackage)) { - name = "net.donnypz" + name.substring(oldPackage.length()); + if (name.startsWith(OLD_PACKAGE)) { + name = NEW_PACKAGE + name.substring(OLD_PACKAGE.length()); } - return Class.forName(name); } + + @Override + protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { + ObjectStreamClass desc = super.readClassDescriptor(); + String name = desc.getName(); + if (name.equals(BUKKIT_SOUND_ENUM)){ //Because of old sound HashMaps using an enum + return ObjectStreamClass.lookup(OldSound.class); + } + if (name.endsWith(ANIMATION_SOUND)){ + return ObjectStreamClass.lookup(DEUSound.class); + } + return desc; + } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java new file mode 100644 index 00000000..b8a9d5f7 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupData.java @@ -0,0 +1,143 @@ +package net.donnypz.displayentityutils.managers; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; +import net.donnypz.displayentityutils.utils.DisplayEntities.DisplayEntityGroup; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; + + +/** + * Assign a {@link DisplayEntityGroup} that will spawn where an {@link ItemStack}, of a block type, is placed. + */ +public class PlaceableGroupData { + + String groupTag; + String permission; + boolean respectPlayerFacing = true; + boolean respectBlockFace = true; + boolean dropItemOnBreak = true; + boolean placerBreaksOnly = true; + ArrayList placeSounds = new ArrayList<>(); + ArrayList breakSounds = new ArrayList<>(); + + + public PlaceableGroupData(@NotNull String groupTag) { + this.groupTag = groupTag; + } + + /** + * Set the group that should be spawned when the block is placed + * @param groupTag the group's tag + * @return this + */ + public PlaceableGroupData setGroupTag(@NotNull String groupTag){ + this.groupTag = groupTag; + return this; + } + + /** + * Set the required permission to spawn the group when the block is placed + * @param permission the permission + * @return this + */ + public PlaceableGroupData setPermission(@Nullable String permission) { + this.permission = permission; + return this; + } + + + /** + * Set whether the group should spawn with respect to the player's facing direction. True by default + * @param respectPlayerFacing whether the group should respect the player's facing direction + * @return this + */ + public PlaceableGroupData setRespectPlayerFacing(boolean respectPlayerFacing) { + this.respectPlayerFacing = respectPlayerFacing; + return this; + } + + /** + * Set whether the group associated with the given item should spawn with respect to the block face its placed on. True by default + * @param respectBlockFace whether the group should respect the block face its placed on + * @return this + */ + public PlaceableGroupData setRespectBlockFace(boolean respectBlockFace) { + this.respectBlockFace = respectBlockFace; + return this; + } + + /** + * Set whether the item used to place the group should be dropped when the group is destroyed + * @param dropItemOnBreak + * @return this + */ + public PlaceableGroupData setDropItemOnBreak(boolean dropItemOnBreak){ + this.dropItemOnBreak = dropItemOnBreak; + return this; + } + + /** + * Set whether only the placer of the group is the one who can break it + * @param placerBreaksOnly + * @return this + */ + public PlaceableGroupData setPlacerBreaksOnly(boolean placerBreaksOnly){ + this.placerBreaksOnly = placerBreaksOnly; + return this; + } + + + /** + * Add a sound to play when the group is placed or removed/broken + * @param sound the sound + * @param isPlace whether the sound should play when placed or removed/broken + */ + public PlaceableGroupData addSound(@NotNull DEUSound sound, boolean isPlace){ + if (isPlace){ + placeSounds.add(sound); + } + else{ + breakSounds.add(sound); + } + return this; + } + + /** + * Apply the data to a provided itemstack, spawning the group when placed + * @param itemStack + * @throws IllegalArgumentException if the itemstack is not of a block type + */ + public void apply(@NotNull ItemStack itemStack){ + if (!PlaceableGroupManager.isValidItem(itemStack)){ + throw new IllegalArgumentException("The provided ItemStack is not of a block type"); + } + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + + pdc.set(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING, groupTag); + + if (permission != null){ + pdc.set(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING, permission); + } + + pdc.set(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN, respectPlayerFacing); + pdc.set(DisplayAPI.getPlaceableGroupRespectBlockFace(), PersistentDataType.BOOLEAN, respectBlockFace); + + + pdc.set(DisplayAPI.getPlaceableGroupPlacerBreaksOnly(), PersistentDataType.BOOLEAN, placerBreaksOnly); + pdc.set(DisplayAPI.getPlaceableGroupDropItem(), PersistentDataType.BOOLEAN, dropItemOnBreak); + + pdc.set(DisplayAPI.getPlaceableGroupPlaceSounds(), PersistentDataType.BYTE_ARRAY, + PlaceableGroupManager.writeSoundList(placeSounds)); + pdc.set(DisplayAPI.getPlaceableGroupBreakSounds(), PersistentDataType.BYTE_ARRAY, + PlaceableGroupManager.writeSoundList(breakSounds)); + itemStack.setItemMeta(meta); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java new file mode 100644 index 00000000..01915938 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/managers/PlaceableGroupManager.java @@ -0,0 +1,591 @@ +package net.donnypz.displayentityutils.managers; + +import com.jeff_media.customblockdata.CustomBlockData; +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.events.GroupSpawnedEvent; +import net.donnypz.displayentityutils.events.ItemPlaceGroupEvent; +import net.donnypz.displayentityutils.events.PreItemPlaceGroupEvent; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import org.bukkit.*; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Quaternionf; + +import java.io.*; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.UUID; + +public final class PlaceableGroupManager { + + private PlaceableGroupManager(){} + + /** + * Set the group that will spawn where an itemstack of a block type is placed. + * @param itemStack the itemstack + * @param group the group + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void setGroup(@NotNull ItemStack itemStack, @NotNull DisplayEntityGroup group){ + setGroup(itemStack, group.getTag()); + } + + /** + * Set the group that will spawn where an itemstack of a block type is placed. + * @param itemStack the itemstack + * @param groupTag the group's tag + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied through a {@link PlaceableGroupData} + */ + public static void setGroup(@NotNull ItemStack itemStack, @NotNull String groupTag){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + pdc.set(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING, groupTag); + itemStack.setItemMeta(meta); + } + + + /** + * Set the permission a player needs to place an itemstack's assigned group. Set the permission to {@code null} to unset it + * @param itemStack the item + * @param placePermission the permission + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void setPlacePermission(@NotNull ItemStack itemStack, @Nullable String placePermission){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + if (placePermission == null){ + pdc.remove(DisplayAPI.getPlaceableGroupPermissionKey()); + } + else{ + pdc.set(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING, placePermission); + } + itemStack.setItemMeta(meta); + } + + /** + * Set whether the group associated with the given item should spawn with respect to the player's facing direction + * @param itemStack the item + * @param respect whether the group should respect the player's facing direction + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void setRespectPlayerFacing(@NotNull ItemStack itemStack, boolean respect){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + pdc.set(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN, respect); + itemStack.setItemMeta(meta); + } + + /** + * Set whether the group associated with the given item should spawn with respect to the block face its placed on + * @param itemStack the item + * @param respect whether the group should respect the block face its placed on + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void setRespectBlockFace(@NotNull ItemStack itemStack, boolean respect){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + pdc.set(DisplayAPI.getPlaceableGroupRespectBlockFace(), PersistentDataType.BOOLEAN, respect); + itemStack.setItemMeta(meta); + } + + /** + * Set whether the item used to place the group should be dropped when the group is broken + * @param itemStack the item + * @param dropItem + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void setDropItemOnBreak(@NotNull ItemStack itemStack, boolean dropItem){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + pdc.set(DisplayAPI.getPlaceableGroupDropItem(), PersistentDataType.BOOLEAN, dropItem); + itemStack.setItemMeta(meta); + } + + /** + * Set whether only the placer of the group can break the group + * @param itemStack the item + * @param placerBreaksOnly + */ + public static void setPlacerBreaksOnly(@NotNull ItemStack itemStack, boolean placerBreaksOnly){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + pdc.set(DisplayAPI.getPlaceableGroupPlacerBreaksOnly(), PersistentDataType.BOOLEAN, placerBreaksOnly); + itemStack.setItemMeta(meta); + } + + /** + * Add a sound to play when the given item's assigned group is placed or removed/broken + * @param itemStack the sound's index + * @param sound the sound + * @param isPlace whether the sound should play when placed or removed/broken + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void addSound(@NotNull ItemStack itemStack, @NotNull DEUSound sound, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + List sounds = getSounds(pdc, isPlace); + sounds.add(sound); + + pdc.set(getSoundKey(isPlace), PersistentDataType.BYTE_ARRAY, writeSoundList(sounds)); + itemStack.setItemMeta(meta); + } + + /** + * Remove a sound to placed when the given item's assigned group is placed or removed/broken + * @param itemStack the item + * @param index the sound's index + * @param isPlace whether to remove a place or remove/break sound + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void removeSound(@NotNull ItemStack itemStack, int index, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + List sounds = getSounds(pdc, isPlace); + sounds.remove(index); + + pdc.set(getSoundKey(isPlace), PersistentDataType.BYTE_ARRAY, writeSoundList(sounds)); + itemStack.setItemMeta(meta); + } + + /** + * Remove a sound to placed when the given item's assigned group is placed or removed/broken + * @param itemStack the item + * @param sound the sound + * @param isPlace whether to remove a place or remove/break sound + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void removeSound(@NotNull ItemStack itemStack, @NotNull DEUSound sound, boolean isPlace){ + removeSound(itemStack, sound.getSoundName(), sound.getVolume(), sound.getPitch(), isPlace); + } + + /** + * Remove a sound to placed when the given item's assigned group is placed or removed/broken + * @param itemStack the item + * @param sound the sound + * @param isPlace whether to remove a place or remove/break sound + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void removeSound(@NotNull ItemStack itemStack, @NotNull Sound sound, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + List sounds = getSounds(pdc, isPlace); + sounds.removeIf(s -> sound == s.getSound()); + + pdc.set(getSoundKey(isPlace), PersistentDataType.BYTE_ARRAY, writeSoundList(sounds)); + itemStack.setItemMeta(meta); + } + + /** + * Remove a sound to placed when the given item's assigned group is placed or removed/broken + * @param itemStack the item + * @param sound the sound + * @param isPlace whether to remove a place or remove/break sound + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void removeSound(@NotNull ItemStack itemStack, @NotNull String sound, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + List sounds = getSounds(pdc, isPlace); + sounds.removeIf(s -> s.getSoundName().equalsIgnoreCase(sound)); + + pdc.set(getSoundKey(isPlace), PersistentDataType.BYTE_ARRAY, writeSoundList(sounds)); + itemStack.setItemMeta(meta); + } + + /** + * Remove a sound to placed when the given item's assigned group is placed or removed/broken + * @param itemStack the item + * @param sound the sound + * @param isPlace whether to remove a place or remove/break sound + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void removeSound(@NotNull ItemStack itemStack, @NotNull String sound, float volume, float pitch, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + List sounds = getSounds(pdc, isPlace); + sounds.removeIf(s -> + s.getSoundName().equalsIgnoreCase(sound) + && s.getVolume() == volume + && s.getPitch() == pitch + ); + + pdc.set(getSoundKey(isPlace), PersistentDataType.BYTE_ARRAY, writeSoundList(sounds)); + itemStack.setItemMeta(meta); + } + + /** + * Remove a sound to placed when the given item's assigned group is placed or removed/broken + * @param itemStack the item + * @param isPlace whether to remove place or remove/break sounds + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void removeAllSounds(@NotNull ItemStack itemStack, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + pdc.remove(getSoundKey(isPlace)); + itemStack.setItemMeta(meta); + } + + /** + * Get the {@link DEUSound}s added to an item that will play when the item is placed or removed/broken + * @param itemStack the item + * @param isPlace whether to get place or break sounds + * @return a {@link DEUSound} list + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static @NotNull List getSounds(@NotNull ItemStack itemStack, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + return getSounds(pdc, isPlace); + } + + private static List getSounds(PersistentDataContainer pdc, boolean isPlace){ + NamespacedKey key = getSoundKey(isPlace); + byte[] soundArr = pdc.get(key, PersistentDataType.BYTE_ARRAY); + return soundArr == null ? new ArrayList<>() : readSoundList(soundArr); + } + + + /** + * + * @param itemStack the item + * @param location where the sounds should play + * @param isPlace whether to play place or break sounds + * @throws IllegalArgumentException if the provided itemstack did not already have placeable group data applied with {@link PlaceableGroupData} + */ + public static void playSounds(@NotNull ItemStack itemStack, @NotNull Location location, boolean isPlace){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + checkExistingData(pdc); + + for (DEUSound sound : getSounds(pdc, isPlace)){ + sound.playSound(location); + } + } + + private static NamespacedKey getSoundKey(boolean isPlace){ + return isPlace ? DisplayAPI.getPlaceableGroupPlaceSounds() : DisplayAPI.getPlaceableGroupBreakSounds(); + } + + @ApiStatus.Internal + public static byte[] writeSoundList(List sounds) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(baos); + + out.writeInt(sounds.size()); + for (DEUSound sound : sounds) { + sound.writeExternal(out); + } + + out.flush(); + return baos.toByteArray(); + } catch (IOException e) { + throw new RuntimeException("Failed to write DEUSound list", e); + } + } + + private static List readSoundList(byte[] data) { + try { + ObjectInputStream in = + new ObjectInputStream(new ByteArrayInputStream(data)); + + int size = in.readInt(); + List sounds = new ArrayList<>(size); + + for (int i = 0; i < size; i++) { + DEUSound sound = new DEUSound(); + sound.readExternal(in); + sounds.add(sound); + } + + return sounds; + } catch (IOException | ClassNotFoundException e) { + throw new RuntimeException("Failed to read DEUSound list", e); + } + } + + private static void checkExistingData(PersistentDataContainer pdc){ + if (!pdc.has(DisplayAPI.getPlaceableGroupKey())) throw new IllegalArgumentException("ItemStack was never provided PlaceableGroupData"); + } + + /** + * Unassign a {@link DisplayEntityGroup} from an {@link ItemStack} + * @param itemStack the item + */ + public static void unassign(@NotNull ItemStack itemStack){ + ItemMeta meta = itemStack.getItemMeta(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + pdc.remove(DisplayAPI.getPlaceableGroupKey()); + pdc.remove(DisplayAPI.getPlaceableGroupPermissionKey()); + pdc.remove(DisplayAPI.getPlaceableGroupRespectPlayerFacing()); + pdc.remove(DisplayAPI.getPlaceableGroupRespectBlockFace()); + pdc.remove(DisplayAPI.getPlaceableGroupPlaceSounds()); + pdc.remove(DisplayAPI.getPlaceableGroupBreakSounds()); + pdc.remove(DisplayAPI.getPlaceableGroupPlacerBreaksOnly()); + pdc.remove(DisplayAPI.getPlaceableGroupDropItem()); + itemStack.setItemMeta(meta); + } + + /** + * Check if an item has an assigned {@link DisplayEntityGroup} + * @param itemStack the item + * @return a boolean + */ + public static boolean hasData(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return pdc.has(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING); + } + + /** + * Get the tag of the group assigned to an {@link ItemStack} + * @param itemStack the item + * @return the group's tag or null + */ + public static @Nullable String getGroupTag(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return pdc.get(DisplayAPI.getPlaceableGroupKey(), PersistentDataType.STRING); + } + + /** + * Get the {@link DisplayEntityGroup} assigned to an {@link ItemStack} based on the group tag stored on the item + * @param itemStack the item + * @return the {@link DisplayEntityGroup} or null if the group doesn't exist or if the item doesn't have placeable group data + */ + public static @Nullable DisplayEntityGroup getGroup(@NotNull ItemStack itemStack){ + String tag = getGroupTag(itemStack); + return tag == null ? null : DisplayGroupManager.getGroup(tag); + } + + + + /** + * Check if an itemstack has a place permission, determining if a player can place its assigned group + * @param itemStack the itemstack + * @return a boolean + */ + public static boolean hasPlacePermission(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return pdc.has(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING); + } + + /** + * Get the permission that determines whether a player can place an itemstack's assigned group + * @param itemStack the item + * @return the permission or null if the item doesn't have placeable group data + */ + public static @Nullable String getPlacePermission(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return pdc.get(DisplayAPI.getPlaceableGroupPermissionKey(), PersistentDataType.STRING); + } + + /** + * Get whether the group associated with the given item will respect the player's facing direction + * @param itemStack the item + * @return a boolean + */ + public static boolean isRespectingPlayerFacing(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupRespectPlayerFacing(), PersistentDataType.BOOLEAN)); + } + + /** + * Get whether the group associated with the given item will respect the block face its placed on + * @param itemStack the item + * @return a boolean + */ + public static boolean isRespectingBlockFace(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupRespectBlockFace(), PersistentDataType.BOOLEAN)); + } + + /** + * Get whether only the placer of a placed group can break it + * @param itemStack the item + * @return a boolean + */ + public static boolean isPlacerBreaksOnly(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupPlacerBreaksOnly(), PersistentDataType.BOOLEAN)); + } + + /** + * Get whether the itemstack used to place a group will drop when the group is broken + * @param itemStack the item + * @return a boolean + */ + public static boolean isDropItem(@NotNull ItemStack itemStack){ + PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); + return Boolean.TRUE.equals(pdc.get(DisplayAPI.getPlaceableGroupDropItem(), PersistentDataType.BOOLEAN)); + } + + /** + * Check if the given player has permission to place the itemstack's assigned group + * @param itemStack the item + * @param player the player + * @return a boolean + */ + public static boolean canPlace(@NotNull ItemStack itemStack, @NotNull Player player){ + String placePerm = getPlacePermission(itemStack); + if (placePerm == null) return true; + return player.hasPermission(placePerm); + } + + + /** + * Spawn the placeable group stored on an item + * @param itemStack the item + * @param spawnLocation the spawn location + * @return a {@link PacketDisplayEntityGroup} or null if the itemstack does not contain placeable group data, or if the {@link PreItemPlaceGroupEvent} is cancelled + */ + public static @Nullable PacketDisplayEntityGroup spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @Nullable Player itemHolder){ + return spawnGroup(itemStack, spawnLocation, new Quaternionf(), itemHolder); + } + + /** + * Spawn the placeable group stored on an item + * @param itemStack the item + * @param spawnLocation the spawn location + * @return a {@link PacketDisplayEntityGroup}, or null if the itemstack does not contain placeable group data or if the {@link PreItemPlaceGroupEvent} is cancelled + */ + public static @Nullable PacketDisplayEntityGroup spawnGroup(@NotNull ItemStack itemStack, @NotNull Location spawnLocation, @NotNull Quaternionf rotation, @Nullable Player itemHolder){ + String tag = getGroupTag(itemStack); + if (tag == null) return null; + + DisplayEntityGroup group = DisplayGroupManager.getGroup(tag); + if (group == null) return null; + + PacketDisplayEntityGroup pg = group.createPacketGroup(spawnLocation, GroupSpawnedEvent.SpawnReason.ITEMSTACK, true, true); + if (pg == null) return null; + pg.rotateDisplays(rotation); + pg.setPersistent(true); + + Bukkit.getScheduler().runTask(DisplayAPI.getPlugin(), () -> { + setBlockData(itemHolder, spawnLocation.getBlock(), itemStack.clone(), pg.getPersistentGlobalId()); + new ItemPlaceGroupEvent(pg, itemStack, itemHolder).callEvent(); + }); + + return pg; + } + + + /** + * Get the UUID of the player who placed a group + * @param group the placed group + * @return a {@link UUID} or null if the group wasn't placed with an item or if a placer wasn't specified + */ + public static @Nullable UUID getWhoPlaced(@NotNull PacketDisplayEntityGroup group){ + if (!group.isPlaced()) return null; + + Location loc = group.getLocation(); + if (loc == null) return null; + + return getWhoPlaced(loc.getBlock()); + } + + /** + * Get the UUID of the player who placed a group + * @param block the block where a placed group is + * @return a {@link UUID} or null if the group wasn't placed with an item or if a placer wasn't specified + */ + public static @Nullable UUID getWhoPlaced(@NotNull Block block){ + if (!CustomBlockData.hasCustomBlockData(block, DisplayAPI.getPlugin())) return null; + CustomBlockData data = new CustomBlockData(block, DisplayAPI.getPlugin()); + String uuidStr = data.get(DisplayAPI.getPlaceableGroupPlacer(), PersistentDataType.STRING); + return uuidStr == null ? null : UUID.fromString(uuidStr); + } + + /** + * Get the ItemStack used to place a group + * @param group the placed group + * @return an item or null if the group wasn't placed with an item + */ + public static @Nullable ItemStack getItemStack(@NotNull PacketDisplayEntityGroup group){ + if (!group.isPlaced()) return null; + + Location loc = group.getLocation(); + if (loc == null) return null; + + return getItemStack(loc.getBlock()); + } + + /** + * Get the ItemStack used to place a group + * @param block the block where a placed group is + * @return an item or null if the group wasn't placed with an item + */ + public static @Nullable ItemStack getItemStack(@NotNull Block block){ + if (!CustomBlockData.hasCustomBlockData(block, DisplayAPI.getPlugin())) return null; + CustomBlockData data = new CustomBlockData(block, DisplayAPI.getPlugin()); + + String b64 = data.get(DisplayAPI.getPlaceableGroupItemStack(), PersistentDataType.STRING); + return ItemStack.deserializeBytes(Base64.getDecoder().decode(b64)); + } + + /** + * Get the {@link PacketDisplayEntityGroup} placed at a block + * @param block the block where a placed group is + * @return an {@link PacketDisplayEntityGroup} or null + */ + public static @Nullable PacketDisplayEntityGroup getPlacedGroup(@NotNull Block block){ + if (!CustomBlockData.hasCustomBlockData(block, DisplayAPI.getPlugin())) return null; + CustomBlockData data = new CustomBlockData(block, DisplayAPI.getPlugin()); + + String id = data.get(DisplayAPI.getPlaceableGroupId(), PersistentDataType.STRING); + return PacketDisplayEntityGroup.getGroup(id); + } + + private static void setBlockData(Player itemHolder, Block block, ItemStack itemStack, String groupID){ + block.setType(Material.BARRIER); + PersistentDataContainer pdc = new CustomBlockData(block, DisplayAPI.getPlugin()); + pdc.set(DisplayAPI.getPlaceableGroupId(), PersistentDataType.STRING, groupID); + + itemStack.setAmount(1); + String b64 = Base64.getEncoder().encodeToString(itemStack.serializeAsBytes()); + pdc.set(DisplayAPI.getPlaceableGroupItemStack(), PersistentDataType.STRING, b64); + if (itemHolder != null) pdc.set(DisplayAPI.getPlaceableGroupPlacer(), PersistentDataType.STRING, itemHolder.getUniqueId().toString()); + } + + + /** + * Get whether an itemstack can be used to place groups + * @param itemStack the itemstack + * @return a boolean + */ + public static boolean isValidItem(@NotNull ItemStack itemStack){ + return itemStack.getType() != Material.AIR && itemStack.getType().isBlock(); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/Direction.java b/api/src/main/java/net/donnypz/displayentityutils/utils/Direction.java index 30cc3be0..0fc2195e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/Direction.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/Direction.java @@ -1,10 +1,9 @@ package net.donnypz.displayentityutils.utils; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; import org.bukkit.Location; +import org.bukkit.entity.Display; import org.bukkit.entity.Entity; -import org.bukkit.entity.Interaction; import org.bukkit.util.Vector; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -89,8 +88,8 @@ else if (this != FORWARD && this != BACK){ * @return A vector */ public Vector getVector(@NotNull Entity entity, boolean localSpace) { - boolean isInteraction = entity instanceof Interaction; - return getVector(entity.getLocation(), localSpace && !isInteraction); + boolean isDisplay = entity instanceof Display; + return getVector(entity.getLocation(), localSpace && isDisplay); } /** @@ -99,8 +98,7 @@ public Vector getVector(@NotNull Entity entity, boolean localSpace) { * @return A vector */ public Vector getVector(@NotNull ActivePart part, boolean localSpace) { - boolean isInteraction = part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION; - return getVector(part.getLocation(), localSpace && !isInteraction); + return getVector(part.getLocation(), localSpace && part.isDisplay()); } /** diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java index ded292db..284d522a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActiveGroup.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.Quaternionf; import java.util.*; @@ -60,6 +61,13 @@ public ActiveGroup addPlayerSelection(Player player){ */ public abstract void addPart(T part); + /** + * Add an entity to this group as a part, when you don't know the type of entity you're dealing with + * @param entity the eligible entity to add + * @return a corresponding part or null if the entity is not an eligible part entity + */ + public abstract @Nullable T addEntity(@NotNull Entity entity); + /** * Get this group's tag @@ -125,10 +133,10 @@ public void removeCulling(){ * Change the scale of all parts in this group by the given scale multiplier * @param newScaleMultiplier the scale multiplier to apply to this group * @param durationInTicks how long it should take for the group to scale - * @param scaleInteractions whether interaction entities should be scaled + * @param scaleNonDisplays whether non-display entities should scale * @throws IllegalArgumentException if newScaleMultiplier is less than or equal to 0 */ - public abstract boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleInteractions); + public abstract boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleNonDisplays); /** * Change the true location of this group. @@ -138,6 +146,31 @@ public void removeCulling(){ */ public abstract boolean teleport(@NotNull Location location, boolean respectGroupDirection); + + /** + * Teleport this group in the given direction. + * @param direction The direction to translate the group + * @param distance How far the group should be translated + * @return true if the teleport was successful + */ + public boolean teleport(@NotNull Direction direction, double distance){ + return teleport(direction.getVector(masterPart, false), distance); + } + + /** + * Teleport this group in the given vector's direction. + * @param direction The direction to translate the group + * @param distance How far the group should be translated + * @return true if the teleport was successful + */ + public boolean teleport(@NotNull Vector direction, double distance){ + Location l = getLocation(); + if (l == null) return false; + l.add(direction.clone().normalize().multiply(distance)); + teleport(l, true); + return true; + } + /** * Move the model through smooth teleportation of both interaction and display entities. Doing this multiple times in a short amount of time may bring unexpected results. * @param direction The direction to translate the group @@ -154,7 +187,7 @@ public void teleportMove(@NotNull Direction direction, double distance, int dura * @param distance How far the group should be translated * @param durationInTicks How long it should take for the translation to complete */ - public abstract void teleportMove(Vector direction, double distance, int durationInTicks); + public abstract void teleportMove(@NotNull Vector direction, double distance, int durationInTicks); /** * Set the teleportation duration of all parts in this group @@ -188,15 +221,25 @@ public void setInterpolationDelay(int interpolationDelay){ } } + /** + * Rotate the display entities in this group + * @param rotation the rotation + */ + public void rotateDisplays(@NotNull Quaternionf rotation){ + for (ActivePart p : groupParts.values()){ + p.rotateDisplay(rotation, true); + } + } + /** * Change the yaw of this group * @param yaw The yaw to set for this group - * @param pivotInteractions true if interactions should pivot around the group with the yaw change + * @param pivot whether non-display entities should pivot around the group */ @Override - public void setYaw(float yaw, boolean pivotInteractions){ + public void setYaw(float yaw, boolean pivot){ for (ActivePart part : groupParts.values()){ - part.setYaw(yaw, pivotInteractions); + part.setYaw(yaw, pivot); } } @@ -300,9 +343,7 @@ public void glow(long durationInTicks){ @Override public void glow(@NotNull Player player, long durationInTicks){ for (ActivePart part : groupParts.values()){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION || part.type == SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY){ - continue; - } + if (!part.canGlow()) continue; if (!part.isGlowing()){ part.glow(player, durationInTicks); } @@ -441,7 +482,7 @@ public List getParts(@NotNull SpawnedDisplayEntityPart.PartType partType){ public List getDisplayParts(){ List partList = new ArrayList<>(); for (T part : groupParts.sequencedValues()){ - if (part.type != SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (part.isDisplay()){ partList.add(part); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java index 37a529bc..451b9628 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/ActivePart.java @@ -1,5 +1,7 @@ package net.donnypz.displayentityutils.utils.DisplayEntities; +import com.destroystokyo.paper.profile.PlayerProfile; +import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.DisplayConfig; import net.donnypz.displayentityutils.events.GroupSpawnedEvent; @@ -15,19 +17,22 @@ import org.bukkit.Location; import org.bukkit.block.data.BlockData; import org.bukkit.entity.*; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.MainHand; import org.bukkit.util.Transformation; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; +import org.joml.Quaternionf; import org.joml.Vector3f; import java.util.*; import java.util.concurrent.ConcurrentHashMap; public abstract class ActivePart implements Active{ - private static final ConcurrentHashMap partsById = new ConcurrentHashMap<>(); + protected static final ConcurrentHashMap partsById = new ConcurrentHashMap<>(); protected SpawnedDisplayEntityPart.PartType type; protected UUID partUUID; private int entityId; @@ -35,9 +40,9 @@ public abstract class ActivePart implements Active{ private boolean valid = true; final Set clientAnimationPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>()); - protected ActivePart(int entityId, boolean mapped){ + protected ActivePart(int entityId, boolean autoMap){ this.entityId = entityId; - if (mapped) { + if (autoMap) { partsById.put(entityId, this); } } @@ -157,6 +162,12 @@ public boolean hasTag(@NotNull String tag){ public abstract boolean hasGroup(); + /** + * Teleport this part to the given location. This will fail if the part is a display entity, in a group, and is not the group's master part. + * @param location the teleport location + */ + public abstract void teleport(@NotNull Location location); + public abstract @Nullable Location getLocation(); protected abstract void cull(float width, float height); @@ -168,7 +179,7 @@ public boolean hasTag(@NotNull String tag){ * @param heightAdder The amount of height to be added to the culling range */ public void autoCull(float widthAdder, float heightAdder){ - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; + if (!isDisplay()) return; Transformation transformation = getTransformation(); if (transformation == null) return; DisplayAPI.getScheduler().partRunAsync(this, () -> { @@ -187,13 +198,29 @@ public SpawnedDisplayEntityPart.PartType getType(){ return type; } + /** + * Get whether this part will visually glow if glowing is applied to it + * @return a boolean + */ + public boolean canGlow(){ + return type != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY + && type != SpawnedDisplayEntityPart.PartType.INTERACTION; + } + + public boolean isDisplay(){ + return type == SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY + || type == SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY + || type == SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY; + } + /** * Make this part glow for a player * @param player the player */ public void glow(@NotNull Player player){ - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - PacketUtils.setGlowing(player, getEntityId(), true); + if (canGlow()){ + PacketUtils.setGlowing(player, getEntityId(), true); + } } /** @@ -202,9 +229,8 @@ public void glow(@NotNull Player player){ */ @Override public void glow(long durationInTicks){ - if (type == SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY || type == SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY){ + if (canGlow()){ glow(); - DisplayAPI.getScheduler().partRunLater(this, this::unglow, durationInTicks); } } @@ -217,7 +243,7 @@ public void glow(long durationInTicks){ */ @Override public void glow(@NotNull Player player, long durationInTicks){ - if (type == SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY || type == SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY){ + if (canGlow()){ if (durationInTicks <= -1){ PacketUtils.setGlowing(player, getEntityId(), true); } @@ -267,7 +293,7 @@ public void markInteraction(@NotNull Player player, long durationInTicks){ */ @Override public void unglow(@NotNull Player player) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; + if (!canGlow()) return; PacketUtils.setGlowing(player, getEntityId(), false); } @@ -309,34 +335,41 @@ public void unglow(@NotNull Player player) { public abstract void setTransformationMatrix(@NotNull Matrix4f matrix); /** - * Change the X scale of this part - * @param scale The X scale to set for this part - * @return false if this part is an Interaction + * Change this display entity part's X scale + * @param scale The X scale to set + * @return false if this part is not a display entity + */ + public abstract boolean setDisplayXScale(float scale); + + /** + * Change this display entity part's Y scale + * @param scale The Y scale to set + * @return false if this part is not a display entity */ - public abstract boolean setXScale(float scale); + public abstract boolean setDisplayYScale(float scale); /** - * Change the Y scale of this part - * @param scale The Y scale to set for this part - * @return false if this part is an Interaction + * Change this display entity part's Z scale + * @param scale The Z scale to set + * @return false if this part is not a display entity */ - public abstract boolean setYScale(float scale); + public abstract boolean setDisplayZScale(float scale); /** - * Change the Z scale of this part - * @param scale The Z scale to set for this part - * @return false if this part is an Interaction + * Change this display entity part's scale + * @param x The X scale to set + * @param y The Y scale to set + * @param z The Z scale to set + * @return false if this part is not a display entity */ - public abstract boolean setZScale(float scale); + public abstract boolean setDisplayScale(float x, float y, float z); /** - * Change the scale of this part - * @param x The X scale to set for this part - * @param y The Y scale to set for this part - * @param z The Z scale to set for this part - * @return false if this part is an Interaction + * Rotate this display entity part by a given quaternion + * @param rotation the rotation + * @param rotateTranslation whether the display's translation should be rotated, pivoting it around the entity's location */ - public abstract boolean setScale(float x, float y, float z); + public abstract void rotateDisplay(@NotNull Quaternionf rotation, boolean rotateTranslation); /** * Set the text of this part if its type is {@link SpawnedDisplayEntityPart.PartType#TEXT_DISPLAY}. @@ -410,6 +443,8 @@ public void unglow(@NotNull Player player) { */ public abstract void setItemDisplayItemGlint(boolean hasGlint); + public abstract boolean hasItemDisplayItemGlint(); + public abstract @Nullable Component getTextDisplayText(); public abstract int getTextDisplayLineWidth(); @@ -473,11 +508,19 @@ public void unglow(@NotNull Player player) { public abstract int getTeleportDuration(); /** - * Get the interaction translation of this part, relative to its group's location - * group's location only if the part's type is {@link SpawnedDisplayEntityPart.PartType#INTERACTION}. - * @return a {@link Vector} or null if the part is not an Interaction, or if the part is ungrouped + * Get the translation of this non-display entity part, relative to its group's location + * @return a {@link Vector} or null if the part is a display entity, or if the part is ungrouped */ - public abstract @Nullable Vector getInteractionTranslation(); + public abstract @Nullable Vector getNonDisplayTranslation(); + + + public abstract void setCustomName(@Nullable Component text); + + public abstract void setCustomNameVisible(boolean visible); + + public abstract @Nullable Component getCustomName(); + + public abstract boolean isCustomNameVisible(); public abstract void setInteractionHeight(float height); @@ -504,74 +547,145 @@ public void unglow(@NotNull Player player) { public abstract boolean isInteractionResponsive(); /** - * Adds a command to this part to execute when clicked, if its type is {@link SpawnedDisplayEntityPart.PartType#INTERACTION} - * @param command The command to assign - * @param isLeftClick whether the command is executed on left click - * @param isConsole whether the command should be executed by console or the clicker + * Set the profile of this mannequin part effectively changing its skin, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param profile the profile */ - public abstract void addInteractionCommand(@NotNull String command, boolean isLeftClick, boolean isConsole); + public abstract void setMannequinProfile(@NotNull PlayerProfile profile); /** - * Remove a command from this part, if its type is {@link SpawnedDisplayEntityPart.PartType#INTERACTION} - * @param command The command to remove + * Set the profile of this mannequin part effectively changing its skin, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param profile the profile */ - public abstract void removeInteractionCommand(@NotNull InteractionCommand command); + public abstract void setMannequinProfile(@NotNull ResolvableProfile profile); - public abstract @NotNull List getInteractionCommands(); + /** + * Set the profile of this mannequin part effectively changing its skin, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN}. + * The profile change will only be visible for the provided player + * @param profile the profile + * @param player the player to send profile change to + */ + public void setMannequinProfile(@NotNull PlayerProfile profile, @NotNull Player player){ + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setMannequinProfile(ResolvableProfile.resolvableProfile(profile), player); + } - public abstract @NotNull List getInteractionCommandsWithData(); + /** + * Set the profile of this mannequin part effectively changing its skin, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN}. + * The profile change will only be visible for the provided player + * @param profile the profile + * @param player the player to send profile change to + */ + public void setMannequinProfile(@NotNull ResolvableProfile profile, @NotNull Player player){ + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + PacketUtils.setAttribute(player, entityId, DisplayAttributes.Mannequin.RESOLVABLE_PROFILE, profile); + } - static class PartData { + /** + * Set the description/below name text of this mannequin part, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param text the pose text + */ + public abstract void setMannequinBelowName(@Nullable Component text); - private final UUID entityUUID; - private String worldName; + /** + * Set the pose of this mannequin part, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param pose the pose + */ + public abstract void setMannequinPose(Pose pose); - PartData(@NotNull Entity entity) { - this(entity.getUniqueId(), entity.getWorld().getName()); - } + /** + * Set the scale attribute of this mannequin part, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param scale the scale + */ + public abstract void setMannequinScale(double scale); - PartData(@NotNull UUID entityUUID, @NotNull String worldName) { - this.entityUUID = entityUUID; - this.worldName = worldName; - } + /** + * Set whether the mannequin part should be immovable, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param immovable the immovability + */ + public abstract void setMannequinImmovable(boolean immovable); - void setWorldName(String worldName) { - this.worldName = worldName; - } + /** + * Set whether the mannequin part should have gravity, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param gravity the gravity + */ + public abstract void setMannequinGravity(boolean gravity); - /** - * Get the UUID of the entity this PartData represents - * @return a UUID - */ - public UUID getUUID() { - return entityUUID; - } + /** + * Set the mannequin part's main hand, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param mainHand the main hand + */ + public abstract void setMannequinMainHand(@NotNull MainHand mainHand); - /** - * Get the world name of the entity this PartData represents - * - * @return a string - */ - public String getWorldName() { - return worldName; - } + /** + * Set the item in mannequin part's equipment slot, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @param slot the equipment slot + * @param itemStack the item to put in the slot + */ + public abstract void setMannequinEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack); - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } + /** + * Get a mannequin part's profile, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a {@link ResolvableProfile} or null + */ + public abstract ResolvableProfile getMannequinProfile(); - PartData data = (PartData) obj; - return entityUUID.equals(data.entityUUID) && worldName.equals(data.worldName); - } + /** + * Get a mannequin part's description/below name text, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a {@link Component} or null + */ + public abstract @Nullable Component getMannequinBelowName(); - @Override - public int hashCode() { - return Objects.hash(entityUUID, worldName); - } - } + /** + * Get a mannequin part's pose, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a {@link Pose} or null + */ + public abstract @Nullable Pose getMannequinPose(); + + /** + * Get a mannequin part's scale attribute, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a double or -1 if the part is not a mannequin + */ + public abstract double getMannequinScale(); + + /** + * Get whether mannequin part is immovable, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a boolean, always false if the part is not a mannequin + */ + public abstract boolean isMannequinImmovable(); + + /** + * Get whether mannequin part has gravity, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a boolean, always false if the part is not a mannequin + */ + public abstract boolean hasMannequinGravity(); + + /** + * Get whether mannequin part has gravity, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a {@link MainHand} or null if the part is not a mannequin + */ + public abstract @Nullable MainHand getMannequinMainHand(); + + /** + * Get the item in a mannequin part's equipment slot, if its type is {@link SpawnedDisplayEntityPart.PartType#MANNEQUIN} + * @return a {@link ItemStack} or null if the part is not a mannequin + */ + public abstract @Nullable ItemStack getMannequinEquipment(@NotNull EquipmentSlot equipmentSlot); + + /** + * Adds a command to this part to execute when clicked, if its type is {@link SpawnedDisplayEntityPart.PartType#INTERACTION} + * @param command The command to assign + * @param isLeftClick whether the command is executed on left click + * @param isConsole whether the command should be executed by console or the clicker + */ + public abstract void addInteractionCommand(@NotNull String command, boolean isLeftClick, boolean isConsole); + + /** + * Remove a command from this part, if its type is {@link SpawnedDisplayEntityPart.PartType#INTERACTION} + * @param command The command to remove + */ + public abstract void removeInteractionCommand(@NotNull InteractionCommand command); + + public abstract @NotNull List getInteractionCommands(); + + public abstract @NotNull List getInteractionCommandsWithData(); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationPlayer.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationPlayer.java index c45717e3..5e973b52 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationPlayer.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationPlayer.java @@ -187,7 +187,7 @@ void animateInteractions(Collection players, Location groupLoc, SpawnedD continue; } - Vector currentVector = part.getInteractionTranslation(); + Vector currentVector = part.getNonDisplayTranslation(); if (currentVector == null){ continue; } @@ -227,7 +227,7 @@ void animateInteractions(Collection players, Location groupLoc, SpawnedD part.translate(moveVector, (float) moveVector.length(), frame.duration, 0); } else { - PacketUtils.translateInteraction(players, part, moveVector, (float) moveVector.length(), frame.duration, 0); + PacketUtils.translateNonDisplay(players, part, moveVector, (float) moveVector.length(), frame.duration, 0); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEGJSONAdapter.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUJSONAdapter.java similarity index 57% rename from api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEGJSONAdapter.java rename to api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUJSONAdapter.java index b083adce..09f0a66a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEGJSONAdapter.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUJSONAdapter.java @@ -3,13 +3,18 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -public final class DEGJSONAdapter { +public final class DEUJSONAdapter { + + static final String PART_UUID_FIELD = "partUUID"; + static final String PDC_FIELD = "persistentDataContainer"; public static final Gson GSON = new GsonBuilder() .registerTypeAdapter(DisplayEntity.class, new JSONAdapter_DisplayEntity()) + .registerTypeAdapter(InteractionEntity.class, new JSONAdapter_InteractionEntity()) + .registerTypeAdapter(MannequinEntity.class, new JSONAdapter_MannequinEntity()) .registerTypeHierarchyAdapter(DisplayEntitySpecifics.class, new JSONAdapter_DisplayEntitySpecifics()) .registerTypeHierarchyAdapter(FramePoint.class, new JSONAdapter_FramePoint()) .create(); - private DEGJSONAdapter(){} + private DEUJSONAdapter(){} } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationSound.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUSound.java similarity index 60% rename from api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationSound.java rename to api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUSound.java index 32a6c9b1..79614e6c 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/AnimationSound.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DEUSound.java @@ -2,6 +2,11 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.utils.version.VersionUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.*; import org.bukkit.entity.Player; import org.jetbrains.annotations.ApiStatus; @@ -10,9 +15,9 @@ import java.io.*; import java.util.Collection; +import java.util.function.Consumer; -@ApiStatus.Internal -public class AnimationSound implements Externalizable, Cloneable { +public class DEUSound implements Externalizable, Cloneable { //i have no clue what i was doing when making this class, now its externalizable forever transient Sound sound; String soundName; float volume; @@ -24,27 +29,26 @@ public class AnimationSound implements Externalizable, Cloneable { private static final long serialVersionUID = 0; @ApiStatus.Internal - public AnimationSound(){} + public DEUSound(){} - public AnimationSound(@NotNull String soundName, float volume, float pitch, int delayInTicks){ + public DEUSound(@NotNull String soundName, float volume, float pitch, int delayInTicks){ this.soundName = soundName; this.volume = volume; this.pitch = pitch; this.delay = delayInTicks; this.sound = VersionUtils.getSound(soundName); - existsInGameVersion = this.sound != null; + this.existsInGameVersion = this.sound != null; } - public AnimationSound(@NotNull Sound sound, float volume, float pitch, int delayInTicks){ + public DEUSound(@NotNull Sound sound, float volume, float pitch, int delayInTicks){ this.sound = sound; this.soundName = sound.getKey().getKey(); this.volume = volume; this.pitch = pitch; this.delay = delayInTicks; - this.existsInGameVersion = true; } - public AnimationSound(@NotNull AnimationSound sound){ + public DEUSound(@NotNull DEUSound sound){ this.sound = sound.sound; this.soundName = sound.soundName; this.volume = sound.volume; @@ -111,11 +115,22 @@ else if (group.isActiveAnimator(animator)){ } public void playSound(@NotNull Location location){ - location.getWorld().playSound(location, sound, volume, pitch); + if (sound == null){ + location.getWorld().playSound(location, soundName, volume, pitch); + } + else{ + location.getWorld().playSound(location, sound, volume, pitch); + } + } public void playSound(@NotNull Location location, Player player){ - player.playSound(location, sound, volume, pitch); + if (sound == null){ + player.playSound(location, soundName, volume, pitch); + } + else{ + player.playSound(location, sound, volume, pitch); + } } public void playSound(@NotNull Location location, Collection players){ @@ -175,11 +190,50 @@ public boolean existsInGameVersion() { } @Override - public AnimationSound clone() { + public DEUSound clone() { try { - return (AnimationSound) super.clone(); + return (DEUSound) super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(); } } + + @ApiStatus.Internal + public void sendInfo(Player player, Consumer clickRemovalAction){ + Component msgComp = Component.text("- "+soundName, NamedTextColor.YELLOW); + Component hoverComp = Component.text("| Vol: "+volume+", Pitch: "+pitch, NamedTextColor.GRAY); + if (!existsInGameVersion){ + msgComp = msgComp.append(Component.text(" [UNKNOWN]", NamedTextColor.GRAY)); + hoverComp = hoverComp + .append(Component.newline()) + .append(Component.text("This sound no longer exists or is a resource pack sound!", NamedTextColor.RED)); + } + + if (clickRemovalAction != null){ + hoverComp = hoverComp.append(Component.newline()) + .append(Component.text("Click to remove this sound", NamedTextColor.YELLOW)); + msgComp = msgComp.clickEvent(ClickEvent.callback(a -> { + clickRemovalAction.accept(this); + a.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Sound Removed!", NamedTextColor.YELLOW))); + })); + } + + msgComp = msgComp.hoverEvent(HoverEvent.showText(hoverComp)); + player.sendMessage(msgComp); + } + + @ApiStatus.Internal + public static void sendInfo(Collection sounds, Player player, String soundListTitle, Consumer clickRemovalAction){ + if (soundListTitle == null) soundListTitle = "Sounds"; + player.sendMessage(MiniMessage.miniMessage().deserialize(soundListTitle+": "+sounds.size())); + if (sounds.isEmpty()){ + player.sendMessage(Component.text("| NONE", NamedTextColor.GRAY)); + } + else{ + for (DEUSound sound : sounds){ + sound.sendInfo(player, clickRemovalAction); + } + } + player.sendMessage(Component.empty()); + } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationFrame.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationFrame.java index f4f1020f..f280e0bd 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationFrame.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/DisplayAnimationFrame.java @@ -28,8 +28,8 @@ public final class DisplayAnimationFrame implements Serializable { HashMap startSoundMap; HashMap endSoundMap; - HashMap startSounds; - HashMap endSounds; + HashMap startSounds; + HashMap endSounds; transient Set frameStartParticles; transient Set frameEndParticles; @@ -79,9 +79,9 @@ public SpawnedDisplayAnimationFrame toSpawnedDisplayAnimationFrame(){ //Start Sounds if (startSounds != null){ - for (Map.Entry entry : startSounds.entrySet()){ + for (Map.Entry entry : startSounds.entrySet()){ String soundName = entry.getKey(); - AnimationSound sound = entry.getValue(); + DEUSound sound = entry.getValue(); sound.delay = 0; point.sounds.put(soundName, sound); } @@ -89,11 +89,10 @@ public SpawnedDisplayAnimationFrame toSpawnedDisplayAnimationFrame(){ //End Sounds if (endSounds != null){ - for (Map.Entry entry : endSounds.entrySet()){ - String soundName = entry.getKey(); - AnimationSound sound = entry.getValue(); - sound.delay = duration; - point.sounds.put(soundName, sound); + for (Map.Entry entry : endSounds.entrySet()){ + DEUSound sound = entry.getValue(); + sound.delay = this.duration; + point.addSound(sound); } } @@ -108,9 +107,8 @@ public SpawnedDisplayAnimationFrame toSpawnedDisplayAnimationFrame(){ for (AnimationParticle particle : frameStartParticles){ String pointTag = OLD_ANIM_PARTICLE+animationParticle; FramePoint point = new FramePoint(pointTag, particle.getVector(), particle.getGroupYawAtCreation(), particle.getGroupPitchAtCreation()); - particle.setDelayInTicks(0); - point.particles.add(particle); - frame.framePoints.put(pointTag, point); + point.addParticle(particle); + frame.addFramePoint(point); animationParticle++; } } @@ -121,8 +119,8 @@ public SpawnedDisplayAnimationFrame toSpawnedDisplayAnimationFrame(){ String pointTag = OLD_ANIM_PARTICLE+animationParticle; FramePoint point = new FramePoint(pointTag, particle.getVector(), particle.getGroupYawAtCreation(), particle.getGroupPitchAtCreation()); particle.setDelayInTicks(duration); - point.particles.add(particle); - frame.framePoints.put(pointTag, point); + point.addParticle(particle); + frame.addFramePoint(point); animationParticle++; } } @@ -130,7 +128,7 @@ public SpawnedDisplayAnimationFrame toSpawnedDisplayAnimationFrame(){ //Frame Points if (framePoints != null){ for (FramePoint fp : framePoints.values()){ - frame.framePoints.put(fp.tag, new FramePoint(fp)); + frame.addFramePoint(new FramePoint(fp)); } } @@ -177,25 +175,25 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo void repairOldSounds(){ - HashMap map1 = handleOldSoundMaps(startSoundMap, 0); + HashMap map1 = handleEnumSoundMaps(startSoundMap, 0); if (!map1.isEmpty()){ if (startSounds == null) startSounds = new HashMap<>(); startSounds.putAll(map1); } - HashMap map2 = handleOldSoundMaps(endSoundMap, duration); + HashMap map2 = handleEnumSoundMaps(endSoundMap, duration); if (!map2.isEmpty()){ if (endSounds == null) endSounds = new HashMap<>(); endSounds.putAll(map2); } } - private HashMap handleOldSoundMaps(HashMap soundMap, int delayInTicks) { + private HashMap handleEnumSoundMaps(HashMap soundMap, int delayInTicks) { if (soundMap == null || soundMap.isEmpty()){ return new HashMap<>(); } - HashMap convertedMap = new HashMap<>(); + HashMap convertedMap = new HashMap<>(); for (Map.Entry entry : soundMap.entrySet()) { OldSound sound = entry.getKey(); Float[] values = entry.getValue(); @@ -204,10 +202,10 @@ private HashMap handleOldSoundMaps(HashMap displayEntities = new ArrayList<>(); private final ArrayList interactionEntities = new ArrayList<>(); + private final ArrayList mannequinEntities = new ArrayList<>(); DisplayEntity masterEntity; - private String tag; + private final String tag; private Boolean isPersistent = true; @Serial @@ -35,9 +35,11 @@ public final class DisplayEntityGroup implements Serializable{ this.masterEntity = addDisplayEntity(spawnedMasterEntity).setMaster(); for (SpawnedDisplayEntityPart part : spawnedGroup.getParts()){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - Interaction i = (Interaction) part.getEntity(); - addInteractionEntity(i); + if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + addInteractionEntity((Interaction) part.getEntity()); + } + else if (VersionUtils.IS_1_21_9 && part.type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + addMannequinEntity(part.getEntity()); } else{ if (!part.isMaster()){ @@ -55,10 +57,12 @@ public final class DisplayEntityGroup implements Serializable{ this.masterEntity = addDisplayEntity(packetGroup.masterPart, packetGroup).setMaster(); for (PacketDisplayEntityPart part : packetGroup.getParts()){ - - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ addInteractionEntity(part); } + else if (VersionUtils.IS_1_21_9 && part.type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + addMannequinEntity(part); + } else{ if (!part.isMaster()){ addDisplayEntity(part, packetGroup); @@ -105,81 +109,34 @@ private DisplayEntity addDisplayEntity(PacketDisplayEntityPart part, PacketDispl return display; } - private InteractionEntity addInteractionEntity(Interaction entity){ - InteractionEntity interaction = new InteractionEntity(entity); - interactionEntities.add(interaction); - return interaction; - } - - private InteractionEntity addInteractionEntity(PacketDisplayEntityPart part){ - InteractionEntity interaction = new InteractionEntity(part); - interactionEntities.add(interaction); - return interaction; - } - - - /** - * Get the DisplayEntities in this group - * @return DisplayEntity List containing the ones in this group - */ - List getDisplayEntities() { - return new ArrayList<>(displayEntities); + private void addInteractionEntity(Interaction entity){ + interactionEntities.add(new InteractionEntity(entity)); } - /** - * Get the DisplayEntities in this group of the specified type - * @return DisplayEntity List containing the ones in this group with the specified type - */ - List getDisplayEntities(DisplayEntity.Type type){ - ArrayList displayEntities = new ArrayList<>(); - for (DisplayEntity entity : this.displayEntities){ - if (entity.getType() == type){ - displayEntities.add(entity); - } - } - return displayEntities; + private void addInteractionEntity(PacketDisplayEntityPart part){ + interactionEntities.add(new InteractionEntity(part)); } - /** - * Get the InteractionEntities in this group - * @return InteractionEntity List containing the ones in this group - */ - List getInteractionEntities() { - return new ArrayList<>(interactionEntities); + private void addMannequinEntity(Entity entity){ + mannequinEntities.add(SavedEntityBuilder.buildMannequin(entity)); } - /** - * Get whether this DisplayEntityGroup has display entities - * @return boolean of whether the group has display entities - */ - public boolean hasDisplayEntities(){ - return !displayEntities.isEmpty(); + private void addMannequinEntity(PacketDisplayEntityPart part){ + mannequinEntities.add(SavedEntityBuilder.buildMannequin(part)); } - /** - * Get whether this DisplayEntityGroup has display entities of the specified type - * @return boolean of whether the group has display entities of the specified type - */ - public boolean hasDisplayEntities(DisplayEntity.Type type){ - for (DisplayEntity entity : displayEntities){ - if (entity.getType() == type){ - return true; - } - } - return false; - } /** - * Get whether this DisplayEntityGroup has interaction entities - * @return boolean of whether the group has interaction entities + * Get whether this group has interaction entities + * @return a boolean */ public boolean hasInteractionEntities(){ return !interactionEntities.isEmpty(); } /** - * Get the tag of this Display Entity Group - * @return This DisplayEntityGroup's Tag + * Get this group's tag + * @return a string */ public String getTag() { return tag; @@ -199,7 +156,7 @@ public String getTag() { * Spawns this {@link DisplayEntityGroup} at a specified location returning a {@link SpawnedDisplayEntityGroup} that represents this. * @param location The location to spawn the group * @param spawnReason The reason for this display entity group to spawn - * @param settings The settings to apply to every display and interaction entity created from this. This may be overridden with the {@link PreGroupSpawnedEvent}. + * @param settings The settings to apply when spawning this group. This may be overridden with the {@link PreGroupSpawnedEvent}. * @return A {@link SpawnedDisplayEntityGroup} representative of this. Null if the {@link PreGroupSpawnedEvent} is cancelled */ public @Nullable SpawnedDisplayEntityGroup spawn(@NotNull Location location, @NotNull GroupSpawnedEvent.SpawnReason spawnReason, @NotNull GroupSpawnSettings settings){ @@ -236,12 +193,19 @@ public String getTag() { masterDisplay.getLocation(), settings); - SpawnedDisplayEntityPart part = group.addInteractionEntity(interaction); + SpawnedDisplayEntityPart part = group.addEntity(interaction); if (entity.hasLegacyPartTags()){ part.adaptScoreboardTags(true); } } + if (mannequinEntities != null){ + for (MannequinEntity entity : mannequinEntities){ + Entity e = SavedEntityLoader.spawnMannequin(masterDisplay.getLocation(), settings, entity); + group.addEntity(e); + } + } + group.setPersistenceOverride(settings.persistenceOverride); if (tag != null){ @@ -261,9 +225,6 @@ public String getTag() { return group; } - - - /** * Spawns this {@link DisplayEntityGroup} at a specified location returning a {@link PacketDisplayEntityGroup} that represents this. * @param spawnLocation The location where this group spawn be spawned for players @@ -314,7 +275,7 @@ public String getTag() { * @param spawnLocation The location where this group spawn be spawned for players * @param spawnReason The reason for this display entity group to spawn * @param playSpawnAnimation whether this packet group should automatically play its spawn animation when created - * @param settings The settings to apply to every display and interaction entity created from this. This may be overridden with the {@link PrePacketGroupCreateEvent}.
The persistence of the settings is ignored for packet-based groups + * @param settings The settings to apply when spawning this group. This may be overridden with the {@link PrePacketGroupCreateEvent}.
The persistence of the settings is ignored for packet-based groups * @return A {@link PacketDisplayEntityGroup} representative of this. Null if the {@link PrePacketGroupCreateEvent} is cancelled */ public @Nullable PacketDisplayEntityGroup createPacketGroup(@NotNull Location spawnLocation, @NotNull GroupSpawnedEvent.SpawnReason spawnReason, boolean playSpawnAnimation, @NotNull GroupSpawnSettings settings){ @@ -351,6 +312,14 @@ public String getTag() { packetGroup.addPartSilent(part); } + if (mannequinEntities != null){ //old models won't have this field + for (MannequinEntity entity : mannequinEntities){ + PacketDisplayEntityPart part = entity.createPacketPart(spawnLocation, settings); + packetGroup.addPartSilent(part); + } + } + + if (playSpawnAnimation){ packetGroup.playSpawnAnimation(); } @@ -363,6 +332,10 @@ public String getTag() { packetGroup.autoCull(widthCullingAdder, heightCullingAdder); } + if (spawnReason == GroupSpawnedEvent.SpawnReason.CHUNK_LOAD_PLACED || spawnReason == GroupSpawnedEvent.SpawnReason.ITEMSTACK){ + packetGroup.isPlaced = true; + } + return packetGroup; } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/FramePoint.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/FramePoint.java index 6bdb532c..cebeffb4 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/FramePoint.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/FramePoint.java @@ -22,7 +22,7 @@ public class FramePoint extends RelativePoint implements Serializable { Set particles = new HashSet<>(); - Map sounds = new HashMap<>(); + Map sounds = new HashMap<>(); @Serial private static final long serialVersionUID = 99L; @@ -44,7 +44,7 @@ public FramePoint(@NotNull FramePoint point) { for (AnimationParticle p : point.particles){ this.particles.add(p.clone()); } - for (Map.Entry entry : point.sounds.entrySet()){ + for (Map.Entry entry : point.sounds.entrySet()){ this.sounds.put(entry.getKey(), entry.getValue().clone()); } } @@ -234,7 +234,7 @@ public void showParticles(@NotNull Location location){ * @param limited whether to limit the played audio only to players who can visibly see the group */ public void playSounds(@NotNull ActiveGroup group, @Nullable DisplayAnimator animator, boolean limited){ - for (AnimationSound sound : sounds.values()){ + for (DEUSound sound : sounds.values()){ if (limited){ sound.playSound(getLocation(group), group, animator, getPlayers(group)); } @@ -252,7 +252,7 @@ public void playSounds(@NotNull ActiveGroup group, @Nullable DisplayAnimator * @param limited whether to limit the played audio only to players who can visibly see the group */ public void playSounds(@NotNull ActiveGroup group, @NotNull Location location, @Nullable DisplayAnimator animator, boolean limited){ - for (AnimationSound sound : sounds.values()){ + for (DEUSound sound : sounds.values()){ if (limited){ sound.playSound(location, group, animator, getPlayers(group)); } @@ -284,7 +284,7 @@ public void playSounds(@NotNull ActiveGroup group, boolean limited){ * @param player the player */ public void playSounds(@NotNull Location location, @NotNull Player player){ - for (AnimationSound sound : sounds.values()){ + for (DEUSound sound : sounds.values()){ sound.playSound(location, player); } } @@ -295,7 +295,7 @@ public void playSounds(@NotNull Location location, @NotNull Player player){ * @param players the players */ public void playSounds(@NotNull Location location, @NotNull Collection players){ - for (AnimationSound sound : sounds.values()){ + for (DEUSound sound : sounds.values()){ sound.playSound(location, players); } } @@ -323,23 +323,23 @@ public void playSounds(@NotNull ActiveGroup group, @NotNull Collection getParticles(){ } /** - * Get the {@link AnimationSound}s that will be played at this frame point - * @return a collection of {@link AnimationSound} + * Get the {@link DEUSound}s that will be played at this frame point + * @return a collection of {@link DEUSound} */ - public Collection getSounds(){ + public Collection getSounds(){ return sounds.values(); } @@ -435,27 +435,8 @@ public void sendInfo(Player player){ player.sendMessage(Component.empty()); //Sounds - player.sendMessage(MiniMessage.miniMessage().deserialize("Sounds: "+sounds.size())); - if (sounds.isEmpty()){ - player.sendMessage(Component.text("| NONE", NamedTextColor.GRAY)); - } - else{ - for (AnimationSound sound : sounds.values()){ - Component msgComp = Component.text("- "+sound.getSoundName(), NamedTextColor.YELLOW); - Component hoverComp = Component.text("| Vol: "+sound.getVolume()+", Pitch: "+sound.getPitch(), NamedTextColor.GRAY); - if (!sound.existsInGameVersion()){ - msgComp = msgComp.append(Component.text(" [UNKNOWN]", NamedTextColor.GRAY)); - hoverComp = hoverComp - .append(Component.newline()) - .append(Component.text("This sound no longer exists!", NamedTextColor.RED)); - } - - msgComp = msgComp.hoverEvent(HoverEvent.showText(hoverComp)); - player.sendMessage(msgComp); - } - } + DEUSound.sendInfo(sounds.values(), player, null, null); - player.sendMessage(Component.empty()); player.sendMessage(MiniMessage.miniMessage().deserialize("RIGHT click to preview effects")); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupEntityFollower.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupEntityFollower.java index 56d048de..33f89ab0 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupEntityFollower.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupEntityFollower.java @@ -173,7 +173,7 @@ private void apply(Entity entity, MultiPartSelection selection, float newYaw, private void pivotDisplayPitch(ActivePart part, boolean zero, float newPitch){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ return; } Transformation t = part.getTransformation(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupPoint.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupPoint.java deleted file mode 100644 index 9e2d5adb..00000000 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupPoint.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.donnypz.displayentityutils.utils.DisplayEntities; - -import org.bukkit.Location; -import org.bukkit.util.Vector; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.joml.Vector3f; - -import java.io.Serializable; - -@ApiStatus.Experimental -public class GroupPoint extends RelativePoint implements Serializable { - public GroupPoint(@NotNull String pointTag, @NotNull SpawnedDisplayEntityGroup group, @NotNull Location location) { - super(pointTag, group, location); - } - - GroupPoint(@NotNull String pointTag, @NotNull Vector vector, float initialYaw, float initialPitch) { - super(pointTag, vector, initialYaw, initialPitch); - } - - GroupPoint(@NotNull String pointTag, @NotNull Vector3f vector, float initialYaw, float initialPitch) { - super(pointTag, vector, initialYaw, initialPitch); - } - - protected GroupPoint(@NotNull GroupPoint point) { - super(point); - } -} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupSpawnSettings.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupSpawnSettings.java index be49aa02..6080f22e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupSpawnSettings.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/GroupSpawnSettings.java @@ -7,10 +7,7 @@ import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.entity.Display; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Interaction; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -154,7 +151,7 @@ boolean applyVisibility(PacketDisplayEntityPart part, Player player){ } boolean applyAttributes(PacketDisplayEntityPart part){ - if (part.type != SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (part.isDisplay()){ //Teleport Duration part.attributeContainer.setAttribute(DisplayAttributes.TELEPORTATION_DURATION, teleportationDuration); @@ -285,21 +282,35 @@ void apply(Interaction interaction){ interaction.setPersistent(persistentByDefault); } - private void determineVisibleByDefault(Display display){ - for (String tag : hiddenPartTags.keySet()){ - if (DisplayUtils.hasPartTag(display, tag)){ - display.setVisibleByDefault(false); - reveal(display, tag); - break; + void apply(Mannequin mannequin){ + //Determine Visibility + if (!visibleByDefault){ + mannequin.setVisibleByDefault(false); + if (!visiblePlayers.isEmpty()){ //Reveal for players + for (UUID uuid : visiblePlayers){ + Player player = Bukkit.getPlayer(uuid); + if (player != null && player.isOnline()){ + player.showEntity(DisplayAPI.getPlugin(), mannequin); + } + } + } + } + else{ + if (hiddenPartTags.isEmpty()){ + mannequin.setVisibleByDefault(true); + } + else{ + determineVisibleByDefault(mannequin); } } } - private void determineVisibleByDefault(Interaction interaction){ + + private void determineVisibleByDefault(Entity entity){ for (String tag : hiddenPartTags.keySet()){ - if (DisplayUtils.hasPartTag(interaction, tag)){ - interaction.setVisibleByDefault(false); - reveal(interaction, tag); + if (DisplayUtils.hasPartTag(entity, tag)){ + entity.setVisibleByDefault(false); + reveal(entity, tag); break; } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java index 2a90bbc3..8cd51ca0 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionEntity.java @@ -31,15 +31,16 @@ final class InteractionEntity implements Serializable { UUID partUUID; float height; float width; - private byte[] persistentDataContainer = null; + byte[] persistentDataContainer = null; boolean isResponsive; + InteractionEntity(){} + InteractionEntity(Interaction interaction){ this.height = interaction.getInteractionHeight(); this.width = interaction.getInteractionWidth(); this.isResponsive = interaction.isResponsive(); - this.vector = DisplayUtils.getInteractionTranslation(interaction).toVector3f(); - this.partUUID = DisplayUtils.getPartUUID(interaction); + this.vector = DisplayUtils.getNonDisplayTranslation(interaction).toVector3f(); try{ persistentDataContainer = interaction.getPersistentDataContainer().serializeToBytes(); @@ -55,13 +56,13 @@ final class InteractionEntity implements Serializable { this.height = c.getAttributeOrDefault(DisplayAttributes.Interaction.HEIGHT, 1f); this.width = c.getAttributeOrDefault(DisplayAttributes.Interaction.WIDTH, 1f); this.isResponsive = c.getAttributeOrDefault(DisplayAttributes.Interaction.RESPONSIVE, false); - this.vector = part.getInteractionTranslation().toVector3f(); - this.partUUID = part.partUUID; + this.vector = part.getNonDisplayTranslation().toVector3f(); try{ ItemStack i = new ItemStack(Material.STICK); PersistentDataContainer pdc = i.getItemMeta().getPersistentDataContainer(); pdc.set(DisplayAPI.getPartPDCTagKey(), PersistentDataType.LIST.strings(), new ArrayList<>(part.getTags())); + pdc.set(DisplayAPI.getPartUUIDKey(), PersistentDataType.STRING, part.partUUID.toString()); persistentDataContainer = pdc.serializeToBytes(); } catch(IOException e){ @@ -92,7 +93,11 @@ Interaction createEntity(Location origin, GroupSpawnSettings settings){ } if (partUUID != null){ - i.getPersistentDataContainer().set(DisplayAPI.getPartUUIDKey(), PersistentDataType.STRING, partUUID.toString()); + i + .getPersistentDataContainer() + .set(DisplayAPI.getPartUUIDKey(), + PersistentDataType.STRING, + partUUID.toString()); } settings.apply(i); @@ -123,10 +128,10 @@ PacketDisplayEntityPart createPacketPart(Location origin, GroupSpawnSettings set } part.partTags = DisplayEntity.getSetFromPDC(pdc, DisplayAPI.getPartPDCTagKey()); - part.partUUID = DisplayEntity.getPDCPartUUID(pdc); + part.partUUID = partUUID != null ? partUUID : DisplayEntity.getPDCPartUUID(pdc); part.interactionCommands = getInteractionCommands(pdc); } - settings.applyAttributes(part); + if (settings != null) settings.applyAttributes(part); return part; } @@ -147,20 +152,4 @@ Vector getVector(){ boolean hasLegacyPartTags(){ return partTags != null && !partTags.isEmpty(); } - - ArrayList getLegacyPartTags() { - return partTags; - } - - float getHeight() { - return height; - } - - float getWidth() { - return width; - } - - boolean isReponsive(){ - return isResponsive; - } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionTransformation.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionTransformation.java index 8fedab40..d794061e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionTransformation.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/InteractionTransformation.java @@ -30,6 +30,16 @@ public InteractionTransformation(){} this.width = width; } + + InteractionTransformation(Vector vector, float groupYawAtCreation, float groupPitchAtCreation, float height, float width){ + super(vector.toVector3f()); + this.vector = new Vector(vector.getX(), vector.getY(), vector.getZ()); + this.groupYawAtCreation = groupYawAtCreation; + this.groupPitchAtCreation = groupPitchAtCreation; + this.height = height; + this.width = width; + } + @ApiStatus.Internal public void writeExternal(ObjectOutput out) throws IOException { out.writeFloat(this.x); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_DisplayEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_DisplayEntity.java index 68691b63..23218f84 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_DisplayEntity.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_DisplayEntity.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.lang.reflect.Type; +import java.util.Base64; import java.util.List; @ApiStatus.Internal @@ -25,15 +26,22 @@ public DisplayEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializa entity.type = DisplayEntity.Type.valueOf(obj.get("type").getAsString().toUpperCase()); entity.isMaster = obj.get("isMaster").getAsBoolean(); - List list = ctx.deserialize(obj.get("persistentDataContainer"), List.class); - byte[] bytes = new byte[list.size()]; - for (int i = 0; i < list.size(); i++) { - bytes[i] = list.get(i).byteValue(); + if (obj.has(DEUJSONAdapter.PDC_FIELD)){ + try{ + List list = ctx.deserialize(obj.get(DEUJSONAdapter.PDC_FIELD), List.class); + byte[] bytes = new byte[list.size()]; + for (int i = 0; i < list.size(); i++) { + bytes[i] = list.get(i).byteValue(); + } + + entity.persistentDataContainer = bytes; + } + catch(JsonParseException e){ + String base64 = ctx.deserialize(obj.get(DEUJSONAdapter.PDC_FIELD), String.class); + entity.persistentDataContainer = Base64.getDecoder().decode(base64); + } } - entity.persistentDataContainer = bytes; - - JsonObject specificsJson = obj.getAsJsonObject("specifics"); switch (entity.type) { case BLOCK: @@ -59,6 +67,9 @@ public JsonElement serialize(DisplayEntity src, Type typeOfSrc, JsonSerializatio //Convert Specifics, and remove legacy part tags array json.add("specifics", ctx.serialize(src.specifics, DisplayEntitySpecifics.class)); + //partUUID + json.addProperty(DEUJSONAdapter.PART_UUID_FIELD, src.specifics.getPartUUID().toString()); + //Add part tags try{ PersistentDataContainer pdc = new ItemStack(Material.STICK).getItemMeta().getPersistentDataContainer(); @@ -66,14 +77,13 @@ public JsonElement serialize(DisplayEntity src, Type typeOfSrc, JsonSerializatio List tags = pdc.get(DisplayAPI.getPartPDCTagKey(), PersistentDataType.LIST.strings()); json.add("partTags", new Gson().toJsonTree(tags)); } - catch(IOException e){} + catch(IOException | NullPointerException e){} - //Convert byte arr to int arr - JsonArray arr = new JsonArray(); - for (byte b : src.persistentDataContainer){ - arr.add((int) b); + //pdc to base64 + byte[] pdc = src.persistentDataContainer; + if (pdc != null){ + json.addProperty(DEUJSONAdapter.PDC_FIELD, Base64.getEncoder().encodeToString(pdc)); } - json.add("persistentDataContainer", arr); return json; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_InteractionEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_InteractionEntity.java new file mode 100644 index 00000000..bcf83380 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_InteractionEntity.java @@ -0,0 +1,76 @@ +package net.donnypz.displayentityutils.utils.DisplayEntities; + +import com.google.gson.*; +import net.donnypz.displayentityutils.DisplayAPI; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.joml.Vector3f; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.Base64; +import java.util.List; +import java.util.UUID; + +public class JSONAdapter_InteractionEntity implements JsonSerializer, JsonDeserializer { + + @Override + public InteractionEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext ctx) throws JsonParseException { + JsonObject obj = json.getAsJsonObject(); + InteractionEntity entity = new InteractionEntity(); + + entity.vector = ctx.deserialize(obj.get("vector"), Vector3f.class); + entity.partUUID = UUID.fromString(obj.get(DEUJSONAdapter.PART_UUID_FIELD).getAsString()); + entity.height = obj.get("height").getAsFloat(); + entity.width = obj.get("width").getAsFloat(); + entity.isResponsive = obj.get("isResponsive").getAsBoolean(); + + + //PDC + String base64 = ctx.deserialize(obj.get(DEUJSONAdapter.PDC_FIELD), String.class); + entity.persistentDataContainer = Base64.getDecoder().decode(base64); + + return null; + } + + + @Override + public JsonElement serialize(InteractionEntity src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject json = new Gson().toJsonTree(src).getAsJsonObject(); + PersistentDataContainer pdc = new ItemStack(Material.STICK).getItemMeta().getPersistentDataContainer(); + byte[] pdcBytes = src.persistentDataContainer; + + + + if (pdcBytes != null){ + + //Add part tags + try{ + pdc.readFromBytes(pdcBytes); + List tags = pdc.get(DisplayAPI.getPartPDCTagKey(), PersistentDataType.LIST.strings()); + json.add("partTags", new Gson().toJsonTree(tags)); + } + catch(IOException | NullPointerException e){} + + //partuuid + UUID partUUID; + if (src.partUUID != null){ + partUUID = src.partUUID; + } + else{ + partUUID = UUID.fromString(pdc.get(DisplayAPI.getPartUUIDKey(), PersistentDataType.STRING)); + } + json.addProperty(DEUJSONAdapter.PART_UUID_FIELD, partUUID.toString()); + + + //pdc to base 64 + json.addProperty(DEUJSONAdapter.PDC_FIELD, Base64.getEncoder().encodeToString(pdcBytes)); + } + + return json; + } + + +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_MannequinEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_MannequinEntity.java new file mode 100644 index 00000000..8455fca6 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/JSONAdapter_MannequinEntity.java @@ -0,0 +1,123 @@ +package net.donnypz.displayentityutils.utils.DisplayEntities; + +import com.google.gson.*; +import net.donnypz.displayentityutils.DisplayAPI; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.joml.Vector3f; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.Base64; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class JSONAdapter_MannequinEntity implements JsonSerializer, JsonDeserializer { + Gson gson = new Gson(); + Map AIR_AS_MAP = new ItemStack(Material.AIR).serialize(); + + JSONAdapter_MannequinEntity(){} + + + @Override + public JsonElement serialize(MannequinEntity src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject json = gson.toJsonTree(src).getAsJsonObject(); + + //Equipment items as json objects + JsonArray equipmentArr = new JsonArray(); + for (byte[] itemBytes : src.equipment){ + Map itemStackMap; + if (itemBytes != null){ + itemStackMap = ItemStack.deserializeBytes(itemBytes).serialize(); + } + else{ + itemStackMap = AIR_AS_MAP; + } + JsonElement jsonElement = gson.toJsonTree(itemStackMap); + equipmentArr.add(jsonElement); + + } + + json.add("equipment", equipmentArr); + + //Add part tags + try{ + PersistentDataContainer pdc = new ItemStack(Material.STICK).getItemMeta().getPersistentDataContainer(); + pdc.readFromBytes(src.persistentDataContainer); + List tags = pdc.get(DisplayAPI.getPartPDCTagKey(), PersistentDataType.LIST.strings()); + json.add("partTags", new Gson().toJsonTree(tags)); + } + catch(IOException | NullPointerException e){} + + //pdc to base 64 + json.addProperty(DEUJSONAdapter.PDC_FIELD, + Base64.getEncoder().encodeToString(src.persistentDataContainer)); + return json; + } + + @Override + public MannequinEntity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject obj = json.getAsJsonObject(); + + MannequinEntity mannequin = new MannequinEntity(); + + mannequin.vector = context.deserialize(obj.get("vector"), Vector3f.class); + + mannequin.customName = getString(obj, "customName"); + mannequin.customNameVisible = getBoolean(obj, "customNameVisible"); + mannequin.description = getString(obj, "description"); + + mannequin.profileName = getString(obj, "profileName"); + mannequin.profileUUID = obj.has("profileUUID") && !obj.get("profileUUID").isJsonNull() + ? UUID.fromString(obj.get("profileUUID").getAsString()) + : null; + + mannequin.scale = getDouble(obj, "scale"); + mannequin.pose = getString(obj, "pose"); + mannequin.isRightMainHand = getBoolean(obj, "isRightMainHand"); + + //Equipment + if (obj.has("equipment") && obj.get("equipment").isJsonArray()) { + JsonArray arr = obj.getAsJsonArray("equipment"); + mannequin.equipment = new byte[arr.size()][]; + + for (int i = 0; i < arr.size(); i++) { + JsonElement el = arr.get(i); + if (el == null || el.isJsonNull()) { + mannequin.equipment[i] = null; + continue; + } + + Map map = gson.fromJson(el, Map.class); + ItemStack stack = ItemStack.deserialize(map); + try{ + mannequin.equipment[i] = stack.serializeAsBytes(); + } + catch(IllegalArgumentException e){} //thrown if itemstack is empty (air, or 0 count) + } + } + + //PDC + if (obj.has("persistentDataContainer") && !obj.get("persistentDataContainer").isJsonNull()) { + String pdcBase64 = obj.get("persistentDataContainer").getAsString(); + mannequin.persistentDataContainer = Base64.getDecoder().decode(pdcBase64); + } + + return mannequin; + } + + private static String getString(JsonObject obj, String key) { + return obj.has(key) && !obj.get(key).isJsonNull() ? obj.get(key).getAsString() : null; + } + + private static boolean getBoolean(JsonObject obj, String key) { + return obj.has(key) && !obj.get(key).isJsonNull() && obj.get(key).getAsBoolean(); + } + + private static double getDouble(JsonObject obj, String key) { + return obj.has(key) && !obj.get(key).isJsonNull() ? obj.get(key).getAsDouble() : 0.0D; + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java new file mode 100644 index 00000000..c01d33f4 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MannequinEntity.java @@ -0,0 +1,160 @@ +package net.donnypz.displayentityutils.utils.DisplayEntities; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.packet.PacketAttributeContainer; +import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Pose; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.MainHand; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.util.Vector; +import org.joml.Vector3f; + +import java.io.IOException; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import java.util.UUID; + + +//DTO +final class MannequinEntity implements Serializable { + @Serial + private static final long serialVersionUID = 99L; + + Vector3f vector; + String customName; + boolean customNameVisible; + String description; + String profileName; + UUID profileUUID; + List profileProperties; + String profileSkinPatchBody; + String profileSkinPatchCape; + String profileSkinPatchElytra; + String profileSkinPatchModel; + + double scale; + String pose; + boolean isRightMainHand; + byte[][] equipment; //0,1,2,3,4,5 = helm,chest,legs,boots,main,off | x bytes for itemstack + byte[] persistentDataContainer; + + + MannequinEntity(){} + + PacketDisplayEntityPart createPacketPart(Location origin, GroupSpawnSettings settings){ + PacketAttributeContainer attributeContainer = new PacketAttributeContainer() + .setAttribute(DisplayAttributes.Mannequin.SCALE, (float) scale) + .setAttribute(DisplayAttributes.Mannequin.IMMOVABLE, true) + .setAttribute(DisplayAttributes.Mannequin.NO_GRAVITY, true) + .setAttribute(DisplayAttributes.CUSTOM_NAME_VISIBLE, customNameVisible) + .setAttribute(DisplayAttributes.Mannequin.POSE, Pose.valueOf(pose)) + .setAttribute(DisplayAttributes.Mannequin.MAIN_HAND, isRightMainHand ? MainHand.RIGHT : MainHand.LEFT) + .setAttribute(DisplayAttributes.Equipment.HELMET, getHelmet()) + .setAttribute(DisplayAttributes.Equipment.CHESTPLATE, getChestplate()) + .setAttribute(DisplayAttributes.Equipment.LEGGINGS, getLeggings()) + .setAttribute(DisplayAttributes.Equipment.BOOTS, getBoots()) + .setAttribute(DisplayAttributes.Equipment.MAIN_HAND, getMainHand()) + .setAttribute(DisplayAttributes.Equipment.OFF_HAND, getOffHand()); + + if (customName != null){ + attributeContainer.setAttribute(DisplayAttributes.CUSTOM_NAME, MiniMessage.miniMessage().deserialize(customName)); + } + + if (description != null){ + attributeContainer.setAttribute(DisplayAttributes.Mannequin.BELOW_NAME, MiniMessage.miniMessage().deserialize(description)); + } + + if (profileName != null || profileUUID != null){ + attributeContainer + .setAttribute( + DisplayAttributes.Mannequin.RESOLVABLE_PROFILE, + SavedEntityLoader.getMannequinProfile(this) + ); + } + + Location spawnLoc = DisplayUtils.getPivotLocation( + vector, + origin, + origin.getYaw()); + + PacketDisplayEntityPart part = attributeContainer.createPart(SpawnedDisplayEntityPart.PartType.MANNEQUIN, spawnLoc); + + ItemStack i = new ItemStack(Material.STICK); + PersistentDataContainer pdc = i.getItemMeta().getPersistentDataContainer(); + + try { + pdc.readFromBytes(persistentDataContainer); + } catch (IOException e) { + throw new RuntimeException(e); + } + + part.partTags = DisplayEntity.getSetFromPDC(pdc, DisplayAPI.getPartPDCTagKey()); + part.partUUID = DisplayEntity.getPDCPartUUID(pdc); + if (settings != null) settings.applyAttributes(part); + + return part; + } + + ItemStack getHelmet(){ + return getItemStack(equipment[0]); + } + + ItemStack getChestplate(){ + return getItemStack(equipment[1]); + } + + ItemStack getLeggings(){ + return getItemStack(equipment[2]); + } + + ItemStack getBoots(){ + return getItemStack(equipment[3]); + } + + ItemStack getMainHand(){ + return getItemStack(equipment[4]); + } + + ItemStack getOffHand(){ + return getItemStack(equipment[5]); + } + + Vector getVector(){ + return Vector.fromJOML(vector); + } + + ItemStack getItemStack(byte[] itemStack){ + if (itemStack == null) return new ItemStack(Material.AIR); + return ItemStack.deserializeBytes(itemStack); + } + + static class ProfileProperty implements Serializable{ + + @Serial + private static final long serialVersionUID = 99L; + + String name; + String value; + String signature; + + ProfileProperty(com.destroystokyo.paper.profile.ProfileProperty property){ + this(property.getName(), property.getValue(), property.getSignature()); + } + + ProfileProperty(String name, String value, String signature){ + this.name = name; + this.value = value; + this.signature = signature; + } + + com.destroystokyo.paper.profile.ProfileProperty toBukkitProperty(){ + return new com.destroystokyo.paper.profile.ProfileProperty(name, value, signature); + } + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MultiPartSelection.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MultiPartSelection.java index 64d93f0c..1ecf1d54 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MultiPartSelection.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/MultiPartSelection.java @@ -487,7 +487,7 @@ public void unglow(@NotNull Player player){ } /** - * Pivot all Interaction parts in this selection around the SpawnedDisplayEntityGroup's master part + * Pivot all non-display parts in this selection around this selection's group * @param angleInDegrees the pivot angle */ @Override @@ -500,11 +500,12 @@ public void pivot(float angleInDegrees){ /** * Set the yaw of all parts in this selection * @param yaw the yaw to set + * @param pivot whether non-display entities should pivot around the group */ @Override - public void setYaw(float yaw, boolean pivotInteractions){ + public void setYaw(float yaw, boolean pivot){ for (T part : selectedParts){ - part.setYaw(yaw, pivotInteractions); + part.setYaw(yaw, pivot); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java index 5c9c42c6..c956b616 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityGroup.java @@ -34,13 +34,13 @@ public class PacketDisplayEntityGroup extends ActiveGroup allPacketGroups = new ConcurrentHashMap<>(); private static final ConcurrentHashMap groupVehicles = new ConcurrentHashMap<>(); - int interactionCount; int[] passengerIds; UUID vehicleUUID; boolean autoShow; Predicate autoShowCondition; int persistentLocalId = -1; String persistentGlobalId; + boolean isPlaced; PacketDisplayEntityGroup(String tag){ @@ -126,6 +126,11 @@ public static String buildPersistentGlobalId(@NotNull Chunk chunk, int localId){ return chunk.getWorld().getName()+"|"+chunk.getChunkKey()+"|"+localId; //world,chunkkey,localid } + /** + * {@inheritDoc} + *

The group cannot become persistent if {@link #isRiding()} is true + *
The group cannot become non-persistent if {@link #isPlaced()} is true + */ @Override public void setPersistent(boolean persistent) { if (persistent){ @@ -135,7 +140,7 @@ public void setPersistent(boolean persistent) { } } else{ - if (isPersistent()){ + if (isPersistent() && !isPlaced){ DisplayGroupManager.removePersistentPacketGroup(this, false); setPersistentIds(-1, null); } @@ -151,6 +156,14 @@ public boolean isPersistent(){ return this.persistentLocalId != -1; } + /** + * Get whether this group was placed by a player's held item + * @return a boolean + */ + public boolean isPlaced(){ + return this.isPlaced; + } + @ApiStatus.Internal public static void removeWorld(@NotNull World world){ //Viewers are already removed since this is only called on unloaded worlds (Viewers are forced to a new world) @@ -161,7 +174,7 @@ void updateChunkAndWorld(@NotNull Location location){ Location oldLoc = getLocation(); //Remove from previous if (oldLoc != null){ - if (location.getWorld().equals(oldLoc.getWorld()) && location.getChunk().getChunkKey() == oldLoc.getChunk().getChunkKey()){ + if (location.getWorld().equals(oldLoc.getWorld()) && location.getChunk().getChunkKey() == oldLoc.getChunk().getChunkKey() && vehicleUUID == null){ return; } String oldWorldName = oldLoc.getWorld().getName(); @@ -196,10 +209,22 @@ public void chunkUnloadLocation(){ @Override public void addPart(@NotNull PacketDisplayEntityPart part){ addPartSilent(part); - updatePartCount(part, true); + updatePassengerIds(part.getEntityId(), true); } - void addPartSilent(PacketDisplayEntityPart part){ + /** + * {@inheritDoc} + * This will create a {@link PacketDisplayEntityPart} representative of the entity + */ + @Override + public @Nullable PacketDisplayEntityPart addEntity(@NotNull Entity entity) { + PacketDisplayEntityPart part = PacketDisplayEntityPart.getPart(entity, true); + if (part == null) return null; + addPart(part); + return part; + } + + void addPartSilent(PacketDisplayEntityPart part){ if (groupParts.get(part.partUUID) == part) return; if (part.partUUID == null){ @@ -216,21 +241,7 @@ void addPartSilent(PacketDisplayEntityPart part){ } } - void updatePartCount(PacketDisplayEntityPart part, boolean add){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - if (add){ - interactionCount++; - } - else{ - interactionCount--; - } - } - else{ - updatePassengerIds(part.getEntityId(), add); - } - } - - private void updatePassengerIds(int passengerId, boolean add){ + void updatePassengerIds(int passengerId, boolean add){ int[] ids; if (add){ ids = new int[passengerIds.length+1]; @@ -278,7 +289,7 @@ private void updatePassengerIds(int passengerId, boolean add){ @Override - public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleInteractions) { + public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleNonDisplays) { if (newScaleMultiplier <= 0){ throw new IllegalArgumentException("New Scale Multiplier cannot be <= 0"); } @@ -286,11 +297,11 @@ public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scal return true; } - for (PacketDisplayEntityPart p : groupParts.values()){ + for (PacketDisplayEntityPart part : groupParts.values()){ //Displays - if (p.getType() != SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (part.isDisplay()){ DisplayAttributeMap attributeMap = new DisplayAttributeMap(); - Transformation transformation = p.getTransformation(); + Transformation transformation = part.getTransformation(); //Reset Scale then multiply by newScaleMultiplier Vector3f scale = transformation.getScale(); scale.x = (scale.x/scaleMultiplier)*newScaleMultiplier; @@ -303,40 +314,46 @@ public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scal translationVector.y = (translationVector.y/scaleMultiplier)*newScaleMultiplier; translationVector.z = (translationVector.z/scaleMultiplier)*newScaleMultiplier; - if (!transformation.equals(p.getTransformation())){ + if (!transformation.equals(part.getTransformation())){ attributeMap.add(DisplayAttributes.Interpolation.DURATION, durationInTicks) .add(DisplayAttributes.Interpolation.DELAY, -1) .addTransformation(transformation); } //Culling if (DisplayConfig.autoCulling()){ - float[] values = DisplayUtils.getAutoCullValues(p, DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); + float[] values = DisplayUtils.getAutoCullValues(part, DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); attributeMap.add(DisplayAttributes.Culling.HEIGHT, values[1]) .add(DisplayAttributes.Culling.WIDTH, values[0]); } - p.attributeContainer.setAttributesAndSend(attributeMap, p.getEntityId(), p.viewers); + part.attributeContainer.setAttributesAndSend(attributeMap, part.getEntityId(), part.viewers); } - //Interactions - else if (scaleInteractions){ - - //Reset Scale then multiply by newScaleMultiplier - float newHeight = (p.getInteractionHeight()/scaleMultiplier)*newScaleMultiplier; - float newWidth = (p.getInteractionWidth()/scaleMultiplier)*newScaleMultiplier; - PacketUtils.scaleInteraction(p, newHeight, newWidth, durationInTicks, 0); + //Non Displays + else if (scaleNonDisplays){ + if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + //Reset Scale then multiply by newScaleMultiplier + float newHeight = (part.getInteractionHeight()/scaleMultiplier)*newScaleMultiplier; + float newWidth = (part.getInteractionWidth()/scaleMultiplier)*newScaleMultiplier; + PacketUtils.scaleInteraction(part, newHeight, newWidth, durationInTicks, 0); + + //Reset Translation then multiply by newScaleMultiplier + Vector translationVector = part.getNonDisplayTranslation(); + if (translationVector == null){ + continue; + } + Vector oldVector = new Vector(translationVector.getX(), translationVector.getY(), translationVector.getZ()); + translationVector.setX((translationVector.getX()/scaleMultiplier)*newScaleMultiplier); + translationVector.setY((translationVector.getY()/scaleMultiplier)*newScaleMultiplier); + translationVector.setZ((translationVector.getZ()/scaleMultiplier)*newScaleMultiplier); - //Reset Translation then multiply by newScaleMultiplier - Vector translationVector = p.getInteractionTranslation(); - if (translationVector == null){ - continue; + Vector moveVector = oldVector.subtract(translationVector); + PacketUtils.translateNonDisplay(part, moveVector, moveVector.length(), durationInTicks, 0); + } + else if (part.type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + double scale = part.attributeContainer.getAttributeOrDefault(DisplayAttributes.Mannequin.SCALE, 1f); + scale = (scale/scaleMultiplier)*newScaleMultiplier; + part.attributeContainer.setAttributeAndSend(DisplayAttributes.Mannequin.SCALE, (float) scale, part.getEntityId(), part.viewers); } - Vector oldVector = new Vector(translationVector.getX(), translationVector.getY(), translationVector.getZ()); - translationVector.setX((translationVector.getX()/scaleMultiplier)*newScaleMultiplier); - translationVector.setY((translationVector.getY()/scaleMultiplier)*newScaleMultiplier); - translationVector.setZ((translationVector.getZ()/scaleMultiplier)*newScaleMultiplier); - - Vector moveVector = oldVector.subtract(translationVector); - PacketUtils.translateInteraction(p, moveVector, moveVector.length(), durationInTicks, 0); } } @@ -418,7 +435,7 @@ public void run() { } updateChunkAndWorld(entity.getLocation()); } - }, 0, 30); + }, 0, 20); } return true; } @@ -529,23 +546,27 @@ public void setAttributes(@NotNull DisplayAttributeMap attributeMap, SpawnedDisp } @Override - public void setRotation(float pitch, float yaw, boolean pivotIfInteraction){ + public void setRotation(float pitch, float yaw, boolean pivot){ for (PacketDisplayEntityPart part : groupParts.values()){ - part.setRotation(pitch, yaw, pivotIfInteraction); + part.setRotation(pitch, yaw, pivot); } } + /** + * Pivot all non-display parts in this group around the group + * @param angleInDegrees the pivot angle + */ @Override public void pivot(float angleInDegrees) { for (PacketDisplayEntityPart part : groupParts.values()){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ part.pivot(angleInDegrees); } } } @Override - public void teleportMove(Vector direction, double distance, int durationInTicks) { + public void teleportMove(@NotNull Vector direction, double distance, int durationInTicks) { Location destination = getLocation().add(direction.clone().normalize().multiply(distance)); double movementIncrement = distance/(double) Math.max(durationInTicks, 1); @@ -555,8 +576,8 @@ public void teleportMove(Vector direction, double distance, int durationInTicks) .multiply(movementIncrement); for (PacketDisplayEntityPart part : groupParts.values()){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - PacketUtils.translateInteraction(part, direction, distance, durationInTicks, 0); + if (!part.isDisplay()){ + PacketUtils.translateNonDisplay(part, direction, distance, durationInTicks, 0); } } DisplayAPI.getScheduler().partRunTimerAsync(masterPart, new Scheduler.SchedulerRunnable() { @@ -586,10 +607,11 @@ public void run() { /** * {@inheritDoc} *
It is not recommended to use this multiple times in the same tick, unexpected results may occur. + *

This will fail if {@link #isRiding()} or {@link #isPlaced()} is true */ @Override public boolean teleport(@NotNull Location tpLocation, boolean respectGroupDirection){ - if (isRiding()) return false; + if (isRiding() || isPlaced) return false; Location oldMasterLoc = getLocation(); attemptLocationUpdate(oldMasterLoc, tpLocation); @@ -600,7 +622,7 @@ public boolean teleport(@NotNull Location tpLocation, boolean respectGroupDirect } masterPart.teleportUnsetPassengers(tpLocation); for (PacketDisplayEntityPart part : groupParts.values()){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ Vector vector = oldMasterLoc.toVector().subtract(part.getLocation().toVector()); Location interactionTpLoc = tpLocation.clone().subtract(vector); part.teleport(interactionTpLoc); @@ -706,23 +728,28 @@ public PacketDisplayEntityGroup clone(@NotNull Location location){ * @return a cloned {@link PacketDisplayEntityGroup} */ public PacketDisplayEntityGroup clone(@NotNull Location location, boolean playSpawnAnimation, boolean autoShow){ - //Reset Interaction pivot to 0 yaw - HashMap oldYaws = new HashMap<>(); - for (ActivePart part : this.getParts(SpawnedDisplayEntityPart.PartType.INTERACTION)){ - float oldYaw = part.getYaw(); - oldYaws.put(part, oldYaw); - part.pivot(-oldYaw); + //Reset pivot to 0 + float groupYaw = getLocation().getYaw(); + HashSet resettedParts = new HashSet<>(); + for (ActivePart part : groupParts.values()){ + if (part.isDisplay()) continue; + part.pivot(-groupYaw); + resettedParts.add(part); } + DisplayEntityGroup group = toDisplayEntityGroup(); + float newYaw = location.getYaw(); + location = location.clone(); + location.setYaw(0); PacketDisplayEntityGroup clone = group.createPacketGroup(location, GroupSpawnedEvent.SpawnReason.CLONE, playSpawnAnimation, autoShow); - //Restore Interaction Pivot - for (Map.Entry entry : oldYaws.entrySet()){ - ActivePart part = entry.getKey(); - float oldYaw = entry.getValue(); - part.pivot(oldYaw); + //Restore pivot + for (ActivePart part : resettedParts){ + part.pivot(groupYaw); } + + clone.setYaw(newYaw, true); if (this.isPersistent()) clone.setPersistent(true); return clone; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java index ff6e5bb9..ab497f24 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketDisplayEntityPart.java @@ -1,9 +1,12 @@ package net.donnypz.displayentityutils.utils.DisplayEntities; +import com.destroystokyo.paper.profile.PlayerProfile; import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.util.Vector3d; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityHeadLook; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityTeleport; +import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.events.GroupSpawnedEvent; import net.donnypz.displayentityutils.managers.DEUUser; @@ -16,17 +19,15 @@ import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttribute; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; import net.donnypz.displayentityutils.utils.packet.attributes.TextDisplayOptions; +import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.kyori.adventure.text.Component; -import org.bukkit.Bukkit; -import org.bukkit.Color; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; +import org.bukkit.*; import org.bukkit.block.data.BlockData; -import org.bukkit.entity.Display; -import org.bukkit.entity.ItemDisplay; -import org.bukkit.entity.Player; -import org.bukkit.entity.TextDisplay; +import org.bukkit.entity.*; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.MainHand; +import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.util.Transformation; import org.bukkit.util.Vector; import org.jetbrains.annotations.ApiStatus; @@ -81,14 +82,39 @@ public PacketDisplayEntityPart(@NotNull SpawnedDisplayEntityPart.PartType partTy setDefaultTransformValues(); } + /** + * Create a {@link PacketDisplayEntityPart} representative of the given entity + * @return a {@link PacketDisplayEntityPart} or null if the entity is not an eligible part entity + */ + public static @Nullable PacketDisplayEntityPart getPart(@NotNull Entity entity, boolean removeExistingEntity){ + SpawnedDisplayEntityPart.PartType pt = SpawnedDisplayEntityPart.PartType.getType(entity); + if (pt == null) return null; + PacketDisplayEntityPart part; + if (entity instanceof Display d){ + part = new DisplayEntity(d, DisplayEntity.Type.fromPartType(pt)) + .createPacketPart(null, entity.getLocation(), null); + } + else if (entity instanceof Interaction i){ + part = new InteractionEntity(i).createPacketPart(entity.getLocation(), null); + } + else if (VersionUtils.canSpawnMannequins() && entity instanceof Mannequin){ + MannequinEntity m = SavedEntityBuilder.buildMannequin(entity); + part = m.createPacketPart(entity.getLocation(), null); + } + else{ + return null; + } + if (removeExistingEntity) entity.remove(); + return part; + } + private void setDefaultTransformValues(){ - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - return; + if (isDisplay()){ + attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.TRANSLATION, new Vector3f()); + attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.SCALE, new Vector3f(1)); + attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.LEFT_ROTATION, new Quaternionf()); + attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.RIGHT_ROTATION, new Quaternionf()); } - attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.TRANSLATION, new Vector3f()); - attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.SCALE, new Vector3f(1)); - attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.LEFT_ROTATION, new Quaternionf()); - attributeContainer.setAttributeIfAbsent(DisplayAttributes.Transform.RIGHT_ROTATION, new Quaternionf()); } /** @@ -159,8 +185,8 @@ public void showToPlayer(@NotNull Player player, GroupSpawnedEvent.@NotNull Spaw return; } DEUUser.getOrCreateUser(player).trackPacketEntity(this); - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION && hasGroup()){ - Vector translation = getInteractionTranslation(group.getLocation()); + if (!isDisplay() && hasGroup()){ + Vector translation = getNonDisplayTranslation(group.getLocation()); location = location.clone().add(translation); } attributeContainer.sendEntity(type, getEntityId(), player, location); @@ -208,8 +234,8 @@ public void showToPlayers(@NotNull Collection players, GroupSpawnedEvent DEUUser.getOrCreateUser(player).trackPacketEntity(this); } } - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION && hasGroup()){ - Vector translation = getInteractionTranslation(group.getLocation()); + if (!isDisplay() && hasGroup()){ + Vector translation = getNonDisplayTranslation(group.getLocation()); location = location.clone().add(translation); } attributeContainer.sendEntityUsingPlayers(type, getEntityId(), plrs, location); @@ -289,19 +315,19 @@ public void hideFromPlayers(@NotNull Collection players) { @Override public void setTransformation(@NotNull Transformation transformation) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; + if (!isDisplay()) return; attributeContainer.setTransformationAndSend(transformation, getEntityId(), viewers); } @Override public void setTransformationMatrix(@NotNull Matrix4f matrix) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; + if (!isDisplay()) return; attributeContainer.setTransformationMatrixAndSend(matrix, getEntityId(), viewers); } @Override - public boolean setXScale(float scale) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return false; + public boolean setDisplayXScale(float scale) { + if (!isDisplay()) return false; Vector3f vec = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.SCALE, new Vector3f()); vec.x = scale; attributeContainer.setAttributeAndSend(DisplayAttributes.Transform.SCALE, vec, getEntityId(), viewers); @@ -309,8 +335,8 @@ public boolean setXScale(float scale) { } @Override - public boolean setYScale(float scale) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return false; + public boolean setDisplayYScale(float scale) { + if (!isDisplay()) return false; Vector3f vec = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.SCALE, new Vector3f()); vec.y = scale; attributeContainer.setAttributeAndSend(DisplayAttributes.Transform.SCALE, vec, getEntityId(), viewers); @@ -318,8 +344,8 @@ public boolean setYScale(float scale) { } @Override - public boolean setZScale(float scale) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return false; + public boolean setDisplayZScale(float scale) { + if (!isDisplay()) return false; Vector3f vec = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.SCALE, new Vector3f()); vec.z = scale; attributeContainer.setAttributeAndSend(DisplayAttributes.Transform.SCALE, vec, getEntityId(), viewers); @@ -327,8 +353,8 @@ public boolean setZScale(float scale) { } @Override - public boolean setScale(float x, float y, float z) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return false; + public boolean setDisplayScale(float x, float y, float z) { + if (!isDisplay()) return false; Vector3f vec = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.SCALE, new Vector3f()); vec.x = x; vec.y = y; @@ -337,6 +363,24 @@ public boolean setScale(float x, float y, float z) { return true; } + @Override + public void rotateDisplay(@NotNull Quaternionf rotation, boolean rotateTranslation) { + if (!isDisplay()) return; + Vector3f translation = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.TRANSLATION, new Vector3f()); + Quaternionf originalRot = attributeContainer.getAttributeOrDefault(DisplayAttributes.Transform.LEFT_ROTATION, new Quaternionf()); + + //World Space Rot + if (rotateTranslation){ + translation.rotate(rotation); + } + + rotation.mul(originalRot, originalRot); + + attributeContainer.setAttributesAndSend(new DisplayAttributeMap() + .add(DisplayAttributes.Transform.TRANSLATION, translation) + .add(DisplayAttributes.Transform.LEFT_ROTATION, originalRot), getEntityId(), viewers); + } + @Override public void setTextDisplayText(@NotNull Component text) { @@ -438,13 +482,24 @@ public void setItemDisplayItemGlint(boolean hasGlint) { if (type != SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY) return; ItemStack item = getItemDisplayItem(); if (item != null){ - item.editMeta(meta -> { - meta.setEnchantmentGlintOverride(hasGlint); - }); + ItemMeta meta = item.getItemMeta(); + meta.setEnchantmentGlintOverride(hasGlint); + item.setItemMeta(meta); setAndSend(DisplayAttributes.ItemDisplay.ITEMSTACK, item); } } + @Override + public boolean hasItemDisplayItemGlint() { + if (type == SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY){ + ItemStack i = attributeContainer.getAttribute(DisplayAttributes.ItemDisplay.ITEMSTACK); + if (i == null) return false; + return i.getItemMeta().getEnchantmentGlintOverride(); + } + return false; + } + + @Override public @Nullable Component getTextDisplayText() { if (type == SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY){ @@ -531,6 +586,127 @@ public boolean isTextDisplayDefaultBackground() { return attributeContainer.getAttribute(DisplayAttributes.ItemDisplay.ITEMSTACK); } + @Override + public void setMannequinPose(Pose pose) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.POSE, pose); + } + + @Override + public @Nullable Pose getMannequinPose() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return null; + return attributeContainer.getAttribute(DisplayAttributes.Mannequin.POSE); + } + + @Override + public void setMannequinScale(double scale) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.SCALE, (float) scale); + } + + @Override + public double getMannequinScale() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return -1; + return attributeContainer.getAttribute(DisplayAttributes.Mannequin.SCALE); + } + + @Override + public void setMannequinImmovable(boolean immovable) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.IMMOVABLE, immovable); + } + + @Override + public boolean isMannequinImmovable() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return false; + return attributeContainer.getAttribute(DisplayAttributes.Mannequin.IMMOVABLE); + } + + @Override + public void setMannequinGravity(boolean gravity) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.NO_GRAVITY, !gravity); + } + + @Override + public boolean hasMannequinGravity() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return false; + return !attributeContainer.getAttribute(DisplayAttributes.Mannequin.NO_GRAVITY); + } + + @Override + public void setMannequinMainHand(@NotNull MainHand mainHand) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.MAIN_HAND, mainHand); + } + + @Override + public @Nullable MainHand getMannequinMainHand() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return null; + return attributeContainer.getAttribute(DisplayAttributes.Mannequin.MAIN_HAND); + } + + @Override + public @Nullable ItemStack getMannequinEquipment(@NotNull EquipmentSlot equipmentSlot) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return null; + return attributeContainer.getAttributeOrDefault(DisplayAttributes.Equipment.getAttribute(equipmentSlot), new ItemStack(Material.AIR)); + } + + @Override + public void setMannequinEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Equipment.getAttribute(slot), itemStack); + } + + @Override + public void setMannequinProfile(@NotNull PlayerProfile profile) { + setMannequinProfile(ResolvableProfile.resolvableProfile(profile)); + } + + @Override + public void setMannequinProfile(@NotNull ResolvableProfile profile) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.RESOLVABLE_PROFILE, profile); + } + + @Override + public void setCustomName(@Nullable Component text) { + setAndSend(DisplayAttributes.CUSTOM_NAME, text); + } + + @Override + public void setCustomNameVisible(boolean visible) { + setAndSend(DisplayAttributes.CUSTOM_NAME_VISIBLE, visible); + } + + @Override + public @Nullable Component getCustomName() { + return attributeContainer.getAttribute(DisplayAttributes.CUSTOM_NAME); + } + + @Override + public boolean isCustomNameVisible(){ + return attributeContainer.getAttributeOrDefault(DisplayAttributes.CUSTOM_NAME_VISIBLE, false); + } + + @Override + public void setMannequinBelowName(@Nullable Component text) { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return; + setAndSend(DisplayAttributes.Mannequin.BELOW_NAME, text); + } + + @Override + public ResolvableProfile getMannequinProfile() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return null; + return attributeContainer.getAttribute(DisplayAttributes.Mannequin.RESOLVABLE_PROFILE); + } + + @Override + public @Nullable Component getMannequinBelowName() { + if (type != SpawnedDisplayEntityPart.PartType.MANNEQUIN) return null; + return attributeContainer.getAttribute(DisplayAttributes.Mannequin.BELOW_NAME); + } + @Override public void setAttribute(@NotNull DisplayAttribute attribute, T value) { @@ -557,7 +733,7 @@ public void resendAttributes(@NotNull Player player){ @Override public Transformation getTransformation(){ - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!isDisplay()){ return null; } return new Transformation( @@ -570,7 +746,7 @@ public Transformation getTransformation(){ @Override public int getTeleportDuration() { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!isDisplay()){ return -1; } return attributeContainer.getAttributeOrDefault(DisplayAttributes.TELEPORTATION_DURATION, 0); @@ -583,7 +759,7 @@ public int getTeleportDuration() { @Override public float getViewRange(){ - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!isDisplay()){ return -1; } return attributeContainer.getAttributeOrDefault(DisplayAttributes.VIEW_RANGE, 1f); @@ -591,12 +767,19 @@ public float getViewRange(){ @Override - public @Nullable Vector getInteractionTranslation() { - if (type != SpawnedDisplayEntityPart.PartType.INTERACTION) { - return null; - } - if (group == null) return null; - return getInteractionTranslation(group.getLocation()); + public @Nullable Vector getNonDisplayTranslation() { + if (isDisplay() || group == null) return null; + return getNonDisplayTranslation(group.getLocation()); + } + + /** + * Get the Interaction's translation vector relative to a location + * @param referenceLocation the reference location + * @return A vector or null if the part is not an interaction + */ + public Vector getNonDisplayTranslation(@NotNull Location referenceLocation){ + if (isDisplay()) return null; + return referenceLocation.toVector().subtract(getLocation().toVector()); } @Override @@ -620,19 +803,6 @@ public void setInteractionResponsive(boolean responsive) { } } - /** - * Get the Interaction's translation vector relative to a location - * @param referenceLocation the reference location - * @return A vector or null if the part is not an interaction - */ - public Vector getInteractionTranslation(@NotNull Location referenceLocation){ - if (type != SpawnedDisplayEntityPart.PartType.INTERACTION) { - return null; - } - return referenceLocation.toVector().subtract(getLocation().toVector()); - } - - @Override public float getInteractionHeight() { if (type != SpawnedDisplayEntityPart.PartType.INTERACTION) { @@ -719,7 +889,7 @@ private NamespacedKey getInteractionCMDKey(boolean isLeftClick, boolean isConsol @Override protected void cull(float width, float height) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; + if (!isDisplay()) return; attributeContainer .setAttributesAndSend(new DisplayAttributeMap() .add(DisplayAttributes.Culling.HEIGHT, height) @@ -748,25 +918,31 @@ public Collection getTrackingPlayers() { @Override public @Nullable Color getGlowColor() { - return attributeContainer.getAttribute(DisplayAttributes.GLOW_COLOR_OVERRIDE); + if (isDisplay()){ + return attributeContainer.getAttribute(DisplayAttributes.GLOW_COLOR_OVERRIDE); + } + return null; } @Override public void setGlowColor(@Nullable Color color) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.GLOW_COLOR_OVERRIDE, color); + if (isDisplay()){ + setAndSend(DisplayAttributes.GLOW_COLOR_OVERRIDE, color); + } } @Override public void glow() { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.GLOWING, true); + if (canGlow()){ + setAndSend(DisplayAttributes.GLOWING, true); + } } @Override public void unglow() { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.GLOWING, false); + if (canGlow()){ + setAndSend(DisplayAttributes.GLOWING, false); + } } /** @@ -774,8 +950,9 @@ public void unglow() { */ @Override public void setTeleportDuration(int teleportDuration) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.TELEPORTATION_DURATION, teleportDuration); + if (isDisplay()){ + setAndSend(DisplayAttributes.TELEPORTATION_DURATION, teleportDuration); + } } /** @@ -784,10 +961,9 @@ public void setTeleportDuration(int teleportDuration) { */ @Override public void setInterpolationDuration(int interpolationDuration) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - return; + if (isDisplay()){ + setAndSend(DisplayAttributes.Interpolation.DURATION, interpolationDuration); } - setAndSend(DisplayAttributes.Interpolation.DURATION, interpolationDuration); } /** @@ -796,39 +972,47 @@ public void setInterpolationDuration(int interpolationDuration) { */ @Override public void setInterpolationDelay(int interpolationDelay) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - return; + if (isDisplay()){ + setAndSend(DisplayAttributes.Interpolation.DELAY, interpolationDelay); } - setAndSend(DisplayAttributes.Interpolation.DELAY, interpolationDelay); } @Override public void setViewRange(float viewRangeMultiplier) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.VIEW_RANGE, viewRangeMultiplier); + if (isDisplay()){ + setAndSend(DisplayAttributes.VIEW_RANGE, viewRangeMultiplier); + } } @Override public void setBillboard(Display.@NotNull Billboard billboard) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.BILLBOARD, billboard); + if (isDisplay()){ + setAndSend(DisplayAttributes.BILLBOARD, billboard); + } } @Override public void setBrightness(Display.@Nullable Brightness brightness) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION) return; - setAndSend(DisplayAttributes.BRIGHTNESS, brightness); + if (isDisplay()){ + setAndSend(DisplayAttributes.BRIGHTNESS, brightness); + } } @Override - public void setRotation(float pitch, float yaw, boolean pivotIfInteraction){ - if (pivotIfInteraction && type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + public void setRotation(float pitch, float yaw, boolean pivot){ + if (pivot && !isDisplay()){ pivot(yaw, pitch); } else if (!viewers.isEmpty()){ + WrapperPlayServerEntityHeadLook headLook = getHeadLookPacket(yaw); WrapperPlayServerEntityRotation rotPacket = new WrapperPlayServerEntityRotation(getEntityId(), yaw, pitch, false); for (UUID uuid : getViewers()){ - PacketEvents.getAPI().getPlayerManager().sendPacket(Bukkit.getPlayer(uuid), rotPacket); + Player p = Bukkit.getPlayer(uuid); + if (p == null) continue; + PacketEvents.getAPI().getPlayerManager().sendPacket(p, rotPacket); + if (packetLocation.yaw != yaw && type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + PacketEvents.getAPI().getPlayerManager().sendPacket(p, headLook); + } } } packetLocation.pitch = pitch; @@ -841,6 +1025,11 @@ public void setPitch(float pitch) { setRotation(pitch, getYaw(), false); } + /** + * Change the yaw of this part + * @param yaw The yaw to set for this part + * @param pivot whether the part should pivot around its group's location, if it has one, and if the part is an Interaction + */ @Override public void setYaw(float yaw, boolean pivot) { setRotation(getPitch(), yaw, pivot); @@ -857,12 +1046,12 @@ public float getYaw(){ } /** - * Pivot an Interaction Entity around its group's master part + * Pivot a non-display entity around its group\ * @param angleInDegrees the pivot angle */ @Override public void pivot(float angleInDegrees) { - if (type != SpawnedDisplayEntityPart.PartType.INTERACTION) return; + if (isDisplay() || group == null) return; pivot(getYaw(), getPitch(), angleInDegrees); } @@ -871,27 +1060,36 @@ private void pivot(float yaw, float pitch){ } private void pivot(float yaw, float pitch, float angleInDegrees){ + if (group == null || isDisplay()) return; Location groupLoc = group.getLocation(); Location pivotedLoc = DisplayUtils.getPivotLocation(getLocation(), groupLoc, angleInDegrees); packetLocation.setCoordinates(pivotedLoc); + WrapperPlayServerEntityHeadLook headLook = getHeadLookPacket(yaw); + WrapperPlayServerEntityTeleport teleport = new WrapperPlayServerEntityTeleport(getEntityId(), + new Vector3d(pivotedLoc.x(), pivotedLoc.y(), pivotedLoc.z()), + yaw, + pitch, + false); for (UUID uuid : getViewers()){ Player player = Bukkit.getPlayer(uuid); if (player == null) continue; - PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityTeleport(getEntityId(), - new Vector3d(pivotedLoc.x(), pivotedLoc.y(), pivotedLoc.z()), - yaw, - pitch, - false)); + PacketEvents.getAPI().getPlayerManager().sendPacket(player, teleport); + if (type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + PacketEvents.getAPI().getPlayerManager().sendPacket(player, headLook); + } } } /** - * Set the location of this packet-based entity. The part should be hidden first with {@link #hide()} if being teleported to a different world. + * Set the location of this packet-based entity. + * {@inheritDoc} + *
The part should be hidden first with {@link #hide()} if being teleported to a different world. * @param location the location */ public void teleport(@NotNull Location location){ + if (hasGroup() && isDisplay() && !isMaster) return; packetLocation = new PacketLocation(location); for (UUID uuid : getViewers()){ Player player = Bukkit.getPlayer(uuid); @@ -900,10 +1098,7 @@ public void teleport(@NotNull Location location){ } } - /** - * Set the location of this packet-based entity. The part should be hidden first with {@link #hide()} if being teleported to a different world. - * @param location the location - */ + void teleportUnsetPassengers(@NotNull Location location){ packetLocation = new PacketLocation(location); for (UUID uuid : getViewers()){ @@ -928,7 +1123,7 @@ void teleportUnsetPassengers(@NotNull Location location){ */ @Override public @Nullable Location getLocation(){ - if (!isMaster && group != null && type != SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!isMaster && group != null && isDisplay()){ return group.getLocation(); } if (packetLocation != null){ @@ -966,8 +1161,8 @@ public boolean hasLocation(){ */ @Override public boolean translate(@NotNull Vector direction, float distance, int durationInTicks, int delayInTicks) { - if (type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - PacketUtils.translateInteraction(this, direction, distance, durationInTicks, delayInTicks); + if (!isDisplay()){ + PacketUtils.translateNonDisplay(this, direction, distance, durationInTicks, delayInTicks); } else{ PacketUtils.translate(this, direction, distance, durationInTicks, delayInTicks); @@ -1085,7 +1280,7 @@ public void removeFromGroup(boolean unregister){ if (!hasGroup()) return; group.groupParts.remove(partUUID); if (!isMaster){ - group.updatePartCount(this, false); + group.updatePassengerIds(getEntityId(), false); } group = null; if (unregister){ @@ -1093,6 +1288,15 @@ public void removeFromGroup(boolean unregister){ } } + private WrapperPlayServerEntityHeadLook getHeadLookPacket(float yaw){ + return new WrapperPlayServerEntityHeadLook(getEntityId(), yaw); + } + + private void sendHeadLookPacket(Player player, float yaw){ + PacketEvents.getAPI().getPlayerManager().sendPacket(player, getHeadLookPacket(yaw)); + } + + static final class PacketLocation { String worldName; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketPartSelection.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketPartSelection.java index c301dcbb..e3e5f84c 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketPartSelection.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/PacketPartSelection.java @@ -84,9 +84,9 @@ public void remove() { } @Override - public void setRotation(float pitch, float yaw, boolean pivotIfInteraction) { + public void setRotation(float pitch, float yaw, boolean pivot) { for (PacketDisplayEntityPart part : selectedParts){ - part.setRotation(pitch, yaw, pivotIfInteraction); + part.setRotation(pitch, yaw, pivot); } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/Packeted.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/Packeted.java index c054c043..164c5670 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/Packeted.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/Packeted.java @@ -10,7 +10,7 @@ public interface Packeted{ - void setRotation(float pitch, float yaw, boolean pivotIfInteraction); + void setRotation(float pitch, float yaw, boolean pivot); @Nullable Location getLocation(); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java new file mode 100644 index 00000000..7ef6902b --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityBuilder.java @@ -0,0 +1,150 @@ +package net.donnypz.displayentityutils.utils.DisplayEntities; + +import com.destroystokyo.paper.profile.ProfileProperty; +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.packet.PacketAttributeContainer; +import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Pose; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.MainHand; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.profile.PlayerTextures; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +class SavedEntityBuilder { + + static MannequinEntity buildMannequin(Entity entity){ //Accept entity instead of mannequin, preventing issues on versions below 1.21.9 + MannequinEntity mannequinEntity = new MannequinEntity(); + org.bukkit.entity.Mannequin mannequin = (org.bukkit.entity.Mannequin) entity; + + Component customName = mannequin.customName(); + mannequinEntity.customName = customName != null ? MiniMessage.miniMessage().serialize(customName) : null; + mannequinEntity.customNameVisible = mannequin.isCustomNameVisible(); + + Component description = mannequin.getDescription(); + mannequinEntity.description = description != null ? MiniMessage.miniMessage().serialize(description) : null; + + setProfileFields(mannequinEntity, mannequin.getProfile()); + + mannequinEntity.scale = mannequin.getAttribute(Attribute.SCALE).getBaseValue(); + mannequinEntity.pose = mannequin.getPose().name(); + + mannequinEntity.isRightMainHand = mannequin.getMainHand() == MainHand.RIGHT; + EntityEquipment equipment = mannequin.getEquipment(); + mannequinEntity.equipment = new byte[][]{ + serializeItemStack(equipment.getHelmet()), + serializeItemStack(equipment.getChestplate()), + serializeItemStack(equipment.getLeggings()), + serializeItemStack(equipment.getBoots()), + serializeItemStack(equipment.getItemInMainHand()), + serializeItemStack(equipment.getItemInOffHand()) + }; + + mannequinEntity.vector = DisplayUtils.getNonDisplayTranslation(mannequin).toVector3f(); + + try{ + mannequinEntity.persistentDataContainer = mannequin.getPersistentDataContainer().serializeToBytes(); + } + catch(IOException e){ + e.printStackTrace(); + } + return mannequinEntity; + } + + static MannequinEntity buildMannequin(PacketDisplayEntityPart part){ + MannequinEntity mannequinEntity = new MannequinEntity(); + PacketAttributeContainer c = part.attributeContainer; + + Component customName = part.getCustomName(); + mannequinEntity.customName = customName != null ? MiniMessage.miniMessage().serialize(customName) : null; + mannequinEntity.customNameVisible = part.isCustomNameVisible(); + + Component description = part.getMannequinBelowName(); + mannequinEntity.description = description != null ? MiniMessage.miniMessage().serialize(description) : null; + + setProfileFields(mannequinEntity, part.getMannequinProfile()); + + mannequinEntity.scale = c.getAttributeOrDefault(DisplayAttributes.Mannequin.SCALE, 1.0f); + Pose pose = part.getMannequinPose(); + if (pose == null){ + pose = Pose.STANDING; + } + mannequinEntity.pose = pose.name(); + + mannequinEntity.isRightMainHand = part.getMannequinMainHand() == MainHand.RIGHT; + mannequinEntity.equipment = new byte[][]{ + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.HEAD)), + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.CHEST)), + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.LEGS)), + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.FEET)), + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.HAND)), + serializeItemStack(part.getMannequinEquipment(EquipmentSlot.OFF_HAND)) + }; + + + mannequinEntity.vector = part.getNonDisplayTranslation().toVector3f(); + + try{ + ItemStack i = new ItemStack(Material.STICK); + PersistentDataContainer pdc = i.getItemMeta().getPersistentDataContainer(); + pdc.set(DisplayAPI.getPartPDCTagKey(), PersistentDataType.LIST.strings(), new ArrayList<>(part.getTags())); + pdc.set(DisplayAPI.getPartUUIDKey(), PersistentDataType.STRING, part.partUUID.toString()); + mannequinEntity.persistentDataContainer = pdc.serializeToBytes(); + } + catch(IOException e){ + e.printStackTrace(); + } + return mannequinEntity; + } + + static byte[] serializeItemStack(ItemStack itemStack){ + if (itemStack == null || itemStack.isEmpty()) return null; + return itemStack.serializeAsBytes(); + } + + private static void setProfileFields(MannequinEntity mannequinEntity, ResolvableProfile profile){ + if (profile != null){ + mannequinEntity.profileName = profile.name(); + mannequinEntity.profileUUID = profile.uuid(); + + Collection bukkitProperties = profile.properties(); + if (bukkitProperties != null){ + List properties = new ArrayList<>(); + for (ProfileProperty prop : bukkitProperties){ + properties.add(new MannequinEntity.ProfileProperty(prop)); + } + mannequinEntity.profileProperties = properties; + } + + ResolvableProfile.SkinPatch skinPatch = profile.skinPatch(); + if (skinPatch.isEmpty()) { + return; + } + + Key body = skinPatch.body(); + Key cape = skinPatch.cape(); + Key elytra = skinPatch.elytra(); + PlayerTextures.SkinModel model = skinPatch.model(); + + if (body != null) mannequinEntity.profileSkinPatchBody = body.asString(); + if (cape != null) mannequinEntity.profileSkinPatchCape = cape.asString(); + if (elytra != null) mannequinEntity.profileSkinPatchElytra = elytra.asString(); + if (model != null) mannequinEntity.profileSkinPatchModel = model.name(); + } + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java new file mode 100644 index 00000000..3615d418 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SavedEntityLoader.java @@ -0,0 +1,92 @@ +package net.donnypz.displayentityutils.utils.DisplayEntities; + +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Location; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Mannequin; +import org.bukkit.entity.Pose; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.MainHand; +import org.bukkit.profile.PlayerTextures; + +import java.io.IOException; + +class SavedEntityLoader { + + static Mannequin spawnMannequin(Location origin, GroupSpawnSettings settings, MannequinEntity mannequinEntity){ + Location spawnLoc = DisplayUtils.getPivotLocation( + mannequinEntity.vector, + origin, + origin.getYaw()); + + return spawnLoc.getWorld().spawn(spawnLoc, org.bukkit.entity.Mannequin.class, m ->{ + DisplayUtils.prepareMannequin(m); + + m.customName(mannequinEntity.customName != null ? MiniMessage.miniMessage().deserialize(mannequinEntity.customName): null); + m.setDescription(mannequinEntity.description != null ? MiniMessage.miniMessage().deserialize(mannequinEntity.description) : null); + + m.setProfile(getMannequinProfile(mannequinEntity)); + m.getAttribute(Attribute.SCALE).setBaseValue(mannequinEntity.scale); + m.setPose(Pose.valueOf(mannequinEntity.pose)); + + m.setMainHand(mannequinEntity.isRightMainHand ? MainHand.RIGHT : MainHand.LEFT); + + EntityEquipment equipment = m.getEquipment(); + equipment.setItemInMainHand(mannequinEntity.getMainHand()); + equipment.setItemInOffHand(mannequinEntity.getOffHand()); + equipment.setHelmet(mannequinEntity.getHelmet()); + equipment.setHelmet(mannequinEntity.getChestplate()); + equipment.setHelmet(mannequinEntity.getLeggings()); + equipment.setHelmet(mannequinEntity.getBoots()); + + if (mannequinEntity.persistentDataContainer != null){ + try{ + m.getPersistentDataContainer().readFromBytes(mannequinEntity.persistentDataContainer); + } + catch(IOException ignore){} + } + + settings.apply(m); + }); + } + + static ResolvableProfile getMannequinProfile(MannequinEntity mannequin){ + Key body = null; + Key cape = null; + Key elytra = null; + PlayerTextures.SkinModel model = null; + if (mannequin.profileSkinPatchBody != null){ + body = Key.key(mannequin.profileSkinPatchBody); + } + if (mannequin.profileSkinPatchCape != null){ + cape = Key.key(mannequin.profileSkinPatchCape); + } + if (mannequin.profileSkinPatchElytra != null){ + elytra = Key.key(mannequin.profileSkinPatchElytra); + } + if (mannequin.profileSkinPatchModel != null){ + model = PlayerTextures.SkinModel.valueOf(mannequin.profileSkinPatchModel); + } + + ResolvableProfile.Builder builder = ResolvableProfile.resolvableProfile() + .name(mannequin.profileName) + .uuid(mannequin.profileUUID) + .skinPatch(ResolvableProfile.SkinPatch.skinPatch() + .body(body) + .cape(cape) + .elytra(elytra) + .model(model) + .build()); + + if (mannequin.profileProperties != null){ + for (MannequinEntity.ProfileProperty prop : mannequin.profileProperties){ + builder.addProperty(prop.toBukkitProperty()); + } + } + + return builder.build(); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SinglePartSelection.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SinglePartSelection.java index 2eda5174..5d628c56 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SinglePartSelection.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SinglePartSelection.java @@ -23,6 +23,7 @@ public SinglePartSelection(@NotNull SpawnedDisplayEntityPart part){ @Override public void remove() { + selectedPart.remove(false); selectedPart = null; } @@ -106,6 +107,10 @@ public void setYaw(float yaw, boolean pivot) { selectedPart.setYaw(yaw, pivot); } + /** + * Pivot a non-display entity around its group's master part + * @param angleInDegrees the pivot angle + */ @Override public void pivot(float angleInDegrees) { selectedPart.pivot(angleInDegrees); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayAnimationFrame.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayAnimationFrame.java index 44b2b846..25ffd83f 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayAnimationFrame.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayAnimationFrame.java @@ -124,7 +124,7 @@ public SpawnedDisplayAnimationFrame setTransformation(@NotNull ActiveGroup gr if (p.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ InteractionTransformation transform = new InteractionTransformation( - p.getInteractionTranslation().toVector3f(), + p.getNonDisplayTranslation(), gLoc.getYaw(), gLoc.getPitch(), p.getInteractionHeight(), @@ -157,7 +157,7 @@ public SpawnedDisplayAnimationFrame setTransformation(@NotNull ActiveGroup gr if (p.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ InteractionTransformation transform = new InteractionTransformation( - p.getInteractionTranslation().toVector3f(), + p.getNonDisplayTranslation(), gLoc.getYaw(), gLoc.getPitch(), p.getInteractionHeight(), diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java index 5aa85d0f..d5bd72b6 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityGroup.java @@ -14,6 +14,7 @@ import net.donnypz.displayentityutils.utils.version.folia.FoliaUtils; import net.donnypz.displayentityutils.utils.version.folia.Scheduler; import org.bukkit.*; +import org.bukkit.attribute.Attribute; import org.bukkit.entity.*; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; @@ -120,6 +121,28 @@ public void addPart(@NotNull SpawnedDisplayEntityPart part){ } + /** + * {@inheritDoc} + */ + @Override + public @Nullable SpawnedDisplayEntityPart addEntity(@NotNull Entity entity){ + if (entity instanceof Display display){ + return addDisplayEntity(display); + } + + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); + if (part == null){ + part = new SpawnedDisplayEntityPart(this, entity, partUUIDRandom); + } + else{ + part.setGroup(this); + } + if (getVehicle() != null){ + alignNonDisplayWithMountedGroup(part, getVehicle()); + } + return part; + } + /** * Add a display entity to this group. If this group already contains this display entity as a registered part it will return the existing * {@link SpawnedDisplayEntityPart}. If it doesn't then it will return a new {@link SpawnedDisplayEntityPart} @@ -152,98 +175,39 @@ else if (!groupParts.isEmpty()){ } - /** - * Add an interaction entity to this group. If this group already contains this interaction entity as a registered part it will return the existing - * {@link SpawnedDisplayEntityPart}. If it doesn't then it will return a new {@link SpawnedDisplayEntityPart} - * @param interactionEntity - * @return a {@link SpawnedDisplayEntityPart} representing the Interaction entity - */ - public SpawnedDisplayEntityPart addInteractionEntity(@NotNull Interaction interactionEntity){ - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(interactionEntity); - if (part == null){ - part = new SpawnedDisplayEntityPart(this, interactionEntity, partUUIDRandom); - } - else{ - part.setGroup(this); - } - if (getVehicle() != null){ - alignInteractionWithMountedGroup(part, getVehicle()); - } - return part; - } - - /** - * Add a valid part entity (Display or Interaction) to this group, when you don't know the type of entity you're dealing with - * @param entity the part entity to add - * @return a corresponding {@link SpawnedDisplayEntityPart} or null if the entity is not a part entity - */ - public SpawnedDisplayEntityPart addPartEntity(@NotNull Entity entity){ - if (entity instanceof Interaction interaction){ - return addInteractionEntity(interaction); - } - else if (entity instanceof Display display){ - return addDisplayEntity(display); - } - else{ - return null; - } - } - - /** - * Check if this group and a Display entity share the same creation time. If this returns true this does not guarantee - * that the part is registered to this group. Using {@link SpawnedDisplayEntityGroup#addDisplayEntity(Display)} will - * add the display entity to the group if it is not added already - * @param display - * @return a boolean - */ - public boolean hasSameCreationTime(Display display){ - return sameCreationTime(display); - } /** - * Check if this group and an Interaction entity share the same creation time. If this returns true this does not guarantee - * that the part is registered to this group. Using {@link SpawnedDisplayEntityGroup#addInteractionEntity(Interaction)} will + * Check if this group and an entity share the same creation time. If this returns true this does not guarantee + * that the part is registered to this group. + *
Using {@link SpawnedDisplayEntityGroup#addEntity(Entity)} will * add the interaction entity to the group if it is not added already - * @param interaction + * @param entity the entity * @return a boolean */ - public boolean hasSameCreationTime(Interaction interaction){ - return sameCreationTime(interaction); - } - - - - private boolean sameCreationTime(Entity entity){ + public boolean hasSameCreationTime(Entity entity){ PersistentDataContainer container = entity.getPersistentDataContainer(); if (!container.has(creationTimeKey, PersistentDataType.LONG)){ return false; } - return creationTime == container.get(creationTimeKey, PersistentDataType.LONG); } /** - * Add Interactions that are meant to be a part of this group - * Usually these Interactions are unadded when a SpawnedDisplayEntityGroup is created during a new play session - * @param searchRange Distance to search for Interaction entities from the group's location - * @return a list of the interaction entities added to the group + * Add entities that are meant to be a part of this group. + * Usually these entities are unadded when a {@link SpawnedDisplayEntityGroup} is created during a new play session + * @param searchRange distance to search for entities from the group's location + * @return a list of the entities added to the group */ - public List addMissingInteractionEntities(double searchRange){ - List interactions = new ArrayList<>(); - //List existingInteractions = getSpawnedPartEntities(SpawnedDisplayEntityPart.PartType.INTERACTION); + public @NotNull List addMissingEntities(double searchRange){ + List entities = new ArrayList<>(); for (Entity e : getMasterPart().getEntity().getNearbyEntities(searchRange, searchRange, searchRange)) { - if (!(e instanceof Interaction i)){ - continue; - } - //if (!existingInteractions.contains(i) && sameCreationTime(i)){ - if (!sameCreationTime(i)){ - continue; - } + if (!DisplayUtils.isPartEntity(e) || e instanceof Display) continue; + if (!hasSameCreationTime(e)) continue; - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(i); + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(e); if (part == null){ - new SpawnedDisplayEntityPart(this, i, partUUIDRandom); + new SpawnedDisplayEntityPart(this, e, partUUIDRandom); } else{ if (this == part.getGroup()){ //Already in this group @@ -251,9 +215,9 @@ public List addMissingInteractionEntities(double searchRange){ } part.setGroup(this); } - interactions.add(i); + entities.add(e); } - return interactions; + return entities; } @ApiStatus.Internal @@ -275,8 +239,8 @@ public void seedPartUUIDs(long seed){ */ @Override public void showToPlayer(@NotNull Player player){ - for (ActivePart part : groupParts.values()){ - ((SpawnedDisplayEntityPart) part).showToPlayer(player); + for (SpawnedDisplayEntityPart part : groupParts.values()){ + part.showToPlayer(player); } } @@ -330,8 +294,7 @@ public List getUnaddedInteractionEntitiesInRange(double searchRange if ((e instanceof Interaction interaction)){ if (!existingInteractions.contains(e)){ if (addToGroup){ - addInteractionEntity(interaction); - + addEntity(interaction); } interactions.add(interaction); } @@ -451,7 +414,7 @@ public SpawnedDisplayEntityGroup setPersistenceOverride(boolean override){ } @Override - public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleInteractions){ + public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scaleNonDisplays){ if (newScaleMultiplier <= 0){ throw new IllegalArgumentException("New Scale Multiplier cannot be <= 0"); } @@ -467,10 +430,10 @@ public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scal return false; } - for (SpawnedDisplayEntityPart p : groupParts.values()){ + for (SpawnedDisplayEntityPart part : groupParts.values()){ //Displays - if (p.getType() != SpawnedDisplayEntityPart.PartType.INTERACTION){ - Display d = (Display) p.getEntity(); + if (part.isDisplay()){ + Display d = (Display) part.getEntity(); Transformation transformation = d.getTransformation(); //Reset Scale then multiply by newScaleMultiplier @@ -493,30 +456,38 @@ public boolean scale(float newScaleMultiplier, int durationInTicks, boolean scal } //Culling if (DisplayConfig.autoCulling()){ - p.autoCull(DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); + part.autoCull(DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); } } //Interactions - else if (scaleInteractions){ - Interaction i = (Interaction) p.getEntity(); - - //Reset Scale then multiply by newScaleMultiplier - float newHeight = (i.getInteractionHeight()/scaleMultiplier)*newScaleMultiplier; - float newWidth = (i.getInteractionWidth()/scaleMultiplier)*newScaleMultiplier; - DisplayUtils.scaleInteraction(i, newHeight, newWidth, durationInTicks, 0); + else if (scaleNonDisplays){ + if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ + Interaction i = (Interaction) part.getEntity(); + + //Reset Scale then multiply by newScaleMultiplier + float newHeight = (i.getInteractionHeight()/scaleMultiplier)*newScaleMultiplier; + float newWidth = (i.getInteractionWidth()/scaleMultiplier)*newScaleMultiplier; + DisplayUtils.scaleInteraction(i, newHeight, newWidth, durationInTicks, 0); + + //Reset Translation then multiply by newScaleMultiplier + Vector translationVector = DisplayUtils.getNonDisplayTranslation(i); + if (translationVector == null){ + continue; + } + Vector oldVector = new Vector(translationVector.getX(), translationVector.getY(), translationVector.getZ()); + translationVector.setX((translationVector.getX()/scaleMultiplier)*newScaleMultiplier); + translationVector.setY((translationVector.getY()/scaleMultiplier)*newScaleMultiplier); + translationVector.setZ((translationVector.getZ()/scaleMultiplier)*newScaleMultiplier); - //Reset Translation then multiply by newScaleMultiplier - Vector translationVector = DisplayUtils.getInteractionTranslation(i); - if (translationVector == null){ - continue; + Vector moveVector = oldVector.subtract(translationVector); + part.translateForce(moveVector, (float) moveVector.length(), durationInTicks, 0); + } + else if (part.type == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + Mannequin m = (Mannequin) part.getEntity(); + double scale = m.getAttribute(Attribute.SCALE).getBaseValue(); + scale = (scale/scaleMultiplier)*newScaleMultiplier; + m.getAttribute(Attribute.SCALE).setBaseValue(scale); } - Vector oldVector = new Vector(translationVector.getX(), translationVector.getY(), translationVector.getZ()); - translationVector.setX((translationVector.getX()/scaleMultiplier)*newScaleMultiplier); - translationVector.setY((translationVector.getY()/scaleMultiplier)*newScaleMultiplier); - translationVector.setZ((translationVector.getZ()/scaleMultiplier)*newScaleMultiplier); - - Vector moveVector = oldVector.subtract(translationVector); - p.translateForce(moveVector, (float) moveVector.length(), durationInTicks, 0); } } @@ -548,57 +519,57 @@ private void teleportWithoutEvent(Location location, boolean respectGroupDirecti } FoliaUtils.teleport(master, location, TeleportFlag.EntityState.RETAIN_PASSENGERS); - World w = location.getWorld(); - for (SpawnedDisplayEntityPart part : this.getParts()){ part.getEntity().setRotation(location.getYaw(), location.getPitch()); - //Interaction Entity TP - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + //Non-Display TP + if (!part.isDisplay()){ Interaction interaction = (Interaction) part.getEntity(); Vector vector = oldMasterLoc.toVector().subtract(interaction.getLocation().toVector()); Location tpLocation = location.clone().subtract(vector); FoliaUtils.teleport(part.getEntity(), tpLocation, TeleportFlag.EntityState.RETAIN_PASSENGERS); } - - if (w != null && part.getEntity().getWorld() != w){ //Keep world name consistent within part's data - part.getPartData().setWorldName(w.getName()); - } } } - private static void translateInteractionEventless(@NotNull Interaction interaction, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ - Location destination = interaction.getLocation().clone().add(direction.clone().normalize().multiply(distance)); + private static void translateEntityEventless(@NotNull Entity entity, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + DisplayUtils.translate(entity, direction, distance, durationInTicks, delayInTicks); + Location destination = entity.getLocation().clone().add(direction.clone().normalize().multiply(distance)); + + if (durationInTicks <= 0 && delayInTicks <= 0){ + FoliaUtils.teleport(entity, destination); + return; + } + double movementIncrement = distance/(double) Math.max(durationInTicks, 1); Vector incrementVector = direction .clone() .normalize() .multiply(movementIncrement); - DisplayAPI.getScheduler().entityRunTimer(interaction, new Scheduler.SchedulerRunnable(){ + DisplayAPI.getScheduler().entityRunTimer(entity, new Scheduler.SchedulerRunnable() { double currentDistance = 0; - float lastYaw = interaction.getYaw(); + float lastYaw = entity.getYaw(); @Override public void run() { - float newYaw = interaction.getYaw(); + float newYaw = entity.getYaw(); if (newYaw != lastYaw){ incrementVector.rotateAroundY(Math.toRadians(lastYaw-newYaw)); lastYaw = newYaw; } currentDistance+=Math.abs(movementIncrement); - Location tpLoc = interaction.getLocation().clone().add(incrementVector); + Location tpLoc = entity.getLocation().clone().add(incrementVector); if (currentDistance >= distance){ - FoliaUtils.teleport(interaction, destination); + FoliaUtils.teleport(entity, destination); cancel(); } else{ - FoliaUtils.teleport(interaction, tpLoc); + FoliaUtils.teleport(entity, tpLoc); } } }, delayInTicks, 1); - } @Override @@ -616,8 +587,8 @@ public void teleportMove(@NotNull Vector direction, double distance, int duratio .multiply(movementIncrement); for (SpawnedDisplayEntityPart part : groupParts.values()){ - if (part.type == SpawnedDisplayEntityPart.PartType.INTERACTION){ - translateInteractionEventless((Interaction) part.getEntity(), direction, distance, durationInTicks, 0); + if (!part.isDisplay()){ + translateEntityEventless(part.getEntity(), direction, distance, durationInTicks, 0); } } @@ -684,13 +655,13 @@ public List getTeleportMoveLocations(Vector direction, double distance /** - * Pivot all Interaction parts in this selection around this group's master part + * Pivot all non-display parts in this group around the group * @param angleInDegrees the pivot angle */ @Override public void pivot(float angleInDegrees){ for (ActivePart part : groupParts.values()){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ part.pivot(angleInDegrees); } } @@ -844,7 +815,7 @@ public boolean rideEntity(@NotNull Entity vehicle){ } for (SpawnedDisplayEntityPart interactionPart: this.getParts(SpawnedDisplayEntityPart.PartType.INTERACTION)){ - alignInteractionWithMountedGroup(interactionPart, vehicle); + alignNonDisplayWithMountedGroup(interactionPart, vehicle); } return true; } @@ -871,7 +842,7 @@ public boolean isRiding(){ return getVehicle() != null; } - private void alignInteractionWithMountedGroup(SpawnedDisplayEntityPart part, Entity vehicle){ + private void alignNonDisplayWithMountedGroup(SpawnedDisplayEntityPart part, Entity vehicle){ final Interaction interaction = (Interaction) part.getEntity(); DisplayAPI.getScheduler().entityRunTimer(interaction, new Scheduler.SchedulerRunnable() { Location lastLoc = getLocation(); @@ -1156,12 +1127,13 @@ public SpawnedDisplayEntityGroup clone(@NotNull Location location){ * @return a cloned {@link SpawnedDisplayEntityGroup} */ public SpawnedDisplayEntityGroup clone(@NotNull Location location, @NotNull GroupSpawnSettings settings){ - //Reset Interaction pivot to 0 yaw - HashMap oldYaws = new HashMap<>(); - for (SpawnedDisplayEntityPart part : this.getParts(SpawnedDisplayEntityPart.PartType.INTERACTION)){ - float oldYaw = part.getYaw(); - oldYaws.put(part, oldYaw); - part.pivot(-oldYaw); + //Reset pivot to 0 yaw + float groupYaw = getLocation().getYaw(); + HashSet resettedParts = new HashSet<>(); + for (ActivePart part : groupParts.values()){ + if (part.isDisplay()) continue; + part.pivot(-groupYaw); + resettedParts.add(part); } DisplayEntityGroup savedGroup = toDisplayEntityGroup(); @@ -1170,23 +1142,22 @@ public SpawnedDisplayEntityGroup clone(@NotNull Location location, @NotNull Grou location.setYaw(0); SpawnedDisplayEntityGroup cloned = savedGroup.spawn(location, GroupSpawnedEvent.SpawnReason.CLONE, settings); - //Restore Interaction Pivot - for (Map.Entry entry : oldYaws.entrySet()){ - SpawnedDisplayEntityPart part = entry.getKey(); - float oldYaw = entry.getValue(); - part.pivot(oldYaw); + //Restore pivot + for (ActivePart part : resettedParts){ + part.pivot(groupYaw); } + cloned.setYaw(newYaw, true); return cloned; } public PacketDisplayEntityGroup toPacket(@NotNull Location location, boolean playSpawnAnimation, boolean autoShow, boolean persistent){ - //Reset Interaction pivot to 0 yaw - HashMap oldYaws = new HashMap<>(); - for (SpawnedDisplayEntityPart part : this.getParts(SpawnedDisplayEntityPart.PartType.INTERACTION)){ - float oldYaw = part.getEntity().getYaw(); - oldYaws.put(part, oldYaw); - part.pivot(-oldYaw); + //Reset pivot to 0 yaw + float groupYaw = getLocation().getYaw(); + HashSet resettedParts = new HashSet<>(); + for (ActivePart part : groupParts.values()){ + part.pivot(-groupYaw); + resettedParts.add(part); } DisplayEntityGroup savedGroup = toDisplayEntityGroup(); @@ -1195,7 +1166,6 @@ public PacketDisplayEntityGroup toPacket(@NotNull Location location, boolean pla location.setYaw(0); PacketDisplayEntityGroup packetGroup; - if (persistent){ packetGroup = DisplayGroupManager.addPersistentPacketGroup(location, savedGroup, autoShow, GroupSpawnedEvent.SpawnReason.INTERNAL); } @@ -1203,11 +1173,9 @@ public PacketDisplayEntityGroup toPacket(@NotNull Location location, boolean pla packetGroup = savedGroup.createPacketGroup(location, GroupSpawnedEvent.SpawnReason.INTERNAL, playSpawnAnimation, autoShow); } - //Restore Interaction Pivot - for (Map.Entry entry : oldYaws.entrySet()){ - SpawnedDisplayEntityPart part = entry.getKey(); - float oldYaw = entry.getValue(); - part.pivot(oldYaw); + //Restore pivot + for (ActivePart part : resettedParts){ + part.pivot(groupYaw); } packetGroup.setYaw(newYaw, true); return packetGroup; diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java index 8de8e9cc..22ef2b02 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayEntities/SpawnedDisplayEntityPart.java @@ -1,5 +1,7 @@ package net.donnypz.displayentityutils.utils.DisplayEntities; +import com.destroystokyo.paper.profile.PlayerProfile; +import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.utils.Direction; import net.donnypz.displayentityutils.utils.DisplayUtils; @@ -8,11 +10,16 @@ import net.donnypz.displayentityutils.utils.packet.DisplayAttributeMap; import net.donnypz.displayentityutils.utils.packet.PacketAttributeContainer; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttribute; +import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.kyori.adventure.text.Component; import org.bukkit.*; +import org.bukkit.attribute.Attribute; import org.bukkit.block.data.BlockData; import org.bukkit.entity.*; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.MainHand; +import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import org.bukkit.util.Transformation; @@ -21,63 +28,43 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; +import org.joml.Quaternionf; import org.joml.Vector3f; import java.util.*; public final class SpawnedDisplayEntityPart extends ActivePart implements Spawned { - private static final HashMap allParts = new HashMap<>(); private SpawnedDisplayEntityGroup group; private Entity entity; - private PartData partData; private UUID entityUUID; private final boolean isSingle; - SpawnedDisplayEntityPart(SpawnedDisplayEntityGroup group, Display displayEntity, Random random){ - super(displayEntity.getEntityId(), true); + SpawnedDisplayEntityPart(SpawnedDisplayEntityGroup group, Entity entity, Random random){ + super(entity.getEntityId(), false); this.group = group; - this.entity = displayEntity; - if (displayEntity instanceof BlockDisplay){ - this.type = PartType.BLOCK_DISPLAY; - } - else if (displayEntity instanceof ItemDisplay){ - this.type = PartType.ITEM_DISPLAY; - } - else { - this.type = PartType.TEXT_DISPLAY; - } + this.entity = entity; + this.type = PartType.getType(entity); applyData(random, entity); if (isMaster()){ group.masterPart = this; } - partTags.addAll(DisplayUtils.getTags(displayEntity)); - isSingle = false; - } - - - SpawnedDisplayEntityPart(SpawnedDisplayEntityGroup group, Interaction interactionEntity, Random random){ - super(interactionEntity.getEntityId(), false); - this.group = group; - this.entity = interactionEntity; - this.type = PartType.INTERACTION; - applyData(random, interactionEntity); - partTags.addAll(DisplayUtils.getTags(interactionEntity)); + if (VersionUtils.IS_1_21_9 && entity instanceof Mannequin m){ + DisplayUtils.prepareMannequin(m); + } + partTags.addAll(DisplayUtils.getTags(entity)); isSingle = false; } SpawnedDisplayEntityPart(Entity entity){ - super(entity.getEntityId(), false); - switch (entity) { - case BlockDisplay blockDisplay -> this.type = PartType.BLOCK_DISPLAY; - case ItemDisplay itemDisplay -> this.type = PartType.ITEM_DISPLAY; - case TextDisplay textDisplay -> this.type = PartType.TEXT_DISPLAY; - default -> this.type = PartType.INTERACTION; - } + super(entity.getEntityId(), true); + if (PartType.getType(entity) == null) throw new IllegalArgumentException("Entity is not a valid part type entity"); + this.type = PartType.getType(entity); this.entity = entity; this.entityUUID = entity.getUniqueId(); - isSingle = true; + this.partUUID = UUID.randomUUID(); + this.isSingle = true; } /** @@ -86,59 +73,37 @@ else if (displayEntity instanceof ItemDisplay){ * If the entity is already included in a group, its respective part will be returned. * @param uuid the entity uuid * @return a {@link SpawnedDisplayEntityPart} or null if the entity uuid is not a display or interaction + * @throws IllegalArgumentException if the entity is not a valid entity */ - public static @Nullable SpawnedDisplayEntityPart create(@NotNull UUID uuid){ - Entity entity = Bukkit.getEntity(uuid); - if (entity instanceof Interaction i){ - return create(i); - } - else if (entity instanceof Display d){ - return create(d); - } - return null; + public static @NotNull SpawnedDisplayEntityPart create(@NotNull UUID uuid){ + return create(Bukkit.getEntity(uuid)); } /** * Create a {@link SpawnedDisplayEntityPart} that is not included in any group. *
* If the entity is already included in a group, its respective part will be returned. - * @param display the display entity + * @param entity the valid part entity * @return a {@link SpawnedDisplayEntityPart} + * @throws IllegalArgumentException if the entity is not a valid entity */ - public static @NotNull SpawnedDisplayEntityPart create(@NotNull Display display){ - SpawnedDisplayEntityPart part = getPart(display); - if (part != null) return part; - return new SpawnedDisplayEntityPart(display); - } - - /** - * Create a {@link SpawnedDisplayEntityPart} that is not included in any group. - *
- * If the entity is already included in a group, its respective part will be returned. - * @param interaction the interaction entity - * @return a {@link SpawnedDisplayEntityPart} - */ - public static @NotNull SpawnedDisplayEntityPart create(@NotNull Interaction interaction){ - SpawnedDisplayEntityPart part = getPart(interaction); - if (part != null) return part; - return new SpawnedDisplayEntityPart(interaction); + public static @NotNull SpawnedDisplayEntityPart create(@NotNull Entity entity){ + SpawnedDisplayEntityPart part = getPart(entity); + return part != null ? part : new SpawnedDisplayEntityPart(entity); } private void applyData(Random random, Entity entity){ adaptLegacyPartTags(); entity.getPersistentDataContainer().set(SpawnedDisplayEntityGroup.creationTimeKey, PersistentDataType.LONG, group.getCreationTime()); - if (entity instanceof Display display){ - removeFromPreviousGroup(display); - } - else{ - removeFromPreviousGroup((Interaction) entity); - } - + //Remove from previous group + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); + if (part != null && part.group != group){ + part.remove(false); + } + partsById.put(getEntityId(), this); - this.partData = new PartData(entity); this.entityUUID = entity.getUniqueId(); - allParts.put(partData, this); setPartUUID(random); group.groupParts.put(partUUID, this); @@ -196,18 +161,15 @@ private boolean groupContainsUUID(UUID partUUID){ return group.groupParts.containsKey(partUUID); } - private void removeFromPreviousGroup(Display display){ - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(display); - if (part != null){ - part.remove(false); - } - } - - private void removeFromPreviousGroup(Interaction i){ - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(i); - if (part != null){ - part.remove(false); + private void adaptLegacyPartTags(){ //Don't use getEntity() + List legacyTags = new ArrayList<>(); + for (String s : new HashSet<>(entity.getScoreboardTags())){ + if (s.contains(DisplayAPI.getLegacyPartTagPrefix())){ + legacyTags.add(s.replace(DisplayAPI.getLegacyPartTagPrefix(), "")); + entity.removeScoreboardTag(s); + } } + DisplayUtils.addTags(entity, legacyTags); } /** @@ -221,7 +183,7 @@ private void removeFromPreviousGroup(Interaction i){ /** * Get whether this part can be added to a group. This returns false if the part was - * created through {@link #create(Display)} or {@link #create(Interaction)} + * created through {@link #create(Entity)} * @return a boolean. */ @Override @@ -229,6 +191,15 @@ public boolean hasGroup(){ return !isSingle; } + @Override + public void teleport(@NotNull Location location) { + if (group != null && isDisplay() && !isMaster()){ + return; + } + Entity e = getEntity(); + if (e != null) e.teleport(location); + } + @Override public float getPitch() { return getEntity().getPitch(); @@ -292,19 +263,14 @@ public void refreshEntity(@NotNull Entity nonStaleEntity){ return getEntity().getLocation(); } - - PartData getPartData() { - return partData; - } - /** - * Get the {@link SpawnedDisplayEntityPart} of an entity, during this play session. Use {@link #create(Display)} or similar methods if the part is not grouped. - * @param entity the part entity (Display/Interaction) - * @return The SpawnedDisplayEntityPart. Null if not created during play session or not associated with any group + * Get the {@link SpawnedDisplayEntityPart} of an entity, during this play session. Use {@link #create(Entity)} if the part is not grouped. + * @param entity the part entity + * @return a {@link SpawnedDisplayEntityPart} or null if not created during play session */ public static @Nullable SpawnedDisplayEntityPart getPart(@NotNull Entity entity){ - if (!(entity instanceof Interaction || entity instanceof Display)) return null; - return allParts.get(new PartData(entity)); + if (!DisplayUtils.isPartEntity(entity)) return null; + return (SpawnedDisplayEntityPart) getPart(entity.getEntityId()); } @@ -350,18 +316,6 @@ public SpawnedDisplayEntityPart adaptScoreboardTags(boolean removeFromScoreboard return this; } - - private void adaptLegacyPartTags(){ //Don't use getEntity() - List legacyTags = new ArrayList<>(); - for (String s : new HashSet<>(entity.getScoreboardTags())){ - if (s.contains(DisplayAPI.getLegacyPartTagPrefix())){ - legacyTags.add(s.replace(DisplayAPI.getLegacyPartTagPrefix(), "")); - entity.removeScoreboardTag(s); - } - } - DisplayUtils.addTags(entity, legacyTags); - } - SpawnedDisplayEntityPart setMaster(){ group.masterPart = this; getEntity().getPersistentDataContainer().set(DisplayAPI.getMasterKey(), PersistentDataType.BOOLEAN, true); @@ -379,7 +333,7 @@ public SpawnedDisplayEntityPart setGroup(@NotNull SpawnedDisplayEntityGroup newG } this.group = newGroup; - if (type != PartType.INTERACTION){ + if (isDisplay()){ Display display = (Display) getEntity(); if (isMaster() && this != newGroup.masterPart){ newGroup.masterPart = this; @@ -477,18 +431,13 @@ public boolean isInLoadedChunk(){ } - - - /** * Adds the glow effect to this SpawnDisplayEntityPart. This does NOT apply to Interaction or Text Display entities. Use {@link #markInteraction(Player, long)} to show an outline of * an interaction for a specific player. */ public void glow(){ + if (!canGlow()) return; Entity entity = getEntity(); - if (type == PartType.INTERACTION || type == PartType.TEXT_DISPLAY) { - return; - } entity.setGlowing(true); } @@ -499,10 +448,9 @@ public void glow(){ */ @Override public void glow(long durationInTicks){ + if (!canGlow()) return; + Entity entity = getEntity(); - if (type == PartType.INTERACTION || type == PartType.TEXT_DISPLAY) { - return; - } entity.setGlowing(true); DisplayAPI.getScheduler().entityRunLater(entity, () -> { @@ -521,7 +469,7 @@ public boolean isGlowing() { */ @Override public void unglow(){ - if (type != PartType.INTERACTION) { + if (canGlow()) { getEntity().setGlowing(false); } } @@ -532,7 +480,7 @@ public void unglow(){ */ @Override public void unglow(@NotNull Player player){ - if (type != PartType.INTERACTION) { + if (canGlow()) { PacketUtils.setGlowing(player, getEntityId(), false); } } @@ -545,15 +493,18 @@ public Collection getTrackingPlayers() { /** * Change the yaw of this part * @param yaw The yaw to set for this part - * @param pivotIfInteraction true if this part's type is {@link PartType#INTERACTION} and it should pivot around the group's location + * @param pivot whether the part should pivot around its group's location, if it has one, and if the part is an Interaction */ @Override - public void setYaw(float yaw, boolean pivotIfInteraction){ + public void setYaw(float yaw, boolean pivot){ Entity entity = getEntity(); - if (type == PartType.INTERACTION && pivotIfInteraction){ + if (!isDisplay() && pivot){ pivot(yaw-entity.getYaw()); } entity.setRotation(yaw, entity.getPitch()); + if (entity instanceof LivingEntity le){ + le.setBodyYaw(yaw); + } } /** @@ -567,10 +518,8 @@ public void setPitch(float pitch){ } @Override - public boolean setXScale(float scale){ - if (type == PartType.INTERACTION){ - return false; - } + public boolean setDisplayXScale(float scale){ + if (!isDisplay()) return false; Transformation t = getTransformation(); Vector3f v = t.getScale(); Transformation newT = new Transformation(t.getTranslation(), t.getLeftRotation(), new Vector3f(scale, v.y, v.z), t.getRightRotation()); @@ -580,8 +529,8 @@ public boolean setXScale(float scale){ } @Override - public boolean setYScale(float scale){ - if (type == PartType.INTERACTION) return false; + public boolean setDisplayYScale(float scale){ + if (!isDisplay()) return false; Transformation t = getTransformation(); Vector3f v = t.getScale(); Transformation newT = new Transformation(t.getTranslation(), t.getLeftRotation(), new Vector3f(v.x, scale, v.z), t.getRightRotation()); @@ -591,8 +540,8 @@ public boolean setYScale(float scale){ } @Override - public boolean setZScale(float scale){ - if (type == PartType.INTERACTION) return false; + public boolean setDisplayZScale(float scale){ + if (!isDisplay()) return false; Transformation t = getTransformation(); Vector3f v = t.getScale(); Transformation newT = new Transformation(t.getTranslation(), t.getLeftRotation(), new Vector3f(v.x, v.y, scale), t.getRightRotation()); @@ -602,8 +551,8 @@ public boolean setZScale(float scale){ } @Override - public boolean setScale(float x, float y, float z){ - if (type == PartType.INTERACTION) return false; + public boolean setDisplayScale(float x, float y, float z){ + if (!isDisplay()) return false; Transformation t = getTransformation(); Transformation newT = new Transformation(t.getTranslation(), t.getLeftRotation(), new Vector3f(x, y, z), t.getRightRotation()); Display entity = (Display) getEntity(); @@ -611,8 +560,25 @@ public boolean setScale(float x, float y, float z){ return true; } + @Override + public void rotateDisplay(@NotNull Quaternionf rotation, boolean rotateTranslation) { + if (!isDisplay()) return; + Display display = (Display) getEntity(); + if (display == null) return; + Transformation t = getTransformation(); + Vector3f translation = t.getTranslation(); + Quaternionf originalRot = t.getLeftRotation(); + //World Space Rot + if (rotateTranslation){ + translation.rotate(rotation); + } + + rotation.mul(originalRot, originalRot); + Transformation newT = new Transformation(translation, originalRot, t.getScale(), t.getRightRotation()); + display.setTransformation(newT); + } /** * Set the brightness of this part @@ -621,11 +587,9 @@ public boolean setScale(float x, float y, float z){ @Override public void setBrightness(@Nullable Display.Brightness brightness){ Entity entity = getEntity(); - if (entity instanceof Interaction){ - return; + if (entity instanceof Display display){ + display.setBrightness(brightness); } - Display display = (Display) entity; - display.setBrightness(brightness); } /** @@ -635,11 +599,9 @@ public void setBrightness(@Nullable Display.Brightness brightness){ @Override public void setBillboard(@NotNull Display.Billboard billboard){ Entity entity = getEntity(); - if (entity instanceof Interaction){ - return; + if (entity instanceof Display display){ + display.setBillboard(billboard); } - Display display = (Display) entity; - display.setBillboard(billboard); } /** @@ -647,9 +609,10 @@ public void setBillboard(@NotNull Display.Billboard billboard){ */ @Override public void setTeleportDuration(int teleportDuration) { - if (type == PartType.INTERACTION) return; - Display display = (Display) getEntity(); - display.setTeleportDuration(teleportDuration); + Entity entity = getEntity(); + if (entity instanceof Display display){ + display.setTeleportDuration(teleportDuration); + } } /** @@ -658,11 +621,10 @@ public void setTeleportDuration(int teleportDuration) { */ @Override public void setInterpolationDuration(int interpolationDuration) { - if (type == PartType.INTERACTION){ - return; + Entity entity = getEntity(); + if (entity instanceof Display display){ + display.setInterpolationDuration(interpolationDuration); } - Display display = (Display) getEntity(); - display.setInterpolationDuration(interpolationDuration); } /** @@ -671,11 +633,10 @@ public void setInterpolationDuration(int interpolationDuration) { */ @Override public void setInterpolationDelay(int interpolationDelay) { - if (type == PartType.INTERACTION){ - return; + Entity entity = getEntity(); + if (entity instanceof Display display){ + display.setInterpolationDelay(interpolationDelay); } - Display display = (Display) getEntity(); - display.setInterpolationDelay(interpolationDelay); } /** @@ -685,16 +646,15 @@ public void setInterpolationDelay(int interpolationDelay) { @Override public void setViewRange(float viewRangeMultiplier){ Entity entity = getEntity(); - if (entity instanceof Interaction){ - return; + if (entity instanceof Display display){ + display.setViewRange(viewRangeMultiplier); } - Display display = (Display) entity; - display.setViewRange(viewRangeMultiplier); } @Override protected void cull(float width, float height){ + if (!isDisplay()) return; Entity entity = getEntity(); if (entity instanceof Display display){ display.setDisplayHeight(height); @@ -710,20 +670,18 @@ protected void cull(float width, float height){ @Override public void setGlowColor(@Nullable Color color){ Entity entity = getEntity(); - if (entity instanceof Interaction){ - return; + if (entity instanceof Display display){ + display.setGlowColorOverride(color); } - Display display = (Display) entity; - display.setGlowColorOverride(color); } @Override public @Nullable Color getGlowColor(){ - if (type == PartType.INTERACTION){ - return null; - } Entity entity = getEntity(); - return ((Display) entity).getGlowColorOverride(); + if (entity instanceof Display display){ + return display.getGlowColorOverride(); + } + return null; } /** @@ -771,17 +729,15 @@ void translateForce(Direction direction, float distance, int durationInTicks, in } /** - * Pivot an Interaction Entity around its group's master part + * Pivot a non-display entity around its group * @param angleInDegrees the pivot angle */ @Override public void pivot(float angleInDegrees){ - Entity entity = getEntity(); - if (type != PartType.INTERACTION || isSingle){ - return; - } - Interaction i = (Interaction) entity; - DisplayUtils.pivot(i, group.getLocation(), angleInDegrees); + if (isDisplay() || isSingle || group == null) return; + Entity e = getEntity(); + if (e == null) return; + DisplayUtils.pivot(e, group.getLocation(), angleInDegrees); } @@ -807,20 +763,20 @@ public Interaction spawnInteractionAtDisplay(){ i.setInteractionWidth(width); i.setInteractionHeight(height); }); - group.addInteractionEntity(interaction); + group.addEntity(interaction); return interaction; } @Override public void setTransformation(@NotNull Transformation transformation) { - if (type == PartType.INTERACTION) return; + if (!isDisplay()) return; ((Display) getEntity()).setTransformation(transformation); } @Override public void setTransformationMatrix(@NotNull Matrix4f matrix) { - if (type == PartType.INTERACTION) return; + if (!isDisplay()) return; ((Display) getEntity()).setTransformationMatrix(matrix); } @@ -903,12 +859,19 @@ public void setItemDisplayTransform(ItemDisplay.@NotNull ItemDisplayTransform tr public void setItemDisplayItemGlint(boolean hasGlint) { ItemStack itemStack = getItemDisplayItem(); if (itemStack == null) return; - itemStack.editMeta(meta -> { - meta.setEnchantmentGlintOverride(hasGlint); - }); + ItemMeta meta = itemStack.getItemMeta(); + meta.setEnchantmentGlintOverride(hasGlint); + itemStack.setItemMeta(meta); ((ItemDisplay) getEntity()).setItemStack(itemStack); } + @Override + public boolean hasItemDisplayItemGlint() { + ItemStack itemStack = getItemDisplayItem(); + if (itemStack == null) return false; + return itemStack.getItemMeta().getEnchantmentGlintOverride(); + } + @Override public @Nullable Component getTextDisplayText() { if (type != PartType.TEXT_DISPLAY) return null; @@ -938,7 +901,7 @@ public byte getTextDisplayTextOpacity() { if (type != PartType.TEXT_DISPLAY) return -1; TextDisplay td = (TextDisplay) getEntity(); if (td == null) return -1; - return getTextDisplayTextOpacity(); + return td.getTextOpacity(); } @Override @@ -989,6 +952,169 @@ public boolean isTextDisplayDefaultBackground() { return display.getItemStack(); } + @Override + public void setMannequinPose(Pose pose) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + if (pose == null) pose = Pose.STANDING; + mannequin.setPose(pose, true); + } + + @Override + public @Nullable Pose getMannequinPose() { + if (type != PartType.MANNEQUIN) return null; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return null; + return mannequin.getPose(); + } + + @Override + public void setMannequinScale(double scale) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.getAttribute(Attribute.SCALE).setBaseValue(scale); + } + + @Override + public double getMannequinScale() { + if (type != PartType.MANNEQUIN) return -1; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return -1; + return mannequin.getAttribute(Attribute.SCALE).getBaseValue(); + } + + @Override + public void setMannequinImmovable(boolean immovable) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.setImmovable(immovable); + } + + @Override + public boolean isMannequinImmovable() { + if (type != PartType.MANNEQUIN) return false; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return false; + return mannequin.isImmovable(); + } + + @Override + public void setMannequinGravity(boolean gravity) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.setGravity(gravity); + } + + @Override + public boolean hasMannequinGravity() { + if (type != PartType.MANNEQUIN) return false; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return false; + return mannequin.hasGravity(); + } + + @Override + public void setMannequinMainHand(@NotNull MainHand mainHand) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.setMainHand(mainHand); + } + + @Override + public @Nullable MainHand getMannequinMainHand() { + if (type != PartType.MANNEQUIN) return null; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return null; + return mannequin.getMainHand(); + } + + @Override + public @Nullable ItemStack getMannequinEquipment(@NotNull EquipmentSlot equipmentSlot) { + if (type != PartType.MANNEQUIN) return null; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return null; + return mannequin.getEquipment().getItem(equipmentSlot); + } + + + @Override + public void setMannequinEquipment(@NotNull EquipmentSlot slot, @NotNull ItemStack itemStack) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.getEquipment().setItem(slot, itemStack); + } + + @Override + public void setMannequinProfile(@NotNull PlayerProfile profile) { + setMannequinProfile(ResolvableProfile.resolvableProfile(profile)); + } + + @Override + public void setMannequinProfile(@NotNull ResolvableProfile profile) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.setProfile(profile); + } + + @Override + public void setCustomName(@Nullable Component text) { + Entity e = getEntity(); + if (e == null) return; + e.customName(text); + } + + @Override + public void setCustomNameVisible(boolean visible) { + Entity e = getEntity(); + if (e == null) return; + e.setCustomNameVisible(visible); + } + + @Override + public @Nullable Component getCustomName() { + Entity e = getEntity(); + if (e == null) return null; + return e.customName(); + } + + @Override + public boolean isCustomNameVisible() { + Entity e = getEntity(); + if (e == null) return false; + return e.isCustomNameVisible(); + } + + @Override + public void setMannequinBelowName(@Nullable Component text) { + if (type != PartType.MANNEQUIN) return; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return; + mannequin.setDescription(text); + } + + @Override + public ResolvableProfile getMannequinProfile() { + if (type != PartType.MANNEQUIN) return null; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return null; + return mannequin.getProfile(); + } + + @Override + public @Nullable Component getMannequinBelowName() { + if (type != PartType.MANNEQUIN) return null; + Mannequin mannequin = (Mannequin) getEntity(); + if (mannequin == null) return null; + return mannequin.getDescription(); + } + /** * {@inheritDoc} * The applied changes do not reflect the entity data server-side @@ -1013,12 +1139,9 @@ public void setAttributes(@NotNull DisplayAttributeMap attributeMap) { } @Override - public @Nullable Vector getInteractionTranslation() { - if (type != PartType.INTERACTION) { - return null; - } - if (group == null) return null; - return DisplayUtils.getInteractionTranslation((Interaction) getEntity(), group.getLocation()); + public @Nullable Vector getNonDisplayTranslation() { + if (isDisplay() || group == null) return null; + return DisplayUtils.getNonDisplayTranslation(getEntity(), group.getLocation()); } @Override @@ -1045,7 +1168,7 @@ public void setInteractionResponsive(boolean responsive) { @Override public @Nullable Transformation getTransformation() { - if (type == PartType.INTERACTION) { + if (!isDisplay()) { return null; } return ((Display) getEntity()).getTransformation(); @@ -1053,7 +1176,7 @@ public void setInteractionResponsive(boolean responsive) { @Override public @Nullable Display.Brightness getBrightness() { - if (type == PartType.INTERACTION){ + if (!isDisplay()){ return null; } return ((Display) getEntity()).getBrightness(); @@ -1061,7 +1184,7 @@ public void setInteractionResponsive(boolean responsive) { @Override public float getViewRange() { - if (type == PartType.INTERACTION){ + if (!isDisplay()){ return -1; } return ((Display) getEntity()).getViewRange(); @@ -1091,6 +1214,8 @@ public boolean isInteractionResponsive() { return ((Interaction) getEntity()).isResponsive(); } + + @Override public void addInteractionCommand(@NotNull String command, boolean isLeftClick, boolean isConsole) { if (type == PartType.INTERACTION) DisplayUtils.addInteractionCommand((Interaction) getEntity(), command, isLeftClick, isConsole); @@ -1115,7 +1240,7 @@ public void removeInteractionCommand(@NotNull InteractionCommand command) { @Override public int getTeleportDuration() { - if (type == PartType.INTERACTION){ + if (!isDisplay()){ return -1; } return ((Display) getEntity()).getTeleportDuration(); @@ -1125,24 +1250,30 @@ public enum PartType{ BLOCK_DISPLAY, ITEM_DISPLAY, TEXT_DISPLAY, - INTERACTION; - + INTERACTION, + MANNEQUIN; + + /** + * Get a type, respective of the given entity + * @param entity the entity + * @return a {@link PartType} or null if the entity does not have a type. + */ public static PartType getType(@NotNull Entity entity){ - switch (entity){ - case Interaction i -> { - return INTERACTION; - } - case BlockDisplay d -> { - return BLOCK_DISPLAY; - } - case ItemDisplay d -> { - return ITEM_DISPLAY; - } - case TextDisplay d -> { - return TEXT_DISPLAY; - } - default -> throw new IllegalStateException("Unexpected value: " + entity); - } + if (entity instanceof BlockDisplay) return BLOCK_DISPLAY; + if (entity instanceof ItemDisplay) return ITEM_DISPLAY; + if (entity instanceof TextDisplay) return TEXT_DISPLAY; + if (entity instanceof Interaction) return INTERACTION; + if (VersionUtils.IS_1_21_9 && entity instanceof Mannequin) return MANNEQUIN; + return null; + } + + public boolean isOfType(Entity e){ + if (e instanceof BlockDisplay && this == BLOCK_DISPLAY) return true; + if (e instanceof ItemDisplay && this == ITEM_DISPLAY) return true; + if (e instanceof TextDisplay && this == TEXT_DISPLAY) return true; + if (e instanceof Interaction && this == INTERACTION) return true; + if (e instanceof Mannequin && this == MANNEQUIN) return true; + return false; } } @@ -1164,7 +1295,6 @@ public Entity remove(boolean kill) { } } this.entity = null; - this.partData = null; this.unregister(); return entity; } @@ -1176,7 +1306,6 @@ public Entity remove(boolean kill) { */ public void removeFromGroup() { if (group != null){ - allParts.remove(partData); group.groupParts.remove(partUUID); for (SpawnedPartSelection selection : group.partSelections){ selection.removePart(this); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java index b8000b5c..0e450277 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/DisplayUtils.java @@ -4,18 +4,12 @@ import net.donnypz.displayentityutils.DisplayConfig; import net.donnypz.displayentityutils.events.PartTranslateEvent; import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; -import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityPart; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.donnypz.displayentityutils.utils.version.folia.FoliaUtils; import net.donnypz.displayentityutils.utils.version.folia.Scheduler; import org.bukkit.Location; import org.bukkit.NamespacedKey; -import org.bukkit.entity.BlockDisplay; -import org.bukkit.entity.Display; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Interaction; +import org.bukkit.entity.*; import org.bukkit.persistence.ListPersistentDataType; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; @@ -43,11 +37,15 @@ public final class DisplayUtils { private static final ListPersistentDataType tagPDCType = PersistentDataType.LIST.strings(); private DisplayUtils(){} + public static boolean isPartEntity(Entity entity){ // don't add notnull annotation + return SpawnedDisplayEntityPart.PartType.getType(entity) != null; + } + public static @NotNull List getUngroupedPartEntities(@NotNull Location location, double distance){ List parts = new ArrayList<>(); for (Entity e : location.getNearbyEntities(distance, distance, distance)) { - if (!(e instanceof Display) && !(e instanceof Interaction)) continue; + if (!isPartEntity(e)) continue; if (e instanceof Display){ if (e.getVehicle() instanceof BlockDisplay) continue; } @@ -169,13 +167,13 @@ public static Vector pivotPitchAndYaw(@NotNull Vector vector, float pitchChange, } /** - * Get the location where a {@link PacketDisplayEntityPart} display entity is translated based off of its {@link Transformation}'s translation alone.
+ * Get the location where an {@link PacketDisplayEntityPart} display entity is translated based off of its {@link Transformation}'s translation alone.
* This may not be a perfect representation of where the model's location actually is, due to the shape of models varying (e.g.: Stone Block vs Stone Pressure Plate) * @param part The entity to get the location from * @return the location where the part is translated at. Null if the part is an interaction entity or if the transformation/location of the entity is unset */ public static @Nullable Location getFixedModelLocation(@NotNull PacketDisplayEntityPart part){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ return null; } @@ -188,13 +186,13 @@ public static Vector pivotPitchAndYaw(@NotNull Vector vector, float pitchChange, } /** - * Get the location where a {@link PacketDisplayEntityPart} display entity is translated based off of its {@link Transformation} and pitch and yaw.
+ * Get the location where an {@link ActivePart} display entity is translated based off of its {@link Transformation} and pitch and yaw.
* This may not be a perfect representation of where the model's location actually is, due to the shape of models varying (e.g.: Stone Block vs Stone Pressure Plate) * @param part The entity to get the location from - * @return the location where the part is translated at. Null if the part is an interaction entity + * @return the location where the part is translated at. Null if the part is not a display */ public static @Nullable Location getModelLocation(@NotNull ActivePart part){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!part.isDisplay()){ return null; } @@ -221,7 +219,7 @@ public static Vector pivotPitchAndYaw(@NotNull Vector vector, float pitchChange, /** * Calculate and get the culling values that would be applied to a {@link Display} * @param display the display - * @return a float array containing the width and height, respectively + * @return a float array containing the width and height, respectively. null if the part is not a display */ public static float[] getAutoCullValues(@NotNull Display display){ return getAutoCullValues(display, DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); @@ -232,7 +230,7 @@ public static float[] getAutoCullValues(@NotNull Display display){ * @param display the display * @param widthAdder the fixed value to increase the calculated width by * @param heightAdder the fixed value to increase the calculated height by - * @return a float array containing the width and height, respectively + * @return a float array containing the width and height, respectively. null if the part is not a display */ public static float[] getAutoCullValues(@NotNull Display display, float widthAdder, float heightAdder){ SpawnedDisplayEntityPart.PartType type = display instanceof BlockDisplay ? SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY : null; @@ -243,7 +241,7 @@ public static float[] getAutoCullValues(@NotNull Display display, float widthAdd /** * Calculate and get the culling values that would be applied to an {@link ActivePart} * @param part the part - * @return a float array containing the width and height, respectively + * @return a float array containing the width and height, respectively. null if the part is not a display */ public static float[] getAutoCullValues(@NotNull ActivePart part){ return getAutoCullValues(part, DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); @@ -254,9 +252,10 @@ public static float[] getAutoCullValues(@NotNull ActivePart part){ * @param part the part * @param widthAdder the fixed value to increase the calculated width by * @param heightAdder the fixed value to increase the calculated height by - * @return a float array containing the width and height, respectively + * @return a float array containing the width and height, respectively. null if the part is not a display */ public static float[] getAutoCullValues(@NotNull ActivePart part, float widthAdder, float heightAdder){ + if (!part.isDisplay()) return null; Transformation t = part.getTransformation(); return getAutoCullValues(part.getType(), t.getTranslation(), t.getScale(), t.getLeftRotation(), widthAdder, heightAdder); } @@ -317,33 +316,26 @@ public static Location getInteractionCenter(@NotNull Interaction interaction){ /** - * Get the translation vector from the group's master part to the interaction's location - * @param interaction the interaction - * @return a vector or null if the Interaction entity is not in a group + * Get the translation vector from the entity's group's master part to the entity's location + * @param entity the interaction + * @return a vector or null if the entity is not in a group */ - public static Vector getInteractionTranslation(@NotNull Interaction interaction){ - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(interaction); + public static @Nullable Vector getNonDisplayTranslation(@NotNull Entity entity){ + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); if (part == null){ return null; } - return getInteractionTranslation(interaction, part.getGroup().getLocation()); - /*return part - .getGroup() - .getMasterPart() - .getEntity() - .getLocation() - .toVector() - .subtract(interaction.getLocation().toVector());*/ + return getNonDisplayTranslation(entity, part.getGroup().getLocation()); } /** - * Get the translation vector from a location to the interaction's location - * @param interaction the interaction + * Get the translation vector from a location to the entity's location + * @param entity the entity * @param referenceLocation the reference location * @return a vector */ - public static Vector getInteractionTranslation(@NotNull Interaction interaction, @NotNull Location referenceLocation){ - return referenceLocation.toVector().subtract(interaction.getLocation().toVector()); + public static @NotNull Vector getNonDisplayTranslation(@NotNull Entity entity, @NotNull Location referenceLocation){ + return referenceLocation.toVector().subtract(entity.getLocation().toVector()); } /** @@ -472,24 +464,24 @@ public static void translate(@NotNull Display display, @NotNull Direction direct } /** - * Attempts to change the translation of an interaction entity similar + * Attempts to change the translation of an entity similar * to a Display Entity, through smooth teleportation. - * Doing multiple translations on an Interaction entity at the same time may have unexpected results - * @param direction The direction to translate the interaction entity - * @param interaction Interaction Entity to translate - * @param distance How far the interaction entity should be translated + * Doing multiple translations on an entity at the same time may have unexpected results + * @param direction The direction to translate the entity + * @param entity entity to translate + * @param distance How far the entity should be translated * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translate(@NotNull Interaction interaction, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + public static void translate(@NotNull Entity entity, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ if (distance == 0) return; - Location destination = interaction.getLocation().clone().add(direction.clone().normalize().multiply(distance)); - if (!new PartTranslateEvent(interaction, destination, null,null).callEvent()){ + Location destination = entity.getLocation().clone().add(direction.clone().normalize().multiply(distance)); + if (!new PartTranslateEvent(entity, destination, null,null).callEvent()){ return; } if (durationInTicks <= 0 && delayInTicks <= 0){ - FoliaUtils.teleport(interaction, destination); + FoliaUtils.teleport(entity, destination); return; } @@ -499,25 +491,25 @@ public static void translate(@NotNull Interaction interaction, @NotNull Vector d .normalize() .multiply(movementIncrement); - DisplayAPI.getScheduler().entityRunTimer(interaction, new Scheduler.SchedulerRunnable() { + DisplayAPI.getScheduler().entityRunTimer(entity, new Scheduler.SchedulerRunnable() { double currentDistance = 0; - float lastYaw = interaction.getYaw(); + float lastYaw = entity.getYaw(); @Override public void run() { - float newYaw = interaction.getYaw(); + float newYaw = entity.getYaw(); if (newYaw != lastYaw){ incrementVector.rotateAroundY(Math.toRadians(lastYaw-newYaw)); lastYaw = newYaw; } currentDistance+=Math.abs(movementIncrement); - Location tpLoc = interaction.getLocation().clone().add(incrementVector); + Location tpLoc = entity.getLocation().clone().add(incrementVector); if (currentDistance >= distance){ - FoliaUtils.teleport(interaction, destination); + FoliaUtils.teleport(entity, destination); cancel(); } else{ - FoliaUtils.teleport(interaction, tpLoc); + FoliaUtils.teleport(entity, tpLoc); } } }, delayInTicks, 1); @@ -525,17 +517,17 @@ public void run() { /** - * Attempts to change the translation of an interaction entity similar + * Attempts to change the translation of an entity similar * to a Display Entity, through smooth teleportation. - * Doing multiple translations on an Interaction entity at the same time may have unexpected results - * @param interaction Interaction Entity to translate - * @param direction The direction to translate the interaction entity - * @param distance How far the interaction entity should be translated + * Doing multiple translations on an entity at the same time may have unexpected results + * @param entity entity to translate + * @param direction The direction to translate the entity + * @param distance How far the entity should be translated * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translate(@NotNull Interaction interaction, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - translate(interaction, direction.getVector(interaction, true), distance, durationInTicks, delayInTicks); + public static void translate(@NotNull Entity entity, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ + translate(entity, direction.getVector(entity, true), distance, durationInTicks, delayInTicks); } /** @@ -549,8 +541,8 @@ public static void translate(@NotNull Interaction interaction, @NotNull Directio * @param delayInTicks How long before the translation should begin */ public static void translate(@NotNull SpawnedDisplayEntityPart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - translate((Interaction) part.getEntity(), direction, distance, durationInTicks, delayInTicks); + if (!part.isDisplay()){ + translate(part.getEntity(), direction, distance, durationInTicks, delayInTicks); return; } translate((Display) part.getEntity(), direction, distance, durationInTicks, delayInTicks); @@ -567,9 +559,9 @@ public static void translate(@NotNull SpawnedDisplayEntityPart part, @NotNull Ve * @param delayInTicks How long before the translation should begin */ public static void translate(@NotNull SpawnedDisplayEntityPart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - Interaction interaction = (Interaction) part.getEntity(); - translate(interaction, direction.getVector(interaction, true), distance, durationInTicks, delayInTicks); + if (!part.isDisplay()){ + Entity entity = part.getEntity(); + translate(entity, direction.getVector(entity, true), distance, durationInTicks, delayInTicks); return; } Display display = (Display) part.getEntity(); @@ -578,22 +570,22 @@ public static void translate(@NotNull SpawnedDisplayEntityPart part, @NotNull Di /** - * Pivot an Interaction entity around a location - * @param interaction the interaction - * @param center the location the interaction should pivot around + * Pivot an entity around a location + * @param entity the entity + * @param center the location the entity should pivot around * @param angleInDegrees the pivot angle in degrees */ - public static void pivot(@NotNull Interaction interaction, @NotNull Location center, double angleInDegrees){ - Vector3f translationVector = DisplayUtils.getInteractionTranslation(interaction, center).toVector3f(); + public static void pivot(@NotNull Entity entity, @NotNull Location center, double angleInDegrees){ + Vector3f translationVector = DisplayUtils.getNonDisplayTranslation(entity, center).toVector3f(); new Quaternionf() .rotateY((float) Math.toRadians(-angleInDegrees)) .transform(translationVector); Location newLoc = center.clone().subtract(Vector.fromJOML(translationVector)); - FoliaUtils.teleport(interaction, newLoc); + FoliaUtils.teleport(entity, newLoc); } /** - * Get the location an interaction entity would be pivoted to after using {@link DisplayUtils#pivot(Interaction, Location, double)} + * Get the location an interaction entity would be pivoted to after using {@link DisplayUtils#pivot(Entity, Location, double)} * @param offsetLocation the interaction entity's location * @param origin the location the interaction should pivot around * @param angleInDegrees the pivot angle in degrees @@ -605,7 +597,7 @@ public static void pivot(@NotNull Interaction interaction, @NotNull Location cen } /** - * Get the location an interaction entity would be pivoted to after using {@link DisplayUtils#pivot(Interaction, Location, double)} + * Get the location an interaction entity would be pivoted to after using {@link DisplayUtils#pivot(Entity, Location, double)} * @param translationVector the translation offset for an interaction entity from a center location * @param origin the location the interaction should pivot around * @param angleInDegrees the pivot angle in degrees @@ -616,7 +608,7 @@ public static void pivot(@NotNull Interaction interaction, @NotNull Location cen } /** - * Get the location an interaction entity would be pivoted to after using {@link DisplayUtils#pivot(Interaction, Location, double)} + * Get the location an interaction entity would be pivoted to after using {@link DisplayUtils#pivot(Entity, Location, double)} * @param translationVector the translation offset for an interaction entity from a center location * @param origin the location the interaction should pivot around * @param angleInDegrees the pivot angle in degrees @@ -636,7 +628,7 @@ public static void pivot(@NotNull Interaction interaction, @NotNull Location cen * @param durationInTicks how long the scaling should take * @param delayInTicks how long before the scaling should start */ - public static void scaleInteraction(Interaction interaction, float newHeight, float newWidth, int durationInTicks, int delayInTicks){ + public static void scaleInteraction(@NotNull Interaction interaction, float newHeight, float newWidth, int durationInTicks, int delayInTicks){ if (durationInTicks <= 0 && delayInTicks <= 0){ interaction.setInteractionHeight(newHeight); interaction.setInteractionWidth(newWidth); @@ -662,49 +654,24 @@ public void run() { } /** - * Gets the group tag of a Display Entity - * @param display Display Entity to retrieve the tag from - * @return Group tag of the entity. Null if the entity did not have a group tag. + * Gets the group tag of a valid part entity + * @param entity entity to retrieve the tag from + * @return a string, null if the entity did not have a group tag. */ - public static @Nullable String getGroupTag(Display display){ - return getPDCGroupTag(display); - } - - /** - * Gets the group tag of an Interaction Entity - * @param interaction Interaction Entity to retrieve the tag from - * @return Group tag of the entity. Null if the entity did not have a group tag. - */ - public static @Nullable String getGroupTag(Interaction interaction){ - return getPDCGroupTag(interaction); - } - - private static String getPDCGroupTag(Entity entity){ + public static @Nullable String getGroupTag(Entity entity){ + if (entity == null) return null; PersistentDataContainer pdc = entity.getPersistentDataContainer(); return pdc.get(DisplayAPI.getGroupTagKey(), PersistentDataType.STRING); } /** - * Gets the part uuid of a Display Entity - * @param display Display Entity to retrieve the uuid from - * @return Part UUID of the entity. Null if the entity is not part of a display entity group. Will still return a value if the entity + * Gets the part uuid of a valid part entity + * @param entity entity to retrieve the uuid from + * @return a UUID or null if the entity is not part of a group. Will still return a value if the entity * was previously part of a group, but later removed. */ - public static @Nullable UUID getPartUUID(Display display){ - return getPDCPartUUID(display); - } - - /** - * Gets the part uuid of an Interaction Entity - * @param interaction Interaction Entity to retrieve the uuid from - * @return Part UUID of the entity. Null if the entity is not part of a display entity group. Will still return a value if the entity - * was previously part of a group, but later removed. - */ - public static @Nullable UUID getPartUUID(Interaction interaction){ - return getPDCPartUUID(interaction); - } - - private static UUID getPDCPartUUID(Entity entity){ + public static @Nullable UUID getPartUUID(Entity entity){ + if (entity == null) return null; PersistentDataContainer pdc = entity.getPersistentDataContainer(); String value = pdc.get(DisplayAPI.getPartUUIDKey(), PersistentDataType.STRING); if (value != null){ @@ -719,7 +686,6 @@ private static UUID getPDCPartUUID(Entity entity){ * @return List of commands stored on this interaction entity */ public static @NotNull List getInteractionCommands(@NotNull Interaction interaction){ - List commands = new ArrayList<>(); commands.addAll(getInteractionLeftConsoleCommands(interaction)); commands.addAll(getInteractionLeftPlayerCommands(interaction)); @@ -951,27 +917,14 @@ public static boolean hasPartTag(@NotNull Entity entity, @NotNull String tag){ /** - * Checks if this display entity has the specified group tag - * @param display Display Entity to check for a group tag - * @param tag The tag to check for - * @return boolean whether this display entity has the group tag - */ - public static boolean isGroupTag(Display display, @NotNull String tag){ - String value = display.getPersistentDataContainer().get(DisplayAPI.getGroupTagKey(), PersistentDataType.STRING); - if (value == null){ - return false; - } - return tag.equals(value); - } - - /** - * Checks if this interaction entity has the specified group tag - * @param interaction Interaction Entity to check for a group tag - * @param tag The tag to check for - * @return boolean whether this interaction entity has the group tag + * Checks if an entity has the specified group tag + * @param entity entity to check for a group tag + * @param tag the group tag + * @return a boolean */ - public static boolean isGroupTag(Interaction interaction, @NotNull String tag){ - String value = interaction.getPersistentDataContainer().get(DisplayAPI.getGroupTagKey(), PersistentDataType.STRING); + public static boolean isGroupTag(Entity entity, @NotNull String tag){ + if (entity == null) return false; + String value = entity.getPersistentDataContainer().get(DisplayAPI.getGroupTagKey(), PersistentDataType.STRING); if (value == null){ return false; } @@ -984,31 +937,8 @@ public static boolean isGroupTag(Interaction interaction, @NotNull String tag){ * @return a boolean */ public static boolean isInGroup(Entity entity){ - if (entity instanceof Display display){ - return SpawnedDisplayEntityPart.getPart(display) != null; - } - else if (entity instanceof Interaction interaction){ - return SpawnedDisplayEntityPart.getPart(interaction) != null; - } - return false; - } - - /** - * Get the creation time of a Display Entity - * @param display The Display Entity to check for a creation time - * @return The Display Entity's Group's Creation time. -1 if this display is not part of a group - */ - public static long getCreationTime(Display display){ - return getCreationTime((Entity) display); - } - - /** - * Get the creation time of an Interaction Entity - * @param interaction The Interaction to check for a creation time - * @return The Interaction's Group's Creation time. -1 if this interaction is not part of a group - */ - public static long getCreationTime(Interaction interaction){ - return getCreationTime((Entity) interaction); + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); + return part != null && part.hasGroup(); } /** @@ -1033,6 +963,10 @@ public static boolean isMaster(Display display){ return container.has(DisplayAPI.getMasterKey(), PersistentDataType.BOOLEAN); } - - + @ApiStatus.Internal + public static void prepareMannequin(Mannequin mannequin){ + mannequin.setInvulnerable(true); + mannequin.setImmovable(true); + mannequin.setGravity(false); + } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/PacketUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/PacketUtils.java index 00540419..3cfdb74a 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/PacketUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/PacketUtils.java @@ -6,7 +6,6 @@ import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityTeleport; import io.github.retrooper.packetevents.util.SpigotConversionUtil; import net.donnypz.displayentityutils.DisplayAPI; -import net.donnypz.displayentityutils.managers.DEUUser; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityPart; @@ -16,18 +15,15 @@ import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttribute; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; import net.donnypz.displayentityutils.utils.version.folia.Scheduler; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Interaction; import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; import java.util.Collection; import java.util.List; -import java.util.SequencedCollection; public final class PacketUtils { @@ -279,7 +275,7 @@ private static void sendInteractionPacket(int entityId, float newHeight, float n /** * Change the translation of a {@link PacketDisplayEntityPart} if it's not an {@link SpawnedDisplayEntityPart.PartType#INTERACTION}.

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

- * If it is an interaction, {@link #translateInteraction(PacketDisplayEntityPart, Vector, double, int, int)} will be called instead. + * If it is an interaction, {@link #translateNonDisplay(PacketDisplayEntityPart, Vector, double, int, int)} will be called instead. * @param part the part to translate * @param direction the direction to translate the display entity * @param distance translation distance @@ -306,8 +302,8 @@ public static void translate(@NotNull PacketDisplayEntityPart part, @NotNull Dir */ public static void translate(@NotNull PacketDisplayEntityPart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ if (distance == 0) return; - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - translateInteraction(part, direction, distance, durationInTicks, delayInTicks); + if (!part.isDisplay()){ + translateNonDisplay(part, direction, distance, durationInTicks, delayInTicks); return; } if (delayInTicks < 0){ @@ -333,8 +329,8 @@ public static void translate(@NotNull PacketDisplayEntityPart part, @NotNull Vec * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull PacketDisplayEntityPart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull PacketDisplayEntityPart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); } @@ -348,8 +344,8 @@ public static void translateInteraction(@NotNull PacketDisplayEntityPart part, @ * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull PacketDisplayEntityPart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ - if (part.getType() != SpawnedDisplayEntityPart.PartType.INTERACTION) return; + public static void translateNonDisplay(@NotNull PacketDisplayEntityPart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + if (part.isDisplay()) return; Location destination = part.getLocation().clone().add(direction.clone().normalize().multiply(distance)); if (durationInTicks <= 0 && delayInTicks <= 0){ @@ -398,8 +394,8 @@ public void run() { * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Player player, @NotNull Interaction interaction, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(player, interaction, direction.getVector(interaction, true), distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull Player player, @NotNull Interaction interaction, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(player, interaction, direction.getVector(interaction, true), distance, durationInTicks, delayInTicks); } /** @@ -413,8 +409,8 @@ public static void translateInteraction(@NotNull Player player, @NotNull Interac * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Player player, @NotNull Interaction interaction, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(List.of(player), interaction, direction, distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull Player player, @NotNull Interaction interaction, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(List.of(player), interaction, direction, distance, durationInTicks, delayInTicks); } /** @@ -428,8 +424,8 @@ public static void translateInteraction(@NotNull Player player, @NotNull Interac * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Player player, @NotNull ActivePart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(player, part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull Player player, @NotNull ActivePart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(player, part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); } /** @@ -443,8 +439,8 @@ public static void translateInteraction(@NotNull Player player, @NotNull ActiveP * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Player player, @NotNull ActivePart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(List.of(player), part, direction, distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull Player player, @NotNull ActivePart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(List.of(player), part, direction, distance, durationInTicks, delayInTicks); } /** @@ -458,8 +454,8 @@ public static void translateInteraction(@NotNull Player player, @NotNull ActiveP * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Collection players, @NotNull Interaction interaction, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(players, interaction, direction.getVector(interaction, true), distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull Collection players, @NotNull Interaction interaction, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(players, interaction, direction.getVector(interaction, true), distance, durationInTicks, delayInTicks); } /** @@ -473,9 +469,9 @@ public static void translateInteraction(@NotNull Collection players, @No * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Collection players, @NotNull Interaction interaction, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + public static void translateNonDisplay(@NotNull Collection players, @NotNull Interaction interaction, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ Location l = interaction.getLocation(); - translateInteraction(players, interaction.getEntityId(), l, l.getYaw(), direction, distance, durationInTicks, delayInTicks); + translateNonDisplay(players, interaction.getEntityId(), l, l.getYaw(), direction, distance, durationInTicks, delayInTicks); } /** @@ -489,8 +485,8 @@ public static void translateInteraction(@NotNull Collection players, @No * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Collection players, @NotNull ActivePart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ - translateInteraction(players, part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); + public static void translateNonDisplay(@NotNull Collection players, @NotNull ActivePart part, @NotNull Direction direction, double distance, int durationInTicks, int delayInTicks){ + translateNonDisplay(players, part, direction.getVector(part, true), distance, durationInTicks, delayInTicks); } /** @@ -504,17 +500,17 @@ public static void translateInteraction(@NotNull Collection players, @No * @param durationInTicks How long it should take for the translation to complete * @param delayInTicks How long before the translation should begin */ - public static void translateInteraction(@NotNull Collection players, @NotNull ActivePart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ - if (part.getType() != SpawnedDisplayEntityPart.PartType.INTERACTION) return; + public static void translateNonDisplay(@NotNull Collection players, @NotNull ActivePart part, @NotNull Vector direction, double distance, int durationInTicks, int delayInTicks){ + if (part.isDisplay()) return; Location l = part.getLocation(); if (l == null) return; - translateInteraction(players, part.getEntityId(), l, l.getYaw(), direction, distance, durationInTicks, delayInTicks); + translateNonDisplay(players, part.getEntityId(), l, l.getYaw(), direction, distance, durationInTicks, delayInTicks); } - private static void translateInteraction(Collection players, int entityId, Location location, float lastYaw, Vector direction, double distance, int durationInTicks, int delayInTicks){ + private static void translateNonDisplay(Collection players, int entityId, Location location, float lastYaw, Vector direction, double distance, int durationInTicks, int delayInTicks){ Location destination = location.clone().add(direction.clone().normalize().multiply(distance)); if (durationInTicks <= 0 && delayInTicks <= 0){ - sendInteractionTeleportPacket(entityId, destination, players); + sendTranslateTeleportPacket(entityId, destination, players); return; } @@ -539,17 +535,17 @@ public void run() { tpLoc.add(incrementVector); if (currentDistance >= distance){ - sendInteractionTeleportPacket(entityId, destination, players); + sendTranslateTeleportPacket(entityId, destination, players); cancel(); } else{ - sendInteractionTeleportPacket(entityId, tpLoc, players); + sendTranslateTeleportPacket(entityId, tpLoc, players); } } }, delayInTicks, 1); } - private static void sendInteractionTeleportPacket(int entityId, Location location, Collection players){ + private static void sendTranslateTeleportPacket(int entityId, Location location, Collection players){ for (Player p : players){ PacketEvents.getAPI().getPlayerManager().sendPacket(p, new WrapperPlayServerEntityTeleport(entityId, SpigotConversionUtil.fromBukkitLocation(location), @@ -622,27 +618,4 @@ public static void setGlowing(@NotNull Player player, int entityId, long duratio setGlowing(player, entityId, false); }, durationInTicks); } - - @ApiStatus.Internal - public static int[] getTrackedIntersection(DEUUser user, SequencedCollection parts){ - Player p = Bukkit.getPlayer(user.getUserUUID()); - return parts.stream() - .filter(part -> { - if (part.isTrackedBy(user.getUserUUID())){ - part.hideFromPlayer(p); - return true; - } - return false; - }) - .mapToInt(PacketDisplayEntityPart::getEntityId) - .toArray(); - - /*int[] ids = new int[parts.size()]; - int i = 0; - for (PacketDisplayEntityPart part : parts){ - ids[i] = part.getEntityId(); - i++; - } - return ids;*/ - } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/file/BDEItemDisplay.java b/api/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/file/BDEItemDisplay.java index 1eb24bd8..30bf14d5 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/file/BDEItemDisplay.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/file/BDEItemDisplay.java @@ -40,11 +40,11 @@ void apply(ItemDisplay display) { //For Player Heads if (playerHeadTexture != null && !playerHeadTexture.isBlank()){ - item.editMeta(SkullMeta.class, meta -> { - PlayerProfile profile = Bukkit.createProfile(UUID.randomUUID()); - profile.setProperty(new ProfileProperty("textures", playerHeadTexture)); - meta.setPlayerProfile(profile); - }); + SkullMeta meta = (SkullMeta) item.getItemMeta(); + PlayerProfile profile = Bukkit.createProfile(UUID.randomUUID()); + profile.setProperty(new ProfileProperty("textures", playerHeadTexture)); + meta.setPlayerProfile(profile); + item.setItemMeta(meta); } display.setItemStack(item); } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayController.java b/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayController.java index 8346e0cd..817934e3 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayController.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/controller/DisplayController.java @@ -91,7 +91,7 @@ boolean isMarkedNull(){ return grouplessControllers.containsKey(this); } - @ApiStatus.Internal + /** * Set the {@link DisplayEntityGroup} this controller should use * @param group diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java index 0135456f..c0f9f62f 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/PacketAttributeContainer.java @@ -5,19 +5,26 @@ import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType; import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; +import com.github.retrooper.packetevents.protocol.player.Equipment; +import com.github.retrooper.packetevents.protocol.player.EquipmentSlot; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes; import io.github.retrooper.packetevents.util.SpigotConversionUtil; import io.github.retrooper.packetevents.util.SpigotReflectionUtil; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityPart; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.packet.attributes.AttributeDisplayAttribute; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttribute; import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; +import net.donnypz.displayentityutils.utils.packet.attributes.EquipmentAttribute; import org.bukkit.Bukkit; import org.bukkit.Color; import org.bukkit.Location; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.bukkit.util.Transformation; import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; @@ -138,7 +145,7 @@ public PacketAttributeContainer setAttributes(@NotNull DisplayAttributeMap attri */ public PacketAttributeContainer setAttributeAndSend(@NotNull DisplayAttribute attribute, T value, int entityId, @NotNull Player player){ this.attributes.put(attribute, value); - sendAttributes(player, entityId, getMetadataList(Map.of(attribute, value))); + new PacketResult(entityId, attribute, value).send(player); return this; } @@ -151,7 +158,7 @@ public PacketAttributeContainer setAttributeAndSend(@NotNull DisplayAttri */ public void setAttributeAndSend(@NotNull DisplayAttribute attribute, T value, int entityId, @NotNull Collection playerUUIDs){ this.attributes.put(attribute, value); - sendAttributesToUUIDs(playerUUIDs, entityId, getMetadataList(new DisplayAttributeMap().add(attribute, value).attributes)); + new PacketResult(entityId, attribute, value).sendUUIDs(playerUUIDs); } /** @@ -164,7 +171,7 @@ public void setAttributeAndSend(@NotNull DisplayAttribute attribute */ public PacketAttributeContainer setAttributesAndSend(@NotNull DisplayAttributeMap attributeMap, int entityId, @NotNull Player player){ this.attributes.putAll(attributeMap.attributes); - sendAttributes(player, entityId, getMetadataList(attributeMap.attributes)); + new PacketResult(entityId, attributeMap).send(player); return this; } @@ -178,7 +185,7 @@ public PacketAttributeContainer setAttributesAndSend(@NotNull DisplayAttributeMa */ public PacketAttributeContainer setAttributesAndSend(@NotNull DisplayAttributeMap attributeMap, int entityId, @NotNull Collection playerUUIDs){ this.attributes.putAll(attributeMap.attributes); - sendAttributesToUUIDs(playerUUIDs, entityId, getMetadataList(attributeMap.attributes)); + new PacketResult(entityId, attributeMap).sendUUIDs(playerUUIDs); return this; } @@ -358,7 +365,7 @@ public int sendEntityUsingUUIDs(@NotNull SpawnedDisplayEntityPart.PartType partT * @return this */ private PacketAttributeContainer sendAttributes(SpawnedDisplayEntityPart.PartType partType, Player player, int entityId){ - sendAttributes(player, entityId, getMetadataList(attributes, partType)); + new PacketResult(entityId).send(player); return this; } @@ -370,7 +377,7 @@ private PacketAttributeContainer sendAttributes(SpawnedDisplayEntityPart.PartTyp * @return this */ public PacketAttributeContainer sendAttributes(@NotNull Player player, int entityId){ - sendAttributes(player, entityId, getMetadataList(attributes)); + new PacketResult(entityId).send(player); return this; } @@ -381,7 +388,7 @@ public PacketAttributeContainer sendAttributes(@NotNull Player player, int entit * @return this */ public PacketAttributeContainer sendAttributesUsingUUIDs(@NotNull Collection playerUUIDs, int entityId){ - sendAttributesToUUIDs(playerUUIDs, entityId, getMetadataList(attributes)); + new PacketResult(entityId).sendUUIDs(playerUUIDs); return this; } @@ -392,26 +399,10 @@ public PacketAttributeContainer sendAttributesUsingUUIDs(@NotNull Collection players, int entityId){ - sendAttributesToPlayers(players, entityId, getMetadataList(attributes)); + new PacketResult(entityId).send(players); return this; } - private void sendAttributes(@NotNull Player player, int entityId, List> data){ - PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityMetadata(entityId, data)); - } - - private void sendAttributesToPlayers(@NotNull Collection players, int entityId, List> data){ - for (Player player : players){ - PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerEntityMetadata(entityId, data)); - } - } - - private void sendAttributesToUUIDs(@NotNull Collection playerUUIDs, int entityId, List> data){ - for (UUID uuid : playerUUIDs){ - PacketEvents.getAPI().getPlayerManager().sendPacket(Bukkit.getPlayer(uuid), new WrapperPlayServerEntityMetadata(entityId, data)); - } - } - private WrapperPlayServerSpawnEntity createEntityPacket(int entityId, SpawnedDisplayEntityPart.PartType partType, Location location){ return new WrapperPlayServerSpawnEntity( entityId, @@ -419,86 +410,11 @@ private WrapperPlayServerSpawnEntity createEntityPacket(int entityId, SpawnedDis getEntityType(partType), //SpigotConversionUtil.fromBukkitLocation(getTrueLocation(partType, location)), SpigotConversionUtil.fromBukkitLocation(location), - 0, + location.getYaw(), 0, null); } - private WrapperPlayServerEntityMetadata createFullMetadataPacket(int entityId){ - return new WrapperPlayServerEntityMetadata(entityId, getMetadataList()); - } - - - - private List> getMetadataList() { - return getMetadataList(attributes); - } - - private List> getMetadataList(Map, Object> attributes){ - List> metadata = new ArrayList<>(); - for (Map.Entry, Object> entry : attributes.entrySet()) { - DisplayAttribute attr = entry.getKey(); - Object val = entry.getValue(); - - - DisplayAttribute castedAttr = (DisplayAttribute) attr; - - Object outputValue = castedAttr.getOutputValue(castedAttr.getInputType().cast(val)); - - EntityDataType entityDataType = (EntityDataType) castedAttr.getEntityDataType(); - - metadata.add(new EntityData<>( - castedAttr.getIndex(), - entityDataType, - outputValue - )); - } - return metadata; - } - - private List> getMetadataList(Map, Object> attributes, SpawnedDisplayEntityPart.PartType partType){ - List> metadata = new ArrayList<>(); - for (Map.Entry, Object> entry : attributes.entrySet()) { - DisplayAttribute attr = entry.getKey(); - Object val = entry.getValue(); - - - DisplayAttribute castedAttr = (DisplayAttribute) attr; - - - Object outputValue = castedAttr.getOutputValue(castedAttr.getInputType().cast(val)); - - EntityDataType entityDataType = (EntityDataType) castedAttr.getEntityDataType(); - - metadata.add(new EntityData<>( - castedAttr.getIndex(), - entityDataType, - outputValue - )); - } - return metadata; - } - - /*private List> getDefinedMetadataList(Map, T> attributes){ - List> metadata = new ArrayList<>(); - for (Map.Entry, T> entry : attributes.entrySet()) { - DisplayAttribute attr = entry.getKey(); - Object val = entry.getValue(); - - - V outputValue = attr.getOutputValue(attr.getInputType().cast(val)); - - EntityDataType entityDataType = (EntityDataType) attr.getEntityDataType(); - - metadata.add(new EntityData<>( - attr.getIndex(), - entityDataType, - outputValue - )); - } - return metadata; - }*/ - EntityType getEntityType(SpawnedDisplayEntityPart.PartType partType){ switch (partType){ case BLOCK_DISPLAY -> { @@ -513,8 +429,11 @@ EntityType getEntityType(SpawnedDisplayEntityPart.PartType partType){ case INTERACTION -> { return EntityTypes.INTERACTION; } + case MANNEQUIN -> { + return EntityTypes.MANNEQUIN; + } default -> { - throw new IllegalArgumentException("Invalid part type, expected a display entity type."); + throw new IllegalArgumentException("Invalid part type."); } } } @@ -551,4 +470,112 @@ else if (value instanceof Color c){ throw new RuntimeException(e); } } + + class PacketResult{ + int entityId; + WrapperPlayServerEntityMetadata metadataPacket; + WrapperPlayServerEntityEquipment equipmentPacket; + WrapperPlayServerUpdateAttributes attributesPacket; + + PacketResult(int entityId){ + this.entityId = entityId; + setPackets(attributes); + } + + PacketResult(int entityId, DisplayAttributeMap map){ + this.entityId = entityId; + setPackets(map.attributes); + } + + PacketResult(int entityId, DisplayAttribute attribute, Object value){ + this.entityId = entityId; + setPackets(Map.of(attribute, value)); + } + + void setPackets(Map, Object> attributeMap){ + List> entityData = new ArrayList<>(); + List equipmentData = new ArrayList<>(); + List attributeData = new ArrayList<>(); + for(Map.Entry, Object> entry : attributeMap.entrySet()){ + DisplayAttribute attr = entry.getKey(); + Object val = entry.getValue(); + if (attr.isMetadata()){ + entityData.add(createEntityData(attr, val)); + } + else if (attr.isEquipment()){ + equipmentData.add(createEquipmentData(attr, val)); + } + else if (attr.isAttribute()){ + attributeData.add(createAttributeData(attr, val)); + } + } + + if (!entityData.isEmpty()){ + metadataPacket = new WrapperPlayServerEntityMetadata(entityId, entityData); + } + if (!equipmentData.isEmpty()){ + equipmentPacket = new WrapperPlayServerEntityEquipment(entityId, equipmentData); + } + if (!attributeData.isEmpty()){ + attributesPacket = new WrapperPlayServerUpdateAttributes(entityId, attributeData); + } + } + + EntityData createEntityData(DisplayAttribute attribute, Object value){ + DisplayAttribute castedAttr = (DisplayAttribute) attribute; + Object outputValue = castedAttr.getOutputValue(castedAttr.getInputType().cast(value)); + + EntityDataType entityDataType = (EntityDataType) castedAttr.getEntityDataType(); + return new EntityData<>( + castedAttr.getIndex(), + entityDataType, + outputValue + ); + } + + Equipment createEquipmentData(DisplayAttribute attribute, Object value){ + return new Equipment(EquipmentSlot.values()[attribute.getIndex()], + ((EquipmentAttribute) attribute).getOutputValue((ItemStack) value)); + } + + WrapperPlayServerUpdateAttributes.Property createAttributeData(DisplayAttribute attribute, Object value){ + if (attribute == DisplayAttributes.Mannequin.SCALE){ + value = Math.clamp((float) value, 0, 16); + } + return new WrapperPlayServerUpdateAttributes.Property(((AttributeDisplayAttribute) attribute).getAttribute(), + (float) value, + List.of()); + } + + void send(Player player){ + if (metadataPacket != null){ + PacketEvents.getAPI().getPlayerManager().sendPacket(player, metadataPacket); + } + + if (equipmentPacket != null){ + PacketEvents.getAPI().getPlayerManager().sendPacket(player, equipmentPacket); + } + + if (attributesPacket != null){ + PacketEvents.getAPI().getPlayerManager().sendPacket(player, attributesPacket); + } + } + + void send(UUID playerUUID){ + Player p = Bukkit.getPlayer(playerUUID); + if (p != null) send(p); + } + + void send(Collection players){ + for (Player p : players){ + send(p); + } + } + + void sendUUIDs(Collection playerUUIDs){ + for (UUID uuid : playerUUIDs){ + send(uuid); + } + } + } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java new file mode 100644 index 00000000..f7766982 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/AttributeDisplayAttribute.java @@ -0,0 +1,23 @@ +package net.donnypz.displayentityutils.utils.packet.attributes; + +import com.github.retrooper.packetevents.protocol.attribute.Attribute; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; + +public class AttributeDisplayAttribute extends DisplayAttribute{ + + Attribute attribute; + protected AttributeDisplayAttribute(Attribute attribute) { + super(0, Float.class, EntityDataTypes.FLOAT); + this.attribute = attribute; + setAttributeType(AttributeType.ATTRIBUTE); + } + + public Attribute getAttribute() { + return attribute; + } + + @Override + public Float getOutputValue(Float value) { + return value; + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttribute.java index 130933ae..fc670182 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttribute.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttribute.java @@ -8,6 +8,7 @@ public abstract class DisplayAttribute { Class inputType; Class outputType; EntityDataType entityDataType; + AttributeType type = AttributeType.METADATA; protected DisplayAttribute(int index, Class type, EntityDataType entityDataType){ this.index = index; @@ -39,4 +40,30 @@ public Class getOutputType(){ } public abstract V getOutputValue(T value); + + DisplayAttribute setAttributeType(AttributeType type){ + this.type = type; + return this; + } + + public boolean isMetadata(){ + return type == AttributeType.METADATA; + } + + public boolean isEquipment(){ + return type == AttributeType.EQUIPMENT; + } + + public boolean isAttribute(){ + return type == AttributeType.ATTRIBUTE; + } + + + + + enum AttributeType{ + METADATA, + EQUIPMENT, + ATTRIBUTE + } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java index 1cfa7b79..2fb8bbe2 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/DisplayAttributes.java @@ -1,14 +1,60 @@ package net.donnypz.displayentityutils.utils.packet.attributes; +import com.github.retrooper.packetevents.protocol.attribute.Attributes; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.player.EquipmentSlot; import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; /** - * A class containing all {@link DisplayAttribute}s that apply to both Display and Interaction entities + * A class containing all {@link DisplayAttribute}s that apply to eligible part type entities */ public final class DisplayAttributes { public static final GlowingDisplayAttribute GLOWING = new GlowingDisplayAttribute(0); + public static final OptionalComponentDisplayAttribute CUSTOM_NAME = new OptionalComponentDisplayAttribute(2); + public static final BasicDisplayAttribute CUSTOM_NAME_VISIBLE = new BasicDisplayAttribute<>(3, Boolean.class, EntityDataTypes.BOOLEAN); + + private DisplayAttributes(){} + + public static final class Equipment{ + public static final EquipmentAttribute HELMET = new EquipmentAttribute(EquipmentSlot.HELMET); + public static final EquipmentAttribute CHESTPLATE = new EquipmentAttribute(EquipmentSlot.CHEST_PLATE); + public static final EquipmentAttribute LEGGINGS = new EquipmentAttribute(EquipmentSlot.LEGGINGS); + public static final EquipmentAttribute BOOTS = new EquipmentAttribute(EquipmentSlot.BOOTS); + public static final EquipmentAttribute MAIN_HAND = new EquipmentAttribute(EquipmentSlot.MAIN_HAND); + public static final EquipmentAttribute OFF_HAND = new EquipmentAttribute(EquipmentSlot.OFF_HAND); + public static final EquipmentAttribute BODY = new EquipmentAttribute(EquipmentSlot.BODY); + + public static EquipmentAttribute getAttribute(@NotNull org.bukkit.inventory.EquipmentSlot slot){ + switch (slot){ + case HEAD -> { + return HELMET; + } + case CHEST -> { + return CHESTPLATE; + } + case LEGS -> { + return LEGGINGS; + } + case FEET -> { + return BOOTS; + } + case BODY -> { + return BODY; + } + case HAND -> { + return MAIN_HAND; + } + case OFF_HAND -> { + return OFF_HAND; + } + default -> { + throw new IllegalArgumentException("Invalid/Unexpected slot type"); + } + } + } + } public static final class Interpolation { public static final BasicDisplayAttribute DELAY = new BasicDisplayAttribute<>(8, Integer.class, EntityDataTypes.INT); @@ -40,7 +86,6 @@ public static final class Culling{ public static final BasicDisplayAttribute HEIGHT = new BasicDisplayAttribute<>(21, Float.class, EntityDataTypes.FLOAT); } - public static final ColorDisplayAttribute GLOW_COLOR_OVERRIDE = new ColorDisplayAttribute(22); public static final class BlockDisplay{ @@ -66,4 +111,13 @@ public static final class Interaction{ public static final BasicDisplayAttribute RESPONSIVE = new BasicDisplayAttribute<>(10, Boolean.class, EntityDataTypes.BOOLEAN); } + public static final class Mannequin{ + public static final AttributeDisplayAttribute SCALE = new AttributeDisplayAttribute(Attributes.SCALE); + public static final BasicDisplayAttribute NO_GRAVITY = new BasicDisplayAttribute<>(5, Boolean.class, EntityDataTypes.BOOLEAN); + public static final PoseDisplayAttribute POSE = new PoseDisplayAttribute(6); + public static final MainHandDisplayAttribute MAIN_HAND = new MainHandDisplayAttribute(15); + public static final ResolvableProfileDisplayAttribute RESOLVABLE_PROFILE = new ResolvableProfileDisplayAttribute(17); + public static final BasicDisplayAttribute IMMOVABLE = new BasicDisplayAttribute<>(18, Boolean.class, EntityDataTypes.BOOLEAN); + public static final OptionalComponentDisplayAttribute BELOW_NAME = new OptionalComponentDisplayAttribute(19); + } } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/EquipmentAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/EquipmentAttribute.java new file mode 100644 index 00000000..53429bb3 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/EquipmentAttribute.java @@ -0,0 +1,19 @@ +package net.donnypz.displayentityutils.utils.packet.attributes; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.player.EquipmentSlot; +import io.github.retrooper.packetevents.util.SpigotConversionUtil; +import org.bukkit.inventory.ItemStack; + +public class EquipmentAttribute extends DisplayAttribute{ + + protected EquipmentAttribute(EquipmentSlot slot) { + super(slot.ordinal(), ItemStack.class, EntityDataTypes.ITEMSTACK); + setAttributeType(AttributeType.EQUIPMENT); + } + + @Override + public com.github.retrooper.packetevents.protocol.item.ItemStack getOutputValue(ItemStack value) { + return SpigotConversionUtil.fromBukkitItemStack(value); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/MainHandDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/MainHandDisplayAttribute.java new file mode 100644 index 00000000..cf5d5edb --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/MainHandDisplayAttribute.java @@ -0,0 +1,15 @@ +package net.donnypz.displayentityutils.utils.packet.attributes; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import org.bukkit.inventory.MainHand; + +public class MainHandDisplayAttribute extends DisplayAttribute{ + protected MainHandDisplayAttribute(int index) { + super(index, MainHand.class, Byte.class, EntityDataTypes.BYTE); + } + + @Override + public Byte getOutputValue(MainHand value) { + return (byte) (value == MainHand.LEFT ? 0 : 1); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/OptionalComponentDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/OptionalComponentDisplayAttribute.java new file mode 100644 index 00000000..0a7e324f --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/OptionalComponentDisplayAttribute.java @@ -0,0 +1,17 @@ +package net.donnypz.displayentityutils.utils.packet.attributes; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import net.kyori.adventure.text.Component; + +import java.util.Optional; + +public class OptionalComponentDisplayAttribute extends DisplayAttribute> { + protected OptionalComponentDisplayAttribute(int index) { + super(index, Component.class, EntityDataTypes.OPTIONAL_ADV_COMPONENT); + } + + @Override + public Optional getOutputValue(Component value) { + return Optional.of(value); + } +} \ No newline at end of file diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/PoseDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/PoseDisplayAttribute.java new file mode 100644 index 00000000..d78242af --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/PoseDisplayAttribute.java @@ -0,0 +1,22 @@ +package net.donnypz.displayentityutils.utils.packet.attributes; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose; +import org.bukkit.entity.Pose; + +public class PoseDisplayAttribute extends DisplayAttribute{ + PoseDisplayAttribute(int index) { + super(index, Pose.class, EntityPose.class, EntityDataTypes.ENTITY_POSE); + } + + @Override + public EntityPose getOutputValue(Pose pose) { + if (pose == null) return EntityPose.STANDING; + try{ + return EntityPose.valueOf(pose.name()); + } + catch(IllegalArgumentException e){ + return EntityPose.STANDING; + } + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java new file mode 100644 index 00000000..3700db12 --- /dev/null +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/packet/attributes/ResolvableProfileDisplayAttribute.java @@ -0,0 +1,56 @@ +package net.donnypz.displayentityutils.utils.packet.attributes; + +import com.destroystokyo.paper.profile.ProfileProperty; +import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemProfile; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.player.PlayerModelType; +import com.github.retrooper.packetevents.resources.ResourceLocation; +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import net.kyori.adventure.key.Key; +import org.bukkit.profile.PlayerTextures; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class ResolvableProfileDisplayAttribute extends DisplayAttribute { + protected ResolvableProfileDisplayAttribute(int index) { + super(index, ResolvableProfile.class, ItemProfile.class, EntityDataTypes.RESOLVABLE_PROFILE); + } + + @Override + public ItemProfile getOutputValue(ResolvableProfile value) { + String name = value.name(); + UUID uuid = value.uuid(); + + List properties = new ArrayList<>(); + for (ProfileProperty prop : value.properties()){ + properties.add(new ItemProfile.Property(prop.getName(), prop.getValue(), prop.getSignature())); + } + ItemProfile.SkinPatch skinPatch; + ResolvableProfile.SkinPatch bukkitSkinPatch = value.skinPatch(); + if (bukkitSkinPatch.isEmpty()){ + skinPatch = ItemProfile.SkinPatch.EMPTY; + } + else{ + PlayerModelType modelType; + if (bukkitSkinPatch.model() == null){ + modelType = null; + } + else{ + modelType = (bukkitSkinPatch.model() == PlayerTextures.SkinModel.CLASSIC) ? PlayerModelType.WIDE : PlayerModelType.SLIM; + } + Key bodyKey = bukkitSkinPatch.body(); + Key capeKey = bukkitSkinPatch.cape(); + Key elytraKey = bukkitSkinPatch.elytra(); + + skinPatch = new ItemProfile.SkinPatch( + bodyKey == null ? null : new ResourceLocation(bodyKey), + capeKey == null ? null : new ResourceLocation(capeKey), + elytraKey == null ? null : new ResourceLocation(elytraKey), + modelType); + } + + return new ItemProfile(name, uuid, properties, skinPatch); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java b/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java deleted file mode 100644 index 97364631..00000000 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/GroupPointSelector.java +++ /dev/null @@ -1,44 +0,0 @@ -package net.donnypz.displayentityutils.utils.relativepoints; - -import net.donnypz.displayentityutils.utils.DisplayEntities.GroupPoint; -import net.donnypz.displayentityutils.utils.DisplayEntities.RelativePoint; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -@ApiStatus.Internal -@ApiStatus.Experimental -public class GroupPointSelector extends RelativePointSelector { - SpawnedDisplayEntityGroup group; - - GroupPointSelector(Player player, Location spawnLocation, GroupPoint relativePoint, SpawnedDisplayEntityGroup group){ - super(player, spawnLocation, relativePoint, Material.ORANGE_CONCRETE); - this.group = group; - } - - @Override - public void sendInfo(@NotNull Player player) { - - } - - @Override - public void rightClick(@NotNull Player player) { - - } - - @Override - public boolean removeFromPointHolder() { - //group.relativePoints.remove(relativePoint); - return true; - } - - - @Override - public void despawn(){ - super.despawn(); - group = null; - } -} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/version/VersionUtils.java b/api/src/main/java/net/donnypz/displayentityutils/utils/version/VersionUtils.java index f3afa02a..c6dc6c52 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/version/VersionUtils.java +++ b/api/src/main/java/net/donnypz/displayentityutils/utils/version/VersionUtils.java @@ -22,7 +22,7 @@ public final class VersionUtils { public static boolean IS_1_21_7 = Bukkit.getUnsafe().getProtocolVersion() >= 772; public static boolean IS_1_21_9 = Bukkit.getUnsafe().getProtocolVersion() >= 773; - public static boolean canViewDialogs(Player player, boolean sendErrorMessage){ + public static boolean canViewDialogs(@NotNull Player player, boolean sendErrorMessage){ if (!serverHasDialogs()){ if (sendErrorMessage){ player.sendMessage(DisplayAPI.pluginPrefix @@ -42,6 +42,10 @@ else if (getProtocolVersion(player) < 771){ //1.21.6 return true; } + public static boolean canSpawnMannequins(){ + return IS_1_21_9; + } + private static int getProtocolVersion(Player player){ if (DisplayAPI.isViaVerInstalled()){ return ViaVersionUtil.getProtocolVersion(player); @@ -83,7 +87,15 @@ public static Particle getItemParticle(){ public static Sound getSound(String soundName){ if (soundName == null) return null; - return Registry.SOUNDS.get(NamespacedKey.minecraft(soundName)); + String[] split = soundName.split(":"); + if (split.length < 2){ + return Registry.SOUNDS.get(NamespacedKey.minecraft(soundName)); + } + else{ + String namespace = split[0]; + String key = split[1]; + return Registry.SOUNDS.get(new NamespacedKey(namespace, key)); + } } public static boolean serverHasDialogs(){ //Dialog API came to Paper in 1.21.7, Dialog System came to MC in 1.21.6 diff --git a/plugin/pom.xml b/plugin/pom.xml index 05c414c2..df39f8bd 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.3.8 + 3.4.0 plugin diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java index e2a46f49..86205063 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/DisplayEntityPlugin.java @@ -10,11 +10,9 @@ import net.donnypz.displayentityutils.listeners.bdengine.DatapackEntitySpawned; import net.donnypz.displayentityutils.listeners.entity.DEUEntityListener; import net.donnypz.displayentityutils.listeners.entity.DEUInteractionListener; +import net.donnypz.displayentityutils.listeners.entity.DEUMannequinEditorListener; import net.donnypz.displayentityutils.listeners.entity.mythic.DEUMythicListener; -import net.donnypz.displayentityutils.listeners.player.DEUPlayerChatListener; -import net.donnypz.displayentityutils.listeners.player.DEUPlayerConnectionListener; -import net.donnypz.displayentityutils.listeners.player.DEUPlayerPacketListener; -import net.donnypz.displayentityutils.listeners.player.DEUPlayerWorldListener; +import net.donnypz.displayentityutils.listeners.player.*; import net.donnypz.displayentityutils.managers.LocalManager; import net.donnypz.displayentityutils.managers.MYSQLManager; import net.donnypz.displayentityutils.managers.MongoManager; @@ -89,6 +87,19 @@ private void initializeNamespacedKeys(){ //DO NOT CHANGE DisplayAPI.spawnAnimationTypeKey = new NamespacedKey(this, "spawnanimationtype"); DisplayAPI.spawnAnimationLoadMethodKey = new NamespacedKey(this, "spawnanimationloader"); DisplayAPI.chunkPacketGroupsKey = new NamespacedKey(this, "chunkpacketgroups"); + + DisplayAPI.placeableGroupKey = new NamespacedKey(this, "placeablegroup"); + DisplayAPI.placeableGroupPermissionKey = new NamespacedKey(this, "placeablegroup_perm"); + DisplayAPI.placeableGroupRespectFacingKey = new NamespacedKey(this, "placeablegroup_playerfacing"); + DisplayAPI.placeableGroupRespectBlockFace = new NamespacedKey(this, "placeablegroup_blockface"); + DisplayAPI.placeableGroupPlaceSounds = new NamespacedKey(this, "placeablegroup_placesounds"); + DisplayAPI.placeableGroupBreakSounds = new NamespacedKey(this, "placeablegroup_breaksounds"); + DisplayAPI.placeableGroupPlacerBreaksOnly = new NamespacedKey(this, "placeablegroup_placerbreaks"); + DisplayAPI.placeableGroupDropItem = new NamespacedKey(this, "placeablegroup_dropitem"); + DisplayAPI.placeableGroupItemStack = new NamespacedKey(this, "placeablegroup_itemstack"); + DisplayAPI.placeableGroupPlacer = new NamespacedKey(this, "placeablegroup_placer"); + DisplayAPI.placeableGroupId = new NamespacedKey(this, "placeablegroup_groupid"); + } private void initializeDependencies(){ @@ -125,13 +136,16 @@ private void initializeDependencies(){ private void registerListeners(){ Bukkit.getPluginManager().registerEvents(this, this); + Bukkit.getPluginManager().registerEvents(new DEULoadingListeners(), this); Bukkit.getPluginManager().registerEvents(new DatapackEntitySpawned(), this); + Bukkit.getPluginManager().registerEvents(new DEUEntityListener(), this); Bukkit.getPluginManager().registerEvents(new DEUPlayerConnectionListener(), this); Bukkit.getPluginManager().registerEvents(new DEUPlayerChatListener(), this); Bukkit.getPluginManager().registerEvents(new DEUPlayerWorldListener(), this); - Bukkit.getPluginManager().registerEvents(new DEUEntityListener(), this); - Bukkit.getPluginManager().registerEvents(new DEULoadingListeners(), this); + Bukkit.getPluginManager().registerEvents(new DEUPlayerPlaceBlockListener(), this); + Bukkit.getPluginManager().registerEvents(new DEUPlayerDigListener(), this); Bukkit.getPluginManager().registerEvents(new DEUInteractionListener(), this); + Bukkit.getPluginManager().registerEvents(new DEUMannequinEditorListener(), this); } private void initializeBStats(){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/DEUSubCommand.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/DEUSubCommand.java index 391f47b3..17e95716 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/DEUSubCommand.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/DEUSubCommand.java @@ -3,6 +3,7 @@ import net.donnypz.displayentityutils.utils.Direction; import org.bukkit.entity.Display; import org.bukkit.entity.ItemDisplay; +import org.bukkit.entity.Pose; import org.bukkit.entity.TextDisplay; import org.jetbrains.annotations.NotNull; @@ -57,7 +58,15 @@ protected static class TabSuggestion{ .suggestUsingCurrentString(); public static final TabSuggestion BILLBOARDS = new TabSuggestion(Arrays.stream(Display.Billboard.values()).map(Enum::name).toList()) .suggestUsingCurrentString(); - public static final TabSuggestion PART_TYPES = new TabSuggestion(List.of("block", "item", "text", "interaction")) + public static final TabSuggestion PART_TYPES = new TabSuggestion(List.of("block", "item", "text", "interaction", "mannequin")) + .suggestUsingCurrentString(); + public static final TabSuggestion MANNEQUIN_POSES = new TabSuggestion(List.of( + Pose.SLEEPING.name(), + Pose.SWIMMING.name(), + Pose.SNEAKING.name(), + Pose.STANDING.name(), + Pose.FALL_FLYING.name() //ELYTRA + )) .suggestUsingCurrentString(); public static final TabSuggestion ITEM_DISPLAY_TRANSFORMS = new TabSuggestion(Arrays.stream(ItemDisplay.ItemDisplayTransform.values()).map(Enum::name).toList()) .suggestUsingCurrentString(); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java index c2ae4ec8..5ed1663a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/DisplayEntityPluginCommand.java @@ -3,19 +3,26 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.anim.AnimCMD; import net.donnypz.displayentityutils.command.bdengine.BDEngineCMD; +import net.donnypz.displayentityutils.command.display.DisplayCMD; import net.donnypz.displayentityutils.command.group.GroupCMD; import net.donnypz.displayentityutils.command.interaction.InteractionCMD; import net.donnypz.displayentityutils.command.item.ItemCMD; +import net.donnypz.displayentityutils.command.mannequin.MannequinCMD; import net.donnypz.displayentityutils.command.parts.PartsCMD; +import net.donnypz.displayentityutils.command.place.PlaceCMD; import net.donnypz.displayentityutils.command.text.TextCMD; import net.donnypz.displayentityutils.utils.Direction; import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; +import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Interaction; +import org.bukkit.entity.Mannequin; import org.bukkit.entity.Player; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -43,9 +50,12 @@ public DisplayEntityPluginCommand(){ subCommands.put("hidepoints", new HidePointsCMD()); subCommands.put("group", new GroupCMD()); subCommands.put("parts", new PartsCMD()); + subCommands.put("display", new DisplayCMD()); subCommands.put("item", new ItemCMD()); subCommands.put("text", new TextCMD()); subCommands.put("interaction", new InteractionCMD()); + subCommands.put("mannequin", new MannequinCMD()); + subCommands.put("place", new PlaceCMD()); subCommands.put("anim", new AnimCMD()); subCommands.put("bdengine", new BDEngineCMD()); subCommands.put("reload", new ReloadCMD()); @@ -117,8 +127,9 @@ public static void disallowPacketGroup(Player player){ } public static void noPartSelection(Player player){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You have not selected a part!", NamedTextColor.RED))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You have not selected any part(s)!", NamedTextColor.RED))); player.sendMessage(Component.text("/deu parts cycle ", NamedTextColor.GRAY)); + player.sendMessage(Component.text("/deu parts select ", NamedTextColor.GRAY)); } public static void invalidTag(Player player, String tag){ @@ -133,7 +144,7 @@ public static void invalidTagRestrictions(Player player){ public static void invalidStorage(CommandSender sender){ sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Invalid Storage!", NamedTextColor.RED))); - sender.sendMessage(Component.text("| Valid Storages: local, mysql, mongodb>", NamedTextColor.GRAY)); + sender.sendMessage(MiniMessage.miniMessage().deserialize("| Storages: local, mysql, mongodb")); } public static void hideRelativePoints(Player player){ @@ -142,16 +153,46 @@ public static void hideRelativePoints(Player player){ } } + public static Entity getTargetEntity(Player player){ + Entity entity = player.getTargetEntity(10); + if (!(entity instanceof Interaction || entity instanceof Mannequin)) { + player.sendMessage(Component.text("Your targeted entity must be an interaction or mannequin entity within 10 blocks of you", NamedTextColor.RED)); + return null; + } + return entity; + } + @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (args.length == 0) { - mainCommandHelp(sender); + mainCommandHelp(sender, 1); return true; } + + int pageNum; String arg = args[0]; + if (arg.equalsIgnoreCase("help")){ + if (args.length >= 2){ + try{ + pageNum = Integer.parseInt(args[1]); + } + catch(IllegalArgumentException e){ + pageNum = 1; + } + } + else{ + pageNum = 1; + } + } + else{ + pageNum = 1; + } + + DEUSubCommand subCommand = subCommands.get(arg); + if (subCommand == null){ - mainCommandHelp(sender); + mainCommandHelp(sender, pageNum); } else{ executeCommand(subCommand, sender, args); @@ -184,24 +225,34 @@ public static boolean hasPermission(@NotNull CommandSender sender, @NotNull Perm } - static void mainCommandHelp(CommandSender sender){ + static void mainCommandHelp(CommandSender sender, int page){ if (!hasPermission(sender, Permission.HELP)) { return; } + sender.sendMessage(Component.empty()); sender.sendMessage(DisplayAPI.pluginPrefixLong); - sender.sendMessage(Component.text("v"+DisplayAPI.getVersion(), NamedTextColor.GRAY)); - CMDUtils.sendCMD(sender, "/deu group", "Display Entity Models/Groups related commands"); - CMDUtils.sendCMD(sender, "/deu anim", "Animation related commands"); - CMDUtils.sendCMD(sender, "/deu parts", "Commands related to the parts (individual display entities) of a Display Entity Model/Group"); - CMDUtils.sendCMD(sender, "/deu item", "Commands related to the Item Display parts of a Display Entity Model/Group"); - CMDUtils.sendCMD(sender, "/deu text", "Commands related to the Text Display parts of a Display Entity Model/Group"); - CMDUtils.sendCMD(sender, "/deu interaction", "Commands related to manipulating Interaction entities"); - CMDUtils.sendCMD(sender, "/deu listgroups [page-number]", "List all saved Display Entity Models/Groups"); - CMDUtils.sendCMD(sender, "/deu listanims [page-number]", "List all saved animations"); - CMDUtils.sendCMD(sender, "/deu hidepoints", "Hide any visible points (frame points, persistent packet group points, etc.)"); - CMDUtils.sendCMD(sender, "/deu bdengine", "Import/Convert models from BDEngine"); - CMDUtils.sendCMD(sender, "/deu reload ", "Reload the plugin's config or Display Controllers." + - " To reload Local, MySQL or MongoDB config save options, the server must be restarted"); + if (page == 1){ + sender.sendMessage(Component.text("v"+DisplayAPI.getVersion(), NamedTextColor.GRAY)); + CMDUtils.sendCMD(sender, "/deu help ", "Display the plugin's help commands"); + CMDUtils.sendCMD(sender, "/deu group", "Display Entity Models/Groups related commands"); + CMDUtils.sendCMD(sender, "/deu parts", "Commands related to the parts (individual display entities) of a Display Entity Model/Group"); + CMDUtils.sendCMD(sender, "/deu display", "Commands related to display entities"); + CMDUtils.sendCMD(sender, "/deu item", "Commands related to specifically Item Displays"); + CMDUtils.sendCMD(sender, "/deu text", "Commands related to specifically Text Displays"); + CMDUtils.sendCMD(sender, "/deu interaction", "Commands related to Interaction entities"); + CMDUtils.sendCMD(sender, "/deu mannequin", "Commands related to Mannequin entities"); + } + else{ + CMDUtils.sendCMD(sender, "/deu place", "Assign a Display Entity Model/Group to an block that will spawn when placed"); + CMDUtils.sendCMD(sender, "/deu anim", "Animation related commands"); + CMDUtils.sendCMD(sender, "/deu listgroups [page-number]", "List all saved Display Entity Models/Groups"); + CMDUtils.sendCMD(sender, "/deu listanims [page-number]", "List all saved animations"); + CMDUtils.sendCMD(sender, "/deu hidepoints", "Hide any visible points (frame points, persistent packet group points, etc.)"); + CMDUtils.sendCMD(sender, "/deu bdengine", "Import/Convert models from BDEngine"); + CMDUtils.sendCMD(sender, "/deu reload ", "Reload the plugin's config or Display Controllers." + + " To reload Local, MySQL or MongoDB config save options, the server must be restarted"); + } + sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } @Override @@ -218,7 +269,7 @@ public List onTabComplete(CommandSender sender, Command command, String String subcmd = args[0].toLowerCase(); String current = args[1]; switch (subcmd) { - case "interaction", "anim", "group", "parts", "bdengine", "text", "item" -> { + case "interaction", "anim", "group", "parts", "display", "bdengine", "text", "item", "place", "mannequin" -> { return getTabComplete(subcmd, current); } case "listgroups", "listanims" -> suggestions.addAll(DEUSubCommand.TabSuggestion.STORAGES.suggestions); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/PartsSubCommand.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/PartsSubCommand.java index 5aa8d794..83b5bb87 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/PartsSubCommand.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/PartsSubCommand.java @@ -1,8 +1,11 @@ package net.donnypz.displayentityutils.command; +import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.parts.PartsCMD; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -64,4 +67,20 @@ public void execute(Player player, String[] args){ protected abstract boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args); protected abstract boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args); + + protected boolean isInvalidType(Player player, ActivePart part, SpawnedDisplayEntityPart.PartType validType){ + if (part.getType() != validType){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with "+validType.name().toLowerCase().replace("_"," ")+" entities!", NamedTextColor.RED))); + return true; + } + return false; + } + + protected boolean isNotDisplay(Player player, ActivePart part){ + if (!part.isDisplay()){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with display entities!", NamedTextColor.RED))); + return true; + } + return false; + } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java index 19c2f00c..531190a4 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/Permission.java @@ -34,24 +34,38 @@ public enum Permission { GROUP_CULLING("deu.group.culling"), GROUP_WORLD_EDIT("deu.group.worldedit"), + PLACE_INFO("deu.place.info"), + PLACE_SET_ITEM("deu.place.setitem"), + PLACE_GET_ITEM("deu.place.getitem"), + PLACE_TOGGLE_PLAYER_FACING("deu.place.toggle.playerfacing"), + PLACE_TOGGLE_BLOCK_FACE("deu.place.toggle.blockface"), + PLACE_TOGGLE_DROP_ITEM("deu.place.toggle.dropitem"), + PLACE_TOGGLE_PLACER_ONLY("deu.place.toggle.placeronly"), + PLACE_SET_PERMISSION("deu.place.setpermission"), + PLACE_SOUND("deu.place.sound"), + PLACE_WHO_PLACED("deu.place.whoplaced"), + PLACE_BREAK_MODE("deu.place.breakmode"), + PARTS_INFO("deu.parts.info"), PARTS_CREATE("deu.parts.create"), PARTS_CYCLE("deu.parts.cycle"), PARTS_GLOW("deu.parts.glow"), - PARTS_GLOW_COLOR("deu.parts.glow.set"), PARTS_SELECT("deu.parts.select"), PARTS_TAG("deu.parts.tag"), PARTS_LIST_TAGS("deu.parts.tag.list"), PARTS_REMOVE("deu.parts.remove"), - PARTS_TRANSLATE("deu.parts.translate"), PARTS_TRANSFORM("deu.parts.transform"), - PARTS_SET_BLOCK("deu.parts.setblock"), - PARTS_BILLBOARD("deu.parts.billboard"), - PARTS_BRIGHTNESS("deu.parts.brightness"), - PARTS_VIEWRANGE("deu.parts.viewrange"), + DISPLAY_SET_BLOCK("deu.display.setblock"), + DISPLAY_GLOW_COLOR("deu.display.glowcolor"), + DISPLAY_TRANSLATE("deu.display.translate"), + DISPLAY_TRANSFORM("deu.display.transform"), + DISPLAY_BILLBOARD("deu.display.billboard"), + DISPLAY_BRIGHTNESS("deu.display.brightness"), + DISPLAY_VIEW_RANGE("deu.display.viewrange"), + TEXT_EDIT("deu.text.edit"), TEXT_SET_TEXT("deu.text.set"), TEXT_SET_FONT("deu.text.font"), @@ -76,6 +90,16 @@ public enum Permission { INTERACTION_SPAWN("deu.interaction.spawn"), INTERACTION_INFO("deu.interaction.info"), + MANNEQUIN_SKIN("deu.mannequin.skin"), + MANNEQUIN_NAME("deu.mannequin.name"), + MANNEQUIN_NAME_VISIBLE("deu.mannequin.namevisible"), + MANNEQUIN_POSE("deu.mannequin.pose"), + MANNEQUIN_PIVOT("deu.mannequin.pivot"), + MANNEQUIN_SCALE("deu.mannequin.scale"), + MANNEQUIN_GRAVITY("deu.mannequin.gravity"), + MANNEQUIN_IMMOVABLE("deu.mannequin.immovable"), + MANNEQUIN_SET_EQUIPMENT("deu.mannequin.equipment"), + ANIM_NEW("deu.anim.new"), ANIM_SAVE("deu.anim.save"), ANIM_DELETE("deu.anim.delete"), diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameAfterCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameAfterCMD.java index d085e41a..61bccc79 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameAfterCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameAfterCMD.java @@ -68,7 +68,7 @@ public void execute(Player player, String[] args) { frames.add(id + 1, frame); anim.setFrames(frames); - player.sendMessage(Component.text( "Frame successfully added after frame-id " + id + "!", NamedTextColor.GREEN)); + player.sendMessage(Component.text( "Added frame after frame-id " + id + "!", NamedTextColor.GREEN)); player.playSound(player, Sound.ENTITY_SHEEP_SHEAR, 1, 0.75f); } catch (NumberFormatException e) { diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameCMD.java index fc26ad4e..3b02b054 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddFrameCMD.java @@ -52,7 +52,7 @@ public void execute(Player player, String[] args) { boolean isUnique = anim.addFrame(frame); if (isUnique){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully captured animation frame", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Animation frame captured!", NamedTextColor.GREEN))); player.playSound(player, Sound.ENTITY_SHEEP_SHEAR, 1, 0.75f); } else{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java index af8febcd..31a0fbbc 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimAddSoundCMD.java @@ -5,7 +5,7 @@ import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayAnimationManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.AnimationSound; +import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayAnimation; import net.donnypz.displayentityutils.utils.relativepoints.FramePointSelector; import net.donnypz.displayentityutils.utils.relativepoints.RelativePointSelector; @@ -14,7 +14,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.Sound; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -47,22 +46,22 @@ public void execute(Player player, String[] args) { return; } try { - Sound sound = VersionUtils.getSound(args[2]); - if (sound == null){ - player.sendMessage(Component.text("Invalid Sound Name!", NamedTextColor.RED)); - return; - } + String soundStr = args[2]; float volume = Float.parseFloat(args[3]); float pitch = Float.parseFloat(args[4]); int delayInTicks = Integer.parseInt(args[5]); - display.getRelativePoint().addSound(new AnimationSound(sound, volume, pitch, delayInTicks)); + display.getRelativePoint().addSound(new DEUSound(soundStr, volume, pitch, delayInTicks)); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Sound Added to Frame Point!", NamedTextColor.GREEN))); - player.sendMessage(MiniMessage.miniMessage().deserialize("| Sound: "+sound)); + player.sendMessage(MiniMessage.miniMessage().deserialize("| Sound: "+soundStr)); player.sendMessage(MiniMessage.miniMessage().deserialize("| Volume: "+volume)); player.sendMessage(MiniMessage.miniMessage().deserialize("| Pitch: "+pitch)); player.sendMessage(MiniMessage.miniMessage().deserialize("| Delay: "+delayInTicks)); + + if (VersionUtils.getSound(args[2]) == null){ + player.sendMessage(Component.text("| The provided sound is not a vanilla Minecraft sound, or does not exist in this game version!", NamedTextColor.GRAY)); + } } catch (NumberFormatException | IndexOutOfBoundsException e) { player.sendMessage(Component.text("Invalid number entered! Enter a number >= 0", NamedTextColor.RED)); player.sendMessage(Component.text("| Delay must be a whole number", NamedTextColor.GRAY)); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimDrawPosCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimDrawPosCMD.java index 3a2a529c..90e61243 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimDrawPosCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimDrawPosCMD.java @@ -38,7 +38,7 @@ public void execute(Player player, String[] args) { int pos = Integer.parseInt(args[2]); user.setPointPos(player.getLocation(), pos); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set draw pos", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Draw pos set", NamedTextColor.GREEN))); player.sendMessage(Component.text("| Pos: "+pos, NamedTextColor.GRAY)); } catch(NumberFormatException e) { diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimEditAllFramesCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimEditAllFramesCMD.java index 1d4b3fc5..2653bda0 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimEditAllFramesCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimEditAllFramesCMD.java @@ -48,7 +48,7 @@ public void execute(Player player, String[] args) { frame.setDelay(delay); frame.setDuration(duration); } - player.sendMessage(Component.text("All frames successfully edited!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("All frames have been edited!", NamedTextColor.GREEN)); player.sendMessage(Component.text("Delay: " + delay, NamedTextColor.GRAY)); player.sendMessage(Component.text("Duration: " + duration, NamedTextColor.GRAY)); } catch (NumberFormatException e) { diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimMovePointCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimMovePointCMD.java index 8b0c3153..f8188de9 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimMovePointCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimMovePointCMD.java @@ -47,6 +47,6 @@ public void execute(Player player, String[] args) { pLoc.setPitch(0); pLoc.setYaw(0); rp.setLocation(group, pLoc); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully moved frame point to your location"))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Moved the frame point to your location"))); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimOverwriteFrameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimOverwriteFrameCMD.java index 6714bbdf..4f330cc9 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimOverwriteFrameCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimOverwriteFrameCMD.java @@ -60,7 +60,7 @@ public void execute(Player player, String[] args) { frame.setDelay(delay); frame.setDuration(duration); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully overwritten animation frame", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("The animation frame has been overwritten", NamedTextColor.GREEN))); player.playSound(player, Sound.ENTITY_SHEEP_SHEAR, 1, 0.75f); } catch (NumberFormatException e) { player.sendMessage(Component.text("Invalid value entered! Enter whole numbers >= 0", NamedTextColor.RED)); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimRemoveFrameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimRemoveFrameCMD.java index 9e074588..5e929fa3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimRemoveFrameCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimRemoveFrameCMD.java @@ -46,7 +46,7 @@ public void execute(Player player, String[] args) { return; } anim.removeFrame(frames.get(id)); - player.sendMessage(Component.text("Frame successfully removed!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("Frame removed!", NamedTextColor.GREEN)); } catch (NumberFormatException e) { player.sendMessage(Component.text("Invalid ID! ID's must be 0 or larger", NamedTextColor.RED)); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimReverseCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimReverseCMD.java index 1801ea9d..8ebac083 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimReverseCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimReverseCMD.java @@ -33,6 +33,6 @@ public void execute(Player player, String[] args) { return; } anim.reverse(); - player.sendMessage(Component.text("Animation successfully reversed!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("The animation has been reversed!", NamedTextColor.GREEN)); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectCMD.java index dac544ee..60ce7999 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectCMD.java @@ -62,7 +62,7 @@ static void getAnimation(Player p, String tag, String storage){ DisplayAnimationManager.setSelectedSpawnedAnimation(p, anim); - p.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully selected animation! (Tagged: "+anim.getAnimationTag()+")"))); + p.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Selected animation! (Tagged: "+anim.getAnimationTag()+")"))); DisplayEntityPluginCommand.hideRelativePoints(p); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectJSONCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectJSONCMD.java index 6dcf55d2..5e834fab 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectJSONCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSelectJSONCMD.java @@ -44,7 +44,7 @@ static void getAnimation(Player p, String tag){ DisplayAnimationManager.setSelectedSpawnedAnimation(p, anim); - p.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully selected animation! (Tagged: "+anim.getAnimationTag()+")"))); + p.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Selected animation! (Tagged: "+anim.getAnimationTag()+")"))); DisplayEntityPluginCommand.hideRelativePoints(p); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSetTagCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSetTagCMD.java index 602ba68b..fb6df5ae 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSetTagCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimSetTagCMD.java @@ -31,6 +31,6 @@ public void execute(Player player, String[] args) { } String tag = args[2]; anim.setAnimationTag(tag); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Animation tag successfully set to \"" + tag + "\"", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Animation tag set to \"" + tag + "\"", NamedTextColor.GREEN))); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimUseFilterCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimUseFilterCMD.java index ef6b39ce..535fec15 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimUseFilterCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/anim/AnimUseFilterCMD.java @@ -35,7 +35,7 @@ public void execute(Player player, String[] args) { ActivePartSelection selection = DisplayGroupManager.getPartSelection(player); if (selection == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayBillboardCMD.java similarity index 73% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayBillboardCMD.java index 1d0e93fb..cfa471ab 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBillboardCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayBillboardCMD.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; @@ -12,16 +12,16 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class PartsBillboardCMD extends PartsSubCommand { - PartsBillboardCMD(@NotNull DEUSubCommand parentSubCommand) { - super("billboard", parentSubCommand, Permission.PARTS_BILLBOARD, 3, 3); +class DisplayBillboardCMD extends PartsSubCommand { + DisplayBillboardCMD(@NotNull DEUSubCommand parentSubCommand) { + super("billboard", parentSubCommand, Permission.DISPLAY_BILLBOARD, 3, 3); setTabComplete(2, TabSuggestion.BILLBOARDS); } @Override protected void sendIncorrectUsage(@NotNull Player player) { player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid billboard type!", NamedTextColor.RED))); - player.sendMessage(Component.text("/deu parts billboard [-all]", NamedTextColor.GRAY)); + player.sendMessage(Component.text("/deu display billboard [-all]", NamedTextColor.GRAY)); } @Override @@ -29,20 +29,20 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active Display.Billboard billboard = getBillboard(player, args[2]); if (billboard == null) return false; selection.setBillboard(billboard); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard successfully set for selected display entity part(s) in your selection!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard set for selected display entity part(s) in your selection!", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Interaction entities cannot have a billboard applied!", NamedTextColor.RED))); + if (!selectedPart.isDisplay()) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Only display entities can have a billboard applied!", NamedTextColor.RED))); } else{ Display.Billboard billboard = getBillboard(player, args[2]); if (billboard == null) return false; selectedPart.setBillboard(billboard); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard successfully set for your selected part!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard set for your selected display!", NamedTextColor.GREEN))); } return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBrightnessCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayBrightnessCMD.java similarity index 71% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBrightnessCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayBrightnessCMD.java index ec2fa6d0..832d3bdf 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsBrightnessCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayBrightnessCMD.java @@ -1,10 +1,13 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.PartsSubCommand; import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.parts.PartsCMD; import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.donnypz.displayentityutils.utils.command.DEUCommandUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Display; @@ -12,33 +15,33 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class PartsBrightnessCMD extends PartsSubCommand { - PartsBrightnessCMD(@NotNull DEUSubCommand parentSubCommand) { - super("brightness", parentSubCommand, Permission.PARTS_BRIGHTNESS, 4, 4); +class DisplayBrightnessCMD extends PartsSubCommand { + DisplayBrightnessCMD(@NotNull DEUSubCommand parentSubCommand) { + super("brightness", parentSubCommand, Permission.DISPLAY_BRIGHTNESS, 4, 4); setTabComplete(2, ""); setTabComplete(3, ""); } @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(Component.text("/deu parts brightness [-all]", NamedTextColor.RED)); + player.sendMessage(Component.text("/deu display brightness [-all]", NamedTextColor.RED)); player.sendMessage(Component.text("| Brightness can be whole numbers between 0 and 15", NamedTextColor.GRAY)); player.sendMessage(Component.text("| Set both \"block\" and \"sky\" to -1 to reset brightness", NamedTextColor.GRAY)); } @Override protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { - BrightnessResult result = buildBrightness(player, args[2], args[3]); + BrightnessResult result = buildBrightness(args[2], args[3]); if (!result.correctNumbers()){ sendIncorrectUsage(player); return false; } Display.Brightness brightness = result.brightness; if (brightness == null){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness reset for part selection!", NamedTextColor.YELLOW))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness reset for displays in your selection!", NamedTextColor.YELLOW))); } else{ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness set for your part selection!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness set for displays in your selection!", NamedTextColor.GREEN))); } selection.setBrightness(brightness); return true; @@ -46,23 +49,24 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - BrightnessResult result = buildBrightness(player, args[2], args[3]); + if (isNotDisplay(player, selectedPart)) return false; + BrightnessResult result = buildBrightness(args[2], args[3]); if (!result.correctNumbers()){ sendIncorrectUsage(player); return false; } Display.Brightness brightness = result.brightness; if (brightness == null){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness reset for your selected part!", NamedTextColor.YELLOW))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness reset for your selected display!", NamedTextColor.YELLOW))); } else{ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness set for your selected part!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Brightness set for your selected display!", NamedTextColor.GREEN))); } selectedPart.setBrightness(brightness); return true; } - private BrightnessResult buildBrightness(Player player, String arg1, String arg2){ + private BrightnessResult buildBrightness(String arg1, String arg2){ try{ int block = Integer.parseInt(arg1); int sky = Integer.parseInt(arg2); @@ -79,7 +83,6 @@ private BrightnessResult buildBrightness(Player player, String arg1, String arg2 } } catch(IllegalArgumentException e){ - sendIncorrectUsage(player); return new BrightnessResult(null, false); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java new file mode 100644 index 00000000..193336fc --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayCMD.java @@ -0,0 +1,69 @@ +package net.donnypz.displayentityutils.command.display; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.*; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public final class DisplayCMD extends ConsoleUsableSubCommand { + + + public DisplayCMD(){ + super(Permission.HELP, new DisplayHelpCMD()); + new DisplayGlowColorCMD(this); + new DisplayBrightnessCMD(this); + new DisplayViewRangeCMD(this); + new DisplayBillboardCMD(this); + new DisplayTranslateCMD(this); + new DisplayResetTranslationCMD(this); + new DisplayScaleCMD(this); + new DisplaySetBlockCMD(this); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length < 2){ + help(sender, 1); + return; + } + String arg = args[1]; + DEUSubCommand subCommand = subCommands.get(arg); + if (subCommand == null){ + help(sender, 1); + } + else{ + DisplayEntityPluginCommand.executeCommand(subCommand, sender, args); + } + } + + static void help(CommandSender sender, int page){ + sender.sendMessage(Component.empty()); + sender.sendMessage(DisplayAPI.pluginPrefixLong); + sender.sendMessage(Component.text("| Commands with \"-all\" will apply the command to all display entities in your selection", NamedTextColor.GOLD)); + if (page == 1){ + CMDUtils.sendCMD(sender, "/deu display glowcolor [-all]", "Set your selected display part's glow color"); + CMDUtils.sendCMD(sender, "/deu display brightness [-all]", "Set your selected display part's brightness. Enter values between 0-15. -1 resets"); + CMDUtils.sendCMD(sender, "/deu display viewrange [-all]", "Set the view range multiplier for your selected display part"); + CMDUtils.sendCMD(sender, "/deu display billboard [-all]", "Set the billboard of your selected display part"); + CMDUtils.sendCMD(sender, "/deu display translate [-all]", "Translate your selected display part"); + CMDUtils.sendCMD(sender, "/deu display resettranslation [-all]", "Reset the translation of your selected display part"); + CMDUtils.sendCMD(sender, "/deu display scale [-all]", "Change the scale of your selected display part, by axis"); + } + else{ + CMDUtils.sendCMD(sender, "/deu display setblock <\"-held\" | \"-target\" | block-id> [-all]", "Change the block of a block display part"); + } + sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); + } + + static boolean isDisplay(Player player, ActivePart part){ + if (!part.isDisplay()){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this display entity parts!", NamedTextColor.RED))); + return false; + } + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayGlowColorCMD.java similarity index 61% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayGlowColorCMD.java index 57060a77..1f3ba2cc 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsGlowColorCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayGlowColorCMD.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; @@ -13,16 +13,16 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class PartsGlowColorCMD extends PartsSubCommand { - PartsGlowColorCMD(@NotNull DEUSubCommand parentSubCommand) { - super("glowcolor", parentSubCommand, Permission.PARTS_GLOW_COLOR, 3, 3); +class DisplayGlowColorCMD extends PartsSubCommand { + DisplayGlowColorCMD(@NotNull DEUSubCommand parentSubCommand) { + super("glowcolor", parentSubCommand, Permission.DISPLAY_GLOW_COLOR, 3, 3); setTabComplete(2, TabSuggestion.COLORS); } @Override protected void sendIncorrectUsage(@NotNull Player player) { player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid color!", NamedTextColor.RED))); - player.sendMessage(Component.text("/deu parts glowcolor [-all]", NamedTextColor.GRAY)); + player.sendMessage(Component.text("/deu display glowcolor [-all]", NamedTextColor.GRAY)); } @Override @@ -31,31 +31,27 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (color == null) return false; selection.setGlowColor(color); selection.glow(player, 60); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color successfully set for selected display entity part(s) in your selection!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color set for selected display entity part(s) in your selection!", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isNotDisplay(player, selectedPart)) return false; + Color color = getColor(player, args[2]); if (color == null) return false; - if (selectedPart.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Interaction entities cannot have a glow color applied!", NamedTextColor.RED))); - return false; - } - else{ - selectedPart.setGlowColor(color); - selectedPart.glow(player, 60); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color successfully set for your selected part!", NamedTextColor.GREEN))); - return true; - } + selectedPart.setGlowColor(color); + selectedPart.glow(player, 60); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color set for your selected display!", NamedTextColor.GREEN))); + return true; } private Color getColor(Player player, String arg){ Color c = ConversionUtils.getColorFromText(arg); if (c == null){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid color!", NamedTextColor.RED))); - player.sendMessage(Component.text("/deu parts glowcolor [-all]", NamedTextColor.GRAY)); + player.sendMessage(Component.text("/deu display glowcolor [-all]", NamedTextColor.GRAY)); } return c; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayHelpCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayHelpCMD.java new file mode 100644 index 00000000..0d55f2df --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayHelpCMD.java @@ -0,0 +1,27 @@ +package net.donnypz.displayentityutils.command.display; + +import net.donnypz.displayentityutils.command.ConsoleUsableSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.item.ItemCMD; +import org.bukkit.command.CommandSender; + +public class DisplayHelpCMD extends ConsoleUsableSubCommand { + public DisplayHelpCMD() { + super(Permission.HELP); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length < 3){ + DisplayCMD.help(sender, 1); + } + else{ + try{ + DisplayCMD.help(sender, Integer.parseInt(args[2])); + } + catch(NumberFormatException e){ + DisplayCMD.help(sender, 1); + } + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayResetTranslationCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayResetTranslationCMD.java new file mode 100644 index 00000000..439c1e1f --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayResetTranslationCMD.java @@ -0,0 +1,46 @@ +package net.donnypz.displayentityutils.command.display; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; +import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; + +class DisplayResetTranslationCMD extends PartsSubCommand { + DisplayResetTranslationCMD(@NotNull DEUSubCommand parentSubCommand) { + super("resettranslation", parentSubCommand, Permission.DISPLAY_TRANSLATE, 2, 2); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) {} + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + for (ActivePart p : selection.getSelectedParts()){ + if (!p.isDisplay()) continue; + Vector3f translation = p.getTransformation().getTranslation(); + p.translate(Vector.fromJOML(translation), translation.length(), 0, 0); + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Translation reset for all selected displays!", NamedTextColor.GREEN))); + return true; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (!DisplayCMD.isDisplay(player, selectedPart)) return false; + Vector3f translation = selectedPart.getTransformation().getTranslation().negate(); + selectedPart.translate(Vector.fromJOML(translation), translation.length(), 0, 0); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Reset selected display part's translation!", NamedTextColor.GREEN))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayScaleCMD.java similarity index 73% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayScaleCMD.java index 2f33affd..26bdbb84 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsScaleCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayScaleCMD.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; @@ -13,10 +13,10 @@ import java.util.List; -class PartsScaleCMD extends PartsSubCommand { +class DisplayScaleCMD extends PartsSubCommand { - PartsScaleCMD(@NotNull DEUSubCommand parentSubCommand) { - super("scale", parentSubCommand, Permission.PARTS_TRANSFORM, 4, 4); + DisplayScaleCMD(@NotNull DEUSubCommand parentSubCommand) { + super("scale", parentSubCommand, Permission.DISPLAY_TRANSFORM, 4, 4); setTabComplete(2, List.of("x", "y", "z", "-all")); setTabComplete(3, ""); } @@ -24,12 +24,12 @@ class PartsScaleCMD extends PartsSubCommand { @Override protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { for (ActivePart selectedPart : selection.getSelectedParts()){ - if (selectedPart.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + if (!selectedPart.isDisplay()){ continue; } try { if (applyScaleChange(getDimension(args), getScale(args), selectedPart, player)) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Scale Updated!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Scale updated for selected display parts!", NamedTextColor.GREEN))); } } catch (NumberFormatException e) { player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid number for the scale!", NamedTextColor.RED))); @@ -41,14 +41,10 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION) { - player.sendMessage(Component.text("You cannot do this with an interaction part entity!", NamedTextColor.RED)); - player.sendMessage(Component.text("| Use \"/deu interaction scale\" instead", NamedTextColor.GRAY)); - return false; - } + if (isNotDisplay(player, selectedPart)) return false; try { if (applyScaleChange(getDimension(args), getScale(args), selectedPart, player)) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Scale Updated!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Scale updated!", NamedTextColor.GREEN))); return true; } else{ @@ -62,7 +58,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(Component.text("Incorrect Usage! /deu parts scale [-all]", NamedTextColor.RED)); + player.sendMessage(Component.text("Incorrect Usage! /deu display scale [-all]", NamedTextColor.RED)); } private String getDimension(String[] args){ @@ -76,16 +72,16 @@ private float getScale(String[] args){ private boolean applyScaleChange(String dim, float scale, ActivePart part, Player player){ switch (dim){ case "x" -> { - part.setXScale(scale); + part.setDisplayXScale(scale); } case "y" -> { - part.setYScale(scale); + part.setDisplayYScale(scale); } case "z" -> { - part.setZScale(scale); + part.setDisplayZScale(scale); } case "-all" -> { - part.setScale(scale, scale, scale); + part.setDisplayScale(scale, scale, scale); } default -> { sendIncorrectUsage(player); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSetBlockCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplaySetBlockCMD.java similarity index 73% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSetBlockCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplaySetBlockCMD.java index 096d478d..e5f486d3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSetBlockCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplaySetBlockCMD.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; @@ -15,15 +15,15 @@ import java.util.List; -class PartsSetBlockCMD extends PartsSubCommand { - PartsSetBlockCMD(@NotNull DEUSubCommand parentSubCommand) { - super("setblock", parentSubCommand, Permission.PARTS_SET_BLOCK, 3, 3); +class DisplaySetBlockCMD extends PartsSubCommand { + DisplaySetBlockCMD(@NotNull DEUSubCommand parentSubCommand) { + super("setblock", parentSubCommand, Permission.DISPLAY_SET_BLOCK, 3, 3); setTabComplete(2, List.of("-held", "-target", "")); } @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(Component.text("Incorrect Usage! /deu parts setblock <\"-held\" | \"-target\" | block-id> [-all]", NamedTextColor.RED)); + player.sendMessage(Component.text("Incorrect Usage! /deu display setblock <\"-held\" | \"-target\" | block-id> [-all]", NamedTextColor.RED)); } @Override @@ -36,20 +36,17 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active setBlock(part, blockData); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set block of ALL selected block displays!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set block of ALL selected block displays!", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY)) return false; BlockData blockData = DEUCommandUtils.getBlockFromText(args[2], player); if (blockData == null) return false; - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with block display entities", NamedTextColor.RED))); - return false; - } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set block of selected block display!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set block of selected block display!", NamedTextColor.GREEN))); setBlock(selectedPart, blockData); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsTranslateCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayTranslateCMD.java similarity index 86% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsTranslateCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayTranslateCMD.java index c348ae06..040e0c6d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsTranslateCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayTranslateCMD.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; @@ -15,9 +15,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class PartsTranslateCMD extends PartsSubCommand { - PartsTranslateCMD(@NotNull DEUSubCommand parentSubCommand) { - super("translate", parentSubCommand, Permission.PARTS_TRANSLATE, 5, 5); +class DisplayTranslateCMD extends PartsSubCommand { + DisplayTranslateCMD(@NotNull DEUSubCommand parentSubCommand) { + super("translate", parentSubCommand, Permission.DISPLAY_TRANSLATE, 5, 5); setTabComplete(2, TabSuggestion.DIRECTIONS); setTabComplete(3, ""); setTabComplete(4, ""); @@ -34,7 +34,7 @@ public void execute(Player player, String[] args) { @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("/deu parts translate [-all]", NamedTextColor.RED))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("/deu display translate [-all]", NamedTextColor.RED))); } @Override @@ -43,16 +43,17 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (objects == null) return false; selection.translate((Direction) objects[0], (float) objects[1], (int) objects[2], -1); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Translating all selected parts!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Translating all selected display parts!", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isNotDisplay(player, selectedPart)) return false; Object[] objects = getArgs(player, args); if (objects == null) return false; selectedPart.translate((Direction) objects[0], (float) objects[1], (int) objects[2], -1); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Translating your selected part!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Translating your selected display!", NamedTextColor.GREEN))); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsViewRangeCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayViewRangeCMD.java similarity index 81% rename from plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsViewRangeCMD.java rename to plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayViewRangeCMD.java index ed8ec528..3f7aa48a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsViewRangeCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/display/DisplayViewRangeCMD.java @@ -1,4 +1,4 @@ -package net.donnypz.displayentityutils.command.parts; +package net.donnypz.displayentityutils.command.display; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; @@ -11,15 +11,15 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class PartsViewRangeCMD extends PartsSubCommand { - PartsViewRangeCMD(@NotNull DEUSubCommand parentSubCommand) { - super("viewrange", parentSubCommand, Permission.PARTS_VIEWRANGE, 3, 3); +class DisplayViewRangeCMD extends PartsSubCommand { + DisplayViewRangeCMD(@NotNull DEUSubCommand parentSubCommand) { + super("viewrange", parentSubCommand, Permission.DISPLAY_VIEW_RANGE, 3, 3); setTabComplete(2, ""); } @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(Component.text("Provide a part tag! /deu parts viewrange [-all]", NamedTextColor.RED)); + player.sendMessage(Component.text("Incorrect Usage! /deu display viewrange [-all]", NamedTextColor.RED)); } @Override @@ -27,7 +27,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active Float viewRange = getViewRange(player, args[2]); if (viewRange == null) return false; selection.setViewRange(viewRange); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("View range multiplier updated for all selected parts!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("View range multiplier updated for all selected displays!", NamedTextColor.GREEN))); player.sendMessage(Component.text("New View Range: "+viewRange, NamedTextColor.GRAY)); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java index a0ce139d..38ffa548 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAddTargetCMD.java @@ -9,10 +9,12 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedPartSelection; +import net.donnypz.displayentityutils.utils.DisplayUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Entity; import org.bukkit.entity.Interaction; +import org.bukkit.entity.Mannequin; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -33,19 +35,14 @@ public void execute(Player player, String[] args) { return; } - Entity entity = player.getTargetEntity(10); - if (!(entity instanceof Interaction interaction)) { - player.sendMessage(Component.text("Your targeted entity must be an interaction entity within 10 blocks of you", NamedTextColor.RED)); - return; - } - /*if (FramePointDisplay.isRelativePointEntity(entity)){ - player.sendMessage(Component.text("Your cannot add the interaction entity from a point preview!", NamedTextColor.RED)); - return; - }*/ - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(interaction); + + Entity entity = DisplayEntityPluginCommand.getTargetEntity(player); + if (entity == null) return; + + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.getPart(entity); if (part != null) { if (part.getGroup() == group) { - player.sendMessage(Component.text("That interaction entity is already apart of your selected group!", NamedTextColor.RED)); + player.sendMessage(Component.text("That entity is already apart of your selected group!", NamedTextColor.RED)); } else { part.setGroup(group); @@ -53,10 +50,10 @@ public void execute(Player player, String[] args) { return; } else { - group.addInteractionEntity(interaction); + group.addEntity(entity); SpawnedPartSelection sel = (SpawnedPartSelection) DisplayGroupManager.getPartSelection(player); sel.refresh(); } - player.sendMessage(Component.text("Successfully added interaction entity to your selected group!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("Added entity to your selected group!", NamedTextColor.GREEN)); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAutoCullCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAutoCullCMD.java index 76bd90b9..00b6aec5 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAutoCullCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupAutoCullCMD.java @@ -20,7 +20,7 @@ protected void sendIncorrectUsage(@NotNull Player player) {} @Override protected void execute(@NotNull Player player, @NotNull ActiveGroup group, @NotNull String[] args) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully added culling bounds to your selected group!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Added culling bounds to your selected group!", NamedTextColor.GREEN))); group.autoCull(DisplayConfig.widthCullingAdder(), DisplayConfig.heightCullingAdder()); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupBillboardCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupBillboardCMD.java index ff811f86..9b7cbff5 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupBillboardCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupBillboardCMD.java @@ -29,7 +29,7 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ try{ Display.Billboard billboard = Display.Billboard.valueOf(args[2].toUpperCase()); group.setBillboard(billboard); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard successfully set for your selected group!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Billboard set for your selected group!", NamedTextColor.GREEN))); } catch(IllegalArgumentException e){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid billboard type!", NamedTextColor.RED))); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCMD.java index 7e6ec8e0..c6761a83 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCMD.java @@ -19,6 +19,7 @@ public GroupCMD(){ true)); new GroupSelectCMD(this); new GroupSelectNearestCMD(this); + new GroupSelectPlacedCMD(this); new GroupDeselectCMD(this); new GroupSaveCMD(this); new GroupSaveJsonCMD(this); @@ -90,11 +91,12 @@ static void groupHelp(CommandSender sender, int page){ CMDUtils.sendCMD(sender, "/deu anim list [page-number]", "List all saved display entity groups/models"); CMDUtils.sendCMD(sender, "/deu group select ", "Select from nearby groups within the given distance"); CMDUtils.sendCMD(sender, "/deu group selectnearest ", "Select the nearest group within the given distance"); + CMDUtils.sendCMD(sender, "/deu group selectplaced", "Select a group placed by a player's held item"); CMDUtils.sendCMD(sender, "/deu group deselect", "Clear your group selection"); CMDUtils.sendCMD(sender, "/deu group info", "List information about your selected group"); - CMDUtils.sendCMD(sender, "/deu group spawn [-packet]", "Spawn a saved display entity group/model from a storage location. \"-packet\" will spawn the group/model using packets"); } else if (page == 2) { + CMDUtils.sendCMD(sender, "/deu group spawn [-packet]", "Spawn a saved display entity group/model from a storage location. \"-packet\" will spawn the group/model using packets"); CMDUtils.sendCMD(sender, "/deu group spawnjson [-packet]", "Spawn a JSON saved display entity group/model from a local storage. \"-packet\" will spawn the group/model using packets"); CMDUtils.sendCMD(sender, "/deu group despawn", "Despawn your selected group"); CMDUtils.sendCMD(sender, "/deu group save ", "Save your selected group"); @@ -102,45 +104,45 @@ else if (page == 2) { CMDUtils.sendCMD(sender, "/deu group delete ", "Delete a saved group from a storage location"); CMDUtils.sendCMD(sender, "/deu group topacket [-confirm] [-keep]", "Make your selected group packet-based, making it unselectable. \"-confirm\" confirms the action." + " \"-keep\" keeps the non-packet based version of your group spawned."); - CMDUtils.sendCMD(sender, "/deu group markpacketgroups", "Create markers for all packet groups stored in your current chunk"); } else if (page == 3){ + CMDUtils.sendCMD(sender, "/deu group markpacketgroups", "Create markers for all packet groups stored in your current chunk"); CMDUtils.sendCMD(sender, "/deu group showpacketgroups [-self]", "Show all persistent packet-based groups in your current chunk. \n\"-self\" shows the group only for you"); CMDUtils.sendCMD(sender, "/deu group hidepacketgroups [-self]", "Hide all persistent packet-based groups in your current chunk. \n\"-self\" hides the group only for you"); CMDUtils.sendCMD(sender, "/deu group addtarget", "Add a targeted interaction entity to your group"); CMDUtils.sendCMD(sender, "/deu group ungroupinteractions", "Remove all interactions from your group"); CMDUtils.sendCMD(sender, "/deu group settag ", "Set this group's tag, or identifier"); CMDUtils.sendCMD(sender, "/deu group yaw [-pivot]","Set your selected group's yaw, \"-pivot\" pivots interaction entities around the group"); - CMDUtils.sendCMD(sender, "/deu group pitch ", "Set your selected group's pitch"); } else if (page == 4){ + CMDUtils.sendCMD(sender, "/deu group pitch ", "Set your selected group's pitch"); CMDUtils.sendCMD(sender, "/deu group scale ", "Scale your selected group with a given multiplier"); CMDUtils.sendCMD(sender, "/deu group brightness ", "Set your selected group's brightness. Enter values between 0-15. -1 resets"); CMDUtils.sendCMD(sender, "/deu group clone", "Spawn a cloned group at your selected group's location"); CMDUtils.sendCMD(sender, "/deu group clonehere", "Spawn a cloned group at your location"); - CMDUtils.sendCMD(sender, "/deu group move ", "Change the actual location of your selected group"); - CMDUtils.sendCMD(sender, "/deu group translate ","Changes your selected group's translation, use \"move\" instead if this group uses animations"); + CMDUtils.sendCMD(sender, "/deu group move [tick-duration]", "Change the actual location of your selected group, with an optional duration"); CMDUtils.sendCMD(sender, "/deu group movehere", "Change your selected group's actual location to your location"); } else if (page == 5){ + CMDUtils.sendCMD(sender, "/deu group translate ","Changes your selected group's translation, use \"move\" instead if this group uses animations"); CMDUtils.sendCMD(sender, "/deu group merge ","Merge groups near your selected group"); CMDUtils.sendCMD(sender, "/deu group billboard ", "Set the billboard of all parts in this group"); CMDUtils.sendCMD(sender, "/deu group glowcolor ", "Set the glow color for all parts in this group"); CMDUtils.sendCMD(sender, "/deu group glow", "Make all parts in this group glow"); CMDUtils.sendCMD(sender, "/deu group unglow", "Remove the glowing effect from all parts in this group"); CMDUtils.sendCMD(sender, "/deu group ride <-target | player-name | entity-uuid> [group-tag] [storage] [controller-id]", "Make a group ride an entity. Values in brackets [] are optional"); - CMDUtils.sendCMD(sender, "/deu group safedismount <-target | -selected | player-name | entity-uuid>", "Safely dismount a group from an entity"); } else if (page == 6){ + CMDUtils.sendCMD(sender, "/deu group safedismount <-target | -selected | player-name | entity-uuid>", "Safely dismount a group from an entity"); CMDUtils.sendCMD(sender, "/deu group dismount <-target | -selected | player-name | entity-uuid> [-despawn]", "Dismount a group from an entity, with optional despawning"); CMDUtils.sendCMD(sender, "/deu group setspawnanim ", "Set an animation to play when this group is spawned/loaded"); CMDUtils.sendCMD(sender, "/deu group unsetspawnanim", "Remove the spawn animation that's set on your selected group"); CMDUtils.sendCMD(sender, "/deu group viewrange ", "Set the view range multiplier for your selected group"); CMDUtils.sendCMD(sender, "/deu group autocull", "Calculate and set culling bounds for every part in your selected group"); CMDUtils.sendCMD(sender, "/deu group removecull", "Remove the culling bounds for every part in your selected group"); - CMDUtils.sendCMD(sender, "/deu group togglepersist", "Toggle if your group should persist after a server shutdown"); } else{ + CMDUtils.sendCMD(sender, "/deu group togglepersist", "Toggle if your group should persist after a server shutdown"); CMDUtils.sendCMD(sender, "/deu group togglepersistoverride", "Toggle if your group's persistence can be overriden when loaded by a chunk, " + "only if \"persistenceOverride\" is enabled in the config"); CMDUtils.sendCMD(sender, "/deu group wetogroup [-removeblocks]", "Convert your WorldEdit selection to a display group, with its origin at the lowest center block of the selection (Requires WorldEdit). \nUse \"-removeblocks\" to set all selected blocks to air"); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCloneCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCloneCMD.java index 9310dd45..8aa9645a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCloneCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupCloneCMD.java @@ -30,7 +30,7 @@ static void clone(Player p, ActiveGroup clonedGroup){ p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to clone your selected group!", NamedTextColor.RED))); } else{ - p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully cloned your selected group", NamedTextColor.GREEN))); + p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Cloned your selected group", NamedTextColor.GREEN))); p.sendMessage(Component.text("- Your group selection has been changed to the newly created group", NamedTextColor.GRAY, TextDecoration.ITALIC)); DisplayGroupManager.setSelectedGroup(p, clonedGroup); clonedGroup.glowAndMarkInteractions(p, 80); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java index dd0e1bec..abd1661c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDespawnCMD.java @@ -22,12 +22,14 @@ protected void sendIncorrectUsage(@NotNull Player player) {} @Override protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @NotNull String[] args) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully despawned your selected display entity group!", NamedTextColor.GRAY))); if (group instanceof SpawnedDisplayEntityGroup sg){ - DisplayGroupManager.deselectGroup(player); sg.unregister(true, true); } else if (group instanceof PacketDisplayEntityGroup pg){ + if (pg.isPlaced()){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You must manually break a placed group's block to remove it!", NamedTextColor.RED))); + return; + } if (pg.isPersistent()){ DisplayGroupManager.removePersistentPacketGroup(pg, true); } @@ -35,6 +37,8 @@ else if (group instanceof PacketDisplayEntityGroup pg){ pg.unregister(); } } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Despawned your selected display entity group!", NamedTextColor.GRAY))); + DisplayGroupManager.deselectGroup(player); DisplayEntityPluginCommand.hideRelativePoints(player); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDismountCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDismountCMD.java index 70590409..9c5961f7 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDismountCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupDismountCMD.java @@ -61,7 +61,7 @@ public void execute(CommandSender sender, String[] args) { sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your selected group is not riding an entity!", NamedTextColor.RED))); } else{ - sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully dismounted your selected group!", NamedTextColor.GREEN))); + sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Dismounted your selected group!", NamedTextColor.GREEN))); dismount(group, despawn); if (despawn) despawnMessage(sender); DisplayControllerManager.unregisterEntity(vehicle); @@ -79,7 +79,7 @@ public void execute(CommandSender sender, String[] args) { } DisplayControllerManager.unregisterEntity(vehicle); - sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully dismounted all non-packet groups riding the entity!", NamedTextColor.GREEN))); + sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Dismounted all non-packet groups riding the entity!", NamedTextColor.GREEN))); if (despawn) despawnMessage(sender); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupGlowColorCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupGlowColorCMD.java index 1e41f114..7cb38b70 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupGlowColorCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupGlowColorCMD.java @@ -34,7 +34,7 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ } group.setGlowColor(c); group.glow(player, 60); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color successfully set for display entity group!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Glow color set for display entity group!", NamedTextColor.GREEN))); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMergeCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMergeCMD.java index f867b039..11f119ee 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMergeCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMergeCMD.java @@ -52,7 +52,7 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ } sg.merge(result.group()); } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully merged nearby groups", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Nearby non-packet groups have been merged", NamedTextColor.GREEN))); sg.glowAndMarkInteractions(player, 60); } catch(NumberFormatException e){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveCMD.java index 0e227cf5..85e6224f 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveCMD.java @@ -4,6 +4,7 @@ import net.donnypz.displayentityutils.command.*; import net.donnypz.displayentityutils.utils.Direction; import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -13,16 +14,16 @@ class GroupMoveCMD extends GroupSubCommand { GroupMoveCMD(@NotNull DEUSubCommand parentSubCommand) { - super("move", parentSubCommand, Permission.GROUP_TRANSFORM, 5, false); + super("move", parentSubCommand, Permission.GROUP_TRANSFORM, 4, false); setTabComplete(2, TabSuggestion.DIRECTIONS); setTabComplete(3, ""); - setTabComplete(4, ""); + setTabComplete(4, "[tick-duration]"); } @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(Component.text("/deu group move ", NamedTextColor.RED)); + player.sendMessage(Component.text("/deu group move [tick-duration]", NamedTextColor.RED)); } @Override @@ -32,6 +33,11 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ return; } + if (group instanceof PacketDisplayEntityGroup pg && pg.isPlaced()){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot move a group placed by a player's item!", NamedTextColor.RED))); + return; + } + try{ Direction direction = Direction.valueOf(args[2].toUpperCase()); double distance = Double.parseDouble(args[3]); @@ -39,6 +45,14 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a number greater than 0 for the distance!", NamedTextColor.RED))); return; } + + if (args.length == 4){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Teleporting your selected group!", NamedTextColor.GREEN))); + group.teleport(direction, distance); + return; + } + + //With duration int duration = Integer.parseInt(args[4]); if (duration <= 0){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a whole number greater than 0 for the duration!", NamedTextColor.RED))); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveHereCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveHereCMD.java index 9d70ed2d..f50eb7f1 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveHereCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupMoveHereCMD.java @@ -3,6 +3,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.*; import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -25,6 +26,11 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ return; } + if (group instanceof PacketDisplayEntityGroup pg && pg.isPlaced()){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot move a group placed by a player's item!", NamedTextColor.RED))); + return; + } + if (!group.teleport(player.getLocation(), true)){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to move your selected group to your location", NamedTextColor.RED))); return; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSafeDismountCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSafeDismountCMD.java index f9647acd..1af90e8b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSafeDismountCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSafeDismountCMD.java @@ -100,7 +100,7 @@ public void execute(CommandSender sender, String[] args) { DisplayControllerManager.unregisterEntity(vehicle); - sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully dismounted all groups riding the entity!", NamedTextColor.GREEN))); + sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Dismounted all groups riding the entity!", NamedTextColor.GREEN))); } } \ No newline at end of file diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectCMD.java index 3e31d7fb..51f8379a 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectCMD.java @@ -96,8 +96,8 @@ private void getSelectableGroups(Player player, double distance){ } boolean selectResult = DisplayGroupManager.setSelectedGroup(p, g); if (selectResult){ - g.addMissingInteractionEntities(distance); - p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully selected group!", NamedTextColor.GREEN))); + g.addMissingEntities(distance); + p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Group selected!", NamedTextColor.GREEN))); DisplayEntityPluginCommand.hideRelativePoints(player); } else{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectNearestCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectNearestCMD.java index 49b9225e..5c7c4110 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectNearestCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectNearestCMD.java @@ -54,7 +54,7 @@ public void execute(Player player, String[] args) { return; } - group.addMissingInteractionEntities(searchDistance); + group.addMissingEntities(searchDistance); int selectDuration = 50; group.glowAndMarkInteractions(player, selectDuration); Entity entity = group.getMasterPart().getEntity(); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectPlacedCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectPlacedCMD.java new file mode 100644 index 00000000..907bc419 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSelectPlacedCMD.java @@ -0,0 +1,42 @@ +package net.donnypz.displayentityutils.command.group; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +class GroupSelectPlacedCMD extends PlayerSubCommand { + GroupSelectPlacedCMD(@NotNull DEUSubCommand parentSubCommand) { + super("selectplaced", parentSubCommand, Permission.GROUP_SELECT); + } + + @Override + public void execute(Player player, String[] args) { + Block targetBlock = player.getTargetBlock(null, 15); + PacketDisplayEntityGroup group = PlaceableGroupManager.getPlacedGroup(targetBlock); + + if (group == null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You are not looking at a placed group's block! (Barrier)", NamedTextColor.RED))); + return; + } + + boolean selectResult = DisplayGroupManager.setSelectedGroup(player, group); + if (selectResult){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Selected placed group!", NamedTextColor.GREEN))); + } + else{ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Failed to select placed group! Another player already has that group selected!", NamedTextColor.RED))); + } + + int selectDuration = 50; + group.glowAndMarkInteractions(player, selectDuration); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSetTagCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSetTagCMD.java index 5278430b..dd0344c3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSetTagCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSetTagCMD.java @@ -25,6 +25,6 @@ protected void sendIncorrectUsage(@NotNull Player player) { protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @NotNull String[] args) { String tag = args[2]; group.setTag(tag); - player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully tagged your selected group! (Tagged: "+tag+")"))); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Tagged your selected group! (Tagged: "+tag+")"))); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSpawnCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSpawnCMD.java index a41a071e..fa0beb77 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSpawnCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/group/GroupSpawnCMD.java @@ -147,7 +147,7 @@ else if (storage == LoadMethod.MONGODB){ return; } DisplayAnimationManager.setSelectedSpawnedAnimation(p, anim.toSpawnedDisplayAnimation()); - p.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Successfully selected display animation! (Tagged: "+tag+")"))); + p.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Animation selected! (Tagged: "+tag+")"))); } }); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionAddToGroupCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionAddToGroupCMD.java index fd431df4..dca92698 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionAddToGroupCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionAddToGroupCMD.java @@ -40,7 +40,7 @@ protected void execute(@NotNull Player player, @Nullable ActiveGroup group, @ if (group instanceof SpawnedDisplayEntityGroup sg){ Interaction i = spawnInteraction(player, spawn, args); if (i == null) return; - sg.addInteractionEntity(i); + sg.addEntity(i); } else if (group instanceof PacketDisplayEntityGroup pg){ spawnInteraction(pg, player, spawn, args); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionCMD.java index fd3b7069..c122185c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionCMD.java @@ -28,7 +28,6 @@ public InteractionCMD(){ new InteractionWidthCMD(this); new InteractionScaleCMD(this); new InteractionPivotCMD(this); - new InteractionPivotSelectionCMD(this); new InteractionResponsiveCMD(this); new InteractionAddToGroupCMD(this); new InteractionSpawnHereCMD(this); @@ -66,8 +65,7 @@ static void interactionHelp(CommandSender sender, int page){ CMDUtils.sendCMD(sender, "/deu interaction scale ", "Scale an interaction entity over a period of time"); CMDUtils.sendCMD(sender, "/deu interaction addcmd ", "Add a command to an interaction"); CMDUtils.sendCMD(sender, "/deu interaction listcmds", "List all commands stored on an interaction"); - CMDUtils.sendCMD(sender, "/deu interaction pivot ", " Pivot an interaction around it's group's actual location center"); - CMDUtils.sendCMD(sender, "/deu interaction pivotselection ", "Pivot all Interactions included in your selected group's part filter"); + CMDUtils.sendCMD(sender, "/deu interaction pivot [-all]", " Pivot an interaction around it's group's"); CMDUtils.sendCMD(sender, "/deu interaction responsive", "Toggle the hit sound of an interaction entity"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionHeightCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionHeightCMD.java index 9c4d446e..7d950509 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionHeightCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionHeightCMD.java @@ -39,7 +39,7 @@ static void setInteractionDimensions(Player p , String[] args, String dim){ i.setWidth(change); } - p.sendMessage(Component.text("Successfully set interaction's "+dim+" to "+change, NamedTextColor.GREEN)); + p.sendMessage(Component.text("Set interaction's "+dim+" to "+change, NamedTextColor.GREEN)); } catch(NumberFormatException e) { p.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Invalid " + dim + ", enter a number!", NamedTextColor.RED))); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotCMD.java index cf72eb88..3942b1eb 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotCMD.java @@ -8,10 +8,8 @@ import net.donnypz.displayentityutils.command.parts.PartsCMD; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.*; -import net.donnypz.displayentityutils.utils.DisplayUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import org.bukkit.entity.Interaction; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -19,6 +17,7 @@ class InteractionPivotCMD extends PlayerSubCommand { InteractionPivotCMD(@NotNull DEUSubCommand parentSubCommand) { super("pivot", parentSubCommand, Permission.INTERACTION_PIVOT); setTabComplete(2, ""); + setTabComplete(3, "-all"); } @Override @@ -39,22 +38,38 @@ public void execute(Player player, String[] args) { return; } - MultiPartSelection selection = (MultiPartSelection) sel; if (args.length < 3){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage! /deu interaction pivot ", NamedTextColor.RED))); - return; - } - InteractionCMD.SelectedInteraction interaction = InteractionCMD.getInteraction(player, false); - if (interaction == null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage! /deu interaction pivot [-all]", NamedTextColor.RED))); return; } + double angle; try{ - interaction.pivot(selection.getGroup().getLocation(), Double.parseDouble(args[2])); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Pivoting Interaction around group", NamedTextColor.GREEN))); + angle = Double.parseDouble(args[2]);; } catch(NumberFormatException e){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid number for the angle!", NamedTextColor.RED))); + return; + } + + + MultiPartSelection selection = (MultiPartSelection) sel; + boolean isAll = args.length >= 4 && args[3].equalsIgnoreCase("-all"); + if (isAll){ + for (ActivePart p : selection.getSelectedParts()){ + if (p.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + p.pivot((float) angle); + } + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Pivoting ALL Interaction entities in your selection around your group", NamedTextColor.GREEN))); + } + else{ + InteractionCMD.SelectedInteraction interaction = InteractionCMD.getInteraction(player, false); + if (interaction == null){ + return; + } + interaction.pivot(selection.getGroup().getLocation(), angle); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Pivoting Interaction around group", NamedTextColor.GREEN))); } } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotSelectionCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotSelectionCMD.java deleted file mode 100644 index 5ac80b09..00000000 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/interaction/InteractionPivotSelectionCMD.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.donnypz.displayentityutils.command.interaction; - -import net.donnypz.displayentityutils.DisplayAPI; -import net.donnypz.displayentityutils.command.DEUSubCommand; -import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; -import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.command.PlayerSubCommand; -import net.donnypz.displayentityutils.command.parts.PartsCMD; -import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.*; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -class InteractionPivotSelectionCMD extends PlayerSubCommand { - InteractionPivotSelectionCMD(@NotNull DEUSubCommand parentSubCommand) { - super("pivotselection", parentSubCommand, Permission.INTERACTION_PIVOT); - setTabComplete(2, ""); - } - - @Override - public void execute(Player player, String[] args) { - ActiveGroup group = DisplayGroupManager.getSelectedGroup(player); - if (group == null){ - DisplayEntityPluginCommand.noGroupSelection(player); - return; - } - - if (args.length < 3){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage! /deu interaction pivotselection ", NamedTextColor.RED))); - return; - } - - try{ - float angle = Float.parseFloat(args[2]); - ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); - - if (PartsCMD.isUnwantedSingleSelection(player, sel)){ - return; - } - - sel.pivot(angle); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Pivoting all Interaction Entities in part selection around group!", NamedTextColor.GREEN))); - if (group instanceof PacketDisplayEntityGroup pg){ - pg.update(); - } - } - catch(NumberFormatException e){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid number for the angle!", NamedTextColor.RED))); - } - } -} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemSetCMD.java index f6a3e563..b1764b45 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemSetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemSetCMD.java @@ -37,22 +37,19 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active part.setItemDisplayItem(itemStack); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set item of ALL selected item displays!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set item of ALL selected item displays!", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY)) return false; String item = args[2]; ItemStack itemStack = DEUCommandUtils.getItemFromText(item, player); if (itemStack == null) return false; - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with item display entities", NamedTextColor.RED))); - return false; - } selectedPart.setItemDisplayItem(itemStack); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set item of selected item display!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set item of selected item display!", NamedTextColor.GREEN))); return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java index 0cf293e5..515ab49d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemToggleGlintCMD.java @@ -23,7 +23,7 @@ class ItemToggleGlintCMD extends PartsSubCommand { @Override protected void sendIncorrectUsage(@NotNull Player player) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu item toggleglint -all ", NamedTextColor.RED))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu item toggleglint [-all ]", NamedTextColor.RED))); } @Override @@ -38,12 +38,12 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (s.equalsIgnoreCase("on")){ status = true; player.sendMessage(DisplayAPI.pluginPrefix - .append(MiniMessage.miniMessage().deserialize("Successfully toggled glint for ALL selected item displays ON"))); + .append(MiniMessage.miniMessage().deserialize("Toggled glint for ALL selected item displays ON"))); } else if (s.equalsIgnoreCase("off")){ status = false; player.sendMessage(DisplayAPI.pluginPrefix - .append(MiniMessage.miniMessage().deserialize("Successfully toggled glint for ALL selected item displays OFF"))); + .append(MiniMessage.miniMessage().deserialize("Toggled glint for ALL selected item displays OFF"))); } else{ sendIncorrectUsage(player); @@ -55,20 +55,18 @@ else if (s.equalsIgnoreCase("off")){ part.setItemDisplayItemGlint(status); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully toggled glint of ALL selected item displays!", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with item display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY)) return false; + ItemStack item = selectedPart.getItemDisplayItem(); if (item == null) return false; - selectedPart.setItemDisplayItemGlint(!item.getItemMeta().getEnchantmentGlintOverride()); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully toggled glint of selected item display!", NamedTextColor.GREEN))); + selectedPart.setItemDisplayItemGlint(!selectedPart.hasItemDisplayItemGlint()); + String status = selectedPart.hasItemDisplayItemGlint() ? "ON" : "OFF"; + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled glint of selected item display "+status))); return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemTransformCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemTransformCMD.java index f7f89451..4f27f463 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemTransformCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/item/ItemTransformCMD.java @@ -30,20 +30,17 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active for (ActivePart part : selection.getSelectedParts()){ part.setItemDisplayTransform(transform); } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set item transform of ALL selected item displays!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set item transform of ALL selected item displays!", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY)) return false; ItemDisplay.ItemDisplayTransform transform = getTransform(player, args[2]); if (transform == null) return false; - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with item display entities", NamedTextColor.RED))); - return false; - } selectedPart.setItemDisplayTransform(transform); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set item transform of selected item display!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set item transform of selected item display!", NamedTextColor.GREEN))); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinBelowNameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinBelowNameCMD.java new file mode 100644 index 00000000..6cd35b9e --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinBelowNameCMD.java @@ -0,0 +1,40 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.text.TextSetCMD; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinBelowNameCMD extends PartsSubCommand { + MannequinBelowNameCMD(@NotNull DEUSubCommand parentSubCommand) { + super("belowname", parentSubCommand, Permission.MANNEQUIN_NAME, 3, 0); + setTabComplete(2, ""); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin belowname ", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + return false; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + String name = TextSetCMD.getTextResult(args); + selectedPart.setMannequinBelowName(LegacyComponentSerializer.legacyAmpersand().deserialize(name)); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set text below mannequin name!", NamedTextColor.GREEN))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java new file mode 100644 index 00000000..c4a9bc4e --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinCMD.java @@ -0,0 +1,71 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.*; +import net.donnypz.displayentityutils.utils.version.VersionUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.command.CommandSender; + +public class MannequinCMD extends ConsoleUsableSubCommand { + public MannequinCMD() { + super(Permission.HELP, new MannequinHelpCMD()); + new MannequinNameCMD(this); + new MannequinUnnameCMD(this); + new MannequinBelowNameCMD(this); + new MannequinToggleNameVisibilityCMD(this); + new MannequinSkinCMD(this); + new MannequinPoseCMD(this); + new MannequinPivotCMD(this); + new MannequinScaleCMD(this); + new MannequinToggleGravityCMD(this); + new MannequinToggleImmovableCMD(this); + new MannequinMainHandCMD(this); + new MannequinEquipmentCMD(this); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length < 2){ + help(sender, 1); + return; + } + String arg = args[1]; + DEUSubCommand subCommand = subCommands.get(arg); + if (subCommand == null){ + help(sender, 1); + } + else{ + if (!VersionUtils.IS_1_21_9){ + sender.sendMessage(Component.text("Your server version does not support Mannequin entities!", NamedTextColor.RED)); + return; + } + DisplayEntityPluginCommand.executeCommand(subCommand, sender, args); + } + } + + static void help(CommandSender sender, int page){ + sender.sendMessage(Component.empty()); + sender.sendMessage(DisplayAPI.pluginPrefixLong); + if (page == 1){ + sender.sendMessage(Component.text("| Commands with \"-all\" will apply the command to all mannequins within a part selection", NamedTextColor.GOLD)); + CMDUtils.sendCMD(sender, "/deu mannequin help", "Get help for mannequins"); + CMDUtils.sendCMD(sender, "/deu mannequin 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 toggleimmovable [-all ]", "Toggle the immovability of an mannequin"); + CMDUtils.sendCMD(sender, "/deu mannequin equipment ", "Open a GUI to edit your selected mannequin's equipment."); + CMDUtils.sendCMD(sender, "/deu mannequin mainhand ", "Set your selected mannequin's main hand"); + CMDUtils.sendCMD(sender, "/deu mannequin pivot [-all]"); + CMDUtils.sendCMD(sender, "/deu mannequin pose [-all]", "Change your selected mannequin's pose"); + CMDUtils.sendCMD(sender, "/deu mannequin scale [-all]", "Set your selected mannequin's scale"); + } + sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinEquipmentCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinEquipmentCMD.java new file mode 100644 index 00000000..039341e0 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinEquipmentCMD.java @@ -0,0 +1,36 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.mannequin.ui.MannequinEquipmentGUI; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinEquipmentCMD extends PartsSubCommand { + MannequinEquipmentCMD(@NotNull DEUSubCommand parentSubCommand) { + super("equipment", parentSubCommand, Permission.MANNEQUIN_SET_EQUIPMENT, 2, 0); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu mannequin equipment", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + return false; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + MannequinEquipmentGUI.edit(player, selectedPart); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHelpCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHelpCMD.java new file mode 100644 index 00000000..cef03219 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinHelpCMD.java @@ -0,0 +1,26 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.command.ConsoleUsableSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import org.bukkit.command.CommandSender; + +public class MannequinHelpCMD extends ConsoleUsableSubCommand { + public MannequinHelpCMD() { + super(Permission.HELP); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length < 3){ + MannequinCMD.help(sender, 1); + } + else{ + try{ + MannequinCMD.help(sender, Integer.parseInt(args[2])); + } + catch(NumberFormatException e){ + MannequinCMD.help(sender, 1); + } + } + } +} \ No newline at end of file diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinMainHandCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinMainHandCMD.java new file mode 100644 index 00000000..13a565c3 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinMainHandCMD.java @@ -0,0 +1,62 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.MainHand; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +class MannequinMainHandCMD extends PartsSubCommand { + MannequinMainHandCMD(@NotNull DEUSubCommand parentSubCommand) { + super("mainhand", parentSubCommand, Permission.MANNEQUIN_POSE, 3, 3); + setTabComplete(2, List.of("left", "right")); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin mainhand [-all]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + String handStr = args[2]; + try{ + MainHand hand = MainHand.valueOf(handStr); + for (ActivePart p : selection.getSelectedParts()){ + if (p.getType() != SpawnedDisplayEntityPart.PartType.MANNEQUIN) continue; + p.setMannequinMainHand(hand); + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set main hand of ALL selected mannequins!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Invalid Main Hand!", NamedTextColor.RED))); + return false; + } + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + + String handStr = args[2]; + try{ + MainHand hand = MainHand.valueOf(handStr); + selectedPart.setMannequinMainHand(hand); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set mannequin's main hand!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Invalid Main Hand!", NamedTextColor.RED))); + return false; + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinNameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinNameCMD.java new file mode 100644 index 00000000..faf726f5 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinNameCMD.java @@ -0,0 +1,40 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.text.TextSetCMD; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinNameCMD extends PartsSubCommand { + MannequinNameCMD(@NotNull DEUSubCommand parentSubCommand) { + super("name", parentSubCommand, Permission.MANNEQUIN_NAME, 3, 0); + setTabComplete(2, ""); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin name ", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + return false; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + String name = TextSetCMD.getTextResult(args); + selectedPart.setCustomName(LegacyComponentSerializer.legacyAmpersand().deserialize(name)); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set mannequin name!", NamedTextColor.GREEN))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPivotCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPivotCMD.java new file mode 100644 index 00000000..ee4e4777 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPivotCMD.java @@ -0,0 +1,56 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinPivotCMD extends PartsSubCommand { + MannequinPivotCMD(@NotNull DEUSubCommand parentSubCommand) { + super("pivot", parentSubCommand, Permission.MANNEQUIN_PIVOT, 3, 3); + setTabComplete(2, ""); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin pivot [-all]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + try{ + float angle = Float.parseFloat(args[2]); + for (ActivePart p : selection.getSelectedParts()){ + if (p.getType() != SpawnedDisplayEntityPart.PartType.MANNEQUIN) continue; + p.pivot(angle); + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Pivoted ALL selected mannequins!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + sendIncorrectUsage(player); + return false; + } + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + try{ + float angle = Float.parseFloat(args[2]); + selectedPart.pivot(angle); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Pivot applied to mannequin!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + sendIncorrectUsage(player); + return false; + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPoseCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPoseCMD.java new file mode 100644 index 00000000..6d8c0adf --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinPoseCMD.java @@ -0,0 +1,64 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.entity.Pose; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinPoseCMD extends PartsSubCommand { + MannequinPoseCMD(@NotNull DEUSubCommand parentSubCommand) { + super("pose", parentSubCommand, Permission.MANNEQUIN_POSE, 3, 3); + setTabComplete(2, TabSuggestion.MANNEQUIN_POSES); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin pose [-all]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + String poseStr = args[2]; + try{ + Pose pose = Pose.valueOf(poseStr.toUpperCase()); + for (ActivePart p : selection.getSelectedParts()){ + if (p.getType() != SpawnedDisplayEntityPart.PartType.MANNEQUIN) continue; + p.setMannequinPose(pose); + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set pose of ALL selected mannequins!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Invalid Pose!", NamedTextColor.RED))); + return false; + } + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + String poseStr = args[2]; + try{ + Pose pose = Pose.valueOf(poseStr.toUpperCase()); + selectedPart.setMannequinPose(pose); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set mannequin pose!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Invalid Pose!", NamedTextColor.RED))); + return false; + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinScaleCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinScaleCMD.java new file mode 100644 index 00000000..1b5ea9ce --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinScaleCMD.java @@ -0,0 +1,59 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.entity.Pose; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinScaleCMD extends PartsSubCommand { + MannequinScaleCMD(@NotNull DEUSubCommand parentSubCommand) { + super("scale", parentSubCommand, Permission.MANNEQUIN_SCALE, 3, 3); + setTabComplete(2, ""); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin scale [-all]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + String scaleStr = args[2]; + try{ + float scale = Float.parseFloat(scaleStr); + for (ActivePart p : selection.getSelectedParts()){ + if (p.getType() != SpawnedDisplayEntityPart.PartType.MANNEQUIN) continue; + p.setMannequinScale(scale); + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set scale of ALL selected mannequins!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + sendIncorrectUsage(player); + return false; + } + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + String scaleStr = args[2]; + try{ + float scale = Float.parseFloat(scaleStr); + selectedPart.setMannequinScale(scale); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set mannequin scale!", NamedTextColor.GREEN))); + return true; + } + catch(IllegalArgumentException e){ + sendIncorrectUsage(player); + return false; + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSkinCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSkinCMD.java new file mode 100644 index 00000000..2d737990 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinSkinCMD.java @@ -0,0 +1,47 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import io.papermc.paper.datacomponent.item.ResolvableProfile; +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinSkinCMD extends PartsSubCommand { + MannequinSkinCMD(@NotNull DEUSubCommand parentSubCommand) { + super("skin", parentSubCommand, Permission.MANNEQUIN_SKIN, 3, 3); + setTabComplete(2, ""); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu mannequin skin [-all]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + String name = args[2]; + ResolvableProfile profile = ResolvableProfile.resolvableProfile(Bukkit.createProfile(name)); + for (ActivePart p : selection.getSelectedParts()){ + p.setMannequinProfile(profile); + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set skin of ALL selected mannequins!", NamedTextColor.GREEN))); + return true; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + String name = args[2]; + ResolvableProfile profile = ResolvableProfile.resolvableProfile(Bukkit.createProfile(name)); + selectedPart.setMannequinProfile(profile); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set mannequin skin!", NamedTextColor.GREEN))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java new file mode 100644 index 00000000..dc607863 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleGravityCMD.java @@ -0,0 +1,77 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +class MannequinToggleGravityCMD extends PartsSubCommand { + MannequinToggleGravityCMD(@NotNull DEUSubCommand parentSubCommand) { + super("togglegravity", parentSubCommand, Permission.MANNEQUIN_GRAVITY, 2, 2); + setTabComplete(3, List.of("on", "off")); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu mannequin togglegravity [-all ]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + if (args.length < 4){ + sendIncorrectUsage(player); + return false; + } + + if (group != null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot change the gravity of mannequins in a group!", NamedTextColor.RED))); + return false; + } + + boolean status; + String s = args[3]; + if (s.equalsIgnoreCase("on")){ + status = true; + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("Toggled gravity for ALL selected mannequins ON"))); + } + else if (s.equalsIgnoreCase("off")){ + status = false; + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("Toggled gravity for ALL selected mannequins OFF"))); + } + else{ + sendIncorrectUsage(player); + return false; + } + + for (ActivePart part : selection.getSelectedParts()){ + if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN) { + part.setMannequinGravity(status); + } + } + return true; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + if (group != null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot change the gravity of a mannequin in a group!", NamedTextColor.RED))); + return false; + } + selectedPart.setMannequinGravity(!selectedPart.hasMannequinGravity()); + String status = selectedPart.hasMannequinGravity() ? "ON" : "OFF"; + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled gravity of selected mannequin "+status))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java new file mode 100644 index 00000000..ea1039da --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleImmovableCMD.java @@ -0,0 +1,78 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +class MannequinToggleImmovableCMD extends PartsSubCommand { + MannequinToggleImmovableCMD(@NotNull DEUSubCommand parentSubCommand) { + super("toggleimmovable", parentSubCommand, Permission.MANNEQUIN_IMMOVABLE, 2, 2); + setTabComplete(3, List.of("on", "off")); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu mannequin toggleimmovable [-all ]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + if (args.length < 4){ + sendIncorrectUsage(player); + return false; + } + + if (group != null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot change the immovability of mannequins in a group!", NamedTextColor.RED))); + return false; + } + + boolean status; + String s = args[3]; + if (s.equalsIgnoreCase("on")){ + status = true; + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("Toggled immovability for ALL selected mannequins ON"))); + } + else if (s.equalsIgnoreCase("off")){ + status = false; + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("Toggled immovability for ALL selected mannequins OFF"))); + } + else{ + sendIncorrectUsage(player); + return false; + } + + for (ActivePart part : selection.getSelectedParts()){ + if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN) { + part.setMannequinImmovable(status); + } + } + return true; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + + if (group != null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot change the immovability of a mannequin in a group!", NamedTextColor.RED))); + return false; + } + selectedPart.setMannequinImmovable(!selectedPart.isMannequinImmovable()); + String status = selectedPart.isMannequinImmovable() ? "ON" : "OFF"; + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled immovability of selected mannequin "+status))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleNameVisibilityCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleNameVisibilityCMD.java new file mode 100644 index 00000000..20eaf419 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinToggleNameVisibilityCMD.java @@ -0,0 +1,68 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +class MannequinToggleNameVisibilityCMD extends PartsSubCommand { + MannequinToggleNameVisibilityCMD(@NotNull DEUSubCommand parentSubCommand) { + super("togglenamevisibility", parentSubCommand, Permission.MANNEQUIN_NAME_VISIBLE, 2, 2); + setTabComplete(3, List.of("on", "off")); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect ALL usage! /deu mannequin togglenamevisibility [-all ]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + if (args.length < 4){ + sendIncorrectUsage(player); + return false; + } + + boolean status; + String s = args[3]; + if (s.equalsIgnoreCase("on")){ + status = true; + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("Toggled name visibility for ALL selected mannequins ON"))); + } + else if (s.equalsIgnoreCase("off")){ + status = false; + player.sendMessage(DisplayAPI.pluginPrefix + .append(MiniMessage.miniMessage().deserialize("Toggled name visibility for ALL selected mannequins OFF"))); + } + else{ + sendIncorrectUsage(player); + return false; + } + + for (ActivePart part : selection.getSelectedParts()){ + if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN) { + part.setCustomNameVisible(status); + } + } + return true; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + selectedPart.setCustomNameVisible(!selectedPart.isCustomNameVisible()); + String status = selectedPart.isCustomNameVisible() ? "ON" : "OFF"; + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled name visibility of selected mannequin "+status))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinUnnameCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinUnnameCMD.java new file mode 100644 index 00000000..fd261d3d --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/MannequinUnnameCMD.java @@ -0,0 +1,42 @@ +package net.donnypz.displayentityutils.command.mannequin; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class MannequinUnnameCMD extends PartsSubCommand { + MannequinUnnameCMD(@NotNull DEUSubCommand parentSubCommand) { + super("unname", parentSubCommand, Permission.MANNEQUIN_NAME, 2, 2); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect usage! /deu mannequin unname [-all]", NamedTextColor.RED))); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + for (ActivePart p : selection.getSelectedParts()){ + if (p.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + p.setCustomName(null); + } + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Name removed for ALL selected mannequins!", NamedTextColor.YELLOW))); + return false; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.MANNEQUIN)) return false; + selectedPart.setCustomName(null); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your selected mannequin's name has been removed!", NamedTextColor.YELLOW))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/ui/MannequinEquipmentGUI.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/ui/MannequinEquipmentGUI.java new file mode 100644 index 00000000..e38bbc2c --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/mannequin/ui/MannequinEquipmentGUI.java @@ -0,0 +1,191 @@ +package net.donnypz.displayentityutils.command.mannequin.ui; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import net.donnypz.displayentityutils.utils.version.VersionUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +import java.util.HashMap; +import java.util.Map; + +public class MannequinEquipmentGUI { + + private final static Map mannequins = new HashMap<>(); + private final static ItemStack BACKGROUND_ITEM; + private final static ItemStack EXIT_ITEM; + private final static int EXIT_SLOT = 49; + private final static NamespacedKey BACKGROUND_KEY = new NamespacedKey(DisplayAPI.getPlugin(), "gui_background"); + private final static NamespacedKey EXIT_KEY = new NamespacedKey(DisplayAPI.getPlugin(), "gui_exit"); + + static{ + BACKGROUND_ITEM = new ItemStack(Material.GRAY_STAINED_GLASS_PANE); + ItemMeta bgMeta = BACKGROUND_ITEM.getItemMeta(); + if (VersionUtils.IS_1_20_5){ + bgMeta.setHideTooltip(true); + } + else{ + bgMeta.displayName(Component.empty()); + } + setGUIItem(bgMeta, BACKGROUND_KEY); + BACKGROUND_ITEM.setItemMeta(bgMeta); + + EXIT_ITEM = new ItemStack(Material.BARRIER); + ItemMeta exitMeta = EXIT_ITEM.getItemMeta(); + exitMeta.displayName(Component.text("Exit", NamedTextColor.RED).decoration(TextDecoration.ITALIC, false)); + setGUIItem(exitMeta, EXIT_KEY); + EXIT_ITEM.setItemMeta(exitMeta); + } + + public static void edit(Player player, ActivePart part){ + DEUUser user = DEUUser.getOrCreateUser(player); + int entityId = part.getEntityId(); + user.setEditingMannequinArmor(entityId); + + + Inventory inv = Bukkit.createInventory(null, 6*9, Component.text("Set Mannequin Equipment")); + + for (int i = 0; i <6*9; i++){ + inv.setItem(i, BACKGROUND_ITEM); + } + inv.setItem(EXIT_SLOT, EXIT_ITEM); + + + //Indicator Item Slots + inv.setItem(getHelmetSlot()-2, getHelmetIndicatorItem()); + inv.setItem(getChestplateSlot()-2, getChestplateIndicatorItem()); + inv.setItem(getLeggingsSlot()-2, getLeggingsIndicatorItem()); + inv.setItem(getBootsSlot()-2, getBootsIndicatorItem()); + inv.setItem(getMainHandSlot()-18, getMainHandIndicatorItem()); + inv.setItem(getOffHandSlot()-18, getOffHandIndicatorItem()); + + //Equipment Item Slots + inv.setItem(getHelmetSlot(), part.getMannequinEquipment(EquipmentSlot.HEAD).clone()); + inv.setItem(getChestplateSlot(), part.getMannequinEquipment(EquipmentSlot.CHEST).clone()); + inv.setItem(getLeggingsSlot(), part.getMannequinEquipment(EquipmentSlot.LEGS).clone()); + inv.setItem(getBootsSlot(), part.getMannequinEquipment(EquipmentSlot.FEET).clone()); + inv.setItem(getMainHandSlot(), part.getMannequinEquipment(EquipmentSlot.HAND).clone()); + inv.setItem(getOffHandSlot(), part.getMannequinEquipment(EquipmentSlot.OFF_HAND).clone()); + + + mannequins.put(entityId, inv); + player.openInventory(inv); + } + + public static void removeMannequin(Integer entityId){ + mannequins.remove(entityId); + } + + public static boolean isMannequinInventory(Inventory inventory, ActivePart part){ + return inventory.equals(mannequins.get(part.getEntityId())); + } + + private static void setGUIItem(ItemMeta meta, NamespacedKey key){ + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + pdc.set(key, PersistentDataType.BOOLEAN, true); + meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); + } + + public static boolean isBackgroundItem(ItemStack itemStack){ + if (itemStack == null) return false; + ItemMeta meta = itemStack.getItemMeta(); + return meta.getPersistentDataContainer().has(BACKGROUND_KEY); + } + + public static boolean isExitItem(ItemStack itemStack){ + if (itemStack == null) return false; + ItemMeta meta = itemStack.getItemMeta(); + return meta.getPersistentDataContainer().has(EXIT_KEY); + } + + public static int getHelmetSlot(){ + return 3; + } + + public static int getChestplateSlot(){ + return 12; + } + + public static int getLeggingsSlot(){ + return 21; + } + + public static int getBootsSlot(){ + return 30; + } + + public static int getMainHandSlot(){ + return 32; + } + + public static int getOffHandSlot(){ + return 34; + } + + private static ItemStack getHelmetIndicatorItem(){ + ItemStack item = new ItemStack(Material.LEATHER_HELMET); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text("Set Helmet →", NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)); + setGUIItem(meta, BACKGROUND_KEY); + item.setItemMeta(meta); + return item; + } + + private static ItemStack getChestplateIndicatorItem(){ + ItemStack item = new ItemStack(Material.LEATHER_CHESTPLATE); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text("Set Chestplate →", NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)); + setGUIItem(meta, BACKGROUND_KEY); + item.setItemMeta(meta); + return item; + } + + private static ItemStack getLeggingsIndicatorItem(){ + ItemStack item = new ItemStack(Material.LEATHER_LEGGINGS); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text("Set Leggings →", NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)); + setGUIItem(meta, BACKGROUND_KEY); + item.setItemMeta(meta); + return item; + } + + private static ItemStack getBootsIndicatorItem(){ + ItemStack item = new ItemStack(Material.LEATHER_BOOTS); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text("Set Boots →", NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)); + setGUIItem(meta, BACKGROUND_KEY); + item.setItemMeta(meta); + return item; + } + + private static ItemStack getMainHandIndicatorItem(){ + ItemStack item = new ItemStack(Material.WOODEN_SWORD); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text("↓ Set Mainhand Item ↓", NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)); + setGUIItem(meta, BACKGROUND_KEY); + item.setItemMeta(meta); + return item; + } + + private static ItemStack getOffHandIndicatorItem(){ + ItemStack item = new ItemStack(Material.WOODEN_SWORD); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text("↓ Set Offhand Item ↓", NamedTextColor.YELLOW).decoration(TextDecoration.ITALIC, false)); + setGUIItem(meta, BACKGROUND_KEY); + item.setItemMeta(meta); + return item; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAdaptTagsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAdaptTagsCMD.java index f1476a5e..d309955e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAdaptTagsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAdaptTagsCMD.java @@ -15,9 +15,6 @@ class PartsAdaptTagsCMD extends PartsSubCommand { setTabComplete(2, "-remove"); } - @Override - public void execute(Player player, String[] args) {} - @Override protected void sendIncorrectUsage(@NotNull Player player) {} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAddTagCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAddTagCMD.java index 7048e451..47086629 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAddTagCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsAddTagCMD.java @@ -28,7 +28,7 @@ protected void sendIncorrectUsage(@NotNull Player player) { protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { String tag = args[2]; if (selection.addTag(tag)){ - player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Adding part tag to ALL selected parts! (Added Tag: "+tag+")"))); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Added part tag to ALL selected parts! (Added Tag: "+tag+")"))); return true; } else{ @@ -41,7 +41,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { String tag = args[2]; if (selectedPart.addTag(tag)){ - player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Adding part tag to selected part! (Added Tag: "+tag+")"))); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Added part tag to selected part! (Added Tag: "+tag+")"))); return true; } else{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java index 7584e422..206feb72 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCMD.java @@ -20,7 +20,6 @@ public PartsCMD(){ new PartsCycleCMD(this); new PartsGlowCMD(this); new PartsUnglowCMD(this); - new PartsGlowColorCMD(this); new PartsFilterTagsCMD(this); new PartsFilterTypesCMD(this); new PartsFilterBlocksCMD(this); @@ -32,16 +31,10 @@ public PartsCMD(){ new PartsRemoveTagCMD(this); new PartsListTagsCMD(this); new PartsRemoveCMD(this); - new PartsTranslateCMD(this); - new PartsSetBlockCMD(this); - new PartsBillboardCMD(this); - new PartsViewRangeCMD(this); - new PartsBrightnessCMD(this); new PartsPitchCMD(this); new PartsYawCMD(this); new PartsMoveHereCMD(this); new PartsMoveCMD(this); - new PartsScaleCMD(this); } @Override @@ -64,14 +57,15 @@ static void partsHelp(CommandSender sender, int page){ sender.sendMessage(Component.empty()); sender.sendMessage(DisplayAPI.pluginPrefixLong); if (page <= 1){ - sender.sendMessage(Component.text("\"Parts\" are each individual display/interaction entity that is contained within a group", NamedTextColor.AQUA)); - sender.sendMessage(Component.text("| Add tags to parts to identify each part in a group", NamedTextColor.AQUA)); - sender.sendMessage(Component.text("| \"-all\" will apply the command to all parts within your part selection where valid. By default a selected group's parts is your part selection", NamedTextColor.GOLD)); + sender.sendMessage(Component.text("- \"Parts\" are each entity in a group/model", NamedTextColor.AQUA)); + sender.sendMessage(Component.text("- Add tags to parts to identify each part in a group", NamedTextColor.AQUA)); + sender.sendMessage(Component.text("- \"-all\" will apply a command to all parts in your selection/filter where valid. By default, all of your selected group's parts are your in selection", NamedTextColor.GOLD)); sender.sendMessage(Component.empty()); CMDUtils.sendCMD(sender, "/deu parts help ", "Get help for parts"); CMDUtils.sendCMD(sender, "/deu parts info", "Get information about your current part/selection"); - CMDUtils.sendCMD(sender, "/deu parts create ", "Spawn an entity at your location and automatically select it"); - CMDUtils.sendCMD(sender, "/deu parts select ", "Select an ungrouped display/interaction entity near your location. Use \"-target\" to select your targeted Interaction"); + CMDUtils.sendCMD(sender, "/deu parts create [-addtogroup]", "Spawn an entity at your location and automatically select it. " + + "\"-addtogroup\" will add the part to your selected group"); + CMDUtils.sendCMD(sender, "/deu parts select ", "Select a nearby, ungrouped, Display entity. Use \"-target\" to select your targeted Interaction"); } else if (page == 2) { CMDUtils.sendCMD(sender, "/deu parts cycle [jump]", "Cycle through parts of your selected group"); @@ -93,29 +87,15 @@ else if (page == 3){ CMDUtils.sendCMD(sender, "/deu parts glow [-all]", "Make your selected part glow"); CMDUtils.sendCMD(sender, "/deu parts unglow [-all]", "Remove the glow from your selected part"); } - else if (page == 4){ - CMDUtils.sendCMD(sender, "/deu parts glowcolor [-all]", "Set your selected part's glow color"); - CMDUtils.sendCMD(sender, "/deu parts brightness [-all]", "Set your selected part's brightness. Enter values between 0-15. -1 resets"); - CMDUtils.sendCMD(sender, "/deu parts viewrange [-all]", "Set the view range multiplier for your selected part"); - CMDUtils.sendCMD(sender, "/deu parts billboard [-all]", "Set the billboard of your selected part"); - CMDUtils.sendCMD(sender, "/deu parts translate [-all]", "Translate your selected part"); + else{ CMDUtils.sendCMD(sender, "/deu parts pitch ", "Set the pitch of an ungrouped part entity"); CMDUtils.sendCMD(sender, "/deu parts yaw ", "Set the yaw of an ungrouped part entity"); - } - else{ - CMDUtils.sendCMD(sender, "/deu parts scale [-all]", "Change the scale of your selected part, by axis"); - CMDUtils.sendCMD(sender, "/deu parts move ", "Change the actual location of your selected part"); - CMDUtils.sendCMD(sender, "/deu parts movehere", "Change your selected part's actual location to your location"); - CMDUtils.sendCMD(sender, "/deu parts setblock <\"-held\" | \"-target\" | block-id> [-all]", "Change the block of a block display part"); + CMDUtils.sendCMD(sender, "/deu parts move [-all]", "Change the actual location of your selected part"); + CMDUtils.sendCMD(sender, "/deu parts movehere [-all]", "Change your selected part's actual location to your location"); } sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } - public static void noPartSelection(Player player){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You have not selected any part(s)!", NamedTextColor.RED))); - player.sendMessage(Component.text("/deu parts cycle ", NamedTextColor.GRAY)); - } - public static void invalidPartSelection(CommandSender sender){ sender.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your part selection is invalid!", NamedTextColor.RED))); } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java index d9e029e3..a8d1da02 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCreateCMD.java @@ -1,12 +1,17 @@ package net.donnypz.displayentityutils.command.parts; +import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DEUUser; -import net.donnypz.displayentityutils.utils.DisplayEntities.SinglePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.packet.PacketAttributeContainer; +import net.donnypz.displayentityutils.utils.packet.attributes.DisplayAttributes; import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.donnypz.displayentityutils.utils.dialogs.TextDisplayDialog; import net.kyori.adventure.text.Component; @@ -24,13 +29,16 @@ import org.jetbrains.annotations.NotNull; import java.time.Duration; -import java.util.UUID; +import java.util.function.Function; class PartsCreateCMD extends PlayerSubCommand { + private static final Component DEFAULT_TEXT = Component.text("New Text Display Entity"); + PartsCreateCMD(@NotNull DEUSubCommand parentSubCommand) { super("create", parentSubCommand, Permission.PARTS_CREATE); setTabComplete(2, TabSuggestion.PART_TYPES); + setTabComplete(3, "-addtogroup"); } @Override @@ -40,42 +48,95 @@ public void execute(Player player, String[] args) { return; } + boolean addToGroup; + if (args.length >= 4){ + addToGroup = args[3].equalsIgnoreCase("-addtogroup"); + if (addToGroup && DisplayGroupManager.getSelectedGroup(player) == null){ + DisplayEntityPluginCommand.noGroupSelection(player); + } + } + else{ + addToGroup = false; + } + Location loc = player.getLocation(); + PacketAttributeContainer container = new PacketAttributeContainer(); switch (args[2].toLowerCase()){ case "block" -> { - BlockDisplay entity = loc.getWorld().spawn(loc, BlockDisplay.class, e -> { - e.setBlock(Registry.MATERIAL.get(NamespacedKey.minecraft("stone")).createBlockData()); + selectOrAddEntity(player, "Block Display", addToGroup, bukkit -> { + return loc.getWorld().spawn(loc, BlockDisplay.class, e -> { + e.setBlock(Registry.MATERIAL.get(NamespacedKey.minecraft("stone")).createBlockData()); + }); + }, packet -> { + return container + .setAttribute(DisplayAttributes.BlockDisplay.BLOCK_STATE, Material.STONE.createBlockData()) + .createPart(SpawnedDisplayEntityPart.PartType.BLOCK_DISPLAY, loc); }); - selectEntity(player, entity.getUniqueId(), "Block Display"); } case "item" -> { - ItemDisplay entity = loc.getWorld().spawn(loc, ItemDisplay.class, e -> { - e.setItemStack(new ItemStack(Material.STICK)); + selectOrAddEntity(player, "Item Display", addToGroup, bukkit -> { + return loc.getWorld().spawn(loc, ItemDisplay.class, e -> { + e.setItemStack(new ItemStack(Material.STICK)); + }); + }, packet -> { + return container + .setAttribute(DisplayAttributes.ItemDisplay.ITEMSTACK, new ItemStack(Material.STICK)) + .createPart(SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY, loc); }); - selectEntity(player, entity.getUniqueId(), "Item Display"); } case "text" -> { loc.setYaw(loc.getYaw()+180); loc.setPitch(loc.getPitch()*-1); - TextDisplay entity = loc.getWorld().spawn(loc, TextDisplay.class, e -> { - e.text(Component.text("New Text Display Entity")); + + ActivePart part = selectOrAddEntity(player, "Text Display", addToGroup, bukkit -> { + return loc.getWorld().spawn(loc, TextDisplay.class, e -> { + e.text(DEFAULT_TEXT); + }); + }, packet -> { + return container + .setAttribute(DisplayAttributes.TextDisplay.TEXT, DEFAULT_TEXT) + .createPart(SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY, loc); }); - selectEntity(player, entity.getUniqueId(), "Text Display"); - if (VersionUtils.canViewDialogs(player, false)){ - UUID entityUUID = entity.getUniqueId(); - player.sendMessage(Component.text("| Click here to edit it!", NamedTextColor.LIGHT_PURPLE) - .clickEvent(ClickEvent.callback(audience -> { - Player p = (Player) audience; - TextDisplayDialog.sendDialog(p, entityUUID, true); - }, ClickCallback.Options.builder().uses(-1).lifetime(Duration.ofMinutes(5)).build()))); + if (part != null){ + if (VersionUtils.canViewDialogs(player, false)){ + player.sendMessage(Component.text("| Click here to edit it!", NamedTextColor.LIGHT_PURPLE) + .clickEvent(ClickEvent.callback(audience -> { + Player p = (Player) audience; + TextDisplayDialog.sendDialog(p, part, true); + }, ClickCallback.Options.builder().uses(-1).lifetime(Duration.ofMinutes(5)).build()))); + } } } case "interaction" -> { - Interaction entity = loc.getWorld().spawn(loc, Interaction.class, e -> { - e.setInteractionHeight(1); - e.setInteractionWidth(1); + selectOrAddEntity(player, "Interaction", addToGroup, bukkit -> { + return loc.getWorld().spawn(loc, Interaction.class, e -> { + e.setInteractionHeight(1); + e.setInteractionWidth(1); + }); + }, packet -> { + return container + .setAttribute(DisplayAttributes.Interaction.WIDTH, 1f) + .setAttribute(DisplayAttributes.Interaction.HEIGHT, 1f) + .createPart(SpawnedDisplayEntityPart.PartType.INTERACTION, loc); + }); + } + case "mannequin" -> { + if (!VersionUtils.canSpawnMannequins()){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your server version cannot spawn Mannequins!", NamedTextColor.RED))); + return; + } + selectOrAddEntity(player, "Mannequin", addToGroup, bukkit -> { + return loc.getWorld().spawn(loc, Mannequin.class, m -> { + m.setProfile(ResolvableProfile.resolvableProfile(player.getPlayerProfile())); + DisplayUtils.prepareMannequin(m); + }); + }, packet -> { + return container + .setAttribute(DisplayAttributes.Mannequin.RESOLVABLE_PROFILE, ResolvableProfile.resolvableProfile(player.getPlayerProfile())) + .setAttribute(DisplayAttributes.Mannequin.IMMOVABLE, true) + .setAttribute(DisplayAttributes.Mannequin.NO_GRAVITY, true) + .createPart(SpawnedDisplayEntityPart.PartType.MANNEQUIN, loc); }); - selectEntity(player, entity.getUniqueId(), "Interaction"); } default -> { incorrectUsage(player); @@ -84,15 +145,37 @@ public void execute(Player player, String[] args) { } private void incorrectUsage(Player player){ - player.sendMessage(Component.text("Incorrect Usage! /deu parts create ", NamedTextColor.RED)); + player.sendMessage(Component.text("Incorrect Usage! /deu parts create ", NamedTextColor.RED)); } - private void selectEntity(Player player, UUID entityUUID, String displayName){ + private ActivePart selectOrAddEntity(Player player, String displayName, boolean addToGroup, Function bukkitEntity, Function packetPart){ player.sendMessage(DisplayAPI .pluginPrefix - .append(MiniMessage.miniMessage().deserialize("You have spawned a " + displayName + " entity at your location!"))); - player.sendMessage(Component.text("| The created part has been automatically selected, removing previous selections", NamedTextColor.GRAY, TextDecoration.ITALIC)); - DEUUser.getOrCreateUser(player).setSelectedPartSelection(new SinglePartSelection(SpawnedDisplayEntityPart.create(entityUUID)), false); - } + .append(MiniMessage.miniMessage().deserialize("You have spawned a " + displayName + " entity!"))); + DEUUser user = DEUUser.getOrCreateUser(player); + ActivePart part; + if (addToGroup){ + ActiveGroup group = DisplayGroupManager.getSelectedGroup(player); + if (group instanceof PacketDisplayEntityGroup pdeg){ + part = packetPart.apply(null); + pdeg.addPart((PacketDisplayEntityPart) part); + } + else if (group instanceof SpawnedDisplayEntityGroup sdeg){ + part = sdeg.addEntity(bukkitEntity.apply(null)); + } + else{ + return null; + } + ((MultiPartSelection) user.getSelectedPartSelection()).refresh(); + player.sendMessage(Component.text("| The created part has been automatically added to your group", NamedTextColor.GRAY, TextDecoration.ITALIC)); + } + else{ + Entity entity = bukkitEntity.apply(null); + player.sendMessage(Component.text("| The created part has been automatically selected, removing previous selections", NamedTextColor.GRAY, TextDecoration.ITALIC)); + part = SpawnedDisplayEntityPart.create(entity); + user.setSelectedPartSelection(new SinglePartSelection((SpawnedDisplayEntityPart) part), false); + } + return part; + } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCycleCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCycleCMD.java index 5067062e..86445e04 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCycleCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsCycleCMD.java @@ -1,5 +1,6 @@ package net.donnypz.displayentityutils.command.parts; +import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; @@ -7,7 +8,6 @@ import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.*; -import net.donnypz.displayentityutils.utils.DisplayUtils; import net.donnypz.displayentityutils.utils.PacketUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -122,48 +122,18 @@ else if (part.getBlockDisplayBlock().getMaterial() == Material.AIR){ case ITEM_DISPLAY -> { ItemStack i = part.getItemDisplayItem(); if (i.getType() == Material.AIR){ - desc = Component.text("(Invisible Item Display | AIR, CAVE_AIR, or VOID_AIR)", NamedTextColor.GRAY); + desc = Component.text("(Invisible Item Display | AIR)", NamedTextColor.GRAY); } else{ desc = Component.text("("+i.getType().key().value()+")", NamedTextColor.AQUA); } } - default -> throw new IllegalStateException("Unexpected part type"); - } - return desc; - } - - static Component getPartInfo(@NotNull Entity entity){ - Component desc; - switch(entity){ - case Interaction i -> { - desc = MiniMessage.miniMessage().deserialize("(Interaction, H: "+i.getInteractionHeight()+" W:"+i.getInteractionWidth()+")"); + case MANNEQUIN -> { + Component customName = part.getCustomName(); + if (customName == null) customName = Component.text("Unnamed Mannequin"); + desc = Component.text("(").append(customName).append(Component.text(")")); } - case TextDisplay display -> { - desc = Component.text("(Text Display: \"", NamedTextColor.LIGHT_PURPLE) - .append(display.text()) - .append(Component.text("\")", NamedTextColor.LIGHT_PURPLE)); - } - case BlockDisplay display -> { - if (DisplayUtils.isMaster(display)){ - desc = Component.text("(Master Entity/Part)", NamedTextColor.GOLD); - } - else if (display.getBlock().getMaterial() == Material.AIR){ - desc = Component.text("(Invisible Block Display | AIR, CAVE_AIR, or VOID_AIR)", NamedTextColor.GRAY); - } - else{ - desc = Component.text("("+display.getBlock().getMaterial().key().value()+")", NamedTextColor.YELLOW); - } - } - case ItemDisplay display -> { - if (display.getItemStack().getType() == Material.AIR){ - desc = Component.text("(Invisible Item Display | AIR, CAVE_AIR, or VOID_AIR)", NamedTextColor.GRAY); - } - else{ - desc = Component.text("("+display.getItemStack().getType().key().value()+")", NamedTextColor.AQUA); - } - } - default -> throw new IllegalStateException("Unexpected value: " + entity); + default -> throw new IllegalStateException("Unexpected part type"); } return desc; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterBlocksCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterBlocksCMD.java index a689ab76..fe565b5d 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterBlocksCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterBlocksCMD.java @@ -2,6 +2,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; @@ -30,7 +31,7 @@ class PartsFilterBlocksCMD extends PlayerSubCommand { public void execute(Player player, String[] args) { ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); if (sel == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterItemsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterItemsCMD.java index cadc01ba..dbac5238 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterItemsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterItemsCMD.java @@ -2,6 +2,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; @@ -30,7 +31,7 @@ class PartsFilterItemsCMD extends PlayerSubCommand { public void execute(Player player, String[] args) { ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); if (sel == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTagsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTagsCMD.java index 3305f697..93976a98 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTagsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTagsCMD.java @@ -2,13 +2,13 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; import net.donnypz.displayentityutils.utils.DisplayEntities.PartFilter; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedPartSelection; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; @@ -26,7 +26,7 @@ class PartsFilterTagsCMD extends PlayerSubCommand { public void execute(Player player, String[] args) { ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); if (sel == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTypesCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTypesCMD.java index e47e6b73..413f9b64 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTypesCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsFilterTypesCMD.java @@ -2,6 +2,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; @@ -29,7 +30,7 @@ class PartsFilterTypesCMD extends PlayerSubCommand { public void execute(Player player, String[] args) { ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); if (sel == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } @@ -71,7 +72,8 @@ public void execute(Player player, String[] args) { } try{ - if (!typeText.equals(SpawnedDisplayEntityPart.PartType.INTERACTION.name())){ + if (!typeText.equals(SpawnedDisplayEntityPart.PartType.INTERACTION.name()) + && !typeText.equals(SpawnedDisplayEntityPart.PartType.MANNEQUIN.name())){ typeText = typeText+"_DISPLAY"; } @@ -86,7 +88,7 @@ public void execute(Player player, String[] args) { } catch(IllegalArgumentException e){ player.sendMessage(Component.text("Invalid Part Type listed!", NamedTextColor.RED)); - player.sendMessage(Component.text("Valid Types: BLOCK, ITEM, TEXT, INTERACTION", NamedTextColor.GRAY, TextDecoration.ITALIC)); + player.sendMessage(Component.text("Valid Types: BLOCK, ITEM, TEXT, INTERACTION, MANNEQUIN", NamedTextColor.GRAY, TextDecoration.ITALIC)); return; } player.sendMessage(Component.text("- "+typeText, NamedTextColor.YELLOW)); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsInfoCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsInfoCMD.java index f18f5747..35f62042 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsInfoCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsInfoCMD.java @@ -91,26 +91,26 @@ else if (type.equalsIgnoreCase("selection") || type.equalsIgnoreCase("filter")){ .hoverEvent(HoverEvent.showText(Component.text("Click to copy", NamedTextColor.GREEN))) .clickEvent(ClickEvent.copyToClipboard(partUUID.toString()))); - - player.sendMessage(MiniMessage.miniMessage().deserialize("Is Master Part: "+(part.isMaster() ? "TRUE" : "FALSE"))); player.sendMessage(Component.empty()); - if (part.getType() != SpawnedDisplayEntityPart.PartType.INTERACTION){ - player.sendMessage(MiniMessage.miniMessage().deserialize("View Range Multiplier: "+part.getViewRange())); - sendBrightness(player, part); - DEUCommandUtils.sendGlowColor(player, part.getGlowColor()); - } - else{ - player.sendMessage(MiniMessage.miniMessage().deserialize("Height: "+part.getInteractionHeight())); - player.sendMessage(MiniMessage.miniMessage().deserialize("Width: "+part.getInteractionWidth())); - player.sendMessage(MiniMessage.miniMessage().deserialize("Responsive: "+(part.isInteractionResponsive() ? "ENABLED" : "DISABLED"))); - } } - else{ + if (part.isDisplay()){ player.sendMessage(MiniMessage.miniMessage().deserialize("View Range Multiplier: "+part.getViewRange())); sendBrightness(player, part); DEUCommandUtils.sendGlowColor(player, part.getGlowColor()); } + else if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ + player.sendMessage(MiniMessage.miniMessage().deserialize("Height: "+part.getInteractionHeight())); + player.sendMessage(MiniMessage.miniMessage().deserialize("Width: "+part.getInteractionWidth())); + player.sendMessage(MiniMessage.miniMessage().deserialize("Responsive: "+(part.isInteractionResponsive() ? "ENABLED" : "DISABLED"))); + } + else if (part.getType() == SpawnedDisplayEntityPart.PartType.MANNEQUIN){ + player.sendMessage(MiniMessage.miniMessage().deserialize("Immovable: "+(part.isMannequinImmovable() ? "ENABLED" : "DISABLED"))); + player.sendMessage(MiniMessage.miniMessage().deserialize("Gravity: "+(part.hasMannequinGravity() ? "ENABLED" : "DISABLED"))); + player.sendMessage(MiniMessage.miniMessage().deserialize("Pose: "+part.getMannequinPose())); + player.sendMessage(MiniMessage.miniMessage().deserialize("Scale: "+part.getMannequinScale())); + } + player.sendMessage(Component.empty()); player.sendMessage(Component.text("| Click to view Part Tags", NamedTextColor.GOLD) .clickEvent(ClickEvent.suggestCommand("/deu parts listtags"))); @@ -122,9 +122,7 @@ private void incorrectUsage(Player player){ } private void sendBrightness(Player player, ActivePart part){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - return; - } + if (!part.isDisplay()) return; Display.Brightness brightness = part.getBrightness(); if (brightness == null){ player.sendMessage(MiniMessage.miniMessage().deserialize("Brightness: NOT SET")); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsListTagsCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsListTagsCMD.java index 7f2eb8a0..9aa7ffce 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsListTagsCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsListTagsCMD.java @@ -1,6 +1,7 @@ package net.donnypz.displayentityutils.command.parts; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; @@ -23,7 +24,7 @@ public void execute(Player player, String[] args) { ActivePartSelection partSelection = DisplayGroupManager.getPartSelection(player); if (partSelection == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveCMD.java index becdcf2f..329f571f 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveCMD.java @@ -3,13 +3,11 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.command.PlayerSubCommand; -import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.Direction; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; -import net.donnypz.displayentityutils.utils.version.folia.FoliaUtils; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; @@ -17,57 +15,87 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -class PartsMoveCMD extends PlayerSubCommand { +class PartsMoveCMD extends PartsSubCommand { - PartsMoveCMD(@NotNull DEUSubCommand parentSubCommand) { - super("move", parentSubCommand, Permission.PARTS_TRANSFORM); - setTabComplete(2, TabSuggestion.DIRECTIONS); - setTabComplete(3, ""); + public PartsMoveCMD(@NotNull DEUSubCommand parentSubCommand) { + super("move", parentSubCommand, Permission.PARTS_TRANSFORM, 4, 4); } @Override public void execute(Player player, String[] args) { - ActivePartSelection selection = DisplayGroupManager.getPartSelection(player); - if (selection == null){ - DisplayEntityPluginCommand.noPartSelection(player); + if (RelativePointUtils.isViewingRelativePoints(player)){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot play do that while viewing points!", NamedTextColor.RED))); return; } + super.execute(player, args); + } - if (PartsCMD.isUnwantedMultiSelection(player, selection)){ - return; - } + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(Component.text("Incorrect Usage! /deu parts move ", NamedTextColor.RED)); + } - if (args.length < 3){ - player.sendMessage(Component.text("Incorrect Usage! /deu parts move ", NamedTextColor.RED)); - return; + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + try{ + Direction direction = Direction.valueOf(args[2].toUpperCase()); + float distance = Float.parseFloat(args[3]); + if (distance <= 0){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a number greater than 0 for the distance!", NamedTextColor.RED))); + return false; + } + for (ActivePart part : selection.getSelectedParts()){ + if (part.isDisplay()) continue; + Location loc = part.getLocation(); + Vector v = direction.getVector(selection.getSelectedPart(), false).normalize().multiply(distance); + loc.add(v); + part.teleport(loc); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Moved ALL selected non-display parts!", NamedTextColor.GREEN))); + } } - - if (!selection.hasSelectedPart()){ - PartsCMD.invalidPartSelection(player); - return; + catch(NumberFormatException e){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter valid numbers!", NamedTextColor.RED))); + player.sendMessage(Component.text("Duration must be a positive whole number, distance can be any positive number", NamedTextColor.GRAY, TextDecoration.ITALIC)); + return false; } + catch(IllegalArgumentException e){ + DisplayEntityPluginCommand.invalidDirection(player); + return false; + } + return true; + } + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (selectedPart.isDisplay() && group != null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot do this for grouped display entities!", NamedTextColor.RED))); + player.sendMessage(Component.text("| Use \"/deu display translate\" instead", NamedTextColor.GRAY)); + return false; + } try{ Direction direction = Direction.valueOf(args[2].toUpperCase()); float distance = Float.parseFloat(args[3]); if (distance <= 0){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a number greater than 0 for the distance!", NamedTextColor.RED))); - return; + return false; } - SpawnedDisplayEntityPart part = (SpawnedDisplayEntityPart) selection.getSelectedPart(); - Location loc = part.getLocation(); + Location loc = selectedPart.getLocation(); Vector v = direction.getVector(selection.getSelectedPart(), false).normalize().multiply(distance); loc.add(v); - FoliaUtils.teleport(part.getEntity(), loc); + selectedPart.teleport(loc); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Moved your selected part!", NamedTextColor.GREEN))); } catch(NumberFormatException e){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter valid numbers!", NamedTextColor.RED))); player.sendMessage(Component.text("Duration must be a positive whole number, distance can be any positive number", NamedTextColor.GRAY, TextDecoration.ITALIC)); + return false; } catch(IllegalArgumentException e){ DisplayEntityPluginCommand.invalidDirection(player); + return false; } + return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveHereCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveHereCMD.java index 0db8c20d..55a25878 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveHereCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsMoveHereCMD.java @@ -1,48 +1,62 @@ package net.donnypz.displayentityutils.command.parts; import net.donnypz.displayentityutils.DisplayAPI; -import net.donnypz.displayentityutils.command.DEUSubCommand; -import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; -import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.command.PlayerSubCommand; -import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; -import net.donnypz.displayentityutils.utils.version.folia.FoliaUtils; +import net.donnypz.displayentityutils.command.*; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Location; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -class PartsMoveHereCMD extends PlayerSubCommand { +class PartsMoveHereCMD extends PartsSubCommand { - PartsMoveHereCMD(@NotNull DEUSubCommand parentSubCommand) { - super("movehere", parentSubCommand, Permission.PARTS_TRANSFORM); + public PartsMoveHereCMD(@NotNull DEUSubCommand parentSubCommand) { + super("movehere", parentSubCommand, Permission.PARTS_TRANSFORM, 2, 2); } @Override public void execute(Player player, String[] args) { - ActivePartSelection selection = DisplayGroupManager.getPartSelection(player); - if (selection == null){ - DisplayEntityPluginCommand.noPartSelection(player); + if (RelativePointUtils.isViewingRelativePoints(player)){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot play do that while viewing points!", NamedTextColor.RED))); return; } + super.execute(player, args); + } - if (PartsCMD.isUnwantedMultiSelection(player, selection)){ - return; + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(Component.text("Incorrect Usage! /deu parts movehere [-all]", NamedTextColor.RED)); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + for (ActivePart part : selection.getSelectedParts()){ + if (part.isDisplay()) continue; + Location loc = player.getLocation(); + loc.setYaw(part.getYaw()); + loc.setPitch(part.getPitch()); + part.teleport(loc); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Moved ALL selected non-display parts to your location!", NamedTextColor.GREEN))); } + return true; + } - if (!selection.hasSelectedPart()){ - PartsCMD.invalidPartSelection(player); - return; + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (selectedPart.isDisplay() && group != null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You cannot do this for grouped display entities!", NamedTextColor.RED))); + player.sendMessage(Component.text("| Use \"/deu display translate\" instead", NamedTextColor.GRAY)); + return false; } - Entity e = ((SpawnedDisplayEntityPart) selection.getSelectedPart()).getEntity(); + Location loc = player.getLocation(); - loc.setYaw(e.getYaw()); - loc.setPitch(e.getPitch()); - FoliaUtils.teleport(e, loc); + loc.setYaw(selectedPart.getYaw()); + loc.setPitch(selectedPart.getPitch()); + selectedPart.teleport(loc); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Moved your selected part to your location!", NamedTextColor.GREEN))); + return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRefreshFilterCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRefreshFilterCMD.java index b8f4dce0..f14e2075 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRefreshFilterCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRefreshFilterCMD.java @@ -2,12 +2,12 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedPartSelection; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; @@ -22,7 +22,7 @@ class PartsRefreshFilterCMD extends PlayerSubCommand { public void execute(Player player, String[] args) { ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); if (sel == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRemoveCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRemoveCMD.java index 6074662f..d9100463 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRemoveCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsRemoveCMD.java @@ -34,7 +34,7 @@ else if (part instanceof SpawnedDisplayEntityPart p){ p.remove(true); } } - player.sendMessage(Component.text("Successfully despawned all selected parts!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("Despawned all selected parts!", NamedTextColor.GREEN)); removeGroupIfEmpty(player, group); return true; } @@ -51,7 +51,7 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti else if (selectedPart instanceof PacketDisplayEntityPart pp){ pp.remove(); } - player.sendMessage(Component.text("Successfully despawned your selected part!", NamedTextColor.GREEN)); + player.sendMessage(Component.text("Despawned your selected part!", NamedTextColor.GREEN)); removePartSelectionIfEmpty(player, selection); removeGroupIfEmpty(player, group); return true; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsResetFilterCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsResetFilterCMD.java index a15b8e07..7abbb7ec 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsResetFilterCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsResetFilterCMD.java @@ -2,13 +2,12 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedPartSelection; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; @@ -23,7 +22,7 @@ class PartsResetFilterCMD extends PlayerSubCommand { public void execute(Player player, String[] args) { ActivePartSelection sel = DisplayGroupManager.getPartSelection(player); if (sel == null){ - PartsCMD.noPartSelection(player); + DisplayEntityPluginCommand.noPartSelection(player); return; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java index 3127c321..7a7a2467 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsSelectCMD.java @@ -2,28 +2,18 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.command.PlayerSubCommand; -import net.donnypz.displayentityutils.managers.DEUUser; -import net.donnypz.displayentityutils.utils.ConversionUtils; -import net.donnypz.displayentityutils.utils.DisplayEntities.SinglePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; -import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.relativepoints.DisplayEntitySelector; +import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.event.ClickCallback; -import net.kyori.adventure.text.event.ClickEvent; -import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.TextDecoration; -import org.bukkit.Bukkit; import org.bukkit.entity.Entity; -import org.bukkit.entity.Interaction; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import java.time.Duration; import java.util.List; -import java.util.UUID; class PartsSelectCMD extends PlayerSubCommand { @@ -41,78 +31,23 @@ public void execute(Player player, String[] args) { try{ String arg = args[2]; if (arg.equalsIgnoreCase("-target")){ - Entity entity = player.getTargetEntity(10); - if (!(entity instanceof Interaction)) { - player.sendMessage(Component.text("Your targeted entity must be an interaction entity within 10 blocks of you", NamedTextColor.RED)); - return; - } - select(player, entity.getUniqueId()); + Entity entity = DisplayEntityPluginCommand.getTargetEntity(player); + if (entity == null) return; + + DisplayEntitySelector.select(player, entity); return; } + double distance = Double.parseDouble(arg); if (distance <= 0){ throw new IllegalArgumentException(); } - - player.sendMessage(Component.text("Finding entities within "+distance+" blocks...", NamedTextColor.YELLOW)); - getSelectableEntities(player, distance); + player.sendMessage(Component.empty()); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Finding display entities within "+distance+" blocks...", NamedTextColor.YELLOW))); + RelativePointUtils.spawnDisplayEntityPoints(distance, player); } catch(IllegalArgumentException e){ - player.sendMessage(Component.text("Invalid input! Enter a positive number for the distance, or -target to select a targeted Interaction entity", NamedTextColor.RED)); - } - } - - private void getSelectableEntities(Player player, double distance){ - List parts = DisplayUtils.getUngroupedPartEntities(player.getLocation(), distance); - if (parts.isEmpty()){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("No nearby ungrouped entities found!", NamedTextColor.RED))); - player.sendMessage(Component.text("| Ensure that any nearby ungrouped entities do not have passengers", NamedTextColor.GRAY, TextDecoration.ITALIC)); - return; - } - - if (parts.size() == 1){ - select(player, parts.getFirst().getUniqueId()); - player.sendMessage(PartsCycleCMD.getPartInfo(parts.getFirst()).color(NamedTextColor.GRAY)); - return; - } - - player.sendMessage(Component.text("| Entities found! Click to select.", NamedTextColor.GREEN).appendNewline()); - for (Entity e : parts){ - UUID entityUUID = e.getUniqueId(); - SpawnedDisplayEntityPart.PartType partType = SpawnedDisplayEntityPart.PartType.getType(e); - String coords = ConversionUtils.getCoordinateString(e.getLocation()); - Component comp = Component.text("- "+partType.name()+": ") - .append(PartsCycleCMD.getPartInfo(e)) - .hoverEvent(HoverEvent.showText(Component.text("Location: ", NamedTextColor.AQUA).append(Component.text(coords, NamedTextColor.YELLOW)))) - .clickEvent(ClickEvent.callback(audience -> { - Player p = (Player) audience; - select(p, entityUUID); - }, ClickCallback.Options.builder().uses(ClickCallback.UNLIMITED_USES).lifetime(Duration.ofMinutes(10)).build())); - player.sendMessage(comp); - } - } - - private void select(Player player, UUID entityUUID){ - SpawnedDisplayEntityPart existing = SpawnedDisplayEntityPart.getPart(Bukkit.getEntity(entityUUID)); - if (existing != null){ - player.sendMessage(Component.text("That part is already in a group! Select the group, then cycle through the group's parts!", NamedTextColor.RED)); - return; - } - - SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.create(entityUUID); - if (part == null){ - player.sendMessage(Component.text("That entity is no longer valid!", NamedTextColor.RED)); - return; - } - DEUUser - .getOrCreateUser(player) - .setSelectedPartSelection(new SinglePartSelection(part), false); - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - part.markInteraction(player, 30); - } - else{ - part.glow(player, 30); + player.sendMessage(Component.text("Invalid input! Enter a positive number for the distance, or -target to select a targeted Interaction/Mannequin entity", NamedTextColor.RED)); } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Part Entity Selected!", NamedTextColor.GREEN))); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsYawCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsYawCMD.java index 61b93379..8d1ed136 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsYawCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/parts/PartsYawCMD.java @@ -1,58 +1,45 @@ package net.donnypz.displayentityutils.command.parts; import net.donnypz.displayentityutils.DisplayAPI; -import net.donnypz.displayentityutils.command.DEUSubCommand; -import net.donnypz.displayentityutils.command.DisplayEntityPluginCommand; -import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.command.*; import net.donnypz.displayentityutils.managers.DisplayGroupManager; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -class PartsYawCMD extends PlayerSubCommand { +class PartsYawCMD extends PartsSubCommand { PartsYawCMD(@NotNull DEUSubCommand parentSubCommand) { - super("yaw", parentSubCommand, Permission.PARTS_TRANSFORM); + super("yaw", parentSubCommand, Permission.PARTS_TRANSFORM, 3, 0); setTabComplete(2, ""); } @Override - public void execute(Player player, String[] args) { - ActivePartSelection selection = DisplayGroupManager.getPartSelection(player); - if (selection == null){ - DisplayEntityPluginCommand.noPartSelection(player); - return; - } - - if (PartsCMD.isUnwantedMultiSelection(player, selection)){ - return; - } - - if (args.length < 3){ - player.sendMessage(Component.text("Incorrect Usage! /deu parts yaw ", NamedTextColor.RED)); - return; - } + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(Component.text("Incorrect Usage! /deu parts yaw ", NamedTextColor.RED)); + } - if (!selection.hasSelectedPart()){ - PartsCMD.invalidPartSelection(player); - return; - } + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + return false; + } + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { try{ float yaw = Float.parseFloat(args[2]); - ActivePart part = selection.getSelectedPart(); - double oldYaw = part.getYaw(); - part.setYaw(yaw, false); + double oldYaw = selectedPart.getYaw(); + selectedPart.setYaw(yaw, false); player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Yaw set!", NamedTextColor.GREEN))); player.sendMessage(Component.text("| Old Yaw: "+oldYaw, NamedTextColor.GRAY)); + return true; } catch(NumberFormatException e){ player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Enter a valid number for the yaw!", NamedTextColor.RED))); + return false; } } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceAddSoundCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceAddSoundCMD.java new file mode 100644 index 00000000..7d6281e3 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceAddSoundCMD.java @@ -0,0 +1,72 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; +import net.donnypz.displayentityutils.utils.version.VersionUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +class PlaceAddSoundCMD extends PlayerSubCommand { + PlaceAddSoundCMD(@NotNull DEUSubCommand parentSubCommand) { + super("addsound", parentSubCommand, Permission.PLACE_SOUND); + setTabComplete(2, List.of("place", "break")); + setTabComplete(3, ""); + setTabComplete(4, ""); + setTabComplete(5, ""); + } + + private void incorrectUsage(Player player){ + player.sendMessage(Component.text("Incorrect Usage! /deu anim addsound ", NamedTextColor.RED)); + } + + @Override + public void execute(Player player, String[] args) { + + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + if (args.length < 6) { + incorrectUsage(player); + return; + } + try { + String isPlaceStr = args[2]; + boolean isPlace; + if (isPlaceStr.equalsIgnoreCase("place")){ + isPlace = true; + } + else if (isPlaceStr.equalsIgnoreCase("break")){ + isPlace = false; + } + else{ + incorrectUsage(player); + return; + } + + String soundStr = args[3]; + float volume = Float.parseFloat(args[4]); + float pitch = Float.parseFloat(args[5]); + PlaceableGroupManager.addSound(heldItem, new DEUSound(soundStr, volume, pitch, 0), isPlace); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Sound Added! ", NamedTextColor.GREEN).append(Component.text(isPlace ? "(Place)" : "(Break)", NamedTextColor.GRAY)))); + player.sendMessage(MiniMessage.miniMessage().deserialize("| Sound: "+soundStr)); + player.sendMessage(MiniMessage.miniMessage().deserialize("| Volume: "+volume)); + player.sendMessage(MiniMessage.miniMessage().deserialize("| Pitch: "+pitch)); + + if (VersionUtils.getSound(soundStr) == null){ + player.sendMessage(Component.text("| The provided sound is not a vanilla Minecraft sound, or does not exist in this game version!", NamedTextColor.GRAY)); + } + } catch (NumberFormatException | IndexOutOfBoundsException e) { + player.sendMessage(Component.text("Invalid number entered! Enter numbers >= 0", NamedTextColor.RED)); + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceBreakModeCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceBreakModeCMD.java new file mode 100644 index 00000000..9daef9d5 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceBreakModeCMD.java @@ -0,0 +1,32 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceBreakModeCMD extends PlayerSubCommand { + PlaceBreakModeCMD(@NotNull DEUSubCommand parentSubCommand) { + super("breakmode", parentSubCommand, Permission.PLACE_BREAK_MODE); + } + + @Override + public void execute(Player player, String[] args) { + DEUUser user = DEUUser.getOrCreateUser(player); + if (user.isInPlacedGroupBreakMode()){ + user.setPlacedGroupBreakMode(false); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You have exited break-mode and can only break groups you have placed", NamedTextColor.RED))); + } + else{ + user.setPlacedGroupBreakMode(true); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You have entered break-mode and can break any placed groups", NamedTextColor.GREEN))); + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java new file mode 100644 index 00000000..a97f793a --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceCMD.java @@ -0,0 +1,85 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.*; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class PlaceCMD extends ConsoleUsableSubCommand { + public PlaceCMD() { + super(Permission.HELP, new PlaceHelpCMD()); + new PlaceSetCMD(this); + new PlaceUnsetCMD(this); + new PlaceSetPermissionCMD(this); + new PlaceUnsetPermissionCMD(this); + new PlaceTogglePlayerFacingCMD(this); + new PlaceToggleBlockFaceCMD(this); + new PlaceToggleDropItemCMD(this); + new PlaceTogglePlacerOnlyCMD(this); + new PlaceInfoCMD(this); + new PlaceAddSoundCMD(this); + new PlaceWhoPlacedCMD(this); + new PlaceGetItemCMD(this); + new PlaceBreakModeCMD(this); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length < 2){ + help(sender, 1); + return; + } + String arg = args[1]; + DEUSubCommand subCommand = subCommands.get(arg); + if (subCommand == null){ + help(sender, 1); + } + else{ + DisplayEntityPluginCommand.executeCommand(subCommand, sender, args); + } + } + + static void help(CommandSender sender, int page){ + sender.sendMessage(Component.empty()); + sender.sendMessage(DisplayAPI.pluginPrefixLong); + if (page == 1){ + CMDUtils.sendCMD(sender, "/deu place help", "Get help for placeable groups"); + CMDUtils.sendCMD(sender, "/deu place info", "Get placeable group information for your held block"); + CMDUtils.sendCMD(sender, "/deu place breakmode", "Enter/Exit break-mode allowing you to break any placed group"); + CMDUtils.sendCMD(sender, "/deu place set ", "Assign a group to your held block, which will be spawned when the block is placed"); + CMDUtils.sendCMD(sender, "/deu place unset", "Unassign a group from your held block"); + CMDUtils.sendCMD(sender, "/deu place setpermission", "Set the permission required to place the group"); + CMDUtils.sendCMD(sender, "/deu place unsetpermission", "Remove the permission required to place the group"); + } + else{ + CMDUtils.sendCMD(sender, "/deu place toggleplayerfacing", "Toggle whether the placed group will respect the player's facing direction. True by default"); + CMDUtils.sendCMD(sender, "/deu place toggleblockface", "Toggle whether the placed group will respect the block face it is placed on. True by default"); + CMDUtils.sendCMD(sender, "/deu place toggledropitem", "Toggle whether the placed group will drop the item used to place it, when broken. " + + "The item never drops for players in creative. True by default"); + CMDUtils.sendCMD(sender, "/deu place toggleplaceronly", "Toggle whether only the player who placed a group can break it. True by default"); + CMDUtils.sendCMD(sender, "/deu place addsound ", "Add a sound to play when the block is placed or broken"); + CMDUtils.sendCMD(sender, "/deu place whoplaced", "Get the name and UUID of the player who placed a group"); + CMDUtils.sendCMD(sender, "/deu place getitem", "Get the item used to placed a group"); + } + sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); + } + + static ItemStack getHeldItem(Player player, boolean mustBeAssigned){ + ItemStack heldItem = player.getInventory().getItemInMainHand(); + if (!PlaceableGroupManager.isValidItem(heldItem)){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You must be holding a block to do this command!", NamedTextColor.RED))); + return null; + } + + if (mustBeAssigned && !PlaceableGroupManager.hasData(heldItem)){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item does not have placeable group data!", NamedTextColor.RED))); + return null; + } + return heldItem; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceGetItemCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceGetItemCMD.java new file mode 100644 index 00000000..a814ccd0 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceGetItemCMD.java @@ -0,0 +1,36 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceGetItemCMD extends PlayerSubCommand { + PlaceGetItemCMD(@NotNull DEUSubCommand parentSubCommand) { + super("getitem", parentSubCommand, Permission.PLACE_GET_ITEM); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + + Block targetBlock = player.getTargetBlock(null, 15); + final ItemStack itemStack = PlaceableGroupManager.getItemStack(targetBlock); + if (itemStack == null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You are not looking at a placed group's block! (Barrier)", NamedTextColor.RED))); + return; + } + + player.give(itemStack); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You have been given the item to place the group", NamedTextColor.GREEN))); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceHelpCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceHelpCMD.java new file mode 100644 index 00000000..7f60c8d9 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceHelpCMD.java @@ -0,0 +1,27 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.command.ConsoleUsableSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.item.ItemCMD; +import org.bukkit.command.CommandSender; + +public class PlaceHelpCMD extends ConsoleUsableSubCommand { + public PlaceHelpCMD() { + super(Permission.HELP); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length < 3){ + PlaceCMD.help(sender, 1); + } + else{ + try{ + PlaceCMD.help(sender, Integer.parseInt(args[2])); + } + catch(NumberFormatException e){ + PlaceCMD.help(sender, 1); + } + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java new file mode 100644 index 00000000..062130ea --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceInfoCMD.java @@ -0,0 +1,62 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.DEUSound; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +class PlaceInfoCMD extends PlayerSubCommand { + PlaceInfoCMD(@NotNull DEUSubCommand parentSubCommand) { + super("info", parentSubCommand, Permission.PLACE_INFO); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + player.sendMessage(DisplayAPI.pluginPrefixLong); + + String groupTag = PlaceableGroupManager.getGroupTag(heldItem); + String permission = PlaceableGroupManager.getPlacePermission(heldItem); + if (permission == null){ + permission = "NOT SET"; + } + boolean respectPlayerFacing = PlaceableGroupManager.isRespectingPlayerFacing(heldItem); + boolean respectBlockFace = PlaceableGroupManager.isRespectingBlockFace(heldItem); + boolean dropsItems = PlaceableGroupManager.isDropItem(heldItem); + boolean placerBreaksOnly = PlaceableGroupManager.isPlacerBreaksOnly(heldItem); + List placeSounds = PlaceableGroupManager.getSounds(heldItem, true); + List breakSounds = PlaceableGroupManager.getSounds(heldItem, false); + + player.sendMessage(MiniMessage.miniMessage().deserialize("Group Tag: "+groupTag)); + player.sendMessage(MiniMessage.miniMessage().deserialize("Place Permission: "+permission)); + player.sendMessage(MiniMessage.miniMessage().deserialize("Respect Player Facing: "+(respectPlayerFacing ? "ENABLED" : "DISABLED"))); + player.sendMessage(MiniMessage.miniMessage().deserialize("Respect Block Face: "+(respectBlockFace ? "ENABLED" : "DISABLED"))); + player.sendMessage(MiniMessage.miniMessage().deserialize("Item Drop: "+(dropsItems ? "ENABLED" : "DISABLED"))); + player.sendMessage(MiniMessage.miniMessage().deserialize("Placer Breaks Only: "+(placerBreaksOnly ? "ENABLED" : "DISABLED"))); + DEUSound.sendInfo(placeSounds, player, "Place Sounds", + player.hasPermission(Permission.PLACE_SOUND.getPermission()) + ? s -> + { + PlaceableGroupManager.removeSound(heldItem, s, true); + } + : null); + + DEUSound.sendInfo(breakSounds, player, "Break Sounds", + player.hasPermission(Permission.PLACE_SOUND.getPermission()) + ? s -> + { + PlaceableGroupManager.removeSound(heldItem, s, false); + } + : null); + } +} \ No newline at end of file diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java new file mode 100644 index 00000000..d0e33147 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetCMD.java @@ -0,0 +1,41 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupData; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceSetCMD extends PlayerSubCommand { + PlaceSetCMD(@NotNull DEUSubCommand parentSubCommand) { + super("set", parentSubCommand, Permission.PLACE_SET_ITEM); + setTabComplete(2, ""); + } + + @Override + public void execute(Player player, String[] args) { + if (args.length < 3) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu place set ", NamedTextColor.RED))); + return; + } + + ItemStack heldItem = player.getInventory().getItemInMainHand(); + if (!PlaceableGroupManager.isValidItem(heldItem)){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You must be holding a block to do this command!", NamedTextColor.RED))); + return; + } + + String groupTag = args[2]; + + new PlaceableGroupData(groupTag) + .apply(heldItem); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Assigned a group to your held block (Tag: "+groupTag+")"))); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetPermissionCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetPermissionCMD.java new file mode 100644 index 00000000..4c154a6d --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceSetPermissionCMD.java @@ -0,0 +1,35 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceSetPermissionCMD extends PlayerSubCommand { + PlaceSetPermissionCMD(@NotNull DEUSubCommand parentSubCommand) { + super("setpermission", parentSubCommand, Permission.PLACE_SET_PERMISSION); + setTabComplete(2, ""); + } + + @Override + public void execute(Player player, String[] args) { + if (args.length < 3) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Incorrect Usage /deu place setpermission ", NamedTextColor.RED))); + return; + } + + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + String permission = args[2]; + PlaceableGroupManager.setPlacePermission(heldItem, permission); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Set the permission to place your held item's assigned group (Permission: "+permission+")"))); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleBlockFaceCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleBlockFaceCMD.java new file mode 100644 index 00000000..e80933a6 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleBlockFaceCMD.java @@ -0,0 +1,33 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceToggleBlockFaceCMD extends PlayerSubCommand { + PlaceToggleBlockFaceCMD(@NotNull DEUSubCommand parentSubCommand) { + super("toggleblockface", parentSubCommand, Permission.PLACE_TOGGLE_BLOCK_FACE); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + if (PlaceableGroupManager.isRespectingBlockFace(heldItem)){ + PlaceableGroupManager.setRespectBlockFace(heldItem, false); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will no longer respect the block face its placed on", NamedTextColor.RED))); + } + else{ + PlaceableGroupManager.setRespectBlockFace(heldItem, true); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will respect the block face its placed on", NamedTextColor.GREEN))); + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleDropItemCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleDropItemCMD.java new file mode 100644 index 00000000..d114040d --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceToggleDropItemCMD.java @@ -0,0 +1,33 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceToggleDropItemCMD extends PlayerSubCommand { + PlaceToggleDropItemCMD(@NotNull DEUSubCommand parentSubCommand) { + super("toggledropitem", parentSubCommand, Permission.PLACE_TOGGLE_DROP_ITEM); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + if (PlaceableGroupManager.isDropItem(heldItem)){ + PlaceableGroupManager.setDropItemOnBreak(heldItem, false); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will no longer drop the item used to place it", NamedTextColor.RED))); + } + else{ + PlaceableGroupManager.setDropItemOnBreak(heldItem, true); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will drop the item used to place it", NamedTextColor.GREEN))); + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlacerOnlyCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlacerOnlyCMD.java new file mode 100644 index 00000000..2917c1bf --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlacerOnlyCMD.java @@ -0,0 +1,33 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceTogglePlacerOnlyCMD extends PlayerSubCommand { + PlaceTogglePlacerOnlyCMD(@NotNull DEUSubCommand parentSubCommand) { + super("toggleplaceronly", parentSubCommand, Permission.PLACE_TOGGLE_PLACER_ONLY); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + if (PlaceableGroupManager.isPlacerBreaksOnly(heldItem)){ + PlaceableGroupManager.setPlacerBreaksOnly(heldItem, false); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group can only broken by any player", NamedTextColor.RED))); + } + else{ + PlaceableGroupManager.setPlacerBreaksOnly(heldItem, true); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group can only be broken by the player who placed it", NamedTextColor.GREEN))); + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlayerFacingCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlayerFacingCMD.java new file mode 100644 index 00000000..9e71843a --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceTogglePlayerFacingCMD.java @@ -0,0 +1,33 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceTogglePlayerFacingCMD extends PlayerSubCommand { + PlaceTogglePlayerFacingCMD(@NotNull DEUSubCommand parentSubCommand) { + super("toggleplayerfacing", parentSubCommand, Permission.PLACE_TOGGLE_PLAYER_FACING); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + if (PlaceableGroupManager.isRespectingPlayerFacing(heldItem)){ + PlaceableGroupManager.setRespectPlayerFacing(heldItem, false); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will no longer respect the player's facing direction", NamedTextColor.RED))); + } + else{ + PlaceableGroupManager.setRespectPlayerFacing(heldItem, true); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item's group will respect the player's facing direction", NamedTextColor.GREEN))); + } + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetCMD.java new file mode 100644 index 00000000..b93fc065 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetCMD.java @@ -0,0 +1,26 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceUnsetCMD extends PlayerSubCommand { + PlaceUnsetCMD(@NotNull DEUSubCommand parentSubCommand) { + super("unset", parentSubCommand, Permission.PLACE_SET_ITEM); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + PlaceableGroupManager.unassign(heldItem); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Your held item no longer has an assigned group"))); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetPermissionCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetPermissionCMD.java new file mode 100644 index 00000000..70d9ab23 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceUnsetPermissionCMD.java @@ -0,0 +1,32 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +class PlaceUnsetPermissionCMD extends PlayerSubCommand { + PlaceUnsetPermissionCMD(@NotNull DEUSubCommand parentSubCommand) { + super("unsetpermission", parentSubCommand, Permission.PLACE_SET_PERMISSION); + } + + @Override + public void execute(Player player, String[] args) { + ItemStack heldItem = PlaceCMD.getHeldItem(player, true); + if (heldItem == null) return; + + if (!PlaceableGroupManager.hasPlacePermission(heldItem)) { + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Your held item does not have a set permission to place its group!", NamedTextColor.RED))); + return; + } + PlaceableGroupManager.setPlacePermission(heldItem, null); + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Removed the set permission to your held item's group."))); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceWhoPlacedCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceWhoPlacedCMD.java new file mode 100644 index 00000000..bdc7b63f --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/place/PlaceWhoPlacedCMD.java @@ -0,0 +1,49 @@ +package net.donnypz.displayentityutils.command.place; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.command.PlayerSubCommand; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +class PlaceWhoPlacedCMD extends PlayerSubCommand { + PlaceWhoPlacedCMD(@NotNull DEUSubCommand parentSubCommand) { + super("whoplaced", parentSubCommand, Permission.PLACE_WHO_PLACED); + } + + @Override + public void execute(Player player, String[] args) { + Block targetBlock = player.getTargetBlock(null, 15); + final UUID uuid = PlaceableGroupManager.getWhoPlaced(targetBlock); + if (uuid == null){ + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You are not looking at a placed group's block! (Barrier)", NamedTextColor.RED))); + return; + } + player.sendMessage(DisplayAPI.pluginPrefixLong); + player.sendMessage(Component.text("Block Location: ") + .append(Component.text(targetBlock.getX()+", "+targetBlock.getY()+", "+targetBlock.getZ(), NamedTextColor.YELLOW))); + DisplayAPI.getScheduler().runAsync(() -> { + OfflinePlayer plr = Bukkit.getOfflinePlayer(uuid); + player.sendMessage(Component.text("Player: ") + .append(Component.text(plr.getName(), NamedTextColor.YELLOW) + .clickEvent(ClickEvent.copyToClipboard(plr.getName())) + .hoverEvent(HoverEvent.showText(Component.text("Click to copy"))))); + player.sendMessage(Component.text("UUID: ") + .append(Component.text(uuid.toString(), NamedTextColor.YELLOW) + .clickEvent(ClickEvent.copyToClipboard(uuid.toString())) + .hoverEvent(HoverEvent.showText(Component.text("Click to copy"))) + )); + }); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java new file mode 100644 index 00000000..0ea370e5 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAddLineCMD.java @@ -0,0 +1,44 @@ +package net.donnypz.displayentityutils.command.text; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.DEUSubCommand; +import net.donnypz.displayentityutils.command.PartsSubCommand; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class TextAddLineCMD extends PartsSubCommand { + + public TextAddLineCMD(@NotNull DEUSubCommand parentSubCommand) { + super("addline", parentSubCommand, Permission.TEXT_SET_TEXT, 3, 0); + setTabComplete(2, ""); + } + + @Override + protected void sendIncorrectUsage(@NotNull Player player) { + player.sendMessage(Component.text("Incorrect Usage! /deu text addline ", NamedTextColor.RED)); + } + + @Override + protected boolean executeAllPartsAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull MultiPartSelection selection, @NotNull String[] args) { + return false; + } + + @Override + protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + + Component currentText = selectedPart.getTextDisplayText(); + Key font = currentText.font(); + Component comp = currentText.appendNewline().append(LegacyComponentSerializer.legacyAmpersand().deserialize(TextSetCMD.getTextResult(args))); + selectedPart.setTextDisplayText(comp.font(font)); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Added line to text display!", NamedTextColor.GREEN))); + return true; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAlignCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAlignCMD.java index fd633873..3c99dcf8 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAlignCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextAlignCMD.java @@ -33,20 +33,18 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active part.setTextDisplayAlignment(alignment); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Text alignment successfully set to "+args[2]+" for ALL selected text displays", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Text alignment set to "+args[2]+" for ALL selected text displays", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + TextDisplay.TextAlignment alignment = getAlignment(args[2], player); if (alignment == null) return false; selectedPart.setTextDisplayAlignment(alignment); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Text alignment successfully set to "+args[2], NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Text alignment set to "+args[2], NamedTextColor.GREEN))); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextBackgroundCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextBackgroundCMD.java index 18be9bf2..963ff92c 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextBackgroundCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextBackgroundCMD.java @@ -34,20 +34,17 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active part.setTextDisplayBackgroundColor(color); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set background color for ALL selected text displays", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set background color for ALL selected text displays", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; Color color = getColor(args, player); if (color == null) return false; - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY){ - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } selectedPart.setTextDisplayBackgroundColor(color); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set text display's background color", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set text display's background color", NamedTextColor.GREEN))); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextCMD.java index 991f599b..0d9fac15 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextCMD.java @@ -11,6 +11,7 @@ public TextCMD(){ super(Permission.HELP, new TextHelpCMD()); new TextEditCMD(this); new TextSetCMD(this); + new TextAddLineCMD(this); new TextFontCMD(this); new TextShadowCMD(this); new TextSeeThroughCMD(this); @@ -38,16 +39,21 @@ public void execute(CommandSender sender, String[] args) { static void help(CommandSender sender, int page){ sender.sendMessage(DisplayAPI.pluginPrefixLong); - CMDUtils.sendCMD(sender, "/deu text help", "Get help for text displays"); - CMDUtils.sendCMD(sender, "/deu text edit [-&]", "Open a dialog menu to edit all text display properties. Add the \"-&\" parameter to format the text with \"&\""); - CMDUtils.sendCMD(sender, "/deu text set ", "Set this text for your selected text display"); - CMDUtils.sendCMD(sender, "/deu text font [-all]", "Set the text font for your selected text display"); - CMDUtils.sendCMD(sender, "/deu text shadow [-all ]", "Toggle shadows visibility in your selected text display"); - CMDUtils.sendCMD(sender, "/deu text seethrough [-all ]", "Toggle see through setting of your selected text display"); - CMDUtils.sendCMD(sender, "/deu text align [-all]", "Set your selected text display's text alignment"); - CMDUtils.sendCMD(sender, "/deu text linewidth [-all]", "Set the line width of your selected text display"); - CMDUtils.sendCMD(sender, "/deu text background <0-1> [-all]", "Set the background color of a text display, and the opacity"); - CMDUtils.sendCMD(sender, "/deu text opacity <0-1> [-all]", "Set the text opacity for your selected text display"); - sender.sendMessage(MiniMessage.miniMessage().deserialize("--------------------------")); + if (page == 1){ + CMDUtils.sendCMD(sender, "/deu text help", "Get help for text displays"); + CMDUtils.sendCMD(sender, "/deu text edit [-&]", "Open a dialog menu to edit all text display properties. Add the \"-&\" parameter to format the text with \"&\""); + CMDUtils.sendCMD(sender, "/deu text set ", "Set this text for your selected text display"); + CMDUtils.sendCMD(sender, "/deu text addline ", "Add a line of text to your selected text display"); + CMDUtils.sendCMD(sender, "/deu text font [-all]", "Set the text font for your selected text display"); + CMDUtils.sendCMD(sender, "/deu text shadow [-all ]", "Toggle shadows visibility in your selected text display"); + CMDUtils.sendCMD(sender, "/deu text seethrough [-all ]", "Toggle see through setting of your selected text display"); + } + else{ + CMDUtils.sendCMD(sender, "/deu text align [-all]", "Set your selected text display's text alignment"); + CMDUtils.sendCMD(sender, "/deu text linewidth [-all]", "Set the line width of your selected text display"); + CMDUtils.sendCMD(sender, "/deu text background <0-1> [-all]", "Set the background color of a text display, and the opacity"); + CMDUtils.sendCMD(sender, "/deu text opacity <0-1> [-all]", "Set the text opacity for your selected text display"); + } + sender.sendMessage(MiniMessage.miniMessage().deserialize("----------Page "+page+"----------")); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextEditCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextEditCMD.java index 890927a1..3963c522 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextEditCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextEditCMD.java @@ -1,14 +1,11 @@ package net.donnypz.displayentityutils.command.text; -import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.PartsSubCommand; import net.donnypz.displayentityutils.command.Permission; import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.donnypz.displayentityutils.utils.dialogs.TextDisplayDialog; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -29,10 +26,7 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; boolean legacy = args.length >= 3 && args[2].equals("-&"); if (VersionUtils.canViewDialogs(player, true)){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextFontCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextFontCMD.java index bec3e32e..23c2e3fa 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextFontCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextFontCMD.java @@ -33,20 +33,18 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active part.setTextDisplayText(part.getTextDisplayText().font(font)); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Font successfully set to "+args[2]+" for ALL selected text displays", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Font set to "+args[2]+" for ALL selected text displays", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + Key font = getFont(args, player); if (font == null) return false; selectedPart.setTextDisplayText(selectedPart.getTextDisplayText().font(font)); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Font successfully set to "+args[2], NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Font set to "+args[2], NamedTextColor.GREEN))); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextLineWidthCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextLineWidthCMD.java index 073678e9..2c16a3cb 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextLineWidthCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextLineWidthCMD.java @@ -31,20 +31,19 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active part.setTextDisplayLineWidth(width); } } - player.sendMessage(Component.text("Successfully set text display's line width to "+width+" for ALL selected text displays", NamedTextColor.GREEN)); + player.sendMessage(Component.text("Set text display's line width to "+width+" for ALL selected text displays", NamedTextColor.GREEN)); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + int width = getLineWidth(args, player); if (width == -1) return false; - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + selectedPart.setTextDisplayLineWidth(width); - player.sendMessage(Component.text("Successfully set text display's line width to "+width, NamedTextColor.GREEN)); + player.sendMessage(Component.text("Set text display's line width to "+width, NamedTextColor.GREEN)); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextOpacityCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextOpacityCMD.java index 905dc9fd..ba0f69cd 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextOpacityCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextOpacityCMD.java @@ -32,21 +32,19 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active } } player.sendMessage(DisplayAPI.pluginPrefix - .append(Component.text("Successfully set text display's opacity to "+opacity+" for ALL selected text displays", NamedTextColor.GREEN))); + .append(Component.text("Set text display's opacity to "+opacity+" for ALL selected text displays", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + Byte opacity = getOpacity(args, player); if (opacity == null) return false; - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } selectedPart.setTextDisplayTextOpacity(opacity); player.sendMessage(DisplayAPI.pluginPrefix - .append(Component.text("Successfully set text display's opacity to "+opacity, NamedTextColor.GREEN))); + .append(Component.text("Set text display's opacity to "+opacity, NamedTextColor.GREEN))); return true; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSeeThroughCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSeeThroughCMD.java index 68d50598..55979f4f 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSeeThroughCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSeeThroughCMD.java @@ -37,12 +37,12 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (s.equalsIgnoreCase("on")){ status = true; player.sendMessage(DisplayAPI.pluginPrefix - .append(MiniMessage.miniMessage().deserialize("Successfully toggled see through for ALL selected text displays ON"))); + .append(MiniMessage.miniMessage().deserialize("Toggled see through for ALL selected text displays ON"))); } else if (s.equalsIgnoreCase("off")){ status = false; player.sendMessage(DisplayAPI.pluginPrefix - .append(MiniMessage.miniMessage().deserialize("Successfully toggled see through for ALL selected text displays OFF"))); + .append(MiniMessage.miniMessage().deserialize("Toggled see through for ALL selected text displays OFF"))); } else{ sendIncorrectUsage(player); @@ -59,12 +59,11 @@ else if (s.equalsIgnoreCase("off")){ @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + selectedPart.setTextDisplaySeeThrough(!selectedPart.isTextDisplaySeeThrough()); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully toggled see through for text display!", NamedTextColor.GREEN))); + String status = selectedPart.isTextDisplaySeeThrough() ? "ON" : "OFF"; + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled see through for your selected text display "+status))); return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java index d9d096af..d98ee98b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextSetCMD.java @@ -4,10 +4,7 @@ import net.donnypz.displayentityutils.command.DEUSubCommand; import net.donnypz.displayentityutils.command.PartsSubCommand; import net.donnypz.displayentityutils.command.Permission; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; -import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePartSelection; -import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -16,7 +13,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -class TextSetCMD extends PartsSubCommand { +public class TextSetCMD extends PartsSubCommand { public TextSetCMD(@NotNull DEUSubCommand parentSubCommand) { super("set", parentSubCommand, Permission.TEXT_SET_TEXT, 3, 0); @@ -35,6 +32,18 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + + Component currentText = selectedPart.getTextDisplayText(); + Key font = currentText.font(); + Component comp = LegacyComponentSerializer.legacyAmpersand().deserialize(getTextResult(args)); + selectedPart.setTextDisplayText(comp.font(font)); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Set text display's text!", NamedTextColor.GREEN))); + player.sendMessage(Component.text("You can include \"\\n\" in your to create a new line.", NamedTextColor.GRAY)); + return true; + } + + public static String getTextResult(String[] args){ StringBuilder builder = new StringBuilder(); for (int i = 2; i < args.length; i++){ builder.append(args[i]); @@ -42,13 +51,6 @@ protected boolean executeSinglePartAction(@NotNull Player player, @Nullable Acti builder.append(" "); } } - Component currentText = selectedPart.getTextDisplayText(); - String textResult = builder.toString().replace("\\n", "\n"); - Key oldFont = currentText.font(); - Component comp = LegacyComponentSerializer.legacyAmpersand().deserialize(textResult); - selectedPart.setTextDisplayText(comp.font(oldFont)); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully set text on text display!", NamedTextColor.GREEN))); - player.sendMessage(Component.text("Keep in mind, you can include \"\\n\" in your text display to create a new line.", NamedTextColor.GRAY)); - return true; + return builder.toString().replace("\\n", "\n"); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextShadowCMD.java b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextShadowCMD.java index 66ebfde4..465fa01b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextShadowCMD.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/command/text/TextShadowCMD.java @@ -37,12 +37,12 @@ protected boolean executeAllPartsAction(@NotNull Player player, @Nullable Active if (s.equalsIgnoreCase("on")){ status = true; player.sendMessage(DisplayAPI.pluginPrefix - .append(MiniMessage.miniMessage().deserialize("Successfully toggled shadowed for ALL selected text displays ON"))); + .append(MiniMessage.miniMessage().deserialize("Toggled shadowed for ALL selected text displays ON"))); } else if (s.equalsIgnoreCase("off")){ status = false; player.sendMessage(DisplayAPI.pluginPrefix - .append(MiniMessage.miniMessage().deserialize("Successfully toggled shadowed for ALL selected text displays OFF"))); + .append(MiniMessage.miniMessage().deserialize("Toggled shadowed for ALL selected text displays OFF"))); } else{ sendIncorrectUsage(player); @@ -54,18 +54,17 @@ else if (s.equalsIgnoreCase("off")){ part.setTextDisplayShadowed(status); } } - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully toggled shadowed for ALL selected text displays!", NamedTextColor.GREEN))); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Toggled shadowed for ALL selected text displays!", NamedTextColor.GREEN))); return true; } @Override protected boolean executeSinglePartAction(@NotNull Player player, @Nullable ActiveGroup group, @NotNull ActivePartSelection selection, @NotNull ActivePart selectedPart, @NotNull String[] args) { - if (selectedPart.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY) { - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("You can only do this with text display entities", NamedTextColor.RED))); - return false; - } + if (isInvalidType(player, selectedPart, SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY)) return false; + selectedPart.setTextDisplayShadowed(!selectedPart.isTextDisplayShadowed()); - player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Successfully toggled shadow for text display!", NamedTextColor.GREEN))); + String status = selectedPart.isTextDisplayShadowed() ? "ON" : "OFF"; + player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Toggled shadow for your selected text display "+status))); return true; } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java index ba8b721f..f2b0d0cf 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/AutoGroup.java @@ -2,7 +2,7 @@ import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.DisplayConfig; -import net.donnypz.displayentityutils.events.ChunkAddGroupInteractionsEvent; +import net.donnypz.displayentityutils.events.ChunkAddGroupEntitiesEvent; import net.donnypz.displayentityutils.events.ChunkRegisterGroupEvent; import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; @@ -15,7 +15,6 @@ import org.bukkit.World; import org.bukkit.entity.Display; import org.bukkit.entity.Entity; -import org.bukkit.entity.Interaction; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; @@ -46,26 +45,20 @@ static void detectGroups(Chunk chunk, List entities){ World world = chunk.getWorld(); String worldName = world.getName(); - Set chunks = readChunks - .computeIfAbsent(worldName, name -> Collections.newSetFromMap(new ConcurrentHashMap<>())); + Set chunks = readChunks.computeIfAbsent(worldName, name -> Collections.newSetFromMap(new ConcurrentHashMap<>())); - //Bukkit.broadcastMessage(chunk.getX()+" X | "+chunk.getZ()+" Z | TICK="+Bukkit.getCurrentTick()); - if (chunks.contains(chunk.getChunkKey())){ + if (!chunks.add(chunk.getChunkKey())){ //Already Contained refreshGroupPartEntities(entities); if (!DisplayConfig.readSameChunks()) return; } - else{ - chunks.add(chunk.getChunkKey()); - } - - DisplayGroupManager.spawnPersistentPacketGroups(chunk); + DisplayGroupManager.spawnPersistentPacketGroups(chunk); if (entities.isEmpty()) return; Set foundGroups = new HashSet<>(); - HashMap> addedInteractionsForEvent = new HashMap<>(); - Set interactions = new HashSet<>(); + HashMap> addedEntitiesForEvent = new HashMap<>(); + Set eligibleNonDisplays = new HashSet<>(); HashMap events = new HashMap<>(); for (Entity entity : entities){ @@ -81,7 +74,7 @@ static void detectGroups(Chunk chunk, List entities){ SpawnedDisplayEntityGroup group = result.group(); foundGroups.add(group); - group.addMissingInteractionEntities(DisplayConfig.getMaximumInteractionSearchRange()); + group.addMissingEntities(DisplayConfig.getMaximumInteractionSearchRange()); if (!result.alreadyLoaded()){ group.playSpawnAnimation(); @@ -100,13 +93,13 @@ static void detectGroups(Chunk chunk, List entities){ events.put(group, new ChunkRegisterGroupEvent(group, chunk)); } } - - //Interaction Entities (Required if the interaction happens to be in a different chunk) - else if (entity instanceof Interaction interaction) { - interactions.add(interaction); - } - //Entity with Packet Based Controller else{ + //(Required if the entity happens to be in a different chunk) + if (DisplayUtils.isPartEntity(entity)) { + eligibleNonDisplays.add(entity); + } + + //Entity with Packet Based Controller PersistentDataContainer pdc = entity.getPersistentDataContainer(); String controllerID = pdc.get(DisplayControllerManager.controllerIdKey, PersistentDataType.STRING); if (controllerID == null) continue; //Not a packet based controller @@ -120,13 +113,13 @@ else if (entity instanceof Interaction interaction) { } } - for (Interaction interaction : interactions){ //Processed after all Display Entities - if (SpawnedDisplayEntityPart.getPart(interaction) != null){ //Already added to a group + for (Entity entity : eligibleNonDisplays){ //Processed after all Display Entities + if (SpawnedDisplayEntityPart.getPart(entity) != null){ //Already added to a group continue; } //Bukkit.getScheduler().runTask(DisplayAPI.getPlugin(), () -> { - List results = DisplayGroupManager.getSpawnedGroupsNearLocation(interaction.getLocation(), DisplayConfig.getMaximumInteractionSearchRange()); + List results = DisplayGroupManager.getSpawnedGroupsNearLocation(entity.getLocation(), DisplayConfig.getMaximumInteractionSearchRange()); if (results.isEmpty()){ //Group has not been created yet, or it is not a group interaction continue; } @@ -134,12 +127,12 @@ else if (entity instanceof Interaction interaction) { for (GroupResult result : results){ SpawnedDisplayEntityGroup group = result.group(); - if (group.hasSameCreationTime(interaction)) { - group.addInteractionEntity(interaction); + if (group.hasSameCreationTime(entity)) { + group.addEntity(entity); if (!events.containsKey(group)){ - addedInteractionsForEvent.putIfAbsent(result.group(), new HashSet<>()); - addedInteractionsForEvent.get(group).add(interaction); + addedEntitiesForEvent.putIfAbsent(result.group(), new HashSet<>()); + addedEntitiesForEvent.get(group).add(entity); } } } @@ -158,15 +151,15 @@ else if (entity instanceof Interaction interaction) { event.callEvent(); } - for (Map.Entry> entry : addedInteractionsForEvent.entrySet()){ + for (Map.Entry> entry : addedEntitiesForEvent.entrySet()){ SpawnedDisplayEntityGroup g = entry.getKey(); if (!g.isSpawned()){ continue; } - Collection coll = entry.getValue(); + Set coll = entry.getValue(); if (!coll.isEmpty()){ - new ChunkAddGroupInteractionsEvent(g, addedInteractionsForEvent.get(g), chunk).callEvent(); + new ChunkAddGroupEntitiesEvent(g, addedEntitiesForEvent.get(g), chunk).callEvent(); } } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/DEULoadingListeners.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/DEULoadingListeners.java index 1f19e1da..de2aef54 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/DEULoadingListeners.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/autogroup/DEULoadingListeners.java @@ -23,16 +23,7 @@ public final class DEULoadingListeners implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onEntityLoad(EntitiesLoadEvent e){ - Chunk chunk = e.getChunk(); - //if (chunk.isLoaded()){ - AutoGroup.detectGroups(chunk, e.getEntities()); - //} -// else{ -// CompletableFuture futureChunk = e.getWorld().getChunkAtAsync(chunk.getX(), chunk.getZ()); -// futureChunk.thenAccept(c -> { -// Bukkit.getScheduler().runTask(DisplayAPI.getPlugin(), () -> AutoGroup.detectGroups(c, e.getEntities())); -// }); -// } + AutoGroup.detectGroups(e.getChunk(), e.getEntities()); } @EventHandler(priority = EventPriority.LOWEST) diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/bdengine/DatapackEntitySpawned.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/bdengine/DatapackEntitySpawned.java index f136b3df..4e9668d3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/bdengine/DatapackEntitySpawned.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/bdengine/DatapackEntitySpawned.java @@ -1,8 +1,8 @@ package net.donnypz.displayentityutils.listeners.bdengine; -import net.donnypz.displayentityutils.managers.LocalManager; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.utils.bdengine.convert.datapack.BDEngineDPConverter; import org.bukkit.Location; import org.bukkit.entity.Display; import org.bukkit.entity.Entity; @@ -71,7 +71,7 @@ private static void applyToEntity(Display display, Object projectValue){ //DisplayEntityGroups created outside the animator spawn ungrouped parts last, //while the animator spawns them after the MAIN master part if (tag.contains(projectValue +"_")) { - display.addScoreboardTag(LocalManager.datapackUngroupedAddLaterTag); + display.addScoreboardTag(BDEngineDPConverter.UNGROUPED_ADD_LATER_TAG); } group.addDisplayEntity(display); } @@ -108,10 +108,10 @@ private static void finalize(SpawnedDisplayEntityGroup group){ } Display display = (Display) part.getEntity(); - if (display.getScoreboardTags().contains(LocalManager.datapackConvertDeleteSubParentTag)){ + if (display.getScoreboardTags().contains(BDEngineDPConverter.CONVERT_DELETE_SUB_PARENT_TAG)){ part.remove(true); } - else if (display.getScoreboardTags().contains(LocalManager.datapackUngroupedAddLaterTag)){ + else if (display.getScoreboardTags().contains(BDEngineDPConverter.UNGROUPED_ADD_LATER_TAG)){ laterParts.add(part.remove(false)); } else{ @@ -119,8 +119,8 @@ else if (display.getScoreboardTags().contains(LocalManager.datapackUngroupedAddL } } - for (Entity part : laterParts){ - group.addPartEntity(part); + for (Entity partEntity : laterParts){ + group.addEntity(partEntity); } } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUEntityListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUEntityListener.java index 3fcf4c05..65b2eb60 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUEntityListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUEntityListener.java @@ -10,6 +10,7 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.machine.DisplayStateMachine; import net.donnypz.displayentityutils.utils.DisplayEntities.machine.MachineState; +import net.donnypz.displayentityutils.utils.DisplayUtils; import net.donnypz.displayentityutils.utils.controller.DisplayControllerManager; import org.bukkit.Location; import org.bukkit.damage.DamageSource; @@ -44,6 +45,14 @@ public void onDamaged(EntityDamageEvent e){ applyState(e.getEntity(), MachineState.StateType.DAMAGED); } + //Disable non-display entity damage, if in a group + @EventHandler(priority = EventPriority.HIGHEST) + public void onMannequinDamaged(EntityDamageByEntityEvent e){ + if (DisplayUtils.isInGroup(e.getEntity())) { + e.setCancelled(true); + } + } + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onMelee(EntityDamageByEntityEvent e){ DamageSource source = e.getDamageSource(); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUInteractionListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUInteractionListener.java index dd325050..4762e361 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUInteractionListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUInteractionListener.java @@ -128,7 +128,7 @@ public void onPacketReceive(PacketReceiveEvent event) { } //Right Click - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST) private void rClick(PlayerInteractEntityEvent e){ if (e.getRightClicked() instanceof Interaction entity){ determineBukkitAction(entity, e.getPlayer(), InteractionClickEvent.ClickType.RIGHT); @@ -136,7 +136,7 @@ private void rClick(PlayerInteractEntityEvent e){ } //Left Click - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST) private void lClick(EntityDamageByEntityEvent e){ if (e.getEntity() instanceof Interaction entity){ determineBukkitAction(entity, (Player) e.getDamager(), InteractionClickEvent.ClickType.LEFT); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUMannequinEditorListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUMannequinEditorListener.java new file mode 100644 index 00000000..b3c81d56 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/entity/DEUMannequinEditorListener.java @@ -0,0 +1,90 @@ +package net.donnypz.displayentityutils.listeners.entity; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.mannequin.ui.MannequinEquipmentGUI; +import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; +import net.donnypz.displayentityutils.utils.version.VersionUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +public class DEUMannequinEditorListener implements Listener { + + +// @EventHandler(priority = EventPriority.HIGHEST) +// public void onInventoryDrag(InventoryDragEvent event){ +// if (!VersionUtils.IS_1_21_9) return; +// Inventory inv = event.getInventory(); +// +// Player player = (Player) event.getWhoClicked(); +// DEUUser user = DEUUser.getUser(player); +// if (user == null || !user.isEditingMannequinArmor()) return; +// +// ActivePart part = ActivePart.getPart(user.getEditingMannequin()); +// if (part == null || !MannequinArmorGUI.isMannequinInventory(inv, part)) return; +// +// event.setCancelled(true); +// } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onInventoryClick(InventoryClickEvent event){ + if (!VersionUtils.canSpawnMannequins()) return; + Inventory inv = event.getInventory(); + + Player player = (Player) event.getWhoClicked(); + DEUUser user = DEUUser.getUser(player); + if (user == null || !user.isEditingMannequinArmor()) return; + + ActivePart part = ActivePart.getPart(user.getEditingMannequin()); + if (part == null || !MannequinEquipmentGUI.isMannequinInventory(inv, part)) return; + + if (MannequinEquipmentGUI.isBackgroundItem(event.getCurrentItem())){ + event.setCancelled(true); + return; + } + + if (MannequinEquipmentGUI.isExitItem(event.getCurrentItem())) { + event.setCancelled(true); + player.closeInventory(); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryClose(InventoryCloseEvent event) { + if (!VersionUtils.canSpawnMannequins()) return; + Inventory inv = event.getInventory(); + + Player player = (Player) event.getPlayer(); + DEUUser user = DEUUser.getUser(player); + if (user == null || !user.isEditingMannequinArmor()) return; + + ActivePart part = ActivePart.getPart(user.getEditingMannequin()); + if (part == null || !MannequinEquipmentGUI.isMannequinInventory(inv, part)) return; + + user.setEditingMannequinArmor(null); + MannequinEquipmentGUI.removeMannequin(part.getEntityId()); + + part.setMannequinEquipment(EquipmentSlot.HEAD, getItem(inv, MannequinEquipmentGUI.getHelmetSlot())); + part.setMannequinEquipment(EquipmentSlot.CHEST, getItem(inv, MannequinEquipmentGUI.getChestplateSlot())); + part.setMannequinEquipment(EquipmentSlot.LEGS, getItem(inv, MannequinEquipmentGUI.getLeggingsSlot())); + part.setMannequinEquipment(EquipmentSlot.FEET, getItem(inv, MannequinEquipmentGUI.getBootsSlot())); + part.setMannequinEquipment(EquipmentSlot.HAND, getItem(inv, MannequinEquipmentGUI.getMainHandSlot())); + part.setMannequinEquipment(EquipmentSlot.OFF_HAND, getItem(inv, MannequinEquipmentGUI.getOffHandSlot())); + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text("Mannequin Equipment Set!", NamedTextColor.GREEN))); + } + + private ItemStack getItem(Inventory inv, int slot){ + ItemStack i = inv.getItem(slot); + return i == null ? new ItemStack(Material.AIR) : i; + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerConnectionListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerConnectionListener.java index 1ea005a7..3b4ae2d9 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerConnectionListener.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerConnectionListener.java @@ -4,6 +4,7 @@ import com.google.gson.JsonParser; import net.donnypz.displayentityutils.DisplayAPI; import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.utils.relativepoints.RelativePointUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; @@ -67,6 +68,7 @@ public void onQuit(PlayerQuitEvent e){ if (user != null){ user.remove(); } + RelativePointUtils.removeRelativePoints(player); } private String getLatest() throws IOException, InterruptedException, URISyntaxException { diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java new file mode 100644 index 00000000..81db2ea3 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerDigListener.java @@ -0,0 +1,108 @@ +package net.donnypz.displayentityutils.listeners.player; + +import com.jeff_media.customblockdata.CustomBlockData; +import io.papermc.paper.event.block.BlockBreakProgressUpdateEvent; +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.command.Permission; +import net.donnypz.displayentityutils.events.PlacedGroupBreakEvent; +import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; + +import java.util.UUID; + +public class DEUPlayerDigListener implements Listener { + + @EventHandler(priority = EventPriority.HIGHEST) + public void onDig(BlockBreakProgressUpdateEvent e){ + if (!(e.getEntity() instanceof Player player)){ + return; + } + + if (e.getProgress() != 0){ + return; + } + + Block b = e.getBlock(); + breakPlacedGroup(player, b); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onBreak(BlockBreakEvent e){ + Player p = e.getPlayer(); + Block b = e.getBlock(); + if (p.getGameMode() == GameMode.CREATIVE && b.getType() == Material.BARRIER){ + if (!breakPlacedGroup(e.getPlayer(), e.getBlock())) e.setCancelled(true); + } + } + + //bool determines whether to break the block or not + private boolean breakPlacedGroup(Player player, Block block){ + CustomBlockData data = new CustomBlockData(block, DisplayAPI.getPlugin()); + + String groupId = data.get(DisplayAPI.getPlaceableGroupId(), PersistentDataType.STRING); + if (groupId == null) return true; //Not a placed group block + + PacketDisplayEntityGroup group = PacketDisplayEntityGroup.getGroup(groupId); + if (group == null){ //group was removed by other means + clearPDC(data); + if (block.getType() == Material.BARRIER) block.setType(Material.AIR); + return true; + } + + ItemStack itemStack = PlaceableGroupManager.getItemStack(block); + String uuidString = data.get(DisplayAPI.getPlaceableGroupPlacer(), PersistentDataType.STRING); + UUID placerUUID = uuidString == null ? null : UUID.fromString(uuidString); + + DEUUser user = DEUUser.getUser(player); + if ((user == null || !user.isInPlacedGroupBreakMode()) + && placerUUID != null + && PlaceableGroupManager.isPlacerBreaksOnly(itemStack) + && !player.getUniqueId().equals(placerUUID)) { + player.sendMessage(Component.text("Only the player who placed this can break it!", NamedTextColor.RED)); + if (player.hasPermission(Permission.PLACE_BREAK_MODE.getPermission())) { + player.sendMessage(Component.text("| You have permission to enter break-mode with \"/deu place breakmode\"", NamedTextColor.GRAY)); + } + return false; + } + + + if (!new PlacedGroupBreakEvent(block, group, player).callEvent()) return false; + + Location blockLoc = block.getLocation().add(0.5f, 0.5f, 0.5f); + + if (PlaceableGroupManager.isDropItem(itemStack) && player.getGameMode() != GameMode.CREATIVE) { + final ItemStack finalItemStack = itemStack; + DisplayAPI.getScheduler().run(() -> { + block.getWorld().dropItemNaturally(blockLoc, finalItemStack); + }); + } + + DisplayGroupManager.removePersistentPacketGroup(group, true); + PlaceableGroupManager.playSounds(itemStack, blockLoc, false); + clearPDC(data); + block.setType(Material.AIR); + return true; + } + + private void clearPDC(CustomBlockData data){ + data.clear(); +// data.remove(DisplayAPI.getPlaceableGroupId()); +// data.remove(DisplayAPI.getPlaceableGroupPlacer()); +// data.remove(DisplayAPI.getPlaceableGroupItemStack()); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java new file mode 100644 index 00000000..53daaece --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/listeners/player/DEUPlayerPlaceBlockListener.java @@ -0,0 +1,83 @@ +package net.donnypz.displayentityutils.listeners.player; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.events.PreItemPlaceGroupEvent; +import net.donnypz.displayentityutils.managers.PlaceableGroupManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; +import org.joml.Quaternionf; + + +public class DEUPlayerPlaceBlockListener implements Listener { + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPlaceBlock(BlockPlaceEvent e){ + Player player = e.getPlayer(); + ItemStack heldItem = player.getInventory().getItemInMainHand(); + if (!heldItem.getType().isBlock()){ + return; + } + + if (!PlaceableGroupManager.hasData(heldItem)){ + return; + } + + e.setCancelled(true); + if (!PlaceableGroupManager.canPlace(heldItem, player)){ + player.sendMessage(Component.text("You do not have permission to use this!", NamedTextColor.RED)); + return; + } + + BlockFace face = e.getBlockAgainst().getFace(e.getBlockPlaced()); + if (face == BlockFace.SELF){ + player.sendMessage(Component.text("You cannot place this inside another block!", NamedTextColor.RED)); + return; + } + + Quaternionf rot; + Location placeLoc; + + if (face != null && PlaceableGroupManager.isRespectingBlockFace(heldItem)){ + Vector faceDir = face.getDirection(); + rot = getRotation(faceDir); + placeLoc = e.getBlockPlaced().getLocation() + .add(0.5f, 0.5f, 0.5f) + .subtract(faceDir.multiply(0.499)); + } + else{ + rot = new Quaternionf(); + placeLoc = e.getBlockPlaced().getLocation().add(0.5, 0, 0.5); + } + + + if ((face == BlockFace.UP || face == BlockFace.DOWN) && PlaceableGroupManager.isRespectingPlayerFacing(heldItem)){ + placeLoc.setYaw(player.getYaw()+180); + } + + ItemStack itemClone = heldItem.clone(); + itemClone.setAmount(1); + if (!new PreItemPlaceGroupEvent(itemClone, player).callEvent()) return; + DisplayAPI.getScheduler().runAsync(() -> { + PlaceableGroupManager.spawnGroup(itemClone, placeLoc, rot, player); + PlaceableGroupManager.playSounds(itemClone, placeLoc, true); + }); + if (player.getGameMode() != GameMode.CREATIVE){ + heldItem.setAmount(heldItem.getAmount()-1); + } + } + + private Quaternionf getRotation(Vector faceDir){ + Vector upVec = new Vector(0, 1, 0); + return upVec.toVector3f().rotationTo(faceDir.toVector3f(), new Quaternionf()); + } +} diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/managers/LocalManager.java b/plugin/src/main/java/net/donnypz/displayentityutils/managers/LocalManager.java index aba3da71..01da25ab 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/managers/LocalManager.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/managers/LocalManager.java @@ -17,8 +17,6 @@ import java.util.zip.GZIPOutputStream; public final class LocalManager implements DisplayStorage{ - public static final String datapackConvertDeleteSubParentTag = "deu_delete_sub_parent"; - public static final String datapackUngroupedAddLaterTag = "deu_add_later"; public boolean saveDisplayEntityGroup(@NotNull DisplayEntityGroup displayEntityGroup, @Nullable Player saver){ try{ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/SkriptTypes.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/SkriptTypes.java index ef4930f8..3594409e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/SkriptTypes.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/SkriptTypes.java @@ -448,10 +448,11 @@ public String toVariableNameString(InteractionCommand o) { EnumWrapper partTypeWrapper = new EnumWrapper<>(SpawnedDisplayEntityPart.PartType.class, null, null); partTypeWrapper.replace("interaction", "deu_interaction"); + partTypeWrapper.replace("mannequin", "deu_mannequin"); Classes.registerClass(partTypeWrapper.getClassInfo("parttype") .user("part( | -)?type") .name("Part Type") - .description("Represents a part type being BLOCK_DISPLAY, ITEM_DISPLAY, TEXT_DISPLAY, or INTERACTION") + .description("Represents a part's (display, interaction, etc.) type") .since("2.6.2, 3.3.6 (Removed \"parttype_\" prefix)")); EnumWrapper clickTypeWrapper = new EnumWrapper<>(InteractionClickEvent.ClickType.class, "iClickType", null); diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/effects/EffActiveGroupUnregister.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/effects/EffActiveGroupUnregister.java index 064be915..5cc26ec3 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/effects/EffActiveGroupUnregister.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/effects/EffActiveGroupUnregister.java @@ -9,6 +9,7 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityGroup; import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; @@ -48,7 +49,12 @@ protected void execute(Event event) { sg.unregister(despawn, forced); } else if (g instanceof PacketDisplayEntityGroup pg){ - pg.unregister(); + if (pg.isPersistent()){ + DisplayGroupManager.removePersistentPacketGroup(pg, true); + } + else{ + pg.unregister(); + } } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/events/SimpleEvents.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/events/SimpleEvents.java index cdffcfe6..a6c6e2cd 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/events/SimpleEvents.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/events/SimpleEvents.java @@ -11,6 +11,7 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Interaction; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.ApiStatus; import java.util.UUID; @@ -79,6 +80,22 @@ public class SimpleEvents extends SimpleEvent { EventValues.registerEventValue(PacketGroupDestroyEvent.class, PacketDisplayEntityGroup.class, PacketGroupDestroyEvent::getGroup); EventValues.registerEventValue(PacketGroupDestroyEvent.class, Player[].class, e -> e.getPlayers().toArray(new Player[0])); + //Pre Item Place Group Event + Skript.registerEvent("Item Place Group Event", SimpleEvents.class, PreItemPlaceGroupEvent.class, "pre item place[d] [packet] [display] group") + .description("Called before a player places a packet-based using an item") + .since("3.4.0"); + EventValues.registerEventValue(PreItemPlaceGroupEvent.class, String.class, PreItemPlaceGroupEvent::getGroupTag); + EventValues.registerEventValue(PreItemPlaceGroupEvent.class, Player.class, PreItemPlaceGroupEvent::getPlayer); + EventValues.registerEventValue(PreItemPlaceGroupEvent.class, ItemStack.class, PreItemPlaceGroupEvent::getItemStack); + + //Item Place Group Event + Skript.registerEvent("Item Place Group Event", SimpleEvents.class, ItemPlaceGroupEvent.class, "item place[d] [packet] [display] group") + .description("Called when a player places a packet-based using an item") + .since("3.4.0"); + EventValues.registerEventValue(ItemPlaceGroupEvent.class, ActiveGroup.class, ItemPlaceGroupEvent::getGroup); + EventValues.registerEventValue(ItemPlaceGroupEvent.class, Player.class, ItemPlaceGroupEvent::getPlayer); + EventValues.registerEventValue(ItemPlaceGroupEvent.class, ItemStack.class, ItemPlaceGroupEvent::getItemStack); + //Animation Start Event Skript.registerEvent("Animation Start", SimpleEvents.class, AnimationStartEvent.class, "[deu] anim[ation] start[ed]") .description("Called when a display animator starts playing an animation") diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGetGroup.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGetGroup.java index 0c8c0d18..8abbe22e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGetGroup.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGetGroup.java @@ -12,6 +12,7 @@ import net.donnypz.displayentityutils.utils.DisplayEntities.MultiPartSelection; import net.donnypz.displayentityutils.utils.GroupResult; import org.bukkit.entity.Display; +import org.bukkit.entity.Entity; import org.bukkit.entity.Interaction; import org.jetbrains.annotations.Nullable; @@ -50,8 +51,8 @@ else if (obj instanceof Display display){ if (result == null) return null; return result.group(); } - else if (obj instanceof Interaction interaction){ - return DisplayGroupManager.getSpawnedGroup(interaction, DisplayConfig.getMaximumInteractionSearchRange()); + else if (obj instanceof Entity entity){ + return DisplayGroupManager.getSpawnedGroup(entity, DisplayConfig.getMaximumInteractionSearchRange()); } return null; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGlowColor.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGlowColor.java index eec4c379..8e7fa978 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGlowColor.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActiveGlowColor.java @@ -49,8 +49,8 @@ else if (object instanceof ActivePart part){ if (part.getGlowColor() != null){ return ColorRGB.fromBukkitColor(part.getGlowColor()); } - else if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - Skript.error("You can not get the glow color of an INTERACTION active part"); + else if (!part.isDisplay()){ + Skript.error("You can only get the glow color of a DISPLAY active part"); } return null; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActivePartTransLocation.java b/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActivePartTransLocation.java index 572f5c1d..32d0bb5b 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActivePartTransLocation.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/skript/expressions/ExprActivePartTransLocation.java @@ -5,12 +5,11 @@ import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; -import net.donnypz.displayentityutils.utils.DisplayEntities.PacketDisplayEntityPart; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActivePart; import net.donnypz.displayentityutils.utils.DisplayUtils; import org.bukkit.Location; import org.bukkit.entity.Display; -import org.bukkit.entity.Interaction; +import org.bukkit.entity.Entity; import org.jetbrains.annotations.Nullable; @Name("Translated Location of Active Part / Entity") @@ -32,27 +31,19 @@ public Class getReturnType() { @Override @Nullable public Location convert(Object o) { - if (o instanceof SpawnedDisplayEntityPart part){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ - return part.getLocation(); + if (o instanceof ActivePart part){ + if (part.isDisplay()){ + return DisplayUtils.getModelLocation(part); } else{ - return DisplayUtils.getModelLocation((Display) part.getEntity()); - } - } - else if (o instanceof PacketDisplayEntityPart part){ - if (part.getType() == SpawnedDisplayEntityPart.PartType.INTERACTION){ return part.getLocation(); } - else{ - return DisplayUtils.getModelLocation(part); - } } else if (o instanceof Display d){ return DisplayUtils.getModelLocation(d); } - else if (o instanceof Interaction i){ - return i.getLocation(); + else if (o instanceof Entity e && DisplayUtils.isPartEntity(e)){ + return e.getLocation(); } return null; } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineDPConverter.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineDPConverter.java index 8cbecd76..cb8d9e82 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineDPConverter.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineDPConverter.java @@ -4,10 +4,7 @@ import net.donnypz.displayentityutils.listeners.bdengine.DatapackEntitySpawned; import net.donnypz.displayentityutils.managers.*; import net.donnypz.displayentityutils.utils.ConversionUtils; -import net.donnypz.displayentityutils.utils.DisplayEntities.AnimationCamera; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayAnimation; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayAnimationFrame; -import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.*; import net.donnypz.displayentityutils.utils.version.VersionUtils; import net.donnypz.displayentityutils.utils.version.folia.Scheduler; import net.kyori.adventure.text.Component; @@ -23,15 +20,16 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.LinkedHashMap; -import java.util.List; +import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class BDEngineDPConverter { + private static final String FRAME_POINT_SOUND_TAG = "deu_dp_convert"; + public static final String CONVERT_DELETE_SUB_PARENT_TAG = "deu_delete_sub_parent"; + public static final String UNGROUPED_ADD_LATER_TAG = "deu_add_later"; + static final CommandSender silentSender = Bukkit.createCommandSender(feedback -> {}); static final String FUNCTION_FOLDER = VersionUtils.IS_1_21 ? "function" : "functions"; private static final String CREATE_MODEL_PATH = "/create.mcfunction"; @@ -40,6 +38,8 @@ public class BDEngineDPConverter { private final String groupSaveTag; private final String animationSavePrefix; private final LinkedHashMap> animations = new LinkedHashMap<>(); + private final HashSet bufferedSounds = new HashSet<>(); + Location spawnLoc; public BDEngineDPConverter(@NotNull Player player, @NotNull String datapackName, @NotNull String groupSaveTag, @NotNull String animationSavePrefix){ @@ -201,6 +201,17 @@ public void run() { //Create Frame frame.setTransformation(createdGroup); + + //Add Sounds + if (!bufferedSounds.isEmpty()){ + FramePoint point = new FramePoint(FRAME_POINT_SOUND_TAG, createdGroup, spawnLoc); + for (DEUSound sound : bufferedSounds){ + point.addSound(sound); + } + bufferedSounds.clear(); + frame.addFramePoint(point); + } + anim.addFrame(frame); i++; } @@ -261,8 +272,9 @@ else if (line.contains("@s")){ line = line.replace("@s", player.getName()); line = "execute"+line.split("nearest]")[1]; } - - line = line.substring(0, line.length()-2)+",\""+LocalManager.datapackConvertDeleteSubParentTag+"\"]}"; + if (!line.startsWith("ride")) { + line = line.substring(0, line.length()-2)+",\""+CONVERT_DELETE_SUB_PARENT_TAG+"\"]}"; + } } else if (line.startsWith("schedule")) { @@ -277,6 +289,20 @@ else if (line.startsWith("schedule")) { continue; } + //Animation Sound + if (line.startsWith("playsound")){ + DEUSound sound = getSound(line); + if (sound != null){ + bufferedSounds.add(sound); + } + } + else if (line.startsWith("execute") && line.contains("playsound")){ + DEUSound sound = getSound("."+line.split(" playsound ")[1]); + if (sound != null){ + bufferedSounds.add(sound); + } + } + String coordinates = ConversionUtils.getCoordinateString(spawnLoc); World w = spawnLoc.getWorld(); String worldName = ConversionUtils.getExecuteCommandWorldName(w); @@ -308,7 +334,27 @@ private void setCameraVectorAndDirection(SpawnedDisplayAnimationFrame frame, Str Location cameraLoc = spawnLoc.clone().add(x, y, z); cameraLoc.getWorld().spawnParticle(Particle.DRAGON_BREATH, cameraLoc, 1, 0,0,0,0); } catch(IndexOutOfBoundsException e){} + } + + DEUSound getSound(String line){ + String[] strings = line.split(" "); + String soundStr = strings[1]; + float volume = -1; + float pitch = -1; + try{ + volume = Float.parseFloat(strings[7]); + pitch = Float.parseFloat(strings[8]); + } + catch(IllegalArgumentException | IndexOutOfBoundsException e){ + if (volume == -1){ + volume = 1; + } + if (pitch == -1){ + pitch = 1; + } + } + return new DEUSound(soundStr, volume, pitch, 0); } } diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineLegacyDPConverter.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineLegacyDPConverter.java index fa2340a2..35af044e 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineLegacyDPConverter.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/bdengine/convert/datapack/BDEngineLegacyDPConverter.java @@ -231,7 +231,7 @@ else if (line.contains("@s")){ String replacement = player.getName(); line = line.replace("@s", replacement); } - line = line.substring(0, line.length()-2)+",\""+LocalManager.datapackConvertDeleteSubParentTag+"\"]}"; + line = line.substring(0, line.length()-2)+",\""+BDEngineDPConverter.CONVERT_DELETE_SUB_PARENT_TAG +"\"]}"; } else if (zipEntry.getName().contains("start_animation.mcfunction")){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/command/DEUCommandUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/command/DEUCommandUtils.java index a8aba4b9..66e62c4f 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/command/DEUCommandUtils.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/command/DEUCommandUtils.java @@ -21,14 +21,12 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.util.RayTraceResult; -import org.jetbrains.annotations.ApiStatus; import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.UUID; -@ApiStatus.Internal public class DEUCommandUtils { public static void removeRelativePoint(Player player, RelativePointSelector selector){ diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/dialogs/TextDisplayDialog.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/dialogs/TextDisplayDialog.java index e5275188..1717d2e1 100644 --- a/plugin/src/main/java/net/donnypz/displayentityutils/utils/dialogs/TextDisplayDialog.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/dialogs/TextDisplayDialog.java @@ -43,8 +43,6 @@ public final class TextDisplayDialog{ private static final String COLOR_CODE = "deu_text_display_color_code"; private static final String BACKGROUND_COLOR = "deu_text_display_background_color"; - private static final DialogAction CONFIRM_ACTION = getConfirmAction(); - private TextDisplayDialog(){} @@ -55,19 +53,7 @@ private TextDisplayDialog(){} * @param miniMessageFormatted whether the text display's text should be formatted as minimessage or ampersand */ public static void sendDialog(@NotNull Player player, @NotNull TextDisplay textDisplay, boolean miniMessageFormatted){ - Dialog dialog = Dialog.create(builder -> { - builder.empty() - .base(DialogBase.builder(Component.text("Edit a Text Display")) - .inputs(getInputs(textDisplay, miniMessageFormatted)) - .build()) - .type(DialogType.confirmation(ActionButton.create(Component.text("Confirm", NamedTextColor.GREEN), - Component.text("Set your selected text display's text", NamedTextColor.YELLOW), - 200, CONFIRM_ACTION), - ActionButton.create(Component.text("Cancel", NamedTextColor.RED), - Component.text("Cancel this action", NamedTextColor.YELLOW), - 200, null))); - }); - player.showDialog(dialog); + sendDialog(player, SpawnedDisplayEntityPart.create(textDisplay), miniMessageFormatted); } /** @@ -85,7 +71,7 @@ public static void sendDialog(@NotNull Player player, @NotNull ActivePart textDi .build()) .type(DialogType.confirmation(ActionButton.create(Component.text("Confirm", NamedTextColor.GREEN), Component.text("Set your selected text display's text", NamedTextColor.YELLOW), - 200, CONFIRM_ACTION), + 200, getConfirmAction(textDisplayPart)), ActionButton.create(Component.text("Cancel", NamedTextColor.RED), Component.text("Cancel this action", NamedTextColor.YELLOW), 200, null))); @@ -108,21 +94,6 @@ public static void sendDialog(@NotNull Player player, @NotNull UUID entityUUID, sendDialog(player, textDisplay, miniMessageFormatted); } - private static List getInputs(TextDisplay textDisplay, boolean miniMessageFormatted){ - return List.of( - getColorType(miniMessageFormatted), - getTextInput(textDisplay.text(), miniMessageFormatted), - getFont(textDisplay.text().font()), - getAlignment(textDisplay.getAlignment()), - getLineWidth(textDisplay.getLineWidth()), - getOpacity(textDisplay.getTextOpacity()), - getBackgroundColor(), - getShadow(textDisplay.isShadowed()), - getSeeThrough(textDisplay.isSeeThrough()), - getDefaultBackground(textDisplay.isDefaultBackground()) - ); - } - private static List getInputs(ActivePart part, boolean miniMessageFormatted){ Component text = part.getTextDisplayText(); return List.of( @@ -230,19 +201,14 @@ private static DialogInput getDefaultBackground(boolean defaultBackground){ .build(); } - private static DialogAction getConfirmAction(){ + private static DialogAction getConfirmAction(ActivePart part){ return DialogAction.customClick((view, audience) -> { Player p = (Player) audience; ActivePartSelection selection = DisplayGroupManager.getPartSelection(p); - if (selection == null){ + if (selection == null) { p.sendMessage(Component.text("Part selection lost!", NamedTextColor.RED)); return; } - ActivePart part = selection.getSelectedPart(); - if (part == null || part.getType() != SpawnedDisplayEntityPart.PartType.TEXT_DISPLAY){ - p.sendMessage(Component.text("You do not have a text display selected!", NamedTextColor.RED)); - return; - } //Set Text Display Properties Component text; diff --git a/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java new file mode 100644 index 00000000..45806e82 --- /dev/null +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/DisplayEntitySelector.java @@ -0,0 +1,101 @@ +package net.donnypz.displayentityutils.utils.relativepoints; + +import net.donnypz.displayentityutils.DisplayAPI; +import net.donnypz.displayentityutils.managers.DEUUser; +import net.donnypz.displayentityutils.managers.DisplayGroupManager; +import net.donnypz.displayentityutils.utils.DisplayEntities.ActiveGroup; +import net.donnypz.displayentityutils.utils.DisplayEntities.RelativePoint; +import net.donnypz.displayentityutils.utils.DisplayEntities.SinglePartSelection; +import net.donnypz.displayentityutils.utils.DisplayEntities.SpawnedDisplayEntityPart; +import net.donnypz.displayentityutils.utils.DisplayUtils; +import net.donnypz.displayentityutils.utils.version.VersionUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.*; + +public class DisplayEntitySelector extends RelativePointSelector { + + Display display; + + DisplayEntitySelector(Player player, Display display){ + super(player, + DisplayUtils.getModelLocation(display), + null, + Material.LIME_STAINED_GLASS, + display.getTransformation()); + this.display = display; + } + + @Override + public boolean removeFromPointHolder() { + return true; + } + + @Override + public void sendInfo(Player player) { + player.sendMessage(MiniMessage.miniMessage().deserialize("Entity Type: " + display.getType().name())); + player.sendMessage(MiniMessage.miniMessage().deserialize("Persistent: "+(display.isPersistent() ? "TRUE" : "FALSE"))); + player.sendMessage(Component.text("| Add to your selected group", NamedTextColor.AQUA) + .clickEvent(ClickEvent.callback(a -> { + Player p = (Player) a; + ActiveGroup group = DisplayGroupManager.getSelectedGroup(player); + if (group == null){ + p.sendMessage(DisplayAPI.pluginPrefix + .append(Component.text("You do not have a group selected!", NamedTextColor.RED))); + return; + } + player.sendMessage(DisplayAPI.pluginPrefix + .append(Component.text("Entity added to your selected group!", NamedTextColor.GREEN))); + Location groupLoc = group.getLocation(); + display.setRotation(groupLoc.getYaw(), groupLoc.getPitch()); + group.addEntity(display); + RelativePointUtils.removeRelativePoints(player); + }))); + player.sendMessage(Component.empty()); + } + + @Override + public void rightClick(Player player) { + DisplayAPI.getScheduler().run(() -> { + select(player, display); + }); + } + + public static void select(Player player, Entity entity){ + SpawnedDisplayEntityPart existing = SpawnedDisplayEntityPart.getPart(entity); + if (existing != null){ + player.sendMessage(Component.text("That part is already in a group!", NamedTextColor.RED)); + player.sendMessage(Component.text("| Select the group, then cycle through the group's parts", NamedTextColor.GRAY)); + return; + } + + SpawnedDisplayEntityPart part = SpawnedDisplayEntityPart.create(entity.getUniqueId()); + if (part == null){ + player.sendMessage(Component.text("That entity is no longer valid!", NamedTextColor.RED)); + return; + } + DEUUser + .getOrCreateUser(player) + .setSelectedPartSelection(new SinglePartSelection(part), false); + part.glow(player, 30); + RelativePointUtils.removeRelativePoints(player); + String entityType; + if (entity instanceof Display){ + entityType = "Display"; + } + else if (entity instanceof Interaction){ + entityType = "Interaction"; + } + else if (VersionUtils.canSpawnMannequins() && entity instanceof Mannequin){ + entityType = "Mannequin"; + } + else{ + entityType = ""; + } + player.sendMessage(DisplayAPI.pluginPrefix.append(Component.text(entityType+" Entity Selected!", NamedTextColor.GREEN))); + } +} diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/FramePointSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/FramePointSelector.java similarity index 100% rename from api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/FramePointSelector.java rename to plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/FramePointSelector.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/MultiFramePointHelper.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/MultiFramePointHelper.java similarity index 100% rename from api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/MultiFramePointHelper.java rename to plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/MultiFramePointHelper.java diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java similarity index 98% rename from api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java rename to plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java index 5cdac536..5217084b 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/PacketGroupSelector.java @@ -67,7 +67,6 @@ public void rightClick(Player player) { boolean selectResult = DisplayGroupManager.setSelectedGroup(player, group); if (selectResult){ group.glowAndMarkInteractions(player, 40); - RelativePointUtils.deselectRelativePoint(player); RelativePointUtils.removeRelativePoints(player); player.sendMessage(DisplayAPI.pluginPrefix.append(MiniMessage.miniMessage().deserialize("Selected the clicked point's packet-based group!"))); player.playSound(spawnLocation, Sound.UI_STONECUTTER_TAKE_RESULT, 1, 2f); diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java similarity index 67% rename from api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java rename to plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java index c26d6d68..245dfa3e 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointSelector.java @@ -11,6 +11,7 @@ import org.bukkit.entity.Display; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Transformation; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -61,6 +62,34 @@ public abstract class RelativePointSelector { this.relativePoint = relativePoint; } + RelativePointSelector(Player player, Location spawnLocation, T relativePoint, Material itemType, Transformation transformation){ + Vector3f scaleVector = transformation.getScale(); + float xInteractionScale = scaleVector.x+0.075f; + float yInteractionScale = scaleVector.y+0.075f; + float zInteractionScale = scaleVector.z+0.075f; + this.playerUUID = player.getUniqueId(); + ItemStack stack = new ItemStack(itemType); + displayPart = new PacketAttributeContainer() + .setAttribute(DisplayAttributes.Transform.LEFT_ROTATION, transformation.getLeftRotation()) + .setAttribute(DisplayAttributes.Transform.SCALE, transformation.getScale().add(0.05f, 0.05f, 0.05f)) + .setAttribute(DisplayAttributes.GLOW_COLOR_OVERRIDE, Color.BLACK) + .setAttribute(DisplayAttributes.GLOWING, true) + .setAttribute(DisplayAttributes.BRIGHTNESS, new Display.Brightness(15,15)) + .setAttribute(DisplayAttributes.ItemDisplay.ITEMSTACK, stack) + .createPart(SpawnedDisplayEntityPart.PartType.ITEM_DISPLAY, spawnLocation, pointDisplayTag); + displayPart.showToPlayer(player, GroupSpawnedEvent.SpawnReason.INTERNAL); + + selectPart = new PacketAttributeContainer() + .setAttribute(DisplayAttributes.Interaction.WIDTH, Math.max(xInteractionScale, zInteractionScale)) + .setAttribute(DisplayAttributes.Interaction.HEIGHT, yInteractionScale) + .createPart(SpawnedDisplayEntityPart.PartType.INTERACTION, spawnLocation.clone().subtract(0, yInteractionScale/2, 0), pointDisplayTag); + selectPart.showToPlayer(player, GroupSpawnedEvent.SpawnReason.INTERNAL); + + interactionParts.put(selectPart, this); + + this.spawnLocation = spawnLocation; + this.relativePoint = relativePoint; + } public void select(){ if (!isValid) return; @@ -109,8 +138,8 @@ public void despawn(){ relativePoint = null; Player player = Bukkit.getPlayer(playerUUID); if (player != null){ - displayPart.hideFromPlayer(player); - selectPart.hideFromPlayer(player); + displayPart.remove(); + selectPart.remove(); } isValid = false; } diff --git a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java similarity index 80% rename from api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java rename to plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java index b1c7c514..0d4a854b 100644 --- a/api/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java +++ b/plugin/src/main/java/net/donnypz/displayentityutils/utils/relativepoints/RelativePointUtils.java @@ -1,13 +1,15 @@ package net.donnypz.displayentityutils.utils.relativepoints; import net.donnypz.displayentityutils.utils.DisplayEntities.*; +import net.donnypz.displayentityutils.utils.DisplayUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Sound; +import org.bukkit.entity.Display; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -import org.jetbrains.annotations.ApiStatus; import java.util.*; @@ -16,7 +18,6 @@ public class RelativePointUtils { public static final HashMap>> relativePointSelectors = new HashMap<>(); public static final HashMap> selectedSelector = new HashMap<>(); - @ApiStatus.Internal public static void spawnFramePointDisplays(ActiveGroup group, Player player, SpawnedDisplayAnimationFrame frame){ if (stopIfViewing(player)){ return; @@ -38,7 +39,6 @@ public static void spawnFramePointDisplays(ActiveGroup group, Player player, } - @ApiStatus.Internal public static void spawnPacketGroupPoints(Chunk chunk, Player player){ if (stopIfViewing(player)){ return; @@ -56,10 +56,28 @@ public static void spawnPacketGroupPoints(Chunk chunk, Player player){ setDisplays(player, displays); player.sendMessage(Component.text("| Right click a point to select its packet-based group", NamedTextColor.AQUA)); } + } + public static void spawnDisplayEntityPoints(double distance, Player player){ + removeRelativePoints(player); + Set> displays = new HashSet<>(); + for (Entity e : player.getNearbyEntities(distance, distance, distance)){ + if (DisplayUtils.isInGroup(e)) continue; + DisplayEntitySelector selector; + if (e instanceof Display d){ + selector = new DisplayEntitySelector(player, d); + displays.add(selector); + } + } + if (displays.isEmpty()){ + player.sendMessage(Component.text("Failed to find ungrouped Display entities within the given range!", NamedTextColor.RED)); + } + else{ + setDisplays(player, displays); + player.sendMessage(Component.text("| Right click a point to select an entity", NamedTextColor.AQUA)); + } } - @ApiStatus.Internal public static boolean removeRelativePoints(Player player){ if (player == null) return false; Set> selectors = RelativePointUtils.relativePointSelectors.remove(player.getUniqueId()); diff --git a/plugin/src/main/resources/lang/default.lang b/plugin/src/main/resources/lang/default.lang index 5a2e437b..6a01c9fe 100644 --- a/plugin/src/main/resources/lang/default.lang +++ b/plugin/src/main/resources/lang/default.lang @@ -22,6 +22,7 @@ parttype: item_display: item text_display: text interaction: interaction + mannequin: mannequin types: groupspawnreason: group spawn reason¦s diff --git a/pom.xml b/pom.xml index ac75a46d..75bec5f2 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.donnypz.displayentityutils deu - 3.3.8 + 3.4.0 pom DisplayEntityUtils @@ -64,6 +64,10 @@ org.bstats net.donnypz.displayentityutils.bstats + + com.jeff_media.customblockdata + net.donnypz.displayentityutils.customblockdata + @@ -143,8 +147,8 @@ - md_5-public - https://repo.md-5.net/content/groups/public/ + libsdisguises-public + https://mvn.lib.co.nz/public @@ -158,7 +162,7 @@ com.github.retrooper packetevents-spigot - 2.9.5 + 2.11.0 provided