diff --git a/src/main/java/net/citizensnpcs/Citizens.java b/src/main/java/net/citizensnpcs/Citizens.java index f2f8c93b7..b0a8afed8 100644 --- a/src/main/java/net/citizensnpcs/Citizens.java +++ b/src/main/java/net/citizensnpcs/Citizens.java @@ -7,9 +7,11 @@ import java.util.logging.Level; import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.api.CitizensAPI; +import net.citizensnpcs.api.CitizensPlugin; import net.citizensnpcs.api.event.CitizensReloadEvent; import net.citizensnpcs.api.exception.NPCLoadException; import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.api.npc.character.CharacterManager; import net.citizensnpcs.api.scripting.EventRegistrar; import net.citizensnpcs.api.scripting.ObjectProvider; import net.citizensnpcs.api.scripting.ScriptCompiler; @@ -19,7 +21,6 @@ import net.citizensnpcs.api.util.DatabaseStorage; import net.citizensnpcs.api.util.NBTStorage; import net.citizensnpcs.api.util.Storage; import net.citizensnpcs.api.util.YamlStorage; -import net.citizensnpcs.api.npc.character.Character; import net.citizensnpcs.command.CommandManager; import net.citizensnpcs.command.Injector; import net.citizensnpcs.command.command.AdminCommands; @@ -41,6 +42,7 @@ import net.citizensnpcs.util.Messaging; import net.citizensnpcs.util.Metrics; import net.citizensnpcs.util.StringHelper; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -51,7 +53,7 @@ import org.bukkit.plugin.java.JavaPlugin; import com.google.common.collect.Iterators; -public class Citizens extends JavaPlugin { +public class Citizens extends JavaPlugin implements CitizensPlugin { private final CitizensCharacterManager characterManager = new CitizensCharacterManager(); private final CommandManager commands = new CommandManager(); private boolean compatible; @@ -61,14 +63,30 @@ public class Citizens extends JavaPlugin { private Storage saves; private TraitManager traitManager; - public CommandManager getCommandManager() { - return commands; + @Override + public CharacterManager getCharacterManager() { + return characterManager; } + public CommandManager getCommandManager() { + return commands; // TODO: this doesn't need to be exposed. + } + + @Override public CitizensNPCManager getNPCManager() { return npcManager; } + @Override + public File getScriptFolder() { + return new File(getDataFolder(), "scripts"); + } + + @Override + public TraitManager getTraitManager() { + return traitManager; + } + @Override public boolean onCommand(CommandSender sender, Command cmd, String cmdName, String[] args) { Player player = null; @@ -111,7 +129,7 @@ public class Citizens extends JavaPlugin { Messaging.sendError(player, "That is not a valid number."); } catch (Throwable ex) { ex.printStackTrace(); - if (sender instanceof Player) { + if (player != null) { Messaging.sendError(player, "Please report this error: [See console]"); Messaging.sendError(player, ex.getClass().getName() + ": " + ex.getMessage()); } @@ -121,6 +139,8 @@ public class Citizens extends JavaPlugin { @Override public void onDisable() { + Bukkit.getPluginManager().callEvent(new CitizensDisableEvent()); + tearDownScripting(); // Don't bother with this part if MC versions are not compatible if (compatible) { @@ -152,10 +172,7 @@ public class Citizens extends JavaPlugin { npcManager = new CitizensNPCManager(this, saves); traitManager = new CitizensTraitManager(this); - CitizensAPI.setNPCManager(npcManager); - CitizensAPI.setCharacterManager(characterManager); - CitizensAPI.setTraitManager(traitManager); - CitizensAPI.setDataFolder(getDataFolder()); + CitizensAPI.setImplementation(this); getServer().getPluginManager().registerEvents(new EventListen(npcManager), this); @@ -168,7 +185,7 @@ public class Citizens extends JavaPlugin { if (getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() { @Override public void run() { - setupNPCs(); + setupNPCs(); // Run metrics "last" startMetrics(); } @@ -178,57 +195,6 @@ public class Citizens extends JavaPlugin { } } - private void startMetrics() { - new Thread() { - @Override - public void run() { - try { - Messaging.log("Starting Metrics"); - Metrics metrics = new Metrics(Citizens.this); - metrics.addCustomData(new Metrics.Plotter("Total NPCs") { - @Override - public int getValue() { - return Iterators.size(npcManager.iterator()); - } - }); - Metrics.Graph graph = metrics.createGraph("Character Type Usage"); - for(final Character character : characterManager.getRegistered()){ - graph.addPlotter(new Metrics.Plotter(StringHelper.capitalize(character.getName())) { - @Override - public int getValue() { - return npcManager.getNPCs(character.getClass()).size(); - } - }); - } - metrics.start(); - } catch (IOException ex) { - Messaging.log("Unable to load metrics"); - } - } - }.start(); - } - - private void setupStorage() { - String type = Setting.STORAGE_TYPE.asString(); - if (type.equalsIgnoreCase("db") || type.equalsIgnoreCase("database")) { - try { - saves = new DatabaseStorage(Setting.DATABASE_DRIVER.asString(), Setting.DATABASE_URL.asString(), - Setting.DATABASE_USERNAME.asString(), Setting.DATABASE_PASSWORD.asString()); - } catch (SQLException e) { - e.printStackTrace(); - Messaging.log("Unable to connect to database, falling back to YAML"); - } - } else if (type.equalsIgnoreCase("nbt")) { - saves = new NBTStorage(getDataFolder() + File.separator + Setting.STORAGE_FILE.asString(), - "Citizens NPC Storage"); - } - if (saves == null) { - saves = new YamlStorage(getDataFolder() + File.separator + Setting.STORAGE_FILE.asString(), - "Citizens NPC Storage"); - } - Messaging.log("Save method set to", saves.toString()); - } - private void registerCommands() { commands.setInjector(new Injector(this)); @@ -256,16 +222,6 @@ public class Citizens extends JavaPlugin { getServer().getPluginManager().callEvent(new CitizensReloadEvent()); } - private void setupScripting() { - contextClassLoader = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(getClassLoader()); - // workaround to fix scripts not loading plugin classes properly - } - - private void tearDownScripting() { - Thread.currentThread().setContextClassLoader(contextClassLoader); - } - public void save() { for (NPC npc : npcManager) ((CitizensNPC) npc).save(saves.getKey("npc." + npc.getId())); @@ -304,6 +260,56 @@ public class Citizens extends JavaPlugin { Messaging.log("Loaded " + created + " NPCs (" + spawned + " spawned)."); } + private void setupScripting() { + contextClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(getClassLoader()); + // workaround to fix scripts not loading plugin classes properly + } + + private void setupStorage() { + String type = Setting.STORAGE_TYPE.asString(); + if (type.equalsIgnoreCase("db") || type.equalsIgnoreCase("database")) { + try { + saves = new DatabaseStorage(Setting.DATABASE_DRIVER.asString(), Setting.DATABASE_URL.asString(), + Setting.DATABASE_USERNAME.asString(), Setting.DATABASE_PASSWORD.asString()); + } catch (SQLException e) { + e.printStackTrace(); + Messaging.log("Unable to connect to database, falling back to YAML"); + } + } else if (type.equalsIgnoreCase("nbt")) { + saves = new NBTStorage(getDataFolder() + File.separator + Setting.STORAGE_FILE.asString(), + "Citizens NPC Storage"); + } + if (saves == null) { + saves = new YamlStorage(getDataFolder() + File.separator + Setting.STORAGE_FILE.asString(), + "Citizens NPC Storage"); + } + Messaging.log("Save method set to", saves.toString()); + } + + private void startMetrics() { + new Thread() { + @Override + public void run() { + try { + Messaging.log("Starting Metrics"); + Metrics metrics = new Metrics(Citizens.this); + metrics.addCustomData(new Metrics.Plotter("Total NPCs") { + @Override + public int getValue() { + return Iterators.size(npcManager.iterator()); + } + }); + Metrics.Graph graph = metrics.createGraph("Character Type Usage"); + characterManager.addPlotters(graph); + metrics.start(); + } catch (IOException ex) { + Messaging.log("Unable to load metrics"); + } + } + }.start(); + } + private boolean suggestClosestModifier(CommandSender sender, String command, String modifier) { int minDist = Integer.MAX_VALUE; String closest = ""; @@ -322,5 +328,15 @@ public class Citizens extends JavaPlugin { return false; } + private void tearDownScripting() { + Thread.currentThread().setContextClassLoader(contextClassLoader); + } + private static final String COMPATIBLE_MC_VERSION = "1.2.5"; + + @Override + public void onImplementationChanged() { + Messaging.severe("Citizens implementation changed, disabling plugin."); + Bukkit.getPluginManager().disablePlugin(this); + } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/CitizensDisableEvent.java b/src/main/java/net/citizensnpcs/CitizensDisableEvent.java new file mode 100644 index 000000000..5407ad970 --- /dev/null +++ b/src/main/java/net/citizensnpcs/CitizensDisableEvent.java @@ -0,0 +1,18 @@ +package net.citizensnpcs; + +import net.citizensnpcs.api.event.CitizensEvent; + +import org.bukkit.event.HandlerList; + +public class CitizensDisableEvent extends CitizensEvent { + @Override + public HandlerList getHandlers() { + return handlers; + } + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/main/java/net/citizensnpcs/npc/CitizensCharacterManager.java b/src/main/java/net/citizensnpcs/npc/CitizensCharacterManager.java index 8b3009430..ed8c0e42a 100644 --- a/src/main/java/net/citizensnpcs/npc/CitizensCharacterManager.java +++ b/src/main/java/net/citizensnpcs/npc/CitizensCharacterManager.java @@ -3,10 +3,14 @@ package net.citizensnpcs.npc; import java.util.HashMap; import java.util.Map; +import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.exception.CharacterException; import net.citizensnpcs.api.npc.character.Character; import net.citizensnpcs.api.npc.character.CharacterFactory; import net.citizensnpcs.api.npc.character.CharacterManager; +import net.citizensnpcs.util.Metrics; +import net.citizensnpcs.util.Metrics.Graph; +import net.citizensnpcs.util.StringHelper; public class CitizensCharacterManager implements CharacterManager { private final Map registered = new HashMap(); @@ -27,7 +31,16 @@ public class CitizensCharacterManager implements CharacterManager { ex.printStackTrace(); } } - public Iterable getRegistered(){ - return registered.values(); + + public void addPlotters(Graph graph) { + for (final Character character : registered.values()) { + graph.addPlotter(new Metrics.Plotter(StringHelper.capitalize(character.getName())) { + @Override + public int getValue() { + return CitizensAPI.getNPCManager().getNPCs(character.getClass()).size(); + } + }); + } + } } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/CitizensNPC.java b/src/main/java/net/citizensnpcs/npc/CitizensNPC.java index 4abc4a5c2..522b81226 100644 --- a/src/main/java/net/citizensnpcs/npc/CitizensNPC.java +++ b/src/main/java/net/citizensnpcs/npc/CitizensNPC.java @@ -55,8 +55,10 @@ public abstract class CitizensNPC extends AbstractNPC { } Bukkit.getPluginManager().callEvent(new NPCDespawnEvent(this)); - - manager.despawn(this, getTrait(Spawned.class).shouldSpawn()); + boolean keepSelected = getTrait(Spawned.class).shouldSpawn(); + if (!keepSelected) + removeMetadata("selectors", CitizensAPI.getPlugin()); + getBukkitEntity().remove(); mcEntity = null; return true; diff --git a/src/main/java/net/citizensnpcs/npc/CitizensNPCManager.java b/src/main/java/net/citizensnpcs/npc/CitizensNPCManager.java index 2ee4cd2df..7c345a2ae 100644 --- a/src/main/java/net/citizensnpcs/npc/CitizensNPCManager.java +++ b/src/main/java/net/citizensnpcs/npc/CitizensNPCManager.java @@ -111,12 +111,6 @@ public class CitizensNPCManager implements NPCManager { return createNPC(type, generateUniqueId(), name, character); } - void despawn(NPC npc, boolean keepSelected) { - if (!keepSelected) - npc.removeMetadata("selectors", plugin); - npc.getBukkitEntity().remove(); - } - private int generateUniqueId() { int count = 0; while (getNPC(count++) != null) @@ -184,9 +178,11 @@ public class CitizensNPCManager implements NPCManager { private void removeMetadata(NPC npc) { // Remove metadata from selectors if (npc.hasMetadata("selectors")) { - for (MetadataValue value : npc.getMetadata("selectors")) - if (Bukkit.getPlayer(value.asString()) != null) - Bukkit.getPlayer(value.asString()).removeMetadata("selected", plugin); + for (MetadataValue value : npc.getMetadata("selectors")) { + Player search = Bukkit.getPlayerExact(value.asString()); + if (search != null) + search.removeMetadata("selected", plugin); + } npc.removeMetadata("selectors", plugin); } } diff --git a/src/main/java/net/citizensnpcs/npc/ai/MCTargetStrategy.java b/src/main/java/net/citizensnpcs/npc/ai/MCTargetStrategy.java index 8b318bdcd..f80b1daee 100644 --- a/src/main/java/net/citizensnpcs/npc/ai/MCTargetStrategy.java +++ b/src/main/java/net/citizensnpcs/npc/ai/MCTargetStrategy.java @@ -4,10 +4,16 @@ import net.citizensnpcs.npc.CitizensNPC; import net.minecraft.server.EntityLiving; import net.minecraft.server.EntityMonster; import net.minecraft.server.EntityPlayer; +import net.minecraft.server.Packet; import net.minecraft.server.Packet18ArmAnimation; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.craftbukkit.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; public class MCTargetStrategy implements PathStrategy { private final boolean aggro; @@ -42,12 +48,26 @@ public class MCTargetStrategy implements PathStrategy { } else if (handle instanceof EntityPlayer) { EntityPlayer humanHandle = (EntityPlayer) handle; humanHandle.attack(target); - humanHandle.netServerHandler.sendPacket(new Packet18ArmAnimation(humanHandle, 1)); + sendPacketNearby(handle.getBukkitEntity().getLocation(), new Packet18ArmAnimation(humanHandle, 1), 64); } } return false; } + private void sendPacketNearby(Location location, Packet packet, double radius) { + radius *= radius; + final World world = location.getWorld(); + for (Player ply : Bukkit.getServer().getOnlinePlayers()) { + if (ply == null || world != ply.getWorld()) { + continue; + } + if (location.distanceSquared(ply.getLocation()) > radius) { + continue; + } + ((CraftPlayer) ply).getHandle().netServerHandler.sendPacket(packet); + } + } + private static final double ATTACK_DISTANCE = 1.75 * 1.75; } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/npc/entity/EntityHumanNPC.java b/src/main/java/net/citizensnpcs/npc/entity/EntityHumanNPC.java index 9137d2bc3..f7a4269b8 100644 --- a/src/main/java/net/citizensnpcs/npc/entity/EntityHumanNPC.java +++ b/src/main/java/net/citizensnpcs/npc/entity/EntityHumanNPC.java @@ -44,6 +44,8 @@ public class EntityHumanNPC extends EntityPlayer implements NPCHandle { @Override public void F_() { super.F_(); + if (noDamageTicks > 0) + --noDamageTicks; npc.update(); } @@ -51,24 +53,24 @@ public class EntityHumanNPC extends EntityPlayer implements NPCHandle { getControllerMove().c(); getControllerLook().a(); getControllerJump().b(); - if (this.aZ) { + if (aZ) { if (aT() || aU()) { - this.motY += 0.04; - } else if (this.onGround && this.q == 0) { - this.motY = 0.5; - this.q = 10; + motY += 0.04; + } else if (onGround && q == 0) { + motY = 0.5; + q = 10; } } else { - this.q = 0; + q = 0; } aX *= 0.98F; - this.a(aW, aX); + a(aW, aX); X = yaw; // TODO: this looks jerky } @Override public NPC getNPC() { - return this.npc; + return npc; } } \ No newline at end of file