From 59c7d125df7619c4a4a88893896e0c7fb92c42bc Mon Sep 17 00:00:00 2001 From: YouHaveTrouble Date: Sun, 23 Nov 2025 20:33:58 +0100 Subject: [PATCH] cleanup and make mannequin profile name persistent when converting to and from armor stand --- .../me/youhavetrouble/standin/StandIn.java | 1 - .../ArmorStandToMannequinConverter.java | 33 +++++++++++-------- .../standin/converter/EntityConverter.java | 9 +++-- .../MannequinToArmorStandConverter.java | 30 +++++++++-------- .../standin/entity/EntityHandler.java | 8 ++--- .../standin/entity/MannequinHandler.java | 33 ++++++++++++++++++- 6 files changed, 76 insertions(+), 38 deletions(-) diff --git a/src/main/java/me/youhavetrouble/standin/StandIn.java b/src/main/java/me/youhavetrouble/standin/StandIn.java index fb94edf..fd1cc11 100644 --- a/src/main/java/me/youhavetrouble/standin/StandIn.java +++ b/src/main/java/me/youhavetrouble/standin/StandIn.java @@ -13,7 +13,6 @@ import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; -@SuppressWarnings("UnstableApiUsage") public final class StandIn extends JavaPlugin { public static final NamespacedKey KEY = new NamespacedKey("stand-in", "stand-in"); diff --git a/src/main/java/me/youhavetrouble/standin/converter/ArmorStandToMannequinConverter.java b/src/main/java/me/youhavetrouble/standin/converter/ArmorStandToMannequinConverter.java index c825c43..cca3f53 100644 --- a/src/main/java/me/youhavetrouble/standin/converter/ArmorStandToMannequinConverter.java +++ b/src/main/java/me/youhavetrouble/standin/converter/ArmorStandToMannequinConverter.java @@ -1,48 +1,55 @@ package me.youhavetrouble.standin.converter; +import io.papermc.paper.datacomponent.item.ResolvableProfile; import me.youhavetrouble.standin.StandIn; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.EntityType; import org.bukkit.entity.Mannequin; import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; +@SuppressWarnings("UnstableApiUsage") public class ArmorStandToMannequinConverter implements EntityConverter { @Override - public Class entityFrom() { - return ArmorStand.class; - } - - @Override - public Class entityTo() { - return Mannequin.class; - } - - @Override - public @NotNull EntityType entityFromType() { + public @NotNull EntityType entityFrom() { return EntityType.ARMOR_STAND; } @Override - public @NotNull EntityType entityToType() { + public @NotNull EntityType entityTo() { return EntityType.MANNEQUIN; } @Override public Mannequin spawn(@NotNull ArmorStand from) { try { - return from.getWorld().spawn(from.getLocation(), entityTo(), (mannequin -> { + return from.getWorld().spawn(from.getLocation(), Mannequin.class, (mannequin -> { + mannequin.customName(from.customName()); + mannequin.setImmovable(!from.canMove()); + mannequin.setGravity(from.hasGravity()); for (EquipmentSlot slot : EquipmentSlot.values()) { try { mannequin.getEquipment().setItem(slot, from.getItem(slot)); } catch (IllegalArgumentException ignored) { } } + PersistentDataContainer pdc = from.getPersistentDataContainer(); + String profileName = pdc.get(EntityConverter.PLAYER_PROFILE_KEY, PersistentDataType.STRING); + if (profileName != null) { + try { + mannequin.setProfile(ResolvableProfile.resolvableProfile().name(profileName).build()); + } catch (IllegalArgumentException e) { + StandIn.getPlugin(StandIn.class).getSLF4JLogger().warn("Failed to set profile for mannequin", e); + } + } })); } catch (IllegalArgumentException e) { StandIn.getPlugin(StandIn.class).getSLF4JLogger().warn("Failed to spawn entity", e); return null; } } + } diff --git a/src/main/java/me/youhavetrouble/standin/converter/EntityConverter.java b/src/main/java/me/youhavetrouble/standin/converter/EntityConverter.java index 71396c9..391ac2e 100644 --- a/src/main/java/me/youhavetrouble/standin/converter/EntityConverter.java +++ b/src/main/java/me/youhavetrouble/standin/converter/EntityConverter.java @@ -1,18 +1,17 @@ package me.youhavetrouble.standin.converter; +import org.bukkit.NamespacedKey; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.jetbrains.annotations.NotNull; public interface EntityConverter { - Class entityFrom(); + NamespacedKey PLAYER_PROFILE_KEY = new NamespacedKey("stand-in", "player-profile"); - @NotNull EntityType entityFromType(); + @NotNull EntityType entityFrom(); - @NotNull EntityType entityToType(); - - Class entityTo(); + @NotNull EntityType entityTo(); /** * Spawn the new entity in the old entity's spot. diff --git a/src/main/java/me/youhavetrouble/standin/converter/MannequinToArmorStandConverter.java b/src/main/java/me/youhavetrouble/standin/converter/MannequinToArmorStandConverter.java index 024aa7f..0c45a7d 100644 --- a/src/main/java/me/youhavetrouble/standin/converter/MannequinToArmorStandConverter.java +++ b/src/main/java/me/youhavetrouble/standin/converter/MannequinToArmorStandConverter.java @@ -5,44 +5,46 @@ import org.bukkit.entity.ArmorStand; import org.bukkit.entity.EntityType; import org.bukkit.entity.Mannequin; import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; +@SuppressWarnings("UnstableApiUsage") public class MannequinToArmorStandConverter implements EntityConverter { @Override - public Class entityFrom() { - return Mannequin.class; - } - - @Override - public Class entityTo() { - return ArmorStand.class; - } - - @Override - public @NotNull EntityType entityFromType() { + public @NotNull EntityType entityFrom() { return EntityType.MANNEQUIN; } @Override - public @NotNull EntityType entityToType() { + public @NotNull EntityType entityTo() { return EntityType.ARMOR_STAND; } @Override public ArmorStand spawn(@NotNull Mannequin from) { try { - return from.getWorld().spawn(from.getLocation(), entityTo(), (armorStand -> { + return from.getWorld().spawn(from.getLocation(), ArmorStand.class, (armorStand -> { + armorStand.customName(from.customName()); + armorStand.setGravity(from.hasGravity()); + armorStand.setCanMove(!from.isImmovable()); for (EquipmentSlot slot : EquipmentSlot.values()) { try { - armorStand.getEquipment().setItem(slot, from.getEquipment().getItem(slot)); + armorStand.setItem(slot, from.getEquipment().getItem(slot)); } catch (IllegalArgumentException ignored) { } } + PersistentDataContainer pdc = armorStand.getPersistentDataContainer(); + String profileName = from.getProfile().name(); + if (profileName != null && !profileName.isEmpty()) { + pdc.set(EntityConverter.PLAYER_PROFILE_KEY, PersistentDataType.STRING, profileName); + } })); } catch (IllegalArgumentException e) { StandIn.getPlugin(StandIn.class).getSLF4JLogger().warn("Failed to spawn entity", e); return null; } } + } diff --git a/src/main/java/me/youhavetrouble/standin/entity/EntityHandler.java b/src/main/java/me/youhavetrouble/standin/entity/EntityHandler.java index bd2a2e1..749cb96 100644 --- a/src/main/java/me/youhavetrouble/standin/entity/EntityHandler.java +++ b/src/main/java/me/youhavetrouble/standin/entity/EntityHandler.java @@ -40,7 +40,7 @@ public abstract class EntityHandler { public final Set> getPossibleConversions() { Set> classes = new HashSet<>(); for (EntityConverter converter : possibleConverters) { - classes.add(converter.entityTo()); + classes.add(converter.entityTo().getEntityClass()); } return Collections.unmodifiableSet(classes); } @@ -80,8 +80,8 @@ public abstract class EntityHandler { for (EntityConverter converter : possibleConverters) { entityEntries.add( SingleOptionDialogInput.OptionEntry.create( - converter.entityTo().getName(), - Component.translatable(converter.entityToType().translationKey()), + converter.entityTo().toString(), + Component.translatable(converter.entityTo().translationKey()), false ) ); @@ -109,7 +109,7 @@ public abstract class EntityHandler { if (newEntityType.equals(existing.getClass().getName())) return; // skip if the class is the same EntityConverter foundConverter = null; for (EntityConverter converter : possibleConverters) { - if (!newEntityType.equals(converter.entityTo().getName())) continue; + if (!newEntityType.equals(converter.entityTo().toString())) continue; foundConverter = converter; break; } diff --git a/src/main/java/me/youhavetrouble/standin/entity/MannequinHandler.java b/src/main/java/me/youhavetrouble/standin/entity/MannequinHandler.java index ea5eb96..533c665 100644 --- a/src/main/java/me/youhavetrouble/standin/entity/MannequinHandler.java +++ b/src/main/java/me/youhavetrouble/standin/entity/MannequinHandler.java @@ -1,5 +1,6 @@ package me.youhavetrouble.standin.entity; +import io.papermc.paper.datacomponent.item.ResolvableProfile; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.registry.data.dialog.ActionButton; import io.papermc.paper.registry.data.dialog.DialogBase; @@ -43,12 +44,30 @@ public class MannequinHandler extends EntityHandler { if (customName != null) { name = PlainTextComponentSerializer.plainText().serialize(customName); } - inputs.add( DialogInput.text("name", Component.text("Name")) .initial(name) .build() ); + String profileName = ""; + if (mannequin.getProfile().name() != null) { + profileName = mannequin.getProfile().name(); + } + inputs.add( + DialogInput.text("profile", Component.text("Skin Profile (Mojang Username)")) + .initial(profileName) + .build() + ); + inputs.add( + DialogInput.bool("immovable", Component.text("Immovable")) + .initial(mannequin.isImmovable()) + .build() + ); + inputs.add( + DialogInput.bool("gravity", Component.text("Gravity")) + .initial(mannequin.hasGravity()) + .build() + ); List actions = new ArrayList<>(); @@ -66,6 +85,18 @@ public class MannequinHandler extends EntityHandler { displayName = MiniMessage.miniMessage().deserialize(newName); } mann.customName(displayName); + mann.setImmovable(Boolean.TRUE.equals(view.getBoolean("immovable"))); + mann.setVelocity(mann.getVelocity().zero()); + mann.setGravity(Boolean.TRUE.equals(view.getBoolean("gravity"))); + try { + String newProfileName = view.getText("profile"); + if (newProfileName == null || newProfileName.isBlank()) { + newProfileName = null; + } + mann.setProfile(ResolvableProfile.resolvableProfile().name(newProfileName).build()); + } catch (IllegalArgumentException e) { + callbackPlayer.sendRichMessage("Profile name not updated: invalid username."); + } }, ClickCallback.Options.builder().lifetime(Duration.ofMinutes(5)).uses(1).build()) ).build(); actions.add(saveButton);