cleanup and make mannequin profile name persistent when converting to and from armor stand

This commit is contained in:
2025-11-23 20:33:58 +01:00
parent 23146380d9
commit 59c7d125df
6 changed files with 76 additions and 38 deletions
@@ -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");
@@ -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<ArmorStand, Mannequin> {
@Override
public Class<ArmorStand> entityFrom() {
return ArmorStand.class;
}
@Override
public Class<Mannequin> 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;
}
}
}
@@ -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<F extends Entity, T extends Entity> {
Class<F> entityFrom();
NamespacedKey PLAYER_PROFILE_KEY = new NamespacedKey("stand-in", "player-profile");
@NotNull EntityType entityFromType();
@NotNull EntityType entityFrom();
@NotNull EntityType entityToType();
Class<T> entityTo();
@NotNull EntityType entityTo();
/**
* Spawn the new entity in the old entity's spot.
@@ -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<Mannequin, ArmorStand> {
@Override
public Class<Mannequin> entityFrom() {
return Mannequin.class;
}
@Override
public Class<ArmorStand> 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;
}
}
}
@@ -40,7 +40,7 @@ public abstract class EntityHandler<E extends Entity> {
public final Set<Class<? extends Entity>> getPossibleConversions() {
Set<Class<? extends Entity>> classes = new HashSet<>();
for (EntityConverter<E, ?> converter : possibleConverters) {
classes.add(converter.entityTo());
classes.add(converter.entityTo().getEntityClass());
}
return Collections.unmodifiableSet(classes);
}
@@ -80,8 +80,8 @@ public abstract class EntityHandler<E extends Entity> {
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<E extends Entity> {
if (newEntityType.equals(existing.getClass().getName())) return; // skip if the class is the same
EntityConverter<E, ?> foundConverter = null;
for (EntityConverter<E, ?> converter : possibleConverters) {
if (!newEntityType.equals(converter.entityTo().getName())) continue;
if (!newEntityType.equals(converter.entityTo().toString())) continue;
foundConverter = converter;
break;
}
@@ -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<Mannequin> {
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<ActionButton> actions = new ArrayList<>();
@@ -66,6 +85,18 @@ public class MannequinHandler extends EntityHandler<Mannequin> {
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("<red>Profile name not updated: invalid username.");
}
}, ClickCallback.Options.builder().lifetime(Duration.ofMinutes(5)).uses(1).build())
).build();
actions.add(saveButton);