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();
+}