diff --git a/src/main/java/me/youhavetrouble/standin/StandIn.java b/src/main/java/me/youhavetrouble/standin/StandIn.java index 883f773..fb94edf 100644 --- a/src/main/java/me/youhavetrouble/standin/StandIn.java +++ b/src/main/java/me/youhavetrouble/standin/StandIn.java @@ -1,30 +1,40 @@ package me.youhavetrouble.standin; +import me.youhavetrouble.standin.entity.ArmorStandHandler; +import me.youhavetrouble.standin.entity.EntityHandler; +import me.youhavetrouble.standin.entity.MannequinHandler; import me.youhavetrouble.standin.stand.StandinInteractionListener; import org.bukkit.NamespacedKey; -import org.bukkit.permissions.Permission; -import org.bukkit.permissions.PermissionDefault; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.plugin.java.JavaPlugin; -import java.util.List; +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"); + private final Map> entityHandlers = new HashMap<>(); + @Override public void onEnable() { - - getServer().getPluginManager().addPermissions( - List.of( - new Permission("standin.edit.armor_stand", PermissionDefault.OP), - new Permission("standin.edit.mannequin", PermissionDefault.OP) - ) - ); - + entityHandlers.put(EntityType.ARMOR_STAND, new ArmorStandHandler()); + entityHandlers.put(EntityType.MANNEQUIN, new MannequinHandler()); getServer().getPluginManager().registerEvents(new StandinInteractionListener(), this); } + /** + * Gets entity handler for given entity class + * @param entityType entity type to get handler for + * @return Entity handler or null + */ + public @Nullable EntityHandler getEntityHandler(EntityType entityType) { + return entityHandlers.get(entityType); + } + } diff --git a/src/main/java/me/youhavetrouble/standin/StandinDialog.java b/src/main/java/me/youhavetrouble/standin/StandinDialog.java deleted file mode 100644 index 7716560..0000000 --- a/src/main/java/me/youhavetrouble/standin/StandinDialog.java +++ /dev/null @@ -1,279 +0,0 @@ -package me.youhavetrouble.standin; - -import io.papermc.paper.dialog.Dialog; -import io.papermc.paper.registry.data.dialog.ActionButton; -import io.papermc.paper.registry.data.dialog.DialogBase; -import io.papermc.paper.registry.data.dialog.action.DialogAction; -import io.papermc.paper.registry.data.dialog.body.DialogBody; -import io.papermc.paper.registry.data.dialog.input.DialogInput; -import io.papermc.paper.registry.data.dialog.input.SingleOptionDialogInput; -import io.papermc.paper.registry.data.dialog.type.DialogType; -import me.youhavetrouble.standin.converter.ArmorStandToMannequinConverter; -import me.youhavetrouble.standin.converter.EntityConverter; -import me.youhavetrouble.standin.converter.MannequinToArmorStandConverter; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.event.ClickCallback; -import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Mannequin; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -// TODO generify this mess - -@SuppressWarnings("UnstableApiUsage") -public class StandinDialog { - - public static void openConversionDialog(@NotNull Player player, @NotNull ArmorStand armorStand) { - if (armorStand.isDead()) return; - - UUID armorStandId = armorStand.getUniqueId(); - UUID playerId = player.getUniqueId(); - - List inputs = List.of( - DialogInput.singleOption("entity_type", Component.text("New entity type"), List.of( - SingleOptionDialogInput.OptionEntry.create("armor_stand", Component.text("Armor Stand"), true), - SingleOptionDialogInput.OptionEntry.create("mannequin", Component.text("Mannequin"), false) - )).build() - ); - - ActionButton saveButton = ActionButton.builder(Component.text("Change type")).action( - DialogAction.customClick((view, audience) -> { - if (!(audience instanceof Player callbackPlayer)) return; - Entity entity = callbackPlayer.getWorld().getEntity(armorStandId); - if (playerId != callbackPlayer.getUniqueId()) return; - if (!(entity instanceof ArmorStand stand)) return; - if (stand.isDead()) return; - String newEntityType = view.getText("entity_type"); - switch (newEntityType) { - case "mannequin" -> { - EntityConverter mannequinConverter = new ArmorStandToMannequinConverter(); - Mannequin mannequin = mannequinConverter.spawn(stand); - if (mannequin == null) { - audience.sendMessage(Component.text("Error spawning new entity. Ensure new entity can spawn in this spot.").color(NamedTextColor.RED)); - return; - } - stand.remove(); - } - case null, default -> { - } - } - }, ClickCallback.Options.builder().lifetime(Duration.ofHours(1)).uses(1).build()) - ).build(); - - Dialog dialog = Dialog.create(builder -> builder.empty() - .base( - DialogBase.builder(Component.text("Armor Stand Conversion")) - .body(List.of( - DialogBody.plainMessage( - Component.text("Some settings might not persist between changing entity type").color(NamedTextColor.RED) - ) - )).inputs(inputs) - .build()) - .type(DialogType.confirmation(saveButton, ActionButton.builder(Component.text("Cancel")).build())) - ); - - player.showDialog(dialog); - } - - public static void openConversionDialog(@NotNull Player player, @NotNull Mannequin mannequin) { - if (mannequin.isDead()) return; - - UUID MannequinId = mannequin.getUniqueId(); - UUID playerId = player.getUniqueId(); - - List inputs = List.of( - DialogInput.singleOption("entity_type", Component.text("New entity type"), List.of( - SingleOptionDialogInput.OptionEntry.create("mannequin", Component.text("Mannequin"), true), - SingleOptionDialogInput.OptionEntry.create("armor_stand", Component.text("Armor Stand"), false) - )).build() - ); - - ActionButton saveButton = ActionButton.builder(Component.text("Change type")).action( - DialogAction.customClick((view, audience) -> { - if (!(audience instanceof Player callbackPlayer)) return; - if (playerId != callbackPlayer.getUniqueId()) return; - Entity entity = callbackPlayer.getWorld().getEntity(MannequinId); - if (!(entity instanceof Mannequin cMannequin)) return; - if (cMannequin.isDead()) return; - String newEntityType = view.getText("entity_type"); - switch (newEntityType) { - case "armor_stand" -> { - EntityConverter armorStandConverter = new MannequinToArmorStandConverter(); - ArmorStand armorStand = armorStandConverter.spawn(cMannequin); - if (armorStand == null) { - audience.sendMessage(Component.text("Error spawning new entity. Ensure new entity can spawn in this spot.").color(NamedTextColor.RED)); - return; - } - cMannequin.remove(); - } - case null, default -> { - } - } - }, ClickCallback.Options.builder().lifetime(Duration.ofMinutes(5)).uses(1).build()) - ).build(); - - Dialog dialog = Dialog.create(builder -> builder.empty() - .base( - DialogBase.builder(Component.text("Mannequin Conversion")) - .body(List.of( - DialogBody.plainMessage( - Component.text("Some settings might not persist between changing entity type").color(NamedTextColor.RED) - ) - )).inputs(inputs) - .build()) - .type(DialogType.confirmation(saveButton, ActionButton.builder(Component.text("Cancel")).build())) - ); - - player.showDialog(dialog); - } - - public static void openArmorStandDialog(@NotNull Player player, @NotNull ArmorStand armorStand) { - if (armorStand.isDead()) return; - - UUID armorStandId = armorStand.getUniqueId(); - UUID playerId = player.getUniqueId(); - - List inputs = new ArrayList<>(); - - inputs.add( - DialogInput.bool("invisible", Component.text("Invisible")) - .initial(armorStand.isInvisible()) - .build() - ); - - inputs.add( - DialogInput.bool("basePlate", Component.text("Base plate")) - .initial(armorStand.hasBasePlate()) - .build() - ); - - inputs.add( - DialogInput.bool("arms", Component.text("Arms")) - .initial(armorStand.hasArms()) - .build() - ); - - inputs.add( - DialogInput.bool("small", Component.text("Small")) - .initial(armorStand.isSmall()) - .build() - ); - - ActionButton saveButton = ActionButton.builder(Component.text("Save")).action( - DialogAction.customClick((view, audience) -> { - if (!(audience instanceof Player callbackPlayer)) return; - if (playerId != callbackPlayer.getUniqueId()) return; - Entity entity = callbackPlayer.getWorld().getEntity(armorStandId); - if (!(entity instanceof ArmorStand stand)) return; - if (stand.isDead()) return; - stand.setInvisible(Boolean.TRUE.equals(view.getBoolean("invisible"))); - stand.setBasePlate(Boolean.TRUE.equals(view.getBoolean("basePlate"))); - stand.setArms(Boolean.TRUE.equals(view.getBoolean("arms"))); - stand.setSmall(Boolean.TRUE.equals(view.getBoolean("small"))); - }, ClickCallback.Options.builder().lifetime(Duration.ofMinutes(5)).uses(1).build()) - ).build(); - - ActionButton changeTypeButton = ActionButton.builder(Component.text("Change type")) - .action( - DialogAction.customClick((view, audience) -> { - if (!(audience instanceof Player callbackPlayer)) return; - if (playerId != callbackPlayer.getUniqueId()) return; - Entity entity = callbackPlayer.getWorld().getEntity(armorStandId); - if (!(entity instanceof ArmorStand stand)) return; - if (stand.isDead()) return; - StandinDialog.openConversionDialog(callbackPlayer, armorStand); - }, ClickCallback.Options.builder().lifetime(Duration.ofMinutes(5)).uses(1).build() - ) - ).build(); - - Dialog dialog = Dialog.create(builder -> builder.empty() - .base( - DialogBase.builder(Component.text("Armor Stand Editor")) - .inputs(inputs) - .build() - ).type( - DialogType.multiAction( - List.of(saveButton, changeTypeButton), - ActionButton.builder(Component.text("Cancel")).build(), - 1) - ) - ); - - player.showDialog(dialog); - } - - public static void openMannequinDialog(@NotNull Player player, @NotNull Mannequin mannequin) { - if (mannequin.isDead()) return; - - UUID mannequinId = mannequin.getUniqueId(); - UUID playerId = player.getUniqueId(); - List inputs = new ArrayList<>(); - - String name = ""; - Component customName = mannequin.customName(); - if (customName != null) { - name = PlainTextComponentSerializer.plainText().serialize(customName); - } - - inputs.add( - DialogInput.text("name", Component.text("Name")) - .initial(name) - .build() - ); - - ActionButton saveButton = ActionButton.builder(Component.text("Save")).action( - DialogAction.customClick((view, audience) -> { - if (!(audience instanceof Player callbackPlayer)) return; - if (playerId != callbackPlayer.getUniqueId()) return; - Entity entity = callbackPlayer.getWorld().getEntity(mannequinId); - if (!(entity instanceof Mannequin cMannequin)) return; - if (cMannequin.isDead()) return; - String newName = view.getText("name"); - Component displayName = null; - if (newName != null) { - displayName = MiniMessage.miniMessage().deserialize(newName); - } - cMannequin.customName(displayName); - - }, ClickCallback.Options.builder().lifetime(Duration.ofMinutes(5)).uses(1).build()) - ).build(); - - ActionButton changeTypeButton = ActionButton.builder(Component.text("Change type")) - .action( - DialogAction.customClick((view, audience) -> { - if (!(audience instanceof Player callbackPlayer)) return; - if (playerId != callbackPlayer.getUniqueId()) return; - Entity entity = callbackPlayer.getWorld().getEntity(mannequinId); - if (!(entity instanceof Mannequin cMannequin)) return; - if (cMannequin.isDead()) return; - StandinDialog.openConversionDialog(callbackPlayer, cMannequin); - }, ClickCallback.Options.builder().lifetime(Duration.ofMinutes(5)).uses(1).build() - ) - ).build(); - - Dialog dialog = Dialog.create(builder -> builder.empty() - .base( - DialogBase.builder(Component.text("Armor Stand Editor")) - .inputs(inputs) - .build() - ).type( - DialogType.multiAction( - List.of(saveButton, changeTypeButton), - ActionButton.builder(Component.text("Cancel")).build(), - 1) - ) - ); - - player.showDialog(dialog); - } - -} diff --git a/src/main/java/me/youhavetrouble/standin/converter/ArmorStandToMannequinConverter.java b/src/main/java/me/youhavetrouble/standin/converter/ArmorStandToMannequinConverter.java index 5692a57..c825c43 100644 --- a/src/main/java/me/youhavetrouble/standin/converter/ArmorStandToMannequinConverter.java +++ b/src/main/java/me/youhavetrouble/standin/converter/ArmorStandToMannequinConverter.java @@ -2,6 +2,7 @@ package me.youhavetrouble.standin.converter; 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.jetbrains.annotations.NotNull; @@ -18,6 +19,16 @@ public class ArmorStandToMannequinConverter implements EntityConverter { Class entityFrom(); + @NotNull EntityType entityFromType(); + + @NotNull EntityType entityToType(); + Class entityTo(); /** diff --git a/src/main/java/me/youhavetrouble/standin/converter/MannequinToArmorStandConverter.java b/src/main/java/me/youhavetrouble/standin/converter/MannequinToArmorStandConverter.java index bcbdcc2..024aa7f 100644 --- a/src/main/java/me/youhavetrouble/standin/converter/MannequinToArmorStandConverter.java +++ b/src/main/java/me/youhavetrouble/standin/converter/MannequinToArmorStandConverter.java @@ -2,6 +2,7 @@ package me.youhavetrouble.standin.converter; 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.jetbrains.annotations.NotNull; @@ -18,6 +19,16 @@ public class MannequinToArmorStandConverter implements EntityConverter { + + public ArmorStandHandler() { + super(ArmorStand.class); + addConverter(new ArmorStandToMannequinConverter()); + } + + public Dialog editDialog(@NotNull Player player, ArmorStand armorStand) { + if (armorStand == null || armorStand.isDead()) return null; + if (!canUseAction(player, armorStand, EntityAction.EDIT)) return null; + + UUID entityId = armorStand.getUniqueId(); + UUID playerId = player.getUniqueId(); + + List inputs = new ArrayList<>(); + + inputs.add( + DialogInput.bool("invisible", Component.text("Invisible")) + .initial(armorStand.isInvisible()) + .build() + ); + inputs.add( + DialogInput.bool("canMove", Component.text("Can move")) + .initial(armorStand.canMove()) + .build() + ); + inputs.add( + DialogInput.bool("gravity", Component.text("Gravity")) + .initial(armorStand.hasGravity()) + .build() + ); + inputs.add( + DialogInput.bool("basePlate", Component.text("Base plate")) + .initial(armorStand.hasBasePlate()) + .build() + ); + inputs.add( + DialogInput.bool("arms", Component.text("Arms")) + .initial(armorStand.hasArms()) + .build() + ); + inputs.add( + DialogInput.bool("small", Component.text("Small")) + .initial(armorStand.isSmall()) + .build() + ); + + ActionButton saveButton = ActionButton.builder(Component.text("Save")).action( + DialogAction.customClick((view, audience) -> { + if (!(audience instanceof Player callbackPlayer)) return; + if (playerId != callbackPlayer.getUniqueId()) return; + Entity entity = callbackPlayer.getWorld().getEntity(entityId); + if (!(entity instanceof ArmorStand stand)) return; + if (!canUseAction(callbackPlayer, stand, EntityAction.EDIT)) return; + if (stand.isDead()) return; + stand.setInvisible(Boolean.TRUE.equals(view.getBoolean("invisible"))); + stand.setBasePlate(Boolean.TRUE.equals(view.getBoolean("basePlate"))); + stand.setArms(Boolean.TRUE.equals(view.getBoolean("arms"))); + stand.setSmall(Boolean.TRUE.equals(view.getBoolean("small"))); + stand.setCanMove(Boolean.TRUE.equals(view.getBoolean("canMove"))); + stand.setGravity(Boolean.TRUE.equals(view.getBoolean("gravity"))); + }, ClickCallback.Options.builder().lifetime(Duration.ofMinutes(5)).uses(1).build()) + ).build(); + + List actions = new ArrayList<>(); + if (player.hasPermission("standin.change_type.armor_stand")) { + ActionButton changeTypeButton = ActionButton.builder(Component.text("Change type")) + .action( + DialogAction.customClick((view, audience) -> { + if (!(audience instanceof Player callbackPlayer)) return; + if (playerId != callbackPlayer.getUniqueId()) return; + Entity entity = callbackPlayer.getWorld().getEntity(entityId); + if (!(entity instanceof ArmorStand stand)) return; + Dialog dialog = conversionDialog(callbackPlayer, stand); + if (dialog == null) return; + callbackPlayer.showDialog(dialog); + }, ClickCallback.Options.builder().lifetime(Duration.ofMinutes(5)).uses(1).build() + ) + ).build(); + actions.add(changeTypeButton); + } + + actions.add(saveButton); + + return Dialog.create(builder -> builder.empty() + .base( + DialogBase.builder(Component.text("Armor Stand Editor")) + .inputs(inputs) + .build() + ).type( + DialogType.multiAction( + actions, + ActionButton.builder(Component.text("Cancel")).build(), + 1) + ) + ); + } + +} diff --git a/src/main/java/me/youhavetrouble/standin/entity/EntityHandler.java b/src/main/java/me/youhavetrouble/standin/entity/EntityHandler.java index 1e112e8..a09e7fc 100644 --- a/src/main/java/me/youhavetrouble/standin/entity/EntityHandler.java +++ b/src/main/java/me/youhavetrouble/standin/entity/EntityHandler.java @@ -23,8 +23,13 @@ import java.util.*; @SuppressWarnings("UnstableApiUsage") public abstract class EntityHandler { + public final Class clazz; private final Set> possibleConverters = new HashSet<>(); + public EntityHandler(Class clazz) { + this.clazz = clazz; + } + /** * Get the classes of entities this entity can convert into. Conversion can be lossy. * @@ -56,16 +61,28 @@ public abstract class EntityHandler { public final @Nullable Dialog conversionDialog(@NotNull Player player, E entity) { if (entity.isDead()) return null; if (possibleConverters.isEmpty()) return null; - + if (!canUseAction(player, entity, EntityAction.CHANGE_TYPE)) return null; UUID entityId = entity.getUniqueId(); UUID playerId = player.getUniqueId(); Class entityClass = entity.getClass(); List entityEntries = new ArrayList<>(); - entityEntries.add(SingleOptionDialogInput.OptionEntry.create(entityClass.getName(), Component.text(entityClass.getName()), true)); + entityEntries.add( + SingleOptionDialogInput.OptionEntry.create( + entity.getType().toString(), + Component.translatable(entity.getType().translationKey(), entity.getType().toString()), + true + ) + ); for (EntityConverter converter : possibleConverters) { - entityEntries.add(SingleOptionDialogInput.OptionEntry.create(converter.entityTo().getName(), Component.text(converter.entityTo().getName()), false)); + entityEntries.add( + SingleOptionDialogInput.OptionEntry.create( + converter.entityTo().getName(), + Component.translatable(converter.entityToType().translationKey()), + false + ) + ); } List inputs = List.of( @@ -84,6 +101,7 @@ public abstract class EntityHandler { if (callbackEntity == null || callbackEntity.isDead()) return; if (!callbackEntity.getClass().equals(entityClass)) return; E existing = (E) callbackEntity; + if (!canUseAction(callbackPlayer, existing, EntityAction.CHANGE_TYPE)) return; String newEntityType = view.getText("entity_type"); if (newEntityType == null) return; if (newEntityType.equals(existing.getClass().getName())) return; // skip if the class is the same @@ -113,6 +131,23 @@ public abstract class EntityHandler { ); } + /** + * Checks if player can execute given action for the entity. This is checked on opening dialogs and on executing + * callbacks. + * @param player player executing action + * @param entity entity action is supposed to be used on + * @param action action to b taken + * @return Boolean representing the allowance state of the action + */ + public boolean canUseAction(@NotNull Player player, E entity, EntityAction action) { + String entityTypeName = entity.getType().toString().toLowerCase(Locale.ENGLISH); + return switch (action) { + case EDIT -> player.hasPermission("standin.edit." + entityTypeName); + case CHANGE_TYPE -> player.hasPermission("standin.change_type." + entityTypeName); + default -> false; + }; + } + /** * Open a dialog allowing to edit properties of the entity * @@ -124,4 +159,9 @@ public abstract class EntityHandler { return null; } + public enum EntityAction { + EDIT, + CHANGE_TYPE, + } + } diff --git a/src/main/java/me/youhavetrouble/standin/entity/MannequinHandler.java b/src/main/java/me/youhavetrouble/standin/entity/MannequinHandler.java new file mode 100644 index 0000000..ea5eb96 --- /dev/null +++ b/src/main/java/me/youhavetrouble/standin/entity/MannequinHandler.java @@ -0,0 +1,104 @@ +package me.youhavetrouble.standin.entity; + +import io.papermc.paper.dialog.Dialog; +import io.papermc.paper.registry.data.dialog.ActionButton; +import io.papermc.paper.registry.data.dialog.DialogBase; +import io.papermc.paper.registry.data.dialog.action.DialogAction; +import io.papermc.paper.registry.data.dialog.input.DialogInput; +import io.papermc.paper.registry.data.dialog.type.DialogType; +import me.youhavetrouble.standin.converter.MannequinToArmorStandConverter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickCallback; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Mannequin; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@SuppressWarnings("UnstableApiUsage") +public class MannequinHandler extends EntityHandler { + + public MannequinHandler() { + super(Mannequin.class); + addConverter(new MannequinToArmorStandConverter()); + } + + public Dialog editDialog(@NotNull Player player, Mannequin mannequin) { + if (mannequin == null || mannequin.isDead()) return null; + if (!canUseAction(player, mannequin, EntityAction.EDIT)) return null; + + UUID entityId = mannequin.getUniqueId(); + UUID playerId = player.getUniqueId(); + + List inputs = new ArrayList<>(); + + String name = ""; + Component customName = mannequin.customName(); + if (customName != null) { + name = PlainTextComponentSerializer.plainText().serialize(customName); + } + + inputs.add( + DialogInput.text("name", Component.text("Name")) + .initial(name) + .build() + ); + + List actions = new ArrayList<>(); + + ActionButton saveButton = ActionButton.builder(Component.text("Save")).action( + DialogAction.customClick((view, audience) -> { + if (!(audience instanceof Player callbackPlayer)) return; + if (playerId != callbackPlayer.getUniqueId()) return; + Entity entity = callbackPlayer.getWorld().getEntity(entityId); + if (!(entity instanceof Mannequin mann)) return; + if (!canUseAction(callbackPlayer, mann, EntityAction.EDIT)) return; + if (mann.isDead()) return; + String newName = view.getText("name"); + Component displayName = null; + if (newName != null) { + displayName = MiniMessage.miniMessage().deserialize(newName); + } + mann.customName(displayName); + }, ClickCallback.Options.builder().lifetime(Duration.ofMinutes(5)).uses(1).build()) + ).build(); + actions.add(saveButton); + + if (player.hasPermission("standin.change_type.armor_stand")) { + ActionButton changeTypeButton = ActionButton.builder(Component.text("Change type")) + .action( + DialogAction.customClick((view, audience) -> { + if (!(audience instanceof Player callbackPlayer)) return; + if (playerId != callbackPlayer.getUniqueId()) return; + Entity entity = callbackPlayer.getWorld().getEntity(entityId); + if (!(entity instanceof Mannequin mann)) return; + Dialog dialog = conversionDialog(callbackPlayer, mann); + if (dialog == null) return; + callbackPlayer.showDialog(dialog); + }, ClickCallback.Options.builder().lifetime(Duration.ofMinutes(5)).uses(1).build() + ) + ).build(); + actions.add(changeTypeButton); + } + + return Dialog.create(builder -> builder.empty() + .base( + DialogBase.builder(Component.text("Armor Stand Editor")) + .inputs(inputs) + .build() + ).type( + DialogType.multiAction( + actions, + ActionButton.builder(Component.text("Cancel")).build(), + 1) + ) + ); + } + +} diff --git a/src/main/java/me/youhavetrouble/standin/stand/StandinInteractionListener.java b/src/main/java/me/youhavetrouble/standin/stand/StandinInteractionListener.java index 280cc8f..908464e 100644 --- a/src/main/java/me/youhavetrouble/standin/stand/StandinInteractionListener.java +++ b/src/main/java/me/youhavetrouble/standin/stand/StandinInteractionListener.java @@ -1,102 +1,50 @@ package me.youhavetrouble.standin.stand; +import io.papermc.paper.dialog.Dialog; import io.papermc.paper.event.player.PlayerPickEntityEvent; -import me.youhavetrouble.standin.StandinDialog; -import org.bukkit.attribute.Attribute; -import org.bukkit.attribute.AttributeInstance; -import org.bukkit.entity.ArmorStand; +import me.youhavetrouble.standin.StandIn; +import me.youhavetrouble.standin.entity.EntityHandler; import org.bukkit.entity.Entity; -import org.bukkit.entity.Mannequin; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerInteractAtEntityEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.inventory.EquipmentSlot; -import org.bukkit.util.RayTraceResult; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class StandinInteractionListener implements Listener { - private boolean handleInteraction(@NotNull Player player, Entity entity) { - if (entity == null) return false; - if (!player.isOnline()) return false; - - if (entity instanceof ArmorStand armorStand && player.hasPermission("standin.edit.armor_stand")) { - StandinDialog.openArmorStandDialog(player, armorStand); - return true; - } - - if (entity instanceof Mannequin mannequin && player.hasPermission("standin.edit.mannequin")) { - StandinDialog.openMannequinDialog(player, mannequin); - return true; - } - - return false; + private @Nullable Dialog invokeEditDialog(EntityHandler handler, Player player, Entity clicked) { + return handler.editDialog(player, handler.clazz.cast(clicked)); } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = false) - public void onInteractWithDisplays(PlayerInteractEvent event) { - if (!event.getPlayer().isSneaking()) return; - if (event.getHand() == EquipmentSlot.OFF_HAND) return; - Player player = event.getPlayer(); - - AttributeInstance instance = player.getAttribute(Attribute.ENTITY_INTERACTION_RANGE); - if (instance == null) return; - - double interactionRange = instance.getValue(); - - RayTraceResult result = player.getWorld().rayTraceEntities( - player.getEyeLocation(), - player.getEyeLocation().getDirection(), - interactionRange, - 0.5, - (entity -> { - switch (entity.getType()) { - case TEXT_DISPLAY, - BLOCK_DISPLAY, - ITEM_DISPLAY -> { - if (entity.getVehicle() == null) return true; - return !player.getUniqueId().equals(entity.getVehicle().getUniqueId()); - } - default -> { - return false; - } - } - }) - ); - if (result == null) return; - - Entity entity = result.getHitEntity(); - if (!handleInteraction(player, entity)) return; - event.setCancelled(true); + private @Nullable Dialog invokeConvertDialog(EntityHandler handler, Player player, Entity clicked) { + return handler.conversionDialog(player, handler.clazz.cast(clicked)); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onInteractWithStands(PlayerInteractAtEntityEvent event) { if (!event.getPlayer().isSneaking()) return; - if (!handleInteraction(event.getPlayer(), event.getRightClicked())) return; + EntityHandler handler = StandIn.getPlugin(StandIn.class).getEntityHandler(event.getRightClicked().getType()); + if (handler == null) return; + Dialog dialog = invokeEditDialog(handler, event.getPlayer(), event.getRightClicked()); + if (dialog == null) return; + event.getPlayer().showDialog(dialog); event.setCancelled(true); } + /** + * This currently does not work for mannequins since pick entity does not fire for them + */ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onInteractWithStands(PlayerPickEntityEvent event) { if (!event.getPlayer().isSneaking()) return; - if (event.getEntity() instanceof ArmorStand armorStand) { - StandinDialog.openConversionDialog(event.getPlayer(), armorStand); - event.setCancelled(true); - return; - } - - // This currently does not work since pick entity does not fire for mannequins - // https://github.com/PaperMC/Paper/issues/13340 - if (event.getEntity() instanceof Mannequin mannequin) { - StandinDialog.openConversionDialog(event.getPlayer(), mannequin); - event.setCancelled(true); - return; - } + EntityHandler handler = StandIn.getPlugin(StandIn.class).getEntityHandler(event.getEntity().getType()); + if (handler == null) return; + Dialog dialog = invokeConvertDialog(handler, event.getPlayer(), event.getEntity()); + if (dialog == null) return; + event.getPlayer().showDialog(dialog); + event.setCancelled(true); } }