diff --git a/README.md b/README.md index 63fdaf1..c4f26fa 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ Simple! * Multiworld support. +* [Citizens](https://www.spigotmc.org/resources/citizens.13811/) support. + * Mod items support! * Repairing does not clear enchantments on enchanted items! @@ -128,6 +130,19 @@ If you want to change sound that NPC are making on interact – you can use inga All other config parameters are configurable in-game, so you don't have to bother about them. But if you want – they are quite self-explanatory. +### Citizens integration + +You can add traits to your npcs to act like respective Griswold NPC types. + +Following traits can be added: +- griswold_tools +- griswold_armor +- griswold_both +- griswold_enchant +- griswold_all + +Please don't add multiple traits at once, lol. + ### How to add a custom item You have to create a new entry in config with name CustomItems. This entry will contain two more entries: Tools and Armor. Under those you add your items in "'id': name" format. @@ -166,10 +181,11 @@ You can copy-paste this snippet to the end of your config. ## Support links * [Plugin page on dev.bukkit.org](http://dev.bukkit.org/bukkit-plugins/griswold/) +* [Plugin page on spigotmc.org](http://spigotmc.org/resources/griswold.49036/) * [Russian discussion and support](http://rubukkit.org/threads/15343/) * Feel free to suggest something or report bugs in Issues * Your pull-requests are always welcome! ## Stats: -![Griswold stats](http://mcstats.org/signature/griswold.png) \ No newline at end of file +![Griswold stats](http://mcstats.org/signature/griswold.png) diff --git a/plugin.yml b/plugin.yml index 92560b3..6c7bd48 100644 --- a/plugin.yml +++ b/plugin.yml @@ -32,4 +32,4 @@ permissions: description: Allows you to add enchantments default: op -softdepend: [Vault] \ No newline at end of file +softdepend: [Vault, Citizens] diff --git a/pom.xml b/pom.xml index 003b968..f9886c0 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,7 @@ UTF-8 1.5.6 1.12.2-R0.1-SNAPSHOT + 2.0.16-SNAPSHOT @@ -26,6 +27,12 @@ ${VaultVersion} provided + + + net.citizensnpcs + citizensapi + ${CitizensApiVersion} + @@ -37,6 +44,10 @@ vault-repo http://nexus.hc.to/content/repositories/pub_releases + + citizens-repo + http://repo.citizensnpcs.co + diff --git a/src/com/github/toxuin/griswold/CommandListener.java b/src/com/github/toxuin/griswold/CommandListener.java index 04e6f28..3424d9c 100644 --- a/src/com/github/toxuin/griswold/CommandListener.java +++ b/src/com/github/toxuin/griswold/CommandListener.java @@ -124,7 +124,7 @@ else if (args[0].equalsIgnoreCase("hide")) { return true; } try { - Repairer.getByName(args[1]).despawn(); + GriswoldNPC.getByName(args[1]).despawn(); sender.sendMessage(Lang.chat_hidden); } catch (IllegalArgumentException ignored) { sender.sendMessage(Lang.error_remove); @@ -139,7 +139,7 @@ else if (args[0].equalsIgnoreCase("unhide")) { return true; } try { - Repairer.getByName(args[1]).spawn(); + GriswoldNPC.getByName(args[1]).spawn(); sender.sendMessage(Lang.chat_unhidden); } catch (IllegalArgumentException ignored) { sender.sendMessage(Lang.chat_error); diff --git a/src/com/github/toxuin/griswold/EventListener.java b/src/com/github/toxuin/griswold/EventListener.java index 03c3879..a9e958e 100644 --- a/src/com/github/toxuin/griswold/EventListener.java +++ b/src/com/github/toxuin/griswold/EventListener.java @@ -17,7 +17,7 @@ public class EventListener implements Listener { private final Griswold plugin; - private final Map npcChunks; + private final Map npcChunks; EventListener(final Griswold plugin) { this.plugin = plugin; @@ -28,7 +28,7 @@ public class EventListener implements Listener { @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onEntityDamage(EntityDamageEvent event) { if (npcChunks.isEmpty()) return; - Set npcs = npcChunks.keySet(); + Set npcs = npcChunks.keySet(); for (Repairer rep : npcs) { if (event.getEntity().equals(rep.getEntity())) { event.setDamage(0d); @@ -46,7 +46,7 @@ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { return; } - Set npcs = npcChunks.keySet(); + Set npcs = npcChunks.keySet(); for (Repairer rep : npcs) { if (event.getRightClicked().equals(rep.getEntity())) { plugin.interactor.interact(event.getPlayer(), rep); @@ -59,7 +59,7 @@ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { @EventHandler public void onZombieTarget(EntityTargetLivingEntityEvent event) { if (event.getEntity() instanceof Zombie) { - Set npcs = npcChunks.keySet(); + Set npcs = npcChunks.keySet(); for (Repairer rep : npcs) { if (rep.getEntity().equals(event.getTarget())) { event.setCancelled(true); @@ -76,7 +76,7 @@ public void onChunkLoad(ChunkLoadEvent event) { for (Pair pair : npcChunks.values()) { if (pair.equals(coords)) { - for (Repairer rep : npcChunks.keySet()) { + for (GriswoldNPC rep : npcChunks.keySet()) { if (npcChunks.get(rep).equals(coords)) { rep.spawn(); if (Griswold.debug) Griswold.log.info("SPAWNED NPC " + rep.getName() + ", HIS CHUNK LOADED"); @@ -93,7 +93,7 @@ public void onChunkUnload(ChunkUnloadEvent event) { for (Pair pair : npcChunks.values()) { if (pair.equals(coords)) { - for (Repairer rep : npcChunks.keySet()) { + for (GriswoldNPC rep : npcChunks.keySet()) { if (npcChunks.get(rep).equals(coords)) { rep.despawn(); if (Griswold.debug) Griswold.log.info("DESPAWNED NPC " + rep.getName() + ", HIS CHUNK GOT UNLOADED"); diff --git a/src/com/github/toxuin/griswold/Griswold.java b/src/com/github/toxuin/griswold/Griswold.java index ead2f0b..f677294 100644 --- a/src/com/github/toxuin/griswold/Griswold.java +++ b/src/com/github/toxuin/griswold/Griswold.java @@ -1,6 +1,7 @@ package com.github.toxuin.griswold; import com.github.toxuin.griswold.Metrics.Graph; +import com.github.toxuin.griswold.adapters.citizens.CitizensAdapter; import com.github.toxuin.griswold.util.Pair; import net.milkbowl.vault.economy.Economy; import org.bukkit.Bukkit; @@ -10,6 +11,7 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.Listener; +import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; @@ -22,6 +24,7 @@ import java.util.logging.Logger; public class Griswold extends JavaPlugin implements Listener { + public static final String PLUGIN_NAME = "Griswold"; static File directory; static boolean debug = false; public static int timeout = 5000; @@ -29,7 +32,7 @@ public class Griswold extends JavaPlugin implements Listener { static FileConfiguration config = null; private static File configFile = null; - static Map npcChunks = new HashMap<>(); + static Map npcChunks = new HashMap<>(); Interactor interactor; static Economy economy = null; @@ -42,6 +45,8 @@ public class Griswold extends JavaPlugin implements Listener { static boolean findDuplicates = false; static int duplicateFinderRadius = 5; + CitizensAdapter citizensAdapter; + public void onEnable() { log = this.getLogger(); directory = this.getDataFolder(); @@ -84,10 +89,24 @@ public void onEnable() { if (Lang.chat_agreed.startsWith("ERROR:")) reloadPlugin(); // this is fucking gold }, 20); + Plugin citizens = getServer().getPluginManager().getPlugin("Citizens"); + if (citizens != null && citizens.isEnabled()) { + citizensAdapter = new CitizensAdapter(); + log.info("Registered Griswold traits with Citizens"); + } + try { Metrics metrics = new Metrics(this); - Graph graph = metrics.createGraph("Number of NPCs"); - graph.addPlotter(new Metrics.Plotter("Total") { + Graph citizensGraph = metrics.createGraph("Using Citizens2"); + citizensGraph.addPlotter(new Metrics.Plotter() { + @Override + public int getValue() { + return citizensAdapter == null ? 0 : 1; + } + }); + + Graph numberOfNpcGraph = metrics.createGraph("Number of NPCs"); + numberOfNpcGraph.addPlotter(new Metrics.Plotter("Total") { @Override public int getValue() { return npcChunks.keySet().size(); @@ -105,6 +124,7 @@ public void onDisable() { interactor = null; getCommand("blacksmith").setExecutor(null); despawnAll(); + if (citizensAdapter != null) citizensAdapter.deregisterTraits(); log.info("Disabled."); } @@ -123,7 +143,7 @@ void createRepairman(String name, Location loc, String type) { void createRepairman(String name, Location loc, String type, String cost) { boolean found = false; - Set npcs = npcChunks.keySet(); + Set npcs = npcChunks.keySet(); for (Repairer rep : npcs) { if (rep.getName().equalsIgnoreCase(name)) found = true; } @@ -147,8 +167,7 @@ void createRepairman(String name, Location loc, String type, String cost) { e.printStackTrace(); } - Repairer meGusta = new Repairer(name, loc, Repairer.getDefaultSound(), type, Double.parseDouble(cost)); - + GriswoldNPC meGusta = new GriswoldNPC(name, loc, Repairer.getDefaultSound(), type, Double.parseDouble(cost)); meGusta.spawn(); } @@ -177,7 +196,7 @@ void listRepairmen(CommandSender sender) { } void despawnAll() { - Griswold.npcChunks.keySet().forEach(Repairer::despawn); + Griswold.npcChunks.keySet().forEach(GriswoldNPC::despawn); npcChunks.clear(); } @@ -195,7 +214,7 @@ void toggleNames() { } void setSound(String name, String sound) { - Set npcs = npcChunks.keySet(); + Set npcs = npcChunks.keySet(); for (Repairer rep : npcs) { if (rep.getName().equals(name)) { rep.setSound(sound); @@ -204,7 +223,7 @@ void setSound(String name, String sound) { } } - Map getNpcChunks() { + Map getNpcChunks() { return npcChunks; } @@ -258,7 +277,7 @@ private void readConfig() { String type = config.getString("repairmen." + repairman + ".type"); double cost = config.getDouble("repairmen." + repairman + ".cost"); - Repairer squidward = new Repairer(repairman, loc, sound, type, cost); + GriswoldNPC squidward = new GriswoldNPC(repairman, loc, sound, type, cost); squidward.loadChunk(); squidward.spawn(); @@ -381,4 +400,8 @@ private boolean setupEconomy() { } return (economy != null); } + + public Interactor getInteractor() { + return interactor; + } } diff --git a/src/com/github/toxuin/griswold/GriswoldNPC.java b/src/com/github/toxuin/griswold/GriswoldNPC.java new file mode 100644 index 0000000..fc69c0c --- /dev/null +++ b/src/com/github/toxuin/griswold/GriswoldNPC.java @@ -0,0 +1,184 @@ +package com.github.toxuin.griswold; + +import com.github.toxuin.griswold.util.Pair; +import com.github.toxuin.griswold.util.RepairerType; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Villager; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; +import java.util.Random; +import java.util.Set; + +public class GriswoldNPC extends Repairer { + private Entity entity; + private Random rnd = new Random(); + private boolean spawned; + + private final Class entityInsentient = ClassProxy.getClass("EntityInsentient"); + private final Class entityHuman = ClassProxy.getClass("EntityHuman"); + private final Class pathfinderGoalSelector = ClassProxy.getClass("PathfinderGoalSelector"); + private final Class pathfinderGoalLookAtPlayer = ClassProxy.getClass("PathfinderGoalLookAtPlayer"); + private final Class pathfinderGoalRandomLookaround = ClassProxy.getClass("PathfinderGoalRandomLookaround"); + private final Class pathfinderGoal = ClassProxy.getClass("PathfinderGoal"); + private final Class craftWorld = ClassProxy.getClass("CraftWorld"); + private final Class craftEntity = ClassProxy.getClass("entity.CraftEntity"); + private final Class craftVillager = ClassProxy.getClass("entity.CraftVillager"); + private final Class entityClass = ClassProxy.getClass("Entity"); + + GriswoldNPC(String name, Location loc, String sound, String type, double cost) { + super(name, loc, sound, type, cost); + this.spawned = false; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private void overwriteAI() { + try { + Method getHandle = craftVillager.getMethod("getHandle"); + Object villager = getHandle.invoke(craftVillager.cast(entity)); + Field goalsField = entityInsentient.getDeclaredField("goalSelector"); + goalsField.setAccessible(true); + Object goals = pathfinderGoalSelector.cast(goalsField.get(villager)); + Field listField = pathfinderGoalSelector.getDeclaredField("b"); + listField.setAccessible(true); + Collection list = (Collection) listField.get(goals); + list.clear(); + + Method setGoal = pathfinderGoalSelector.getMethod("a", int.class, pathfinderGoal); + Constructor lookAtPlayerConstructor = pathfinderGoalLookAtPlayer.getConstructor(entityInsentient, Class.class, float.class, float.class); + Constructor randomLookAroundConstructor = pathfinderGoalRandomLookaround.getConstructor(entityInsentient); + + setGoal.invoke(goals, 1, lookAtPlayerConstructor.newInstance(villager, entityHuman, 12.0F, 1.0F)); + setGoal.invoke(goals, 2, randomLookAroundConstructor.newInstance(villager)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + @SuppressWarnings("unchecked") + public void haggle() { + if (craftEntity == null) return; + if (this.sound != null && !this.sound.isEmpty() && !this.sound.equals("mute") && craftEntity.isInstance(this.entity)) { + try { + Sound snd = Sound.valueOf(sound); + this.entity.getWorld().playSound(entity.getLocation(), snd, 1.2f, 1.6F + (this.rnd.nextFloat() - this.rnd.nextFloat()) * 0.4F); + } catch (IllegalArgumentException e) { + Griswold.log.info("NPC " + this.getName() + " has invalid sound " + sound + "! Disabling sound for it..."); + sound = null; + } + } + } + + void loadChunk() { + getLocation().getWorld().loadChunk(getLocation().getChunk()); + } + + void spawn() { + if (isSpawned()) return; + Location loc = getLocation(); + if (loc == null) { + Griswold.log.info("ERROR: LOCATION IS NULL"); + return; + } + if (getType().equals(RepairerType.ENCHANT) && !Interactor.enableEnchants) { + Griswold.log.info(String.format(Lang.error_enchanter_not_spawned, loc.getX(), loc.getY(), loc.getZ())); + return; + } + LivingEntity repairman = (LivingEntity) loc.getWorld().spawn(loc, EntityType.VILLAGER.getEntityClass()); + repairman.setCustomNameVisible(Griswold.namesVisible); + repairman.setCustomName(name); + if (getType().equals(RepairerType.ENCHANT)) { + ((Villager) repairman).setProfession(Villager.Profession.LIBRARIAN); + } else { + ((Villager) repairman).setProfession(Villager.Profession.BLACKSMITH); + } + + this.entity = repairman; + + if (!Griswold.npcChunks.containsKey(this)) + Griswold.npcChunks.put(this, new Pair(loc.getChunk().getX(), loc.getChunk().getZ())); + + this.overwriteAI(); + + // FILTER DUPLICATES + if (Griswold.findDuplicates) + Arrays.asList(getLocation().getChunk().getEntities()).forEach((doppelganger) -> { + if (this.entityClass == null) return; // YOU'RE WEIRD + if (!(doppelganger.getLocation().distance(getLocation()) <= Griswold.duplicateFinderRadius)) return; + Class craftVillagerClass = ClassProxy.getClass("entity.CraftVillager"); + if (craftVillagerClass == null) { + Griswold.log.severe("ERROR: CANNOT FIND CLASS CraftVillager"); + return; + } + if (!craftVillagerClass.isInstance(doppelganger)) return; // are you even villager? + if (this.entity.equals(doppelganger)) return; // prevent suiciding + if (doppelganger.getName().equals(this.name)) doppelganger.remove(); // 100% DUPLICATE + }); + + if (Griswold.debug) { + Griswold.log.info(String.format(Lang.repairman_spawn, this.entity.getEntityId(), loc.getX(), loc.getY(), loc.getZ())); + } + setSpawned(true); + } + + void despawn() { + if (!this.isSpawned()) return; + Griswold.npcChunks.keySet().forEach((rep) -> { + if (rep.equals(this)) rep.getEntity().remove(); + }); + setSpawned(false); + } + + @Override + public boolean isSpawned() { + return spawned; + } + + @Override + public void setSpawned(boolean newState) { + this.spawned = newState; + } + + public void toggleName(boolean toggle) { + LivingEntity entity = (LivingEntity) this.entity; + entity.setCustomNameVisible(toggle); + } + + @Override + public Entity getEntity() { + return entity; + } + + public void setEntity(Entity entity) { + this.entity = entity; + } + + public static GriswoldNPC getByName(final String name) throws IllegalArgumentException { + for (GriswoldNPC npc : Griswold.npcChunks.keySet()) if (npc.getName().equals(name)) return npc; + + FileConfiguration config = Griswold.config; + Set repairmen = config.getConfigurationSection("repairmen").getKeys(false); + if (!repairmen.contains(name)) throw new IllegalArgumentException("Repairman with name " + name + " not found"); + + + Location loc = new Location(Bukkit.getWorld(config.getString("repairmen." + name + ".world")), + config.getDouble("repairmen." + name + ".X"), + config.getDouble("repairmen." + name + ".Y"), + config.getDouble("repairmen." + name + ".Z")); + String sound = config.getString("repairmen." + name + ".sound"); + String type = config.getString("repairmen." + name + ".type"); + double cost = config.getDouble("repairmen." + name + ".cost"); + + return new GriswoldNPC(name, loc, sound, type, cost); + } +} diff --git a/src/com/github/toxuin/griswold/Interactor.java b/src/com/github/toxuin/griswold/Interactor.java index 9158f08..90dc50c 100644 --- a/src/com/github/toxuin/griswold/Interactor.java +++ b/src/com/github/toxuin/griswold/Interactor.java @@ -18,7 +18,7 @@ import static com.github.toxuin.griswold.Griswold.log; -class Interactor { +public class Interactor { static double basicToolsPrice = 10.0; static double basicArmorPrice = 10.0; static double enchantmentPrice = 30.0; @@ -201,7 +201,7 @@ private boolean isInteger(String number) { @SuppressWarnings("unchecked, deprecation") //noinspection Duplicates - void interact(Player player, Repairer repairman) { + public void interact(Player player, Repairer repairman) { final ItemStack item = (Griswold.apiVersion.getMajor() >= 1 && Griswold.apiVersion.getMinor() >= 9) ? player.getInventory().getItemInMainHand() : player.getInventory().getItemInHand(); diff --git a/src/com/github/toxuin/griswold/Repairer.java b/src/com/github/toxuin/griswold/Repairer.java index a535ba5..9ecb3c4 100644 --- a/src/com/github/toxuin/griswold/Repairer.java +++ b/src/com/github/toxuin/griswold/Repairer.java @@ -1,47 +1,17 @@ package com.github.toxuin.griswold; -import com.github.toxuin.griswold.util.Pair; import com.github.toxuin.griswold.util.RepairerType; -import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.Sound; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Villager; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Collection; -import java.util.Random; -import java.util.Set; - -public class Repairer { - - private Entity entity; - private String name = "Repairman"; + +public abstract class Repairer { + private static final String DEFAULT_SOUND = "ENTITY_VILLAGER_TRADING"; + + public String name = "Repairman"; + public String sound = DEFAULT_SOUND; private Location loc; private RepairerType type = RepairerType.ALL; private double cost = 1.0d; - private static final String DEFAULT_SOUND = "ENTITY_VILLAGER_TRADING"; - private String sound = "ENTITY_VILLAGER_TRADING"; - private boolean spawned; - - private Random rnd = new Random(); - - final Class entityInsentient = ClassProxy.getClass("EntityInsentient"); - final Class entityHuman = ClassProxy.getClass("EntityHuman"); - final Class pathfinderGoalSelector = ClassProxy.getClass("PathfinderGoalSelector"); - final Class pathfinderGoalLookAtPlayer = ClassProxy.getClass("PathfinderGoalLookAtPlayer"); - final Class pathfinderGoalRandomLookaround = ClassProxy.getClass("PathfinderGoalRandomLookaround"); - final Class pathfinderGoal = ClassProxy.getClass("PathfinderGoal"); - final Class craftWorld = ClassProxy.getClass("CraftWorld"); - final Class craftEntity = ClassProxy.getClass("entity.CraftEntity"); - final Class craftVillager = ClassProxy.getClass("entity.CraftVillager"); - final Class entityClass = ClassProxy.getClass("Entity"); public Repairer(final String name, final Location loc, final String sound, final String type, final double cost) { this.name = name; @@ -49,119 +19,11 @@ public Repairer(final String name, final Location loc, final String sound, final this.sound = sound; this.type = RepairerType.fromString(type); this.cost = cost; - this.spawned = false; - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private void overwriteAI() { - try { - Method getHandle = craftVillager.getMethod("getHandle"); - Object villager = getHandle.invoke(craftVillager.cast(entity)); - Field goalsField = entityInsentient.getDeclaredField("goalSelector"); - goalsField.setAccessible(true); - Object goals = pathfinderGoalSelector.cast(goalsField.get(villager)); - Field listField = pathfinderGoalSelector.getDeclaredField("b"); - listField.setAccessible(true); - Collection list = (Collection) listField.get(goals); - list.clear(); - - Method setGoal = pathfinderGoalSelector.getMethod("a", int.class, pathfinderGoal); - Constructor lookAtPlayerConstructor = pathfinderGoalLookAtPlayer.getConstructor(entityInsentient, Class.class, float.class, float.class); - Constructor randomLookAroundConstructor = pathfinderGoalRandomLookaround.getConstructor(entityInsentient); - - setGoal.invoke(goals, 1, lookAtPlayerConstructor.newInstance(villager, entityHuman, 12.0F, 1.0F)); - setGoal.invoke(goals, 2, randomLookAroundConstructor.newInstance(villager)); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @SuppressWarnings("unchecked") - void haggle() { - if (craftEntity == null) return; - if (this.sound != null && !this.sound.isEmpty() && !this.sound.equals("mute") && craftEntity.isInstance(this.entity)) { - try { - Sound snd = Sound.valueOf(sound); - this.entity.getWorld().playSound(entity.getLocation(), snd, 1.2f, 1.6F + (this.rnd.nextFloat() - this.rnd.nextFloat()) * 0.4F); - } catch (IllegalArgumentException e) { - Griswold.log.info("NPC " + name + " has invalid sound " + sound + "! Disabling sound for it..."); - sound = null; - } - } - } - - void loadChunk() { - getLocation().getWorld().loadChunk(getLocation().getChunk()); } - void spawn() { - if(spawned) return; - Location loc = getLocation(); - if (loc == null) { - Griswold.log.info("ERROR: LOCATION IS NULL"); - return; - } - if (getType().equals(RepairerType.ENCHANT) && !Interactor.enableEnchants) { - Griswold.log.info(String.format(Lang.error_enchanter_not_spawned, loc.getX(), loc.getY(), loc.getZ())); - return; - } - LivingEntity repairman = (LivingEntity) loc.getWorld().spawn(loc, EntityType.VILLAGER.getEntityClass()); - repairman.setCustomNameVisible(Griswold.namesVisible); - repairman.setCustomName(name); - if (getType().equals(RepairerType.ENCHANT)) { - ((Villager) repairman).setProfession(Villager.Profession.LIBRARIAN); - } else { - ((Villager) repairman).setProfession(Villager.Profession.BLACKSMITH); - } - - this.entity = repairman; - - if (!Griswold.npcChunks.containsKey(this)) - Griswold.npcChunks.put(this, new Pair(loc.getChunk().getX(), loc.getChunk().getZ())); - - this.overwriteAI(); - - // FILTER DUPLICATES - if (Griswold.findDuplicates) - Arrays.asList(getLocation().getChunk().getEntities()).forEach((doppelganger) -> { - if (this.entityClass == null) return; // YOU'RE WEIRD - if (!(doppelganger.getLocation().distance(getLocation()) <= Griswold.duplicateFinderRadius)) return; - Class craftVillagerClass = ClassProxy.getClass("entity.CraftVillager"); - if (craftVillagerClass == null) { - Griswold.log.severe("ERROR: CANNOT FIND CLASS CraftVillager"); - return; - } - if (!craftVillagerClass.isInstance(doppelganger)) return; // are you even villager? - if (this.entity.equals(doppelganger)) return; // prevent suiciding - if (doppelganger.getName().equals(this.name)) doppelganger.remove(); // 100% DUPLICATE - }); - - if (Griswold.debug) { - Griswold.log.info(String.format(Lang.repairman_spawn, this.entity.getEntityId(), loc.getX(), loc.getY(), loc.getZ())); - } - spawned = true; - } - - public void despawn() { - if(!spawned) return; - Griswold.npcChunks.keySet().forEach((rep) -> { - if (rep.equals(this)) rep.getEntity().remove(); - }); - spawned = false; - } - - public void toggleName(boolean toggle) { - LivingEntity entity = (LivingEntity) this.entity; - entity.setCustomNameVisible(toggle); - } + public abstract void haggle(); - public Entity getEntity() { - return entity; - } - - public void setEntity(Entity entity) { - this.entity = entity; - } + // GETTERS & SETTERS public String getName() { return name; @@ -172,7 +34,7 @@ public void setName(String name) { } public Location getLocation() { - return loc; + return this.loc; } public void setLocation(Location loc) { @@ -207,23 +69,11 @@ public void setSound(String sound) { this.sound = sound; } - public static Repairer getByName(final String name) throws IllegalArgumentException { - for(Repairer r : Griswold.npcChunks.keySet()) if(r.getName().equals(name)) return r; - FileConfiguration config = Griswold.config; - Set repairmen = config.getConfigurationSection("repairmen").getKeys(false); - if (!repairmen.contains(name)) throw new IllegalArgumentException("Repairman with name " + name + " not found"); + public abstract boolean isSpawned(); + public abstract void setSpawned(boolean newState); - Location loc = new Location(Bukkit.getWorld(config.getString("repairmen." + name + ".world")), - config.getDouble("repairmen." + name + ".X"), - config.getDouble("repairmen." + name + ".Y"), - config.getDouble("repairmen." + name + ".Z")); - String sound = config.getString("repairmen." + name + ".sound"); - String type = config.getString("repairmen." + name + ".type"); - double cost = config.getDouble("repairmen." + name + ".cost"); - - return new Repairer(name, loc, sound, type, cost); - } + public abstract Entity getEntity(); @Override public boolean equals(Object o) { diff --git a/src/com/github/toxuin/griswold/adapters/citizens/CitizensAdapter.java b/src/com/github/toxuin/griswold/adapters/citizens/CitizensAdapter.java new file mode 100644 index 0000000..5c78c63 --- /dev/null +++ b/src/com/github/toxuin/griswold/adapters/citizens/CitizensAdapter.java @@ -0,0 +1,41 @@ +package com.github.toxuin.griswold.adapters.citizens; + +import net.citizensnpcs.api.CitizensAPI; +import net.citizensnpcs.api.trait.TraitInfo; + +public class CitizensAdapter { + static final String TOOLS_REPAIR_TRAIT_NAME = "griswold_tools"; + static final String ARMOR_REPAIR_TRAIT_NAME = "griswold_armor"; + static final String BOTH_REPAIR_TRAIT_NAME = "griswold_both"; + static final String ENCHANT_TRAIT_NAME = "griswold_enchant"; + static final String ALL_TRAIT_NAME = "griswold_all"; + + private TraitInfo toolsRepairerTrait; // TOOLS + private TraitInfo armorRepairerTrait; // ARMOR + private TraitInfo anyRepairerTrait; // BOTH + private TraitInfo enchanterTrait; // ENCHANT + private TraitInfo everythingTrait; // ALL + + public CitizensAdapter() { + toolsRepairerTrait = TraitInfo.create(GriswoldToolsTrait.class).withName(TOOLS_REPAIR_TRAIT_NAME); + armorRepairerTrait = TraitInfo.create(GriswoldArmorTrait.class).withName(ARMOR_REPAIR_TRAIT_NAME); + anyRepairerTrait = TraitInfo.create(GriswoldBothTrait.class).withName(BOTH_REPAIR_TRAIT_NAME); + enchanterTrait = TraitInfo.create(GriswoldEnchantTrait.class).withName(ENCHANT_TRAIT_NAME); + everythingTrait = TraitInfo.create(GriswoldAllTrait.class).withName(ALL_TRAIT_NAME); + + CitizensAPI.getTraitFactory().registerTrait(toolsRepairerTrait); + CitizensAPI.getTraitFactory().registerTrait(armorRepairerTrait); + CitizensAPI.getTraitFactory().registerTrait(anyRepairerTrait); + CitizensAPI.getTraitFactory().registerTrait(enchanterTrait); + CitizensAPI.getTraitFactory().registerTrait(everythingTrait); + } + + public void deregisterTraits() { + CitizensAPI.getTraitFactory().deregisterTrait(toolsRepairerTrait); + CitizensAPI.getTraitFactory().deregisterTrait(armorRepairerTrait); + CitizensAPI.getTraitFactory().deregisterTrait(anyRepairerTrait); + CitizensAPI.getTraitFactory().deregisterTrait(enchanterTrait); + CitizensAPI.getTraitFactory().deregisterTrait(everythingTrait); + } + +} diff --git a/src/com/github/toxuin/griswold/adapters/citizens/CitizensFakeNPC.java b/src/com/github/toxuin/griswold/adapters/citizens/CitizensFakeNPC.java new file mode 100644 index 0000000..12dff13 --- /dev/null +++ b/src/com/github/toxuin/griswold/adapters/citizens/CitizensFakeNPC.java @@ -0,0 +1,66 @@ +package com.github.toxuin.griswold.adapters.citizens; + +import com.github.toxuin.griswold.Repairer; +import com.github.toxuin.griswold.util.RepairerType; +import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.api.trait.Trait; +import org.bukkit.entity.Entity; + +public class CitizensFakeNPC extends Repairer { + private NPC citizensNPC; + + public CitizensFakeNPC(NPC npc, RepairerType type, double citizensCost) { + super(npc.getName(), npc.getStoredLocation(), Repairer.getDefaultSound(), type.toString(), citizensCost); + this.citizensNPC = npc; + } + + public NPC getCitizensNpc() { + return citizensNPC; + } + + @Override + public double getCost() { + NPC npc = this.citizensNPC; + GriswoldTrait trait = null; + for (Trait t : npc.getTraits()) { + if (t instanceof GriswoldTrait) trait = (GriswoldTrait) t; + } + if (trait != null) return trait.getCost(); + return 1; + } + + @Override + public void setCost(double cost) { + NPC npc = this.citizensNPC; + GriswoldTrait trait = null; + for (Trait t : npc.getTraits()) { + if (t instanceof GriswoldTrait) trait = (GriswoldTrait) t; + } + if (trait == null) return; + trait.setCost(cost); + } + + void setCitizensNPC(NPC npc) { + this.citizensNPC = npc; + } + + @Override + public void haggle() { + // BEEP BEEP MOTHERFUCKER + } + + @Override + public boolean isSpawned() { + return citizensNPC.isSpawned(); + } + + @Override + public void setSpawned(boolean newState) { + // YOU HAVE NO POWER HERE + } + + @Override + public Entity getEntity() { + return citizensNPC.getEntity(); + } +} diff --git a/src/com/github/toxuin/griswold/adapters/citizens/GriswoldAllTrait.java b/src/com/github/toxuin/griswold/adapters/citizens/GriswoldAllTrait.java new file mode 100644 index 0000000..8976538 --- /dev/null +++ b/src/com/github/toxuin/griswold/adapters/citizens/GriswoldAllTrait.java @@ -0,0 +1,15 @@ +package com.github.toxuin.griswold.adapters.citizens; + +import com.github.toxuin.griswold.util.RepairerType; +import net.citizensnpcs.api.trait.TraitName; + +@TraitName(CitizensAdapter.ALL_TRAIT_NAME) +public class GriswoldAllTrait extends GriswoldTrait { + public GriswoldAllTrait() { + super(CitizensAdapter.ALL_TRAIT_NAME); + } + @Override + public RepairerType getType() { + return RepairerType.ALL; + } +} diff --git a/src/com/github/toxuin/griswold/adapters/citizens/GriswoldArmorTrait.java b/src/com/github/toxuin/griswold/adapters/citizens/GriswoldArmorTrait.java new file mode 100644 index 0000000..4e75fa0 --- /dev/null +++ b/src/com/github/toxuin/griswold/adapters/citizens/GriswoldArmorTrait.java @@ -0,0 +1,15 @@ +package com.github.toxuin.griswold.adapters.citizens; + +import com.github.toxuin.griswold.util.RepairerType; +import net.citizensnpcs.api.trait.TraitName; + +@TraitName(CitizensAdapter.ARMOR_REPAIR_TRAIT_NAME) +public class GriswoldArmorTrait extends GriswoldTrait { + public GriswoldArmorTrait() { + super(CitizensAdapter.ARMOR_REPAIR_TRAIT_NAME); + } + @Override + public RepairerType getType() { + return RepairerType.ARMOR; + } +} \ No newline at end of file diff --git a/src/com/github/toxuin/griswold/adapters/citizens/GriswoldBothTrait.java b/src/com/github/toxuin/griswold/adapters/citizens/GriswoldBothTrait.java new file mode 100644 index 0000000..31e415d --- /dev/null +++ b/src/com/github/toxuin/griswold/adapters/citizens/GriswoldBothTrait.java @@ -0,0 +1,15 @@ +package com.github.toxuin.griswold.adapters.citizens; + +import com.github.toxuin.griswold.util.RepairerType; +import net.citizensnpcs.api.trait.TraitName; + +@TraitName(CitizensAdapter.BOTH_REPAIR_TRAIT_NAME) +public class GriswoldBothTrait extends GriswoldTrait { + public GriswoldBothTrait() { + super(CitizensAdapter.BOTH_REPAIR_TRAIT_NAME); + } + @Override + public RepairerType getType() { + return RepairerType.BOTH; + } +} diff --git a/src/com/github/toxuin/griswold/adapters/citizens/GriswoldEnchantTrait.java b/src/com/github/toxuin/griswold/adapters/citizens/GriswoldEnchantTrait.java new file mode 100644 index 0000000..af03305 --- /dev/null +++ b/src/com/github/toxuin/griswold/adapters/citizens/GriswoldEnchantTrait.java @@ -0,0 +1,15 @@ +package com.github.toxuin.griswold.adapters.citizens; + +import com.github.toxuin.griswold.util.RepairerType; +import net.citizensnpcs.api.trait.TraitName; + +@TraitName(CitizensAdapter.ENCHANT_TRAIT_NAME) +public class GriswoldEnchantTrait extends GriswoldTrait { + public GriswoldEnchantTrait() { + super(CitizensAdapter.ENCHANT_TRAIT_NAME); + } + @Override + public RepairerType getType() { + return RepairerType.ENCHANT; + } +} \ No newline at end of file diff --git a/src/com/github/toxuin/griswold/adapters/citizens/GriswoldToolsTrait.java b/src/com/github/toxuin/griswold/adapters/citizens/GriswoldToolsTrait.java new file mode 100644 index 0000000..907687c --- /dev/null +++ b/src/com/github/toxuin/griswold/adapters/citizens/GriswoldToolsTrait.java @@ -0,0 +1,16 @@ +package com.github.toxuin.griswold.adapters.citizens; + +import com.github.toxuin.griswold.util.RepairerType; +import net.citizensnpcs.api.trait.TraitName; + +@TraitName(CitizensAdapter.TOOLS_REPAIR_TRAIT_NAME) +public class GriswoldToolsTrait extends GriswoldTrait { + public GriswoldToolsTrait() { + super(CitizensAdapter.TOOLS_REPAIR_TRAIT_NAME); + } + + @Override + public RepairerType getType() { + return RepairerType.TOOLS; + } +} diff --git a/src/com/github/toxuin/griswold/adapters/citizens/GriswoldTrait.java b/src/com/github/toxuin/griswold/adapters/citizens/GriswoldTrait.java new file mode 100644 index 0000000..ebfd38a --- /dev/null +++ b/src/com/github/toxuin/griswold/adapters/citizens/GriswoldTrait.java @@ -0,0 +1,43 @@ +package com.github.toxuin.griswold.adapters.citizens; + +import com.github.toxuin.griswold.Griswold; +import com.github.toxuin.griswold.Interactor; +import com.github.toxuin.griswold.util.RepairerType; +import net.citizensnpcs.api.event.NPCRightClickEvent; +import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.api.persistence.Persist; +import net.citizensnpcs.api.trait.Trait; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; + +public abstract class GriswoldTrait extends Trait { + private Griswold griswold; + private final Interactor interactor; + + @Persist private double cost = 1d; + + public GriswoldTrait(String name) { + super(name); + griswold = (Griswold) Bukkit.getServer().getPluginManager().getPlugin(Griswold.PLUGIN_NAME); + interactor = griswold.getInteractor(); + } + + @EventHandler(ignoreCancelled = true) + public void rightCliked(NPCRightClickEvent event) { + NPC npc = event.getNPC(); + if (!npc.equals(this.getNPC())) return; + + CitizensFakeNPC citizensFakeNPC = new CitizensFakeNPC(npc, getType(), getCost()); + interactor.interact(event.getClicker(), citizensFakeNPC); + } + + public double getCost() { + return cost; + } + + public void setCost(double cost) { + this.cost = cost; + } + + public abstract RepairerType getType(); +}