diff --git a/api/src/main/java/de/minebench/tresor/services/npc/NPC.java b/api/src/main/java/de/minebench/tresor/services/npc/NPC.java new file mode 100644 index 0000000..b9d921b --- /dev/null +++ b/api/src/main/java/de/minebench/tresor/services/npc/NPC.java @@ -0,0 +1,24 @@ +package de.minebench.tresor.services.npc; + +import de.minebench.tresor.services.npc.data.Interaction; +import de.minebench.tresor.services.npc.data.NPCMetadata; +import java.util.UUID; +import java.util.function.Consumer; +import org.bukkit.Location; + +public interface NPC { + + UUID getUniqueId(); + + boolean isPersistent(); + + NPCMetadata getMetadata(); + void updateMetadata(NPCMetadata metadata); + + Location getLocation(); + void teleport(Location location); + + void onInteract(Consumer action); + + void remove(); +} diff --git a/api/src/main/java/de/minebench/tresor/services/npc/NPCs.java b/api/src/main/java/de/minebench/tresor/services/npc/NPCs.java new file mode 100644 index 0000000..b0c979b --- /dev/null +++ b/api/src/main/java/de/minebench/tresor/services/npc/NPCs.java @@ -0,0 +1,24 @@ +package de.minebench.tresor.services.npc; + +import de.minebench.tresor.services.TresorServiceProvider; +import java.util.UUID; +import org.bukkit.Location; + +public interface NPCs extends TresorServiceProvider { + + default NPC createNPC(String name, Location location) { + return createNPC(name, location, true); + } + + NPC createNPC(String name, Location location, boolean persistent); + NPC getNPC(UUID uniqueId); + + void removeNPC(UUID uniqueId); + + boolean supports(Feature feature); + + enum Feature { + PERSISTENT + } + +} diff --git a/api/src/main/java/de/minebench/tresor/services/npc/data/Interaction.java b/api/src/main/java/de/minebench/tresor/services/npc/data/Interaction.java new file mode 100644 index 0000000..c863676 --- /dev/null +++ b/api/src/main/java/de/minebench/tresor/services/npc/data/Interaction.java @@ -0,0 +1,34 @@ +package de.minebench.tresor.services.npc.data; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class Interaction { + + private final Player player; + private final Type type; + private final ItemStack heldItem; + + public Interaction(Player player, Type type, ItemStack heldItem) { + this.player = player; + this.type = type; + this.heldItem = heldItem; + } + + public Player getPlayer() { + return player; + } + + public Type getType() { + return type; + } + + public ItemStack getHeldItem() { + return heldItem; + } + + public enum Type { + LEFT_CLICK, + RIGHT_CLICK + } +} diff --git a/api/src/main/java/de/minebench/tresor/services/npc/data/NPCMetadata.java b/api/src/main/java/de/minebench/tresor/services/npc/data/NPCMetadata.java new file mode 100644 index 0000000..8d664ae --- /dev/null +++ b/api/src/main/java/de/minebench/tresor/services/npc/data/NPCMetadata.java @@ -0,0 +1,29 @@ +package de.minebench.tresor.services.npc.data; + +public class NPCMetadata { + + private String displayName; + private NPCSkinData skinData; + + public NPCMetadata(String displayName, NPCSkinData skinData) { + this.displayName = displayName; + this.skinData = skinData; + } + + public String getDisplayName() { + return displayName; + } + + public NPCSkinData getSkinData() { + return skinData; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public void setSkinData(NPCSkinData skinData) { + this.skinData = skinData; + } + +} diff --git a/api/src/main/java/de/minebench/tresor/services/npc/data/NPCSkinData.java b/api/src/main/java/de/minebench/tresor/services/npc/data/NPCSkinData.java new file mode 100644 index 0000000..a7daf21 --- /dev/null +++ b/api/src/main/java/de/minebench/tresor/services/npc/data/NPCSkinData.java @@ -0,0 +1,20 @@ +package de.minebench.tresor.services.npc.data; + +public class NPCSkinData { + + private final String texture; + private final String signature; + + public NPCSkinData(String texture, String signature) { + this.texture = texture; + this.signature = signature; + } + + public String getTexture() { + return texture; + } + + public String getSignature() { + return signature; + } +} diff --git a/providers/citizens/pom.xml b/providers/citizens/pom.xml new file mode 100644 index 0000000..8492e07 --- /dev/null +++ b/providers/citizens/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + de.minebench.tresor.providers + citizens + + + de.minebench.tresor + tresor-providers + 1.0-SNAPSHOT + + + + + citizens-repo + https://maven.citizensnpcs.co/repo + + + + + + net.citizensnpcs + citizens-main + 2.0.33-SNAPSHOT + jar + provided + + + * + * + + + + + + + \ No newline at end of file diff --git a/providers/citizens/src/main/java/de/minebench/tresor/providers/citizens/CitizensNPCs.java b/providers/citizens/src/main/java/de/minebench/tresor/providers/citizens/CitizensNPCs.java new file mode 100644 index 0000000..1c25aeb --- /dev/null +++ b/providers/citizens/src/main/java/de/minebench/tresor/providers/citizens/CitizensNPCs.java @@ -0,0 +1,107 @@ +package de.minebench.tresor.providers.citizens; + +import de.minebench.tresor.Provider; +import de.minebench.tresor.providers.citizens.listener.CitizensNPCListener; +import de.minebench.tresor.services.npc.NPC; +import de.minebench.tresor.services.npc.NPCs; +import java.util.UUID; +import net.citizensnpcs.api.CitizensPlugin; +import net.citizensnpcs.api.npc.MemoryNPCDataStore; +import net.citizensnpcs.api.npc.NPCRegistry; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.EntityType; + +public class CitizensNPCs extends Provider implements NPCs { + + private NPCRegistry persistentRegistry; + private NPCRegistry temporaryRegistry; + + private CitizensPlugin hooked; + + public CitizensNPCs() { + super(NPCs.class); + } + + @Override + public void register() { + super.register(); + Bukkit.getPluginManager().registerEvents(new CitizensNPCListener(this), getHooked()); + } + + @Override + public void unregister() { + super.unregister(); + // TODO + } + + @Override + public boolean isEnabled() { + return getHooked() != null && getHooked().isEnabled(); + } + + @Override + public NPC createNPC(String name, Location location, boolean persistent) { + NPCRegistry registry = persistent ? persistentRegistry : temporaryRegistry; + net.citizensnpcs.api.npc.NPC rawNPC = registry.createNPC(EntityType.PLAYER, name); + rawNPC.spawn(location); + + return new WrappedNPC(rawNPC, persistent); + } + + @Override + public NPC getNPC(UUID uniqueId) { + net.citizensnpcs.api.npc.NPC rawNPC = persistentRegistry.getByUniqueIdGlobal(uniqueId); + boolean isPersistent = true; + + if (rawNPC == null) { + rawNPC = temporaryRegistry.getByUniqueIdGlobal(uniqueId); + isPersistent = false; + } + + if (rawNPC == null) { + return null; + } + + return new WrappedNPC(rawNPC, isPersistent); + } + + @Override + public void removeNPC(UUID uniqueId) { + NPC npc = getNPC(uniqueId); + + if (npc != null) { + npc.remove(); + } + } + + @Override + public boolean supports(Feature feature) { + return feature == Feature.PERSISTENT; + } + + @Override + public CitizensPlugin getHooked() { + if(hooked == null) { + hooked = (CitizensPlugin) Bukkit.getPluginManager().getPlugin(getName()); + ensureRegistries(); + } + + return hooked; + } + + @Override + public String getName() { + return "Citizens"; + } + + private void ensureRegistries() { + if (persistentRegistry == null) { + persistentRegistry = hooked.getNPCRegistry(); + } + + if (temporaryRegistry == null) { + temporaryRegistry = hooked.createAnonymousNPCRegistry(new MemoryNPCDataStore()); + } + } +} diff --git a/providers/citizens/src/main/java/de/minebench/tresor/providers/citizens/WrappedNPC.java b/providers/citizens/src/main/java/de/minebench/tresor/providers/citizens/WrappedNPC.java new file mode 100644 index 0000000..7294f6b --- /dev/null +++ b/providers/citizens/src/main/java/de/minebench/tresor/providers/citizens/WrappedNPC.java @@ -0,0 +1,88 @@ +package de.minebench.tresor.providers.citizens; + +import de.minebench.tresor.services.npc.NPC; +import de.minebench.tresor.services.npc.data.Interaction; +import de.minebench.tresor.services.npc.data.NPCMetadata; +import de.minebench.tresor.services.npc.data.NPCSkinData; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.function.Consumer; +import net.citizensnpcs.trait.SkinTrait; +import org.bukkit.Location; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + +public class WrappedNPC implements NPC { + + private final List> interactActions = new ArrayList<>(); + private final net.citizensnpcs.api.npc.NPC npc; + private final boolean persistent; + + public WrappedNPC(net.citizensnpcs.api.npc.NPC npc, boolean persistent) { + this.npc = npc; + this.persistent = persistent; + } + + @Override + public UUID getUniqueId() { + return npc.getUniqueId(); + } + + @Override + public boolean isPersistent() { + return persistent; + } + + @Override + public NPCMetadata getMetadata() { + String displayName = npc.getName(); + SkinTrait skinTrait = npc.getTraitNullable(SkinTrait.class); + + if (skinTrait == null) { + return new NPCMetadata(displayName, null); + } + + NPCSkinData skinData = new NPCSkinData(skinTrait.getTexture(), skinTrait.getSignature()); + return new NPCMetadata(displayName, skinData); + } + + @Override + public void updateMetadata(NPCMetadata metadata) { + npc.setName(metadata.getDisplayName()); + + NPCSkinData skinData = metadata.getSkinData(); + + if (skinData == null) { + return; + } + + SkinTrait skinTrait = npc.getOrAddTrait(SkinTrait.class); + skinTrait.setTexture(skinData.getTexture(), skinData.getSignature()); + } + + @Override + public Location getLocation() { + return npc.getStoredLocation(); + } + + @Override + public void teleport(Location location) { + npc.teleport(location, TeleportCause.PLUGIN); + } + + @Override + public void onInteract(Consumer action) { + interactActions.add(action); + } + + @Override + public void remove() { + npc.destroy(); + } + + public void handleInteraction(Interaction interaction) { // I don't think this should be exposed + for (Consumer action : interactActions) { + action.accept(interaction); + } + } +} diff --git a/providers/citizens/src/main/java/de/minebench/tresor/providers/citizens/listener/CitizensNPCListener.java b/providers/citizens/src/main/java/de/minebench/tresor/providers/citizens/listener/CitizensNPCListener.java new file mode 100644 index 0000000..ac1f982 --- /dev/null +++ b/providers/citizens/src/main/java/de/minebench/tresor/providers/citizens/listener/CitizensNPCListener.java @@ -0,0 +1,50 @@ +package de.minebench.tresor.providers.citizens.listener; + +import de.minebench.tresor.providers.citizens.CitizensNPCs; +import de.minebench.tresor.providers.citizens.WrappedNPC; +import de.minebench.tresor.services.npc.data.Interaction; +import de.minebench.tresor.services.npc.data.Interaction.Type; +import net.citizensnpcs.api.event.NPCLeftClickEvent; +import net.citizensnpcs.api.event.NPCRightClickEvent; +import net.citizensnpcs.api.npc.NPC; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; + +public class CitizensNPCListener implements Listener { + + private final CitizensNPCs citizensNPCs; + + public CitizensNPCListener(CitizensNPCs citizensNPCs) { + this.citizensNPCs = citizensNPCs; + } + + @EventHandler + public void onLeftClick(NPCLeftClickEvent event) { + handleInteraction(event.getClicker(), event.getNPC(), Type.LEFT_CLICK); + } + + @EventHandler + public void onRightClick(NPCRightClickEvent event) { + handleInteraction(event.getClicker(), event.getNPC(), Type.RIGHT_CLICK); + } + + private void handleInteraction(Player player, NPC citizensNPC, Type interactionType) { + ItemStack item = player.getInventory().getItemInMainHand(); + de.minebench.tresor.services.npc.NPC wrappedNPC = citizensNPCs.getNPC(citizensNPC.getUniqueId()); + + if(!(wrappedNPC instanceof WrappedNPC)) { // Doubles as a null check + return; + } + + WrappedNPC wrappedCitizensNPC = (WrappedNPC) wrappedNPC; + Interaction interaction = new Interaction(player, interactionType, item); + wrappedCitizensNPC.handleInteraction(interaction); + + } + + + + +} diff --git a/providers/pom.xml b/providers/pom.xml index c065288..5f7205e 100644 --- a/providers/pom.xml +++ b/providers/pom.xml @@ -27,6 +27,9 @@ decentholograms + + + citizens