Initial work

This commit is contained in:
fullwall 2012-05-26 23:46:57 +08:00
parent e1bca417d8
commit b0ff804209
27 changed files with 186 additions and 928 deletions

View File

@ -8,15 +8,14 @@ import java.util.Iterator;
import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.CitizensPlugin; import net.citizensnpcs.api.CitizensPlugin;
import net.citizensnpcs.api.attachment.AttachmentFactory;
import net.citizensnpcs.api.event.CitizensReloadEvent; import net.citizensnpcs.api.event.CitizensReloadEvent;
import net.citizensnpcs.api.exception.NPCLoadException; import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.npc.NPCRegistry; import net.citizensnpcs.api.npc.NPCRegistry;
import net.citizensnpcs.api.npc.character.CharacterManager;
import net.citizensnpcs.api.scripting.EventRegistrar; import net.citizensnpcs.api.scripting.EventRegistrar;
import net.citizensnpcs.api.scripting.ObjectProvider; import net.citizensnpcs.api.scripting.ObjectProvider;
import net.citizensnpcs.api.scripting.ScriptCompiler; import net.citizensnpcs.api.scripting.ScriptCompiler;
import net.citizensnpcs.api.trait.TraitManager;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.api.util.DatabaseStorage; import net.citizensnpcs.api.util.DatabaseStorage;
import net.citizensnpcs.api.util.NBTStorage; import net.citizensnpcs.api.util.NBTStorage;
@ -35,7 +34,7 @@ import net.citizensnpcs.command.exception.ServerCommandException;
import net.citizensnpcs.command.exception.UnhandledCommandException; import net.citizensnpcs.command.exception.UnhandledCommandException;
import net.citizensnpcs.command.exception.WrappedCommandException; import net.citizensnpcs.command.exception.WrappedCommandException;
import net.citizensnpcs.editor.Editor; import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.npc.CitizensCharacterManager; import net.citizensnpcs.npc.CitizensAttachmentFactory;
import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.CitizensNPCRegistry; import net.citizensnpcs.npc.CitizensNPCRegistry;
import net.citizensnpcs.npc.CitizensTraitManager; import net.citizensnpcs.npc.CitizensTraitManager;
@ -47,7 +46,6 @@ import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
@ -55,7 +53,6 @@ import org.bukkit.plugin.java.JavaPlugin;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
public class Citizens extends JavaPlugin implements CitizensPlugin { public class Citizens extends JavaPlugin implements CitizensPlugin {
private final CitizensCharacterManager characterManager = new CitizensCharacterManager();
private final CommandManager commands = new CommandManager(); private final CommandManager commands = new CommandManager();
private boolean compatible; private boolean compatible;
private Settings config; private Settings config;
@ -63,12 +60,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
private CitizensNPCRegistry npcRegistry; private CitizensNPCRegistry npcRegistry;
private Storage saves; // TODO: refactor this, it's used in too many places private Storage saves; // TODO: refactor this, it's used in too many places
private NPCSelector selector; private NPCSelector selector;
private TraitManager traitManager; private CitizensAttachmentFactory attachmentFactory;
@Override
public CharacterManager getCharacterManager() {
return characterManager;
}
public Iterable<net.citizensnpcs.command.Command> getCommands(String base) { public Iterable<net.citizensnpcs.command.Command> getCommands(String base) {
return commands.getCommands(base); return commands.getCommands(base);
@ -89,8 +81,8 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
} }
@Override @Override
public TraitManager getTraitManager() { public AttachmentFactory getAttachmentFactory() {
return traitManager; return attachmentFactory;
} }
@Override @Override
@ -139,7 +131,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
@Override @Override
public void onDisable() { public void onDisable() {
Bukkit.getPluginManager().callEvent(new CitizensDisableEvent()); CitizensAPI.getServer().callEvent(new CitizensDisableEvent());
tearDownScripting(); tearDownScripting();
// Don't bother with this part if MC versions are not compatible // Don't bother with this part if MC versions are not compatible
@ -155,7 +147,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
@Override @Override
public void onEnable() { public void onEnable() {
// Disable if the server is not using the compatible Minecraft version // Disable if the server is not using the compatible Minecraft version
String mcVersion = ((CraftServer) getServer()).getServer().getVersion(); String mcVersion = CitizensAPI.getServer().getMinecraftVersion();
compatible = mcVersion.startsWith(COMPATIBLE_MC_VERSION); compatible = mcVersion.startsWith(COMPATIBLE_MC_VERSION);
if (!compatible) { if (!compatible) {
Messaging.severeF("v%s is not compatible with Minecraft v%s. Disabling.", getDescription().getVersion(), Messaging.severeF("v%s is not compatible with Minecraft v%s. Disabling.", getDescription().getVersion(),
@ -170,7 +162,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
setupStorage(); setupStorage();
npcRegistry = new CitizensNPCRegistry(saves); npcRegistry = new CitizensNPCRegistry(saves);
traitManager = new CitizensTraitManager(this); attachmentFactory = new CitizensTraitManager(this);
selector = new NPCSelector(this); selector = new NPCSelector(this);
CitizensAPI.setImplementation(this); CitizensAPI.setImplementation(this);
@ -203,7 +195,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
return Iterables.size(npcRegistry); return Iterables.size(npcRegistry);
} }
}); });
characterManager.addPlotters(metrics); attachmentFactory.addPlotters(metrics);
metrics.start(); metrics.start();
Messaging.log("Metrics started."); Messaging.log("Metrics started.");
} catch (IOException e) { } catch (IOException e) {
@ -248,7 +240,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
despawnNPCs(); despawnNPCs();
setupNPCs(); setupNPCs();
getServer().getPluginManager().callEvent(new CitizensReloadEvent()); CitizensAPI.getServer().callEvent(new CitizensReloadEvent());
} }
private void despawnNPCs() { private void despawnNPCs() {

View File

@ -2,17 +2,5 @@ package net.citizensnpcs;
import net.citizensnpcs.api.event.CitizensEvent; import net.citizensnpcs.api.event.CitizensEvent;
import org.bukkit.event.HandlerList;
public class CitizensDisableEvent extends CitizensEvent { public class CitizensDisableEvent extends CitizensEvent {
@Override
public HandlerList getHandlers() {
return handlers;
}
private static final HandlerList handlers = new HandlerList();
public static HandlerList getHandlerList() {
return handlers;
}
} }

View File

@ -1,7 +1,9 @@
package net.citizensnpcs; package net.citizensnpcs;
import javassist.compiler.ast.Pair;
import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.abstraction.WorldVector;
import net.citizensnpcs.api.event.NPCDamageByEntityEvent; import net.citizensnpcs.api.event.NPCDamageByEntityEvent;
import net.citizensnpcs.api.event.NPCDamageEvent; import net.citizensnpcs.api.event.NPCDamageEvent;
import net.citizensnpcs.api.event.NPCLeftClickEvent; import net.citizensnpcs.api.event.NPCLeftClickEvent;
@ -16,9 +18,6 @@ import net.citizensnpcs.util.Util;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -37,7 +36,6 @@ import org.bukkit.event.world.WorldUnloadEvent;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap; import com.google.common.collect.ListMultimap;
import com.google.gson.internal.Pair;
public class EventListen implements Listener { public class EventListen implements Listener {
private final NPCRegistry npcRegistry = CitizensAPI.getNPCRegistry(); private final NPCRegistry npcRegistry = CitizensAPI.getNPCRegistry();
@ -52,8 +50,8 @@ public class EventListen implements Listener {
if (!toRespawn.containsKey(coord)) if (!toRespawn.containsKey(coord))
return; return;
for (int id : toRespawn.get(coord)) { for (int id : toRespawn.get(coord)) {
NPC npc = npcRegistry.getNPC(id); NPC npc = npcRegistry.getById(id);
npc.spawn(npc.getTrait(CurrentLocation.class).getLocation()); npc.spawn(npc.getAttachment(CurrentLocation.class).getLocation());
} }
toRespawn.removeAll(coord); toRespawn.removeAll(coord);
} }
@ -67,9 +65,8 @@ public class EventListen implements Listener {
for (NPC npc : npcRegistry) { for (NPC npc : npcRegistry) {
if (!npc.isSpawned()) if (!npc.isSpawned())
continue; continue;
Location loc = npc.getBukkitEntity().getLocation(); WorldVector loc = npc.getEntity().getLocation();
if (event.getWorld().equals(loc.getWorld()) && event.getChunk().getX() == loc.getChunk().getX() if (event.getWorld().equals(loc.getWorld()) && event.getChunk().equals(loc.getChunk())) {
&& event.getChunk().getZ() == loc.getChunk().getZ()) {
npc.despawn(); npc.despawn();
toRespawn.put(coord, npc.getId()); toRespawn.put(coord, npc.getId());
} }
@ -87,22 +84,15 @@ public class EventListen implements Listener {
NPC npc = npcRegistry.getNPC(event.getEntity()); NPC npc = npcRegistry.getNPC(event.getEntity());
if (event instanceof EntityDamageByEntityEvent) { if (event instanceof EntityDamageByEntityEvent) {
NPCDamageByEntityEvent damageEvent = new NPCDamageByEntityEvent(npc, (EntityDamageByEntityEvent) event); NPCDamageByEntityEvent damageEvent = new NPCDamageByEntityEvent(npc, (EntityDamageByEntityEvent) event);
Bukkit.getPluginManager().callEvent(damageEvent); CitizensAPI.getServer().callEvent(damageEvent);
if (!damageEvent.isCancelled() || !(damageEvent.getDamager() instanceof Player)) if (!damageEvent.isCancelled() || !(damageEvent.getDamager() instanceof Player))
return; return;
Player damager = (Player) damageEvent.getDamager(); Player damager = (Player) damageEvent.getDamager();
// Call left-click event CitizensAPI.getServer().callEvent(new NPCLeftClickEvent(npc, damager));
NPCLeftClickEvent leftClickEvent = new NPCLeftClickEvent(npc, damager);
Bukkit.getPluginManager().callEvent(leftClickEvent);
if (leftClickEvent.isCancelled())
return;
if (npc.getCharacter() != null)
npc.getCharacter().onLeftClick(npc, damager);
} else { } else {
Bukkit.getPluginManager().callEvent(new NPCDamageEvent(npc, event)); CitizensAPI.getServer().callEvent(new NPCDamageEvent(npc, event));
} }
} }
@ -131,9 +121,6 @@ public class EventListen implements Listener {
// TODO: move this into text.class // TODO: move this into text.class
if (Util.isSettingFulfilled(player, Setting.TALK_ITEM) && !npc.getTrait(Text.class).shouldTalkClose()) if (Util.isSettingFulfilled(player, Setting.TALK_ITEM) && !npc.getTrait(Text.class).shouldTalkClose())
npc.getTrait(Text.class).sendText(player); npc.getTrait(Text.class).sendText(player);
if (npc.getCharacter() != null)
npc.getCharacter().onRightClick(npc, player);
} }
/* /*

View File

@ -15,9 +15,9 @@ import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import net.citizensnpcs.api.abstraction.MobType;
import net.citizensnpcs.api.attachment.builtin.Owner;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.trait.MobType;
import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.command.exception.CommandException; import net.citizensnpcs.command.exception.CommandException;
import net.citizensnpcs.command.exception.CommandUsageException; import net.citizensnpcs.command.exception.CommandUsageException;
import net.citizensnpcs.command.exception.NoPermissionsException; import net.citizensnpcs.command.exception.NoPermissionsException;
@ -104,19 +104,19 @@ public class CommandManager {
throw new RequirementMissingException("You must have an NPC selected to execute that command."); throw new RequirementMissingException("You must have an NPC selected to execute that command.");
if (cmdRequirements.ownership() && npc != null && !sender.hasPermission("citizens.admin") if (cmdRequirements.ownership() && npc != null && !sender.hasPermission("citizens.admin")
&& !npc.getTrait(Owner.class).isOwnedBy(sender)) && !npc.getAttachment(Owner.class).isOwnedBy(sender))
throw new RequirementMissingException("You must be the owner of this NPC to execute that command."); throw new RequirementMissingException("You must be the owner of this NPC to execute that command.");
if (npc != null) { if (npc != null) {
Set<EntityType> types = Sets.newEnumSet(Arrays.asList(cmdRequirements.types()), EntityType.class); Set<MobType> types = Sets.newEnumSet(Arrays.asList(cmdRequirements.types()), MobType.class);
if (types.contains(EntityType.UNKNOWN)) if (types.contains(EntityType.UNKNOWN))
types = EnumSet.allOf(EntityType.class); types = EnumSet.allOf(MobType.class);
types.removeAll(Sets.newHashSet(cmdRequirements.excludedTypes())); types.removeAll(Sets.newHashSet(cmdRequirements.excludedTypes()));
EntityType type = EntityType.valueOf(npc.getTrait(MobType.class).getType()); if (!types.contains(npc.getEntity().getType())) {
if (!types.contains(type)) {
throw new RequirementMissingException("The NPC cannot be the mob type '" throw new RequirementMissingException("The NPC cannot be the mob type '"
+ type.name().toLowerCase().replace('_', '-') + "' to use that command."); + npc.getEntity().getType().name().toLowerCase().replace('_', '-')
+ "' to use that command.");
} }
} }
} }

View File

@ -3,7 +3,7 @@ package net.citizensnpcs.command;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import org.bukkit.entity.EntityType; import net.citizensnpcs.api.abstraction.MobType;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Requirements { public @interface Requirements {
@ -12,7 +12,7 @@ public @interface Requirements {
boolean selected() default false; boolean selected() default false;
EntityType[] types() default { EntityType.UNKNOWN }; MobType[] types() default { MobType.UNKNOWN };
EntityType[] excludedTypes() default { EntityType.UNKNOWN }; MobType[] excludedTypes() default { MobType.UNKNOWN };
} }

View File

@ -6,13 +6,12 @@ import java.util.List;
import net.citizensnpcs.Citizens; import net.citizensnpcs.Citizens;
import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.abstraction.CommandSender;
import net.citizensnpcs.api.abstraction.MobType;
import net.citizensnpcs.api.attachment.builtin.Owner;
import net.citizensnpcs.api.attachment.builtin.Spawned;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.npc.NPCRegistry; import net.citizensnpcs.api.npc.NPCRegistry;
import net.citizensnpcs.api.npc.character.Character;
import net.citizensnpcs.api.npc.character.CharacterManager;
import net.citizensnpcs.api.trait.trait.MobType;
import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.api.trait.trait.Spawned;
import net.citizensnpcs.command.Command; import net.citizensnpcs.command.Command;
import net.citizensnpcs.command.CommandContext; import net.citizensnpcs.command.CommandContext;
import net.citizensnpcs.command.Requirements; import net.citizensnpcs.command.Requirements;
@ -32,10 +31,7 @@ import net.citizensnpcs.util.Paginator;
import net.citizensnpcs.util.StringHelper; import net.citizensnpcs.util.StringHelper;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Ageable; import org.bukkit.entity.Ageable;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Villager.Profession; import org.bukkit.entity.Villager.Profession;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
@ -43,7 +39,6 @@ import com.google.common.base.Splitter;
@Requirements(selected = true, ownership = true) @Requirements(selected = true, ownership = true)
public class NPCCommands { public class NPCCommands {
private final CharacterManager characterManager = CitizensAPI.getCharacterManager();
private final NPCRegistry npcRegistry; private final NPCRegistry npcRegistry;
private final NPCSelector selector; private final NPCSelector selector;
@ -61,10 +56,10 @@ public class NPCCommands {
min = 1, min = 1,
max = 2, max = 2,
permission = "npc.age") permission = "npc.age")
@Requirements(selected = true, ownership = true, types = { EntityType.CHICKEN, EntityType.COW, EntityType.OCELOT, @Requirements(selected = true, ownership = true, types = { MobType.CHICKEN, MobType.COW, MobType.OCELOT,
EntityType.PIG, EntityType.SHEEP, EntityType.VILLAGER, EntityType.WOLF }) MobType.PIG, MobType.SHEEP, MobType.VILLAGER, MobType.WOLF })
public void age(CommandContext args, CommandSender sender, NPC npc) throws CommandException { public void age(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
Age trait = npc.getTrait(Age.class); Age trait = npc.getAttachment(Age.class);
if (args.argsLength() > 1) { if (args.argsLength() > 1) {
int age = 0; int age = 0;
@ -94,7 +89,7 @@ public class NPCCommands {
"behaviour", "ai" }, min = 2, max = -1) "behaviour", "ai" }, min = 2, max = -1)
public void behaviour(CommandContext args, CommandSender sender, NPC npc) throws CommandException { public void behaviour(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
Iterable<String> files = Splitter.on(',').split(args.getJoinedStrings(1, ',')); Iterable<String> files = Splitter.on(',').split(args.getJoinedStrings(1, ','));
npc.getTrait(Behaviour.class).addScripts(files); npc.getAttachment(Behaviour.class).addScripts(files);
sender.sendMessage(ChatColor.GREEN + "Behaviours added."); sender.sendMessage(ChatColor.GREEN + "Behaviours added.");
} }
@ -117,7 +112,7 @@ public class NPCCommands {
&& !sender.hasPermission("citizens.npc.character.*") && !sender.hasPermission("citizens.admin")) && !sender.hasPermission("citizens.npc.character.*") && !sender.hasPermission("citizens.admin"))
throw new NoPermissionsException(); throw new NoPermissionsException();
EntityType type = EntityType.valueOf(npc.getTrait(MobType.class).getType()); MobType type = MobType.valueOf(npc.getAttachment(MobType.class).getType());
if (!character.getValidTypes().isEmpty() && !character.getValidTypes().contains(type)) { if (!character.getValidTypes().isEmpty() && !character.getValidTypes().contains(type)) {
Messaging.sendError(sender, "This NPC cannot be given the character '" + character.getName() + "'."); Messaging.sendError(sender, "This NPC cannot be given the character '" + character.getName() + "'.");
return; return;
@ -143,13 +138,13 @@ public class NPCCommands {
Messaging.sendError(player, "NPC names cannot be longer than 16 characters. The name has been shortened."); Messaging.sendError(player, "NPC names cannot be longer than 16 characters. The name has been shortened.");
name = name.substring(0, 15); name = name.substring(0, 15);
} }
EntityType type = EntityType.PLAYER; MobType type = MobType.PLAYER;
if (args.hasValueFlag("type")) { if (args.hasValueFlag("type")) {
type = EntityType.fromName(args.getFlag("type")); type = MobType.fromName(args.getFlag("type"));
if (type == null) { if (type == null) {
Messaging.sendError(player, "'" + args.getFlag("type") Messaging.sendError(player, "'" + args.getFlag("type")
+ "' is not a valid mob type. Using default NPC."); + "' is not a valid mob type. Using default NPC.");
type = EntityType.PLAYER; type = MobType.PLAYER;
} }
} }
npc = npcRegistry.createNPC(type, name); npc = npcRegistry.createNPC(type, name);
@ -185,7 +180,7 @@ public class NPCCommands {
} }
if (args.hasValueFlag("behaviour")) { if (args.hasValueFlag("behaviour")) {
npc.getTrait(Behaviour.class).addScripts(Splitter.on(",").split(args.getFlag("behaviour"))); npc.getAttachment(Behaviour.class).addScripts(Splitter.on(",").split(args.getFlag("behaviour")));
msg += " with the specified behaviours"; msg += " with the specified behaviours";
} }
@ -194,16 +189,16 @@ public class NPCCommands {
// Initialize necessary traits // Initialize necessary traits
npc.addTrait(Owner.class); npc.addTrait(Owner.class);
if (!Setting.SERVER_OWNS_NPCS.asBoolean()) if (!Setting.SERVER_OWNS_NPCS.asBoolean())
npc.getTrait(Owner.class).setOwner(player.getName()); npc.getAttachment(Owner.class).setOwner(player.getName());
npc.getTrait(MobType.class).setType(type.toString()); npc.getAttachment(MobType.class).setType(type.toString());
npc.addTrait(LookClose.class); npc.addTrait(LookClose.class);
npc.addTrait(Text.class); npc.addTrait(Text.class);
npc.spawn(player.getLocation()); npc.spawn(player.getLocation());
// Set age after entity spawns // Set age after entity spawns
if (npc.getBukkitEntity() instanceof Ageable) if (npc.getEntity() instanceof Ageable)
npc.getTrait(Age.class).setAge(age); npc.getAttachment(Age.class).setAge(age);
selector.select(player, npc); selector.select(player, npc);
Messaging.send(player, msg); Messaging.send(player, msg);
@ -218,7 +213,7 @@ public class NPCCommands {
max = 1, max = 1,
permission = "npc.despawn") permission = "npc.despawn")
public void despawn(CommandContext args, CommandSender sender, NPC npc) { public void despawn(CommandContext args, CommandSender sender, NPC npc) {
npc.getTrait(Spawned.class).setSpawned(false); npc.getAttachment(Spawned.class).setSpawned(false);
npc.despawn(); npc.despawn();
Messaging.send(sender, ChatColor.GREEN + "You despawned " + StringHelper.wrap(npc.getName()) + "."); Messaging.send(sender, ChatColor.GREEN + "You despawned " + StringHelper.wrap(npc.getName()) + ".");
} }
@ -241,14 +236,14 @@ public class NPCCommands {
npcs.add(add); npcs.add(add);
} else if (args.getValueFlags().size() == 0 && sender instanceof Player) { } else if (args.getValueFlags().size() == 0 && sender instanceof Player) {
for (NPC add : npcRegistry) { for (NPC add : npcRegistry) {
if (!npcs.contains(add) && add.getTrait(Owner.class).isOwnedBy(sender)) if (!npcs.contains(add) && add.getAttachment(Owner.class).isOwnedBy(sender))
npcs.add(add); npcs.add(add);
} }
} else { } else {
if (args.hasValueFlag("owner")) { if (args.hasValueFlag("owner")) {
String name = args.getFlag("owner"); String name = args.getFlag("owner");
for (NPC add : npcRegistry) { for (NPC add : npcRegistry) {
if (!npcs.contains(add) && add.getTrait(Owner.class).isOwnedBy(name)) if (!npcs.contains(add) && add.getAttachment(Owner.class).isOwnedBy(name))
npcs.add(add); npcs.add(add);
} }
} }
@ -256,11 +251,11 @@ public class NPCCommands {
if (args.hasValueFlag("type")) { if (args.hasValueFlag("type")) {
String type = args.getFlag("type"); String type = args.getFlag("type");
if (EntityType.fromName(type.replace('-', '_')) == null) if (MobType.fromName(type.replace('-', '_')) == null)
throw new CommandException("'" + type + "' is not a valid mob type."); throw new CommandException("'" + type + "' is not a valid mob type.");
for (NPC add : npcRegistry) { for (NPC add : npcRegistry) {
if (!npcs.contains(add) && add.getTrait(MobType.class).getType().equalsIgnoreCase(type)) if (!npcs.contains(add) && add.getEntity().getType().equalsIgnoreCase(type))
npcs.add(add); npcs.add(add);
} }
} }
@ -301,7 +296,7 @@ public class NPCCommands {
permission = "npc.lookclose") permission = "npc.lookclose")
public void lookClose(CommandContext args, CommandSender sender, NPC npc) { public void lookClose(CommandContext args, CommandSender sender, NPC npc) {
String msg = StringHelper.wrap(npc.getName()) + " will " String msg = StringHelper.wrap(npc.getName()) + " will "
+ (npc.getTrait(LookClose.class).toggle() ? "now rotate" : "no longer rotate"); + (npc.getAttachment(LookClose.class).toggle() ? "now rotate" : "no longer rotate");
Messaging.send(sender, msg + " when a player is nearby."); Messaging.send(sender, msg + " when a player is nearby.");
} }
@ -311,7 +306,7 @@ public class NPCCommands {
Messaging.send(sender, " <a>ID: <e>" + npc.getId()); Messaging.send(sender, " <a>ID: <e>" + npc.getId());
Messaging.send(sender, " <a>Character: <e>" Messaging.send(sender, " <a>Character: <e>"
+ (npc.getCharacter() != null ? npc.getCharacter().getName() : "None")); + (npc.getCharacter() != null ? npc.getCharacter().getName() : "None"));
Messaging.send(sender, " <a>Type: <e>" + npc.getTrait(MobType.class).getType()); Messaging.send(sender, " <a>Type: <e>" + npc.getEntity().getType());
} }
@Command( @Command(
@ -325,13 +320,13 @@ public class NPCCommands {
public void owner(CommandContext args, CommandSender sender, NPC npc) throws CommandException { public void owner(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
if (args.argsLength() == 1) { if (args.argsLength() == 1) {
Messaging.send(sender, StringHelper.wrap(npc.getName() + "'s Owner: ") Messaging.send(sender, StringHelper.wrap(npc.getName() + "'s Owner: ")
+ npc.getTrait(Owner.class).getOwner()); + npc.getAttachment(Owner.class).getOwner());
return; return;
} }
String name = args.getString(1); String name = args.getString(1);
if (npc.getTrait(Owner.class).isOwnedBy(name)) if (npc.getAttachment(Owner.class).isOwnedBy(name))
throw new CommandException("'" + name + "' is already the owner of " + npc.getName() + "."); throw new CommandException("'" + name + "' is already the owner of " + npc.getName() + ".");
npc.getTrait(Owner.class).setOwner(name); npc.getAttachment(Owner.class).setOwner(name);
Messaging.send(sender, (name.equalsIgnoreCase("server") ? "<a>The server" : StringHelper.wrap(name)) Messaging.send(sender, (name.equalsIgnoreCase("server") ? "<a>The server" : StringHelper.wrap(name))
+ " is now the owner of " + StringHelper.wrap(npc.getName()) + "."); + " is now the owner of " + StringHelper.wrap(npc.getName()) + ".");
} }
@ -344,10 +339,10 @@ public class NPCCommands {
min = 1, min = 1,
max = 1, max = 1,
permission = "npc.power") permission = "npc.power")
@Requirements(selected = true, ownership = true, types = { EntityType.CREEPER }) @Requirements(selected = true, ownership = true, types = { MobType.CREEPER })
public void power(CommandContext args, CommandSender sender, NPC npc) { public void power(CommandContext args, CommandSender sender, NPC npc) {
String msg = StringHelper.wrap(npc.getName()) + " will " String msg = StringHelper.wrap(npc.getName()) + " will "
+ (npc.getTrait(Powered.class).toggle() ? "now" : "no longer"); + (npc.getAttachment(Powered.class).toggle() ? "now" : "no longer");
Messaging.send(sender, msg += " be powered."); Messaging.send(sender, msg += " be powered.");
} }
@ -359,11 +354,11 @@ public class NPCCommands {
min = 2, min = 2,
max = 2, max = 2,
permission = "npc.profession") permission = "npc.profession")
@Requirements(selected = true, ownership = true, types = { EntityType.VILLAGER }) @Requirements(selected = true, ownership = true, types = { MobType.VILLAGER })
public void profession(CommandContext args, CommandSender sender, NPC npc) throws CommandException { public void profession(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
String profession = args.getString(1); String profession = args.getString(1);
try { try {
npc.getTrait(VillagerProfession.class).setProfession(Profession.valueOf(profession.toUpperCase())); npc.getAttachment(VillagerProfession.class).setProfession(Profession.valueOf(profession.toUpperCase()));
Messaging.send( Messaging.send(
sender, sender,
StringHelper.wrap(npc.getName()) + " is now the profession " StringHelper.wrap(npc.getName()) + " is now the profession "
@ -396,11 +391,11 @@ public class NPCCommands {
Player player = (Player) sender; Player player = (Player) sender;
if (npc == null) if (npc == null)
throw new CommandException("You must have an NPC selected to execute that command."); throw new CommandException("You must have an NPC selected to execute that command.");
if (!npc.getTrait(Owner.class).isOwnedBy(player)) if (!npc.getAttachment(Owner.class).isOwnedBy(player))
throw new CommandException("You must be the owner of this NPC to execute that command."); throw new CommandException("You must be the owner of this NPC to execute that command.");
if (!player.hasPermission("citizens.npc.remove") && !player.hasPermission("citizens.admin")) if (!player.hasPermission("citizens.npc.remove") && !player.hasPermission("citizens.admin"))
throw new NoPermissionsException(); throw new NoPermissionsException();
npc.remove(); npc.destroy();
Messaging.send(player, "<a>You permanently removed " + StringHelper.wrap(npc.getName()) + "."); Messaging.send(player, "<a>You permanently removed " + StringHelper.wrap(npc.getName()) + ".");
} }
@ -419,7 +414,7 @@ public class NPCCommands {
Messaging.sendError(sender, "NPC names cannot be longer than 16 characters. The name has been shortened."); Messaging.sendError(sender, "NPC names cannot be longer than 16 characters. The name has been shortened.");
newName = newName.substring(0, 15); newName = newName.substring(0, 15);
} }
npc.setName(newName); npc.rename(newName);
String msg = String.format("You renamed %s to %s.", StringHelper.wrap(oldName), StringHelper.wrap(newName)); String msg = String.format("You renamed %s to %s.", StringHelper.wrap(oldName), StringHelper.wrap(newName));
Messaging.send(sender, ChatColor.GREEN + msg); Messaging.send(sender, ChatColor.GREEN + msg);
} }
@ -434,8 +429,8 @@ public class NPCCommands {
permission = "npc.select") permission = "npc.select")
@Requirements(ownership = true) @Requirements(ownership = true)
public void select(CommandContext args, CommandSender sender, NPC npc) throws CommandException { public void select(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
NPC toSelect = npcRegistry.getNPC(args.getInteger(1)); NPC toSelect = npcRegistry.getById(args.getInteger(1));
if (toSelect == null || !toSelect.getTrait(Spawned.class).shouldSpawn()) if (toSelect == null || !toSelect.getAttachment(Spawned.class).shouldSpawn())
throw new CommandException("No NPC with the ID '" + args.getInteger(1) + "' is spawned."); throw new CommandException("No NPC with the ID '" + args.getInteger(1) + "' is spawned.");
if (npc != null && toSelect.getId() == npc.getId()) if (npc != null && toSelect.getId() == npc.getId())
throw new CommandException("You already have that NPC selected."); throw new CommandException("You already have that NPC selected.");
@ -457,7 +452,7 @@ public class NPCCommands {
if (respawn == null) if (respawn == null)
throw new CommandException("No NPC with the ID '" + args.getInteger(1) + "' exists."); throw new CommandException("No NPC with the ID '" + args.getInteger(1) + "' exists.");
if (!respawn.getTrait(Owner.class).isOwnedBy(player)) if (!respawn.getAttachment(Owner.class).isOwnedBy(player))
throw new CommandException("You must be the owner of this NPC to execute that command."); throw new CommandException("You must be the owner of this NPC to execute that command.");
if (respawn.spawn(player.getLocation())) { if (respawn.spawn(player.getLocation())) {
@ -478,7 +473,7 @@ public class NPCCommands {
max = 1, max = 1,
permission = "npc.controllable") permission = "npc.controllable")
public void controllable(CommandContext args, CommandSender sender, NPC npc) { public void controllable(CommandContext args, CommandSender sender, NPC npc) {
boolean enabled = npc.getTrait(Controllable.class).toggle(); boolean enabled = npc.getAttachment(Controllable.class).toggle();
if (enabled) { if (enabled) {
Messaging.send(sender, StringHelper.wrap(npc.getName()) + " can now be controlled."); Messaging.send(sender, StringHelper.wrap(npc.getName()) + " can now be controlled.");
} else { } else {
@ -497,8 +492,8 @@ public class NPCCommands {
public void tp(CommandContext args, Player player, NPC npc) { public void tp(CommandContext args, Player player, NPC npc) {
// Spawn the NPC if it isn't spawned to prevent NPEs // Spawn the NPC if it isn't spawned to prevent NPEs
if (!npc.isSpawned()) if (!npc.isSpawned())
npc.spawn(npc.getTrait(CurrentLocation.class).getLocation()); npc.spawn(npc.getAttachment(CurrentLocation.class).getLocation());
player.teleport(npc.getBukkitEntity(), TeleportCause.COMMAND); player.teleport(npc.getEntity(), TeleportCause.COMMAND);
Messaging.send(player, ChatColor.GREEN + "You teleported to " + StringHelper.wrap(npc.getName()) + "."); Messaging.send(player, ChatColor.GREEN + "You teleported to " + StringHelper.wrap(npc.getName()) + ".");
} }
@ -507,8 +502,8 @@ public class NPCCommands {
public void tphere(CommandContext args, Player player, NPC npc) { public void tphere(CommandContext args, Player player, NPC npc) {
// Spawn the NPC if it isn't spawned to prevent NPEs // Spawn the NPC if it isn't spawned to prevent NPEs
if (!npc.isSpawned()) if (!npc.isSpawned())
npc.spawn(npc.getTrait(CurrentLocation.class).getLocation()); npc.spawn(npc.getAttachment(CurrentLocation.class).getLocation());
npc.getBukkitEntity().teleport(player, TeleportCause.COMMAND); npc.getEntity().teleport(player, TeleportCause.COMMAND);
Messaging.send(player, StringHelper.wrap(npc.getName()) + " was teleported to your location."); Messaging.send(player, StringHelper.wrap(npc.getName()) + " was teleported to your location.");
} }
} }

View File

@ -0,0 +1,25 @@
package net.citizensnpcs.npc;
import net.citizensnpcs.api.attachment.Attachment;
import net.citizensnpcs.api.attachment.AttachmentFactory;
import net.citizensnpcs.api.attachment.AttachmentInfo;
public class CitizensAttachmentFactory implements AttachmentFactory {
@Override
public <T extends Attachment> T getAttachment(Class<T> clazz) {
// TODO Auto-generated method stub
return null;
}
@Override
public <T extends Attachment> T getAttachment(String name) {
// TODO Auto-generated method stub
return null;
}
@Override
public void registerAttachment(AttachmentInfo info) {
// TODO Auto-generated method stub
}
}

View File

@ -1,47 +0,0 @@
package net.citizensnpcs.npc;
import java.util.HashMap;
import java.util.Map;
import net.citizensnpcs.Metrics;
import net.citizensnpcs.Metrics.Graph;
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.StringHelper;
public class CitizensCharacterManager implements CharacterManager {
private final Map<String, Character> registered = new HashMap<String, Character>();
@Override
public Character getCharacter(String name) {
return registered.get(name);
}
@Override
public void registerCharacter(CharacterFactory factory) {
try {
Character character = factory.create();
registered.put(character.getName(), character); // TODO: this only
// allows singletons
// for characters.
} catch (CharacterException ex) {
ex.printStackTrace();
}
}
public void addPlotters(Metrics metrics) {
Graph graph = metrics.createGraph("Character Type Usage");
for (final Character character : registered.values()) {
graph.addPlotter(new Metrics.Plotter(StringHelper.capitalize(character.getName())) {
@Override
public int getValue() {
return CitizensAPI.getNPCRegistry().getNPCs(character.getClass()).size();
}
});
}
}
}

View File

@ -1,52 +1,28 @@
package net.citizensnpcs.npc; package net.citizensnpcs.npc;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.abstraction.LivingEntity;
import net.citizensnpcs.api.abstraction.WorldVector;
import net.citizensnpcs.api.attachment.Attachment;
import net.citizensnpcs.api.attachment.builtin.Spawned;
import net.citizensnpcs.api.event.NPCDespawnEvent; import net.citizensnpcs.api.event.NPCDespawnEvent;
import net.citizensnpcs.api.event.NPCSpawnEvent; import net.citizensnpcs.api.event.NPCSpawnEvent;
import net.citizensnpcs.api.exception.NPCLoadException; import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.AbstractNPC; import net.citizensnpcs.api.npc.AbstractNPC;
import net.citizensnpcs.api.npc.character.Character; import net.citizensnpcs.api.npc.NPCRegistry;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.trait.Spawned;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.npc.ai.CitizensAI;
import net.citizensnpcs.trait.CurrentLocation; import net.citizensnpcs.trait.CurrentLocation;
import net.citizensnpcs.util.Messaging; import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.StringHelper;
import net.minecraft.server.EntityLiving;
import org.apache.commons.lang.Validate; public class CitizensNPC extends AbstractNPC {
import org.bukkit.Bukkit; public CitizensNPC(String name) {
import org.bukkit.Location; super(CitizensAPI.getNPCRegistry(), name);
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
public abstract class CitizensNPC extends AbstractNPC {
private final CitizensAI ai = new CitizensAI(this);
protected EntityLiving mcEntity;
private final CitizensTraitManager traitManager;
protected CitizensNPC(int id, String name) {
super(id, name);
traitManager = (CitizensTraitManager) CitizensAPI.getTraitManager();
// TODO: remove this dependency
} }
@Override public CitizensNPC(NPCRegistry registry, String name) {
public void chat(Player player, String message) { super(registry, name);
Messaging.sendWithNPC(player, Setting.CHAT_PREFIX.asString() + message, this);
} }
@Override
public void chat(String message) {
for (Player player : Bukkit.getOnlinePlayers())
chat(player, message);
}
protected abstract EntityLiving createHandle(Location loc);
@Override @Override
public boolean despawn() { public boolean despawn() {
if (!isSpawned()) { if (!isSpawned()) {
@ -54,136 +30,85 @@ public abstract class CitizensNPC extends AbstractNPC {
return false; return false;
} }
Bukkit.getPluginManager().callEvent(new NPCDespawnEvent(this)); CitizensAPI.getServer().callEvent(new NPCDespawnEvent(this));
boolean keepSelected = getTrait(Spawned.class).shouldSpawn(); getEntity().remove();
if (!keepSelected) controller = null;
removeMetadata("selectors", CitizensAPI.getPlugin());
getBukkitEntity().remove();
mcEntity = null;
return true; return true;
} }
@Override @Override
public CitizensAI getAI() { public LivingEntity getEntity() {
return ai; return (LivingEntity) controller.getEntity();
}
@Override
public LivingEntity getBukkitEntity() {
return (LivingEntity) getHandle().getBukkitEntity();
}
public EntityLiving getHandle() {
return mcEntity;
}
@Override
public org.bukkit.inventory.Inventory getInventory() {
Inventory inventory = Bukkit.getServer().createInventory(this, 36, StringHelper.parseColors(getFullName()));
inventory.setContents(getTrait(net.citizensnpcs.api.trait.trait.Inventory.class).getContents());
return inventory;
}
@Override
public Trait getTraitFor(Class<? extends Trait> clazz) {
return traitManager.getTrait(clazz, this);
} }
@Override @Override
public boolean isSpawned() { public boolean isSpawned() {
return getHandle() != null; return getEntity() != null;
}
@Override
protected Attachment getAttachmentFor(Class<? extends Attachment> clazz) {
// TODO Auto-generated method stub
return null;
} }
public void load(DataKey root) { public void load(DataKey root) {
Character character = CitizensAPI.getCharacterManager().getCharacter(root.getString("character"));
// Load the character if it exists
if (character != null) {
try {
character.load(root.getRelative("characters." + character.getName()));
} catch (NPCLoadException e) {
Messaging.severe(String.format("Unable to load character '%s': %s.", character.getName(),
e.getMessage()));
}
setCharacter(character);
}
// Load traits // Load traits
for (DataKey traitKey : root.getRelative("traits").getSubKeys()) { for (DataKey attachmentKey : root.getRelative("traits").getSubKeys()) {
Trait trait = traitManager.getTrait(traitKey.name(), this); Attachment trait = attachmentFactory.getTrait(attachmentKey.name(), this);
if (trait == null) { if (trait == null) {
Messaging.severeF("Skipped missing trait '%s' while loading NPC ID: '%d'. Has the name changed?", Messaging.severeF("Skipped missing attachment '%s' while loading NPC ID: '%d'. Has the name changed?",
traitKey.name(), getId()); attachmentKey.name(), getId());
continue; continue;
} }
addTrait(trait); addAttachment(trait);
try { try {
getTrait(trait.getClass()).load(traitKey); getAttachment(trait.getClass()).load(attachmentKey);
} catch (NPCLoadException ex) { } catch (NPCLoadException ex) {
Messaging.logF("The trait '%s' failed to load for NPC ID: '%d'.", traitKey.name(), getId(), Messaging.logF("The attachment '%s' failed to load for NPC ID: '%d'.", attachmentKey.name(), getId(),
ex.getMessage()); ex.getMessage());
} }
} }
// Spawn the NPC // Spawn the NPC
if (getTrait(Spawned.class).shouldSpawn()) { if (getAttachment(Spawned.class).shouldSpawn()) {
Location spawnLoc = getTrait(CurrentLocation.class).getLocation(); WorldVector spawnLoc = getAttachment(CurrentLocation.class).getLocation();
if (spawnLoc != null) if (spawnLoc != null)
spawn(spawnLoc); spawn(spawnLoc);
} }
} }
@Override
public void remove() {
super.remove();
CitizensAPI.getNPCRegistry().deregister(this);
}
public void save(DataKey root) { public void save(DataKey root) {
root.setString("name", getFullName()); root.setString("name", getFullName());
// Save the character if it exists
if (getCharacter() != null) {
root.setString("character", getCharacter().getName());
getCharacter().save(root.getRelative("characters." + getCharacter().getName()));
}
// Save all existing traits // Save all existing traits
for (Trait trait : traits.values()) { for (Attachment trait : attachments.values()) {
trait.save(root.getRelative("traits." + trait.getName())); trait.save(root.getRelative("traits." + trait.getName()));
} }
} }
@Override @Override
public void setName(String name) { public boolean spawn(WorldVector at) {
super.setName(name); if (at == null)
} throw new IllegalArgumentException("location cannot be null");
@Override
public boolean spawn(Location loc) {
Validate.notNull(loc, "location cannot be null");
if (isSpawned()) { if (isSpawned()) {
Messaging.debug("NPC (ID: " + getId() + ") is already spawned."); Messaging.debug("NPC (ID: " + getId() + ") is already spawned.");
return false; return false;
} }
NPCSpawnEvent spawnEvent = new NPCSpawnEvent(this, loc); NPCSpawnEvent spawnEvent = new NPCSpawnEvent(this, at);
Bukkit.getPluginManager().callEvent(spawnEvent); CitizensAPI.getServer().callEvent(spawnEvent);
if (spawnEvent.isCancelled()) if (spawnEvent.isCancelled())
return false; return false;
mcEntity = createHandle(loc); controller.spawn(at);
mcEntity.world.addEntity(mcEntity);
mcEntity.world.players.remove(mcEntity);
// Set the spawned state // Set the spawned state
getTrait(CurrentLocation.class).setLocation(loc); getAttachment(CurrentLocation.class).setLocation(at);
getTrait(Spawned.class).setSpawned(true); getAttachment(Spawned.class).setSpawned(true);
// Modify NPC using traits after the entity has been created // Modify NPC using traits after the entity has been created
for (Trait trait : traits.values()) for (Attachment attached : attachments.values())
trait.onNPCSpawn(); attached.onSpawn();
return true; return true;
} }
@ -191,7 +116,6 @@ public abstract class CitizensNPC extends AbstractNPC {
public void update() { public void update() {
try { try {
super.update(); super.update();
ai.update();
} catch (Exception ex) { } catch (Exception ex) {
Messaging.logF("Exception while updating %d: %s.", getId(), ex.getMessage()); Messaging.logF("Exception while updating %d: %s.", getId(), ex.getMessage());
ex.printStackTrace(); ex.printStackTrace();

View File

@ -1,145 +1,29 @@
package net.citizensnpcs.npc; package net.citizensnpcs.npc;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.citizensnpcs.api.abstraction.MobType;
import net.citizensnpcs.api.abstraction.WorldVector;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.npc.NPCRegistry; import net.citizensnpcs.api.npc.NPCRegistry;
import net.citizensnpcs.api.npc.character.Character;
import net.citizensnpcs.api.util.Storage; import net.citizensnpcs.api.util.Storage;
import net.citizensnpcs.npc.ai.NPCHandle;
import net.citizensnpcs.npc.entity.CitizensBlazeNPC;
import net.citizensnpcs.npc.entity.CitizensCaveSpiderNPC;
import net.citizensnpcs.npc.entity.CitizensChickenNPC;
import net.citizensnpcs.npc.entity.CitizensCowNPC;
import net.citizensnpcs.npc.entity.CitizensCreeperNPC;
import net.citizensnpcs.npc.entity.CitizensEnderDragonNPC;
import net.citizensnpcs.npc.entity.CitizensEndermanNPC;
import net.citizensnpcs.npc.entity.CitizensGhastNPC;
import net.citizensnpcs.npc.entity.CitizensGiantNPC;
import net.citizensnpcs.npc.entity.CitizensHumanNPC;
import net.citizensnpcs.npc.entity.CitizensIronGolemNPC;
import net.citizensnpcs.npc.entity.CitizensMagmaCubeNPC;
import net.citizensnpcs.npc.entity.CitizensMushroomCowNPC;
import net.citizensnpcs.npc.entity.CitizensOcelotNPC;
import net.citizensnpcs.npc.entity.CitizensPigNPC;
import net.citizensnpcs.npc.entity.CitizensPigZombieNPC;
import net.citizensnpcs.npc.entity.CitizensSheepNPC;
import net.citizensnpcs.npc.entity.CitizensSilverfishNPC;
import net.citizensnpcs.npc.entity.CitizensSkeletonNPC;
import net.citizensnpcs.npc.entity.CitizensSlimeNPC;
import net.citizensnpcs.npc.entity.CitizensSnowmanNPC;
import net.citizensnpcs.npc.entity.CitizensSpiderNPC;
import net.citizensnpcs.npc.entity.CitizensSquidNPC;
import net.citizensnpcs.npc.entity.CitizensVillagerNPC;
import net.citizensnpcs.npc.entity.CitizensWolfNPC;
import net.citizensnpcs.npc.entity.CitizensZombieNPC;
import net.citizensnpcs.util.ByIdArray; import net.citizensnpcs.util.ByIdArray;
import org.apache.commons.lang.Validate;
import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
public class CitizensNPCRegistry implements NPCRegistry { public class CitizensNPCRegistry implements NPCRegistry {
private final ByIdArray<NPC> npcs = new ByIdArray<NPC>(); private final ByIdArray<NPC> npcs = new ByIdArray<NPC>();
private final Storage saves; private final Storage saves;
private final Map<EntityType, Class<? extends CitizensNPC>> types = new EnumMap<EntityType, Class<? extends CitizensNPC>>(
EntityType.class);
public CitizensNPCRegistry(Storage saves) { public CitizensNPCRegistry(Storage saves) {
this.saves = saves; this.saves = saves;
types.put(EntityType.BLAZE, CitizensBlazeNPC.class);
types.put(EntityType.CAVE_SPIDER, CitizensCaveSpiderNPC.class);
types.put(EntityType.CHICKEN, CitizensChickenNPC.class);
types.put(EntityType.COW, CitizensCowNPC.class);
types.put(EntityType.CREEPER, CitizensCreeperNPC.class);
types.put(EntityType.ENDER_DRAGON, CitizensEnderDragonNPC.class);
types.put(EntityType.ENDERMAN, CitizensEndermanNPC.class);
types.put(EntityType.GHAST, CitizensGhastNPC.class);
types.put(EntityType.GIANT, CitizensGiantNPC.class);
types.put(EntityType.IRON_GOLEM, CitizensIronGolemNPC.class);
types.put(EntityType.MAGMA_CUBE, CitizensMagmaCubeNPC.class);
types.put(EntityType.MUSHROOM_COW, CitizensMushroomCowNPC.class);
types.put(EntityType.OCELOT, CitizensOcelotNPC.class);
types.put(EntityType.PIG, CitizensPigNPC.class);
types.put(EntityType.PIG_ZOMBIE, CitizensPigZombieNPC.class);
types.put(EntityType.PLAYER, CitizensHumanNPC.class);
types.put(EntityType.SHEEP, CitizensSheepNPC.class);
types.put(EntityType.SILVERFISH, CitizensSilverfishNPC.class);
types.put(EntityType.SKELETON, CitizensSkeletonNPC.class);
types.put(EntityType.SLIME, CitizensSlimeNPC.class);
types.put(EntityType.SNOWMAN, CitizensSnowmanNPC.class);
types.put(EntityType.SPIDER, CitizensSpiderNPC.class);
types.put(EntityType.SQUID, CitizensSquidNPC.class);
types.put(EntityType.VILLAGER, CitizensVillagerNPC.class);
types.put(EntityType.WOLF, CitizensWolfNPC.class);
types.put(EntityType.ZOMBIE, CitizensZombieNPC.class);
}
public NPC createNPC(EntityType type, int id, String name, Character character) {
CitizensNPC npc = getByType(type, id, name);
if (npc == null)
throw new IllegalStateException("Could not create NPC.");
if (character != null)
npc.setCharacter(character);
npcs.put(npc.getId(), npc);
return npc;
} }
@Override @Override
public NPC createNPC(EntityType type, String name) { public NPC getById(int id) {
return createNPC(type, name, null);
}
@Override
public NPC createNPC(EntityType type, String name, Character character) {
return createNPC(type, generateUniqueId(), name, character);
}
private int generateUniqueId() {
int count = 0;
while (getNPC(count++) != null)
; // TODO: doesn't respect existing save data that might not have
// been loaded. This causes DBs with NPCs that weren't loaded to
// have conflicting primary keys.
return count - 1;
}
@Override
public NPC getNPC(Entity entity) {
Validate.notNull(entity);
net.minecraft.server.Entity handle = ((CraftEntity) entity).getHandle();
return handle instanceof NPCHandle ? ((NPCHandle) handle).getNPC() : null;
}
@Override
public NPC getNPC(int id) {
if (id < 0) if (id < 0)
throw new IllegalArgumentException("invalid id"); throw new IllegalArgumentException("invalid id");
return npcs.get(id); return npcs.get(id);
} }
@Override
public Collection<NPC> getNPCs(Class<? extends Character> character) {
List<NPC> npcs = new ArrayList<NPC>();
for (NPC npc : this) {
if (npc.getCharacter() != null && npc.getCharacter().getClass().equals(character))
npcs.add(npc);
}
return npcs;
}
@Override
public boolean isNPC(Entity entity) {
return getNPC(entity) != null;
}
@Override @Override
public Iterator<NPC> iterator() { public Iterator<NPC> iterator() {
return npcs.iterator(); return npcs.iterator();
@ -153,24 +37,15 @@ public class CitizensNPCRegistry implements NPCRegistry {
} }
@Override @Override
public void deregisterAll() { public NPC createAndSpawn(String name, WorldVector at, MobType type) {
Iterator<NPC> itr = iterator(); NPC npc = new CitizensNPC(this, name);
while (itr.hasNext()) { npc.setEntityController(null); // TODO;
NPC npc = itr.next(); npc.spawn(at);
itr.remove(); return npc;
npc.despawn();
saves.getKey("npc").removeKey(String.valueOf(npc.getId()));
}
} }
private CitizensNPC getByType(EntityType type, int id, String name) { @Override
Class<? extends CitizensNPC> npcClass = types.get(type); public int register(NPC npc) {
if (npcClass == null) return npcs.add(npc);
throw new IllegalArgumentException("Invalid EntityType: " + type);
try {
return npcClass.getConstructor(int.class, String.class).newInstance(id, name);
} catch (Exception ex) {
return null;
}
} }
} }

View File

@ -6,9 +6,7 @@ import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.NPCRemoveEvent; import net.citizensnpcs.api.event.NPCRemoveEvent;
import net.citizensnpcs.api.event.NPCRightClickEvent; import net.citizensnpcs.api.event.NPCRightClickEvent;
import net.citizensnpcs.api.event.NPCSelectEvent;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.editor.Editor; import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.util.Messaging; import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.Util; import net.citizensnpcs.util.Util;

View File

@ -1,236 +0,0 @@
package net.citizensnpcs.npc.ai;
import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.List;
import net.citizensnpcs.api.ai.AI;
import net.citizensnpcs.api.ai.Goal;
import net.citizensnpcs.api.ai.NavigationCallback;
import net.citizensnpcs.api.ai.NavigationCallback.CancelReason;
import net.citizensnpcs.npc.CitizensNPC;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import com.google.common.collect.Lists;
public class CitizensAI implements AI {
private final List<WeakReference<NavigationCallback>> callbacks = Lists.newArrayList();
private PathStrategy executing;
private final List<GoalEntry> executingGoals = Lists.newArrayList();
private final List<GoalEntry> goals = Lists.newArrayList();
private List<Goal> toRemove = null;
private final CitizensNPC npc;
private boolean paused;
public CitizensAI(CitizensNPC npc) {
this.npc = npc;
}
@Override
public void addGoal(int priority, Goal goal) {
if (goals.contains(goal))
return;
goals.add(new GoalEntry(priority, goal));
}
@Override
public void cancelDestination() {
if (executing == null)
return;
executing = null;
for (int i = 0; i < callbacks.size(); ++i) {
NavigationCallback next = callbacks.get(i).get();
if (next == null || next.onCancel(this, CancelReason.CANCEL)) {
callbacks.remove(i);
}
}
}
@Override
public boolean hasDestination() {
return executing != null;
}
private boolean isGoalAllowable(GoalEntry test) {
for (int i = 0; i < goals.size(); ++i) {
GoalEntry item = goals.get(i);
if (item == test)
continue;
if (test.getPriority() >= item.getPriority()) {
if (!test.getGoal().isCompatibleWith(item.getGoal()) && executingGoals.contains(item)) {
return false;
}
} /*else if (executingGoals.contains(item) && !item.goal.requiresUpdates()) {
return false;
}*/
}
return true;
}
public void pause() {
paused = true;
}
@Override
public void registerNavigationCallback(NavigationCallback callback) {
if (!callbacks.contains(callback)) {
callbacks.add(new WeakReference<NavigationCallback>(callback));
callback.onAttach(this);
}
}
@Override
public void removeGoal(Goal goal) {
if (toRemove == null)
toRemove = Lists.newArrayList();
toRemove.add(goal);
}
public void resume() {
paused = false;
}
@Override
public void setDestination(Location destination) {
if (destination == null)
throw new IllegalArgumentException("destination cannot be null");
if (!npc.isSpawned())
throw new IllegalStateException("npc is not spawned");
if (destination.getWorld() != npc.getBukkitEntity().getWorld())
throw new IllegalArgumentException("location is not in the same world");
boolean replaced = executing != null;
executing = new MCNavigationStrategy(npc, destination);
for (int i = 0; i < callbacks.size(); ++i) {
NavigationCallback next = callbacks.get(i).get();
if (next == null || (replaced && next.onCancel(this, CancelReason.REPLACE)) || next.onBegin(this)) {
callbacks.remove(i);
}
}
}
@Override
public void setTarget(LivingEntity target, boolean aggressive) {
if (target == null)
throw new IllegalArgumentException("target cannot be null");
boolean replaced = executing != null;
executing = new MCTargetStrategy(npc, target, aggressive);
for (int i = 0; i < callbacks.size(); ++i) {
NavigationCallback next = callbacks.get(i).get();
if (next == null || (replaced && next.onCancel(this, CancelReason.REPLACE)) || next.onBegin(this)) {
callbacks.remove(i);
}
}
}
public void update() {
if (paused || !npc.isSpawned()) {
return;
}
if (executing != null && executing.update()) {
executing = null;
for (int i = 0; i < callbacks.size(); ++i) {
NavigationCallback next = callbacks.get(i).get();
if (next == null || next.onCompletion(this)) {
callbacks.remove(i);
}
}
}
removeGoals();
for (int i = 0; i < goals.size(); ++i) {
GoalEntry entry = goals.get(i);
boolean executing = executingGoals.contains(entry);
if (executing) {
if (!entry.getGoal().continueExecuting() || !isGoalAllowable(entry)) {
entry.getGoal().reset();
executingGoals.remove(entry);
}
} else if (entry.getGoal().shouldExecute() && isGoalAllowable(entry)) {
entry.getGoal().start();
executingGoals.add(entry);
}
}
for (int i = 0; i < executingGoals.size(); ++i) {
executingGoals.get(i).getGoal().update();
}
}
private void removeGoals() {
if (toRemove == null)
return;
for (Goal goal : toRemove) {
Iterator<GoalEntry> itr = executingGoals.iterator();
while (itr.hasNext()) {
GoalEntry entry = itr.next();
if (entry.getGoal().equals(goal)) {
entry.getGoal().reset();
itr.remove();
}
}
itr = goals.iterator();
while (itr.hasNext()) {
GoalEntry entry = itr.next();
if (entry.getGoal().equals(goal))
itr.remove();
}
}
toRemove = null;
}
public static class GoalEntry implements Comparable<GoalEntry> {
private final Goal goal;
private final int priority;
public GoalEntry(int priority, Goal goal) {
this.priority = priority;
this.goal = goal;
}
@Override
public int compareTo(GoalEntry o) {
return o.priority > priority ? 1 : o.priority < priority ? -1 : 0;
}
public Goal getGoal() {
return goal;
}
public int getPriority() {
return priority;
}
@Override
public int hashCode() {
return 31 + ((goal == null) ? 0 : goal.hashCode());
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
GoalEntry other = (GoalEntry) obj;
if (goal == null) {
if (other.goal != null) {
return false;
}
} else if (!goal.equals(other.goal)) {
return false;
}
return true;
}
}
}

View File

@ -1,82 +0,0 @@
package net.citizensnpcs.npc.ai;
import java.lang.reflect.Field;
import java.util.Map;
import net.citizensnpcs.npc.CitizensNPC;
import net.minecraft.server.EntityLiving;
import net.minecraft.server.Navigation;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import com.google.common.collect.Maps;
public class MCNavigationStrategy implements PathStrategy {
private final EntityLiving entity;
private final Navigation navigation;
MCNavigationStrategy(final CitizensNPC npc, final Location dest) {
entity = npc.getHandle();
if (npc.getBukkitEntity() instanceof Player) {
entity.onGround = true;
// not sure of a better way around this - if onGround is false, then
// navigation won't execute, and calling entity.move doesn't
// entirely fix the problem.
}
navigation = entity.al();
navigation.a(dest.getX(), dest.getY(), dest.getZ(), getSpeed(npc.getHandle()));
}
MCNavigationStrategy(EntityLiving entity, EntityLiving target) {
this.entity = entity;
if (entity.getBukkitEntity() instanceof Player) {
entity.onGround = true; // see above
}
navigation = entity.al();
navigation.a(target, getSpeed(entity));
}
private float getSpeed(EntityLiving from) {
Float cached = MOVEMENT_SPEEDS.get(from.getBukkitEntity().getType());
if (cached != null)
return cached;
if (SPEED_FIELD == null) {
MOVEMENT_SPEEDS.put(from.getBukkitEntity().getType(), DEFAULT_SPEED);
return DEFAULT_SPEED;
}
try {
float speed = SPEED_FIELD.getFloat(from);
MOVEMENT_SPEEDS.put(from.getBukkitEntity().getType(), speed);
return speed;
} catch (IllegalAccessException ex) {
ex.printStackTrace();
return DEFAULT_SPEED;
}
}
@Override
public boolean update() {
return navigation.e();
}
private static final float DEFAULT_SPEED = 0.3F;
private static final Map<EntityType, Float> MOVEMENT_SPEEDS = Maps.newEnumMap(EntityType.class);
private static Field SPEED_FIELD;
static {
MOVEMENT_SPEEDS.put(EntityType.IRON_GOLEM, 0.15F);
MOVEMENT_SPEEDS.put(EntityType.CHICKEN, 0.25F);
MOVEMENT_SPEEDS.put(EntityType.COW, 0.2F);
MOVEMENT_SPEEDS.put(EntityType.SHEEP, 0.25F);
MOVEMENT_SPEEDS.put(EntityType.VILLAGER, 0.3F);
MOVEMENT_SPEEDS.put(EntityType.SNOWMAN, 0.25F);
try {
SPEED_FIELD = EntityLiving.class.getDeclaredField("bb");
SPEED_FIELD.setAccessible(true);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

View File

@ -1,55 +0,0 @@
package net.citizensnpcs.npc.ai;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.util.Util;
import net.minecraft.server.EntityLiving;
import net.minecraft.server.EntityMonster;
import net.minecraft.server.EntityPlayer;
import net.minecraft.server.Packet18ArmAnimation;
import org.bukkit.craftbukkit.entity.CraftLivingEntity;
import org.bukkit.entity.LivingEntity;
public class MCTargetStrategy implements PathStrategy {
private final boolean aggro;
private final EntityLiving handle, target;
public MCTargetStrategy(CitizensNPC handle, LivingEntity target, boolean aggro) {
this.handle = handle.getHandle();
this.target = ((CraftLivingEntity) target).getHandle();
this.aggro = aggro;
}
private boolean canAttack() {
return handle.attackTicks == 0
&& (handle.boundingBox.e > target.boundingBox.b && handle.boundingBox.b < target.boundingBox.e)
&& distanceSquared() <= ATTACK_DISTANCE && handle.h(target);
}
private double distanceSquared() {
return handle.getBukkitEntity().getLocation().distanceSquared(target.getBukkitEntity().getLocation());
}
@Override
public boolean update() {
if (target == null || target.dead)
return true;
new MCNavigationStrategy(handle, target).update();
handle.getControllerLook().a(target, 10.0F, handle.D());
if (aggro && canAttack()) {
if (handle instanceof EntityMonster) {
((EntityMonster) handle).a((net.minecraft.server.Entity) target);
// the cast is necessary to resolve overloaded method a
} else if (handle instanceof EntityPlayer) {
EntityPlayer humanHandle = (EntityPlayer) handle;
humanHandle.attack(target);
Util.sendPacketNearby(handle.getBukkitEntity().getLocation(), new Packet18ArmAnimation(humanHandle, 1),
64);
}
}
return false;
}
private static final double ATTACK_DISTANCE = 1.75 * 1.75;
}

View File

@ -1,7 +0,0 @@
package net.citizensnpcs.npc.ai;
import net.citizensnpcs.api.npc.NPC;
public interface NPCHandle {
public NPC getNPC();
}

View File

@ -1,6 +0,0 @@
package net.citizensnpcs.npc.ai;
public interface PathStrategy {
boolean update();
}

View File

@ -4,9 +4,6 @@ import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensMobNPC; import net.citizensnpcs.npc.CitizensMobNPC;
import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.npc.ai.NPCHandle; import net.citizensnpcs.npc.ai.NPCHandle;
import net.minecraft.server.EntityBlaze;
import net.minecraft.server.PathfinderGoalSelector;
import net.minecraft.server.World;
import org.bukkit.entity.Blaze; import org.bukkit.entity.Blaze;

View File

@ -1,13 +1,13 @@
package net.citizensnpcs.trait; package net.citizensnpcs.trait;
import net.citizensnpcs.api.attachment.Attachment;
import net.citizensnpcs.api.exception.NPCLoadException; import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import org.bukkit.entity.Ageable; import org.bukkit.entity.Ageable;
public class Age extends Trait implements Runnable, Toggleable { public class Age extends Attachment implements Runnable, Toggleable {
private int age = 0; private int age = 0;
private boolean locked = true; private boolean locked = true;
private boolean ageable = false; private boolean ageable = false;
@ -26,7 +26,7 @@ public class Age extends Trait implements Runnable, Toggleable {
} }
@Override @Override
public void onNPCSpawn() { public void onSpawn() {
if (npc instanceof Ageable) { if (npc instanceof Ageable) {
Ageable entity = (Ageable) npc.getBukkitEntity(); Ageable entity = (Ageable) npc.getBukkitEntity();
entity.setAge(age); entity.setAge(age);

View File

@ -7,11 +7,11 @@ import java.util.Map.Entry;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.ai.Goal; import net.citizensnpcs.api.ai.Goal;
import net.citizensnpcs.api.attachment.Attachment;
import net.citizensnpcs.api.exception.NPCLoadException; import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.scripting.CompileCallback; import net.citizensnpcs.api.scripting.CompileCallback;
import net.citizensnpcs.api.scripting.ScriptFactory; import net.citizensnpcs.api.scripting.ScriptFactory;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
@ -23,7 +23,7 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
public class Behaviour extends Trait { public class Behaviour extends Attachment {
private final Map<Goal, Integer> addedGoals = Maps.newHashMap(); private final Map<Goal, Integer> addedGoals = Maps.newHashMap();
private final Function<String, File> fileConverterFunction = new Function<String, File>() { private final Function<String, File> fileConverterFunction = new Function<String, File>() {
@Override @Override
@ -59,7 +59,7 @@ public class Behaviour extends Trait {
} }
@Override @Override
public void onNPCSpawn() { public void onSpawn() {
for (Entry<Goal, Integer> entry : addedGoals.entrySet()) { for (Entry<Goal, Integer> entry : addedGoals.entrySet()) {
npc.getAI().addGoal(entry.getValue(), entry.getKey()); npc.getAI().addGoal(entry.getValue(), entry.getKey());
} }

View File

@ -1,22 +1,19 @@
package net.citizensnpcs.trait; package net.citizensnpcs.trait;
import net.citizensnpcs.api.attachment.Attachment;
import net.citizensnpcs.api.event.NPCRightClickEvent; import net.citizensnpcs.api.event.NPCRightClickEvent;
import net.citizensnpcs.api.exception.NPCLoadException; import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.CitizensNPC;
import net.minecraft.server.EntityLiving;
import net.minecraft.server.EntityPlayer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.Action; import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerInteractEvent;
//TODO: reduce reliance on CitizensNPC //TODO: reduce reliance on CitizensNPC
public class Controllable extends Trait implements Runnable, Listener, Toggleable { public class Controllable extends Attachment implements Runnable, Listener, Toggleable {
private final CitizensNPC npc; private final CitizensNPC npc;
private boolean enabled; private boolean enabled;

View File

@ -1,26 +1,27 @@
package net.citizensnpcs.trait; package net.citizensnpcs.trait;
import net.citizensnpcs.api.abstraction.WorldVector;
import net.citizensnpcs.api.attachment.Attachment;
import net.citizensnpcs.api.exception.NPCLoadException; import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
public class CurrentLocation extends Trait implements Runnable { public class CurrentLocation extends Attachment implements Runnable {
private Location loc; private WorldVector loc;
private final NPC npc; private final NPC npc;
public CurrentLocation(NPC npc) { public CurrentLocation(NPC npc) {
this.npc = npc; this.npc = npc;
} }
public Location getLocation() { public WorldVector getLocation() {
return loc; return loc;
} }
public void setLocation(Location loc) { public void setLocation(WorldVector loc) {
this.loc = loc; this.loc = loc;
} }
@ -38,7 +39,7 @@ public class CurrentLocation extends Trait implements Runnable {
if (!npc.isSpawned()) if (!npc.isSpawned())
return; return;
loc = npc.getBukkitEntity().getLocation(); loc = npc.getEntity().getLocation();
} }
@Override @Override

View File

@ -1,14 +1,14 @@
package net.citizensnpcs.trait; package net.citizensnpcs.trait;
import net.citizensnpcs.api.attachment.Attachment;
import net.citizensnpcs.api.exception.NPCLoadException; import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import org.bukkit.entity.Villager; import org.bukkit.entity.Villager;
import org.bukkit.entity.Villager.Profession; import org.bukkit.entity.Villager.Profession;
public class VillagerProfession extends Trait { public class VillagerProfession extends Attachment {
private final NPC npc; private final NPC npc;
private Profession profession = Profession.FARMER; private Profession profession = Profession.FARMER;
@ -26,9 +26,9 @@ public class VillagerProfession extends Trait {
} }
@Override @Override
public void onNPCSpawn() { public void onSpawn() {
if (npc.getBukkitEntity() instanceof Villager) if (npc.getEntity() instanceof Villager)
((Villager) npc.getBukkitEntity()).setProfession(profession); ((Villager) npc.getEntity()).setProfession(profession);
} }
@Override @Override
@ -38,8 +38,8 @@ public class VillagerProfession extends Trait {
public void setProfession(Profession profession) { public void setProfession(Profession profession) {
this.profession = profession; this.profession = profession;
if (npc.getBukkitEntity() instanceof Villager) if (npc.getEntity() instanceof Villager)
((Villager) npc.getBukkitEntity()).setProfession(profession); ((Villager) npc.getEntity()).setProfession(profession);
} }
@Override @Override

View File

@ -1,9 +1,9 @@
package net.citizensnpcs.trait; package net.citizensnpcs.trait;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.attachment.Attachment;
import net.citizensnpcs.api.exception.NPCLoadException; import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import org.bukkit.DyeColor; import org.bukkit.DyeColor;
@ -12,7 +12,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.SheepDyeWoolEvent; import org.bukkit.event.entity.SheepDyeWoolEvent;
public class WoolColor extends Trait implements Listener { public class WoolColor extends Attachment implements Listener {
private DyeColor color = DyeColor.WHITE; private DyeColor color = DyeColor.WHITE;
private final NPC npc; private final NPC npc;
boolean sheep = false; boolean sheep = false;
@ -31,9 +31,9 @@ public class WoolColor extends Trait implements Listener {
} }
@Override @Override
public void onNPCSpawn() { public void onSpawn() {
if (npc.getBukkitEntity() instanceof Sheep) { if (npc.getEntity() instanceof Sheep) {
((Sheep) npc.getBukkitEntity()).setColor(color); ((Sheep) npc.getEntity()).setColor(color);
sheep = true; sheep = true;
} else } else
sheep = false; sheep = false;
@ -53,7 +53,7 @@ public class WoolColor extends Trait implements Listener {
public void setColor(DyeColor color) { public void setColor(DyeColor color) {
this.color = color; this.color = color;
if (sheep) if (sheep)
((Sheep) npc.getBukkitEntity()).setColor(color); ((Sheep) npc.getEntity()).setColor(color);
} }
@Override @Override

View File

@ -8,17 +8,15 @@ import java.util.Map;
import java.util.Random; import java.util.Random;
import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.attachment.Attachment;
import net.citizensnpcs.api.exception.NPCLoadException; import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.editor.Editor; import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.trait.Toggleable; import net.citizensnpcs.trait.Toggleable;
import net.citizensnpcs.util.Messaging; import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.Paginator; import net.citizensnpcs.util.Paginator;
import net.minecraft.server.EntityHuman;
import net.minecraft.server.EntityLiving;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.conversations.Conversation; import org.bukkit.conversations.Conversation;
@ -28,7 +26,7 @@ import org.bukkit.conversations.ConversationFactory;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
public class Text extends Trait implements Runnable, Toggleable, ConversationAbandonedListener { public class Text extends Attachment implements Runnable, Toggleable, ConversationAbandonedListener {
private final Map<String, Calendar> cooldowns = new HashMap<String, Calendar>(); private final Map<String, Calendar> cooldowns = new HashMap<String, Calendar>();
private int currentIndex; private int currentIndex;
private final NPC npc; private final NPC npc;
@ -93,7 +91,7 @@ public class Text extends Trait implements Runnable, Toggleable, ConversationAba
} }
@Override @Override
public void onNPCSpawn() { public void onSpawn() {
if (text.isEmpty()) if (text.isEmpty())
populateDefaultText(); populateDefaultText();
} }

View File

@ -1,85 +0,0 @@
package net.citizensnpcs.trait.waypoint;
import java.util.Iterator;
import net.citizensnpcs.api.ai.AI;
import net.citizensnpcs.api.ai.NavigationCallback;
import org.bukkit.Location;
public class GenericWaypointCallback extends NavigationCallback {
private AI ai;
private Location dest;
private boolean executing;
private Iterator<Waypoint> itr;
private final Iterable<Waypoint> provider;
public GenericWaypointCallback(Iterable<Waypoint> provider) {
this.provider = provider;
}
private void ensureItr() {
if (itr == null || !itr.hasNext()) {
itr = provider.iterator();
}
}
@Override
public void onAttach(AI ai) {
this.ai = ai;
executing |= !ai.hasDestination();
if (!executing)
return;
if (dest == null) {
ensureItr();
if (itr.hasNext()) {
dest = itr.next().getLocation();
}
}
if (dest != null) {
ai.setDestination(dest);
}
}
@Override
public boolean onCancel(AI ai, CancelReason reason) {
if (executing && reason == CancelReason.REPLACE) {
executing = false;
return false;
}
executing = true;
ensureItr();
if (dest == null && itr.hasNext())
dest = itr.next().getLocation();
if (dest != null) {
ai.setDestination(dest);
}
return false;
}
@Override
public boolean onCompletion(AI ai) {
if (executing) { // if we're executing, we need to get the next waypoint
ensureItr();
dest = itr.hasNext() ? itr.next().getLocation() : null;
} else {
executing = true;
// we're free to return to our waypoints!
// if we had a destination, we will return to it.
}
if (dest != null) {
ai.setDestination(dest);
}
return false;
}
public void onProviderChanged() {
itr = provider.iterator();
if (ai == null)
return;
dest = itr.hasNext() ? itr.next().getLocation() : null;
if (dest != null) {
ai.setDestination(dest);
}
}
}

View File

@ -4,13 +4,13 @@ import java.util.Arrays;
import java.util.logging.Level; import java.util.logging.Level;
import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.abstraction.CommandSender;
import net.citizensnpcs.api.abstraction.Player;
import net.citizensnpcs.api.attachment.builtin.Owner;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.trait.Owner;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
@ -68,7 +68,7 @@ public class Messaging {
send = send.replace("<player>", player.getName()); send = send.replace("<player>", player.getName());
send = send.replace("<world>", player.getWorld().getName()); send = send.replace("<world>", player.getWorld().getName());
} }
send = send.replace("<owner>", npc.getTrait(Owner.class).getOwner()); send = send.replace("<owner>", npc.getAttachment(Owner.class).getOwner());
send = send.replace("<npc>", npc.getName()); send = send.replace("<npc>", npc.getName());
send = send.replace("<id>", Integer.toString(npc.getId())); send = send.replace("<id>", Integer.toString(npc.getId()));

View File

@ -7,16 +7,15 @@ import java.util.Comparator;
import java.util.Map; import java.util.Map;
import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.Settings.Setting;
import net.minecraft.server.Packet;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.avaje.ebeaninternal.server.cluster.Packet;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;