diff --git a/main/src/main/java/net/citizensnpcs/editor/GenericEquipperGUI.java b/main/src/main/java/net/citizensnpcs/editor/GenericEquipperGUI.java index 21618139d..10544713f 100644 --- a/main/src/main/java/net/citizensnpcs/editor/GenericEquipperGUI.java +++ b/main/src/main/java/net/citizensnpcs/editor/GenericEquipperGUI.java @@ -17,14 +17,15 @@ import net.citizensnpcs.api.gui.MenuSlot; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.trait.trait.Equipment; import net.citizensnpcs.api.trait.trait.Equipment.EquipmentSlot; +import net.citizensnpcs.util.Util; @Menu(title = "NPC Equipment", type = InventoryType.CHEST, dimensions = { 3, 9 }) +@MenuSlot(slot = { 0, 0 }, material = Material.DIAMOND_SWORD, lore = "Place in hand item below", amount = 1) @MenuSlot( slot = { 0, 1 }, compatMaterial = { "SHIELD", "BARRIER", "FIRE" }, lore = "Place offhand item below", amount = 1) -@MenuSlot(slot = { 0, 0 }, material = Material.DIAMOND_SWORD, lore = "Place in hand item below", amount = 1) @MenuSlot(slot = { 0, 2 }, material = Material.DIAMOND_HELMET, lore = "Place helmet below", amount = 1) @MenuSlot(slot = { 0, 3 }, material = Material.DIAMOND_CHESTPLATE, lore = "Place chestplate below", amount = 1) @MenuSlot(slot = { 0, 4 }, material = Material.DIAMOND_LEGGINGS, lore = "Place leggings below", amount = 1) @@ -48,27 +49,31 @@ public class GenericEquipperGUI extends InventoryMenuPage { ctx.getSlot(1 * 9 + i).setItemStack(trait.get(slot)); if (trait.getCosmetic(slot) != null) { ctx.getSlot(2 * 9 + i).setItemStack(trait.getCosmetic(slot)); + } else { + ctx.getSlot(2 * 9 + i).setItemStack(Util.createItem(Util.getFallbackMaterial("BARRIER", "FIRE"), + "No cosmetic", "Click to enable cosmetic for this equipment")); } - Function filter = type -> true; + Function filter = type -> true; switch (slot) { case BOOTS: case LEGGINGS: - filter = type -> type.name().endsWith(slot.name()); + filter = stack -> Util.isEquippable(stack, slot) || stack.getType().name().endsWith(slot.name()); break; case CHESTPLATE: - filter = type -> type == Material.ELYTRA || type.name().endsWith(slot.name()); + filter = stack -> Util.isEquippable(stack, slot) || stack.getType() == Material.ELYTRA + || stack.getType().name().endsWith(slot.name()); default: break; } - Function ffilter = filter; + Function ffilter = filter; ctx.getSlot(1 * 9 + i).addClickHandler(event -> set(slot, event, ffilter)); ctx.getSlot(2 * 9 + i).addClickHandler(event -> setCosmetic(slot, event, ffilter)); } } - private void set(EquipmentSlot slot, CitizensInventoryClickEvent event, Function filter) { + private void set(EquipmentSlot slot, CitizensInventoryClickEvent event, Function filter) { ItemStack result = event.getResultItemNonNull(); - if (event.isCancelled() || (result.getType() != Material.AIR && !filter.apply(result.getType()))) { + if (event.isCancelled() || (result.getType() != Material.AIR && !filter.apply(result))) { event.setResult(Result.DENY); return; } @@ -76,9 +81,21 @@ public class GenericEquipperGUI extends InventoryMenuPage { } private void setCosmetic(EquipmentSlot slot, CitizensInventoryClickEvent event, - Function filter) { + Function filter) { + if (event.getCursorNonNull().getType() == Material.AIR) { + if (event.getCurrentItemNonNull().getType() == Util.getFallbackMaterial("BARRIER", "FIRE")) { + event.setCurrentItem(null); + npc.getOrAddTrait(Equipment.class).setCosmetic(slot, new ItemStack(Material.AIR, 1)); + } else if (event.getCurrentItem() == null) { + event.setCurrentItem(Util.createItem(Util.getFallbackMaterial("BARRIER", "FIRE"), "No cosmetic", + "Click to enable cosmetic for this equipment")); + npc.getOrAddTrait(Equipment.class).setCosmetic(slot, null); + } + event.setResult(Result.DENY); + return; + } ItemStack result = event.getResultItemNonNull(); - if (event.isCancelled() || (result.getType() != Material.AIR && !filter.apply(result.getType()))) { + if (event.isCancelled() || (result.getType() != Material.AIR && !filter.apply(result))) { event.setResult(Result.DENY); return; } diff --git a/main/src/main/java/net/citizensnpcs/util/Messages.java b/main/src/main/java/net/citizensnpcs/util/Messages.java index 40207cccb..92e78b50a 100644 --- a/main/src/main/java/net/citizensnpcs/util/Messages.java +++ b/main/src/main/java/net/citizensnpcs/util/Messages.java @@ -93,6 +93,7 @@ public class Messages { public static final String CONTROLLABLE_SET = "citizens.commands.npc.controllable.set"; public static final String COPIER_EDITOR_BEGIN = "citizens.editors.copier.begin"; public static final String COPIER_EDITOR_END = "citizens.editors.copier.end"; + public static final String COSMETIC_EQUIPMENT_SET = "citizens.commands.npc.setequipment.cosmetic-set"; public static final String CURRENT_WAYPOINT_PROVIDER = "citizens.waypoints.current-provider"; public static final String DEFAULT_POSE_SET = "citizens.commands.npc.pose.default-pose-set"; public static final String DELAY_TRIGGER_PROMPT = "citizens.editors.waypoints.triggers.delay.prompt"; diff --git a/main/src/main/java/net/citizensnpcs/util/Util.java b/main/src/main/java/net/citizensnpcs/util/Util.java index 74b8ae1f1..b3cadad4b 100644 --- a/main/src/main/java/net/citizensnpcs/util/Util.java +++ b/main/src/main/java/net/citizensnpcs/util/Util.java @@ -51,6 +51,7 @@ import net.citizensnpcs.api.event.NPCCollisionEvent; import net.citizensnpcs.api.event.NPCPistonPushEvent; import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.api.trait.trait.Equipment.EquipmentSlot; import net.citizensnpcs.api.util.BoundingBox; import net.citizensnpcs.api.util.Messaging; import net.citizensnpcs.api.util.Placeholders; @@ -300,6 +301,11 @@ public class Util { return BEDROCK_NAME_PREFIX != null ? name.startsWith(BEDROCK_NAME_PREFIX) : false; } + public static boolean isEquippable(ItemStack stack, EquipmentSlot slot) { + return SUPPORTS_HAS_EQUIPPABLE && stack.hasItemMeta() && stack.getItemMeta().hasEquippable() + && stack.getItemMeta().getEquippable().getSlot() == slot.toBukkit(); + } + public static boolean isHorse(EntityType type) { String name = type.name(); return type == EntityType.HORSE || name.contains("_HORSE") || name.equals("DONKEY") || name.equals("MULE") @@ -622,6 +628,7 @@ public class Util { private static String BEDROCK_NAME_PREFIX = "."; private static Scoreboard DUMMY_SCOREBOARD; private static boolean SUPPORTS_BUKKIT_GETENTITY = true; + private static boolean SUPPORTS_HAS_EQUIPPABLE = false; private static final DecimalFormat TWO_DIGIT_DECIMAL = new DecimalFormat(); static { @@ -630,6 +637,11 @@ public class Util { } catch (NullPointerException e) { } TWO_DIGIT_DECIMAL.setMaximumFractionDigits(2); + try { + ItemMeta.class.getMethod("hasEquippable"); + } catch (NoSuchMethodException e) { + SUPPORTS_HAS_EQUIPPABLE = false; + } try { Bukkit.class.getMethod("getEntity", UUID.class); } catch (Exception e) {