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

View File

@ -2,17 +2,5 @@ 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;
}
}

View File

@ -1,7 +1,9 @@
package net.citizensnpcs;
import javassist.compiler.ast.Pair;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.abstraction.WorldVector;
import net.citizensnpcs.api.event.NPCDamageByEntityEvent;
import net.citizensnpcs.api.event.NPCDamageEvent;
import net.citizensnpcs.api.event.NPCLeftClickEvent;
@ -16,9 +18,6 @@ import net.citizensnpcs.util.Util;
import org.bukkit.Bukkit;
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.event.EventHandler;
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.ListMultimap;
import com.google.gson.internal.Pair;
public class EventListen implements Listener {
private final NPCRegistry npcRegistry = CitizensAPI.getNPCRegistry();
@ -52,8 +50,8 @@ public class EventListen implements Listener {
if (!toRespawn.containsKey(coord))
return;
for (int id : toRespawn.get(coord)) {
NPC npc = npcRegistry.getNPC(id);
npc.spawn(npc.getTrait(CurrentLocation.class).getLocation());
NPC npc = npcRegistry.getById(id);
npc.spawn(npc.getAttachment(CurrentLocation.class).getLocation());
}
toRespawn.removeAll(coord);
}
@ -67,9 +65,8 @@ public class EventListen implements Listener {
for (NPC npc : npcRegistry) {
if (!npc.isSpawned())
continue;
Location loc = npc.getBukkitEntity().getLocation();
if (event.getWorld().equals(loc.getWorld()) && event.getChunk().getX() == loc.getChunk().getX()
&& event.getChunk().getZ() == loc.getChunk().getZ()) {
WorldVector loc = npc.getEntity().getLocation();
if (event.getWorld().equals(loc.getWorld()) && event.getChunk().equals(loc.getChunk())) {
npc.despawn();
toRespawn.put(coord, npc.getId());
}
@ -87,22 +84,15 @@ public class EventListen implements Listener {
NPC npc = npcRegistry.getNPC(event.getEntity());
if (event instanceof EntityDamageByEntityEvent) {
NPCDamageByEntityEvent damageEvent = new NPCDamageByEntityEvent(npc, (EntityDamageByEntityEvent) event);
Bukkit.getPluginManager().callEvent(damageEvent);
CitizensAPI.getServer().callEvent(damageEvent);
if (!damageEvent.isCancelled() || !(damageEvent.getDamager() instanceof Player))
return;
Player damager = (Player) damageEvent.getDamager();
// Call left-click event
NPCLeftClickEvent leftClickEvent = new NPCLeftClickEvent(npc, damager);
Bukkit.getPluginManager().callEvent(leftClickEvent);
if (leftClickEvent.isCancelled())
return;
if (npc.getCharacter() != null)
npc.getCharacter().onLeftClick(npc, damager);
CitizensAPI.getServer().callEvent(new NPCLeftClickEvent(npc, damager));
} 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
if (Util.isSettingFulfilled(player, Setting.TALK_ITEM) && !npc.getTrait(Text.class).shouldTalkClose())
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.Logger;
import net.citizensnpcs.api.abstraction.MobType;
import net.citizensnpcs.api.attachment.builtin.Owner;
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.CommandUsageException;
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.");
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.");
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))
types = EnumSet.allOf(EntityType.class);
types = EnumSet.allOf(MobType.class);
types.removeAll(Sets.newHashSet(cmdRequirements.excludedTypes()));
EntityType type = EntityType.valueOf(npc.getTrait(MobType.class).getType());
if (!types.contains(type)) {
if (!types.contains(npc.getEntity().getType())) {
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.RetentionPolicy;
import org.bukkit.entity.EntityType;
import net.citizensnpcs.api.abstraction.MobType;
@Retention(RetentionPolicy.RUNTIME)
public @interface Requirements {
@ -12,7 +12,7 @@ public @interface Requirements {
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.Settings.Setting;
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.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.CommandContext;
import net.citizensnpcs.command.Requirements;
@ -32,10 +31,7 @@ import net.citizensnpcs.util.Paginator;
import net.citizensnpcs.util.StringHelper;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Ageable;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Villager.Profession;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
@ -43,7 +39,6 @@ import com.google.common.base.Splitter;
@Requirements(selected = true, ownership = true)
public class NPCCommands {
private final CharacterManager characterManager = CitizensAPI.getCharacterManager();
private final NPCRegistry npcRegistry;
private final NPCSelector selector;
@ -61,10 +56,10 @@ public class NPCCommands {
min = 1,
max = 2,
permission = "npc.age")
@Requirements(selected = true, ownership = true, types = { EntityType.CHICKEN, EntityType.COW, EntityType.OCELOT,
EntityType.PIG, EntityType.SHEEP, EntityType.VILLAGER, EntityType.WOLF })
@Requirements(selected = true, ownership = true, types = { MobType.CHICKEN, MobType.COW, MobType.OCELOT,
MobType.PIG, MobType.SHEEP, MobType.VILLAGER, MobType.WOLF })
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) {
int age = 0;
@ -94,7 +89,7 @@ public class NPCCommands {
"behaviour", "ai" }, min = 2, max = -1)
public void behaviour(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
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.");
}
@ -117,7 +112,7 @@ public class NPCCommands {
&& !sender.hasPermission("citizens.npc.character.*") && !sender.hasPermission("citizens.admin"))
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)) {
Messaging.sendError(sender, "This NPC cannot be given the character '" + character.getName() + "'.");
return;
@ -143,13 +138,13 @@ public class NPCCommands {
Messaging.sendError(player, "NPC names cannot be longer than 16 characters. The name has been shortened.");
name = name.substring(0, 15);
}
EntityType type = EntityType.PLAYER;
MobType type = MobType.PLAYER;
if (args.hasValueFlag("type")) {
type = EntityType.fromName(args.getFlag("type"));
type = MobType.fromName(args.getFlag("type"));
if (type == null) {
Messaging.sendError(player, "'" + args.getFlag("type")
+ "' is not a valid mob type. Using default NPC.");
type = EntityType.PLAYER;
type = MobType.PLAYER;
}
}
npc = npcRegistry.createNPC(type, name);
@ -185,7 +180,7 @@ public class NPCCommands {
}
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";
}
@ -194,16 +189,16 @@ public class NPCCommands {
// Initialize necessary traits
npc.addTrait(Owner.class);
if (!Setting.SERVER_OWNS_NPCS.asBoolean())
npc.getTrait(Owner.class).setOwner(player.getName());
npc.getTrait(MobType.class).setType(type.toString());
npc.getAttachment(Owner.class).setOwner(player.getName());
npc.getAttachment(MobType.class).setType(type.toString());
npc.addTrait(LookClose.class);
npc.addTrait(Text.class);
npc.spawn(player.getLocation());
// Set age after entity spawns
if (npc.getBukkitEntity() instanceof Ageable)
npc.getTrait(Age.class).setAge(age);
if (npc.getEntity() instanceof Ageable)
npc.getAttachment(Age.class).setAge(age);
selector.select(player, npc);
Messaging.send(player, msg);
@ -218,7 +213,7 @@ public class NPCCommands {
max = 1,
permission = "npc.despawn")
public void despawn(CommandContext args, CommandSender sender, NPC npc) {
npc.getTrait(Spawned.class).setSpawned(false);
npc.getAttachment(Spawned.class).setSpawned(false);
npc.despawn();
Messaging.send(sender, ChatColor.GREEN + "You despawned " + StringHelper.wrap(npc.getName()) + ".");
}
@ -241,14 +236,14 @@ public class NPCCommands {
npcs.add(add);
} else if (args.getValueFlags().size() == 0 && sender instanceof Player) {
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);
}
} else {
if (args.hasValueFlag("owner")) {
String name = args.getFlag("owner");
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);
}
}
@ -256,11 +251,11 @@ public class NPCCommands {
if (args.hasValueFlag("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.");
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);
}
}
@ -301,7 +296,7 @@ public class NPCCommands {
permission = "npc.lookclose")
public void lookClose(CommandContext args, CommandSender sender, NPC npc) {
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.");
}
@ -311,7 +306,7 @@ public class NPCCommands {
Messaging.send(sender, " <a>ID: <e>" + npc.getId());
Messaging.send(sender, " <a>Character: <e>"
+ (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(
@ -325,13 +320,13 @@ public class NPCCommands {
public void owner(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
if (args.argsLength() == 1) {
Messaging.send(sender, StringHelper.wrap(npc.getName() + "'s Owner: ")
+ npc.getTrait(Owner.class).getOwner());
+ npc.getAttachment(Owner.class).getOwner());
return;
}
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() + ".");
npc.getTrait(Owner.class).setOwner(name);
npc.getAttachment(Owner.class).setOwner(name);
Messaging.send(sender, (name.equalsIgnoreCase("server") ? "<a>The server" : StringHelper.wrap(name))
+ " is now the owner of " + StringHelper.wrap(npc.getName()) + ".");
}
@ -344,10 +339,10 @@ public class NPCCommands {
min = 1,
max = 1,
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) {
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.");
}
@ -359,11 +354,11 @@ public class NPCCommands {
min = 2,
max = 2,
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 {
String profession = args.getString(1);
try {
npc.getTrait(VillagerProfession.class).setProfession(Profession.valueOf(profession.toUpperCase()));
npc.getAttachment(VillagerProfession.class).setProfession(Profession.valueOf(profession.toUpperCase()));
Messaging.send(
sender,
StringHelper.wrap(npc.getName()) + " is now the profession "
@ -396,11 +391,11 @@ public class NPCCommands {
Player player = (Player) sender;
if (npc == null)
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.");
if (!player.hasPermission("citizens.npc.remove") && !player.hasPermission("citizens.admin"))
throw new NoPermissionsException();
npc.remove();
npc.destroy();
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.");
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));
Messaging.send(sender, ChatColor.GREEN + msg);
}
@ -434,8 +429,8 @@ public class NPCCommands {
permission = "npc.select")
@Requirements(ownership = true)
public void select(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
NPC toSelect = npcRegistry.getNPC(args.getInteger(1));
if (toSelect == null || !toSelect.getTrait(Spawned.class).shouldSpawn())
NPC toSelect = npcRegistry.getById(args.getInteger(1));
if (toSelect == null || !toSelect.getAttachment(Spawned.class).shouldSpawn())
throw new CommandException("No NPC with the ID '" + args.getInteger(1) + "' is spawned.");
if (npc != null && toSelect.getId() == npc.getId())
throw new CommandException("You already have that NPC selected.");
@ -457,7 +452,7 @@ public class NPCCommands {
if (respawn == null)
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.");
if (respawn.spawn(player.getLocation())) {
@ -478,7 +473,7 @@ public class NPCCommands {
max = 1,
permission = "npc.controllable")
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) {
Messaging.send(sender, StringHelper.wrap(npc.getName()) + " can now be controlled.");
} else {
@ -497,8 +492,8 @@ public class NPCCommands {
public void tp(CommandContext args, Player player, NPC npc) {
// Spawn the NPC if it isn't spawned to prevent NPEs
if (!npc.isSpawned())
npc.spawn(npc.getTrait(CurrentLocation.class).getLocation());
player.teleport(npc.getBukkitEntity(), TeleportCause.COMMAND);
npc.spawn(npc.getAttachment(CurrentLocation.class).getLocation());
player.teleport(npc.getEntity(), TeleportCause.COMMAND);
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) {
// Spawn the NPC if it isn't spawned to prevent NPEs
if (!npc.isSpawned())
npc.spawn(npc.getTrait(CurrentLocation.class).getLocation());
npc.getBukkitEntity().teleport(player, TeleportCause.COMMAND);
npc.spawn(npc.getAttachment(CurrentLocation.class).getLocation());
npc.getEntity().teleport(player, TeleportCause.COMMAND);
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;
import net.citizensnpcs.Settings.Setting;
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.NPCSpawnEvent;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.AbstractNPC;
import net.citizensnpcs.api.npc.character.Character;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.trait.Spawned;
import net.citizensnpcs.api.npc.NPCRegistry;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.npc.ai.CitizensAI;
import net.citizensnpcs.trait.CurrentLocation;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.StringHelper;
import net.minecraft.server.EntityLiving;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Location;
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
public class CitizensNPC extends AbstractNPC {
public CitizensNPC(String name) {
super(CitizensAPI.getNPCRegistry(), name);
}
@Override
public void chat(Player player, String message) {
Messaging.sendWithNPC(player, Setting.CHAT_PREFIX.asString() + message, this);
public CitizensNPC(NPCRegistry registry, String name) {
super(registry, name);
}
@Override
public void chat(String message) {
for (Player player : Bukkit.getOnlinePlayers())
chat(player, message);
}
protected abstract EntityLiving createHandle(Location loc);
@Override
public boolean despawn() {
if (!isSpawned()) {
@ -54,136 +30,85 @@ public abstract class CitizensNPC extends AbstractNPC {
return false;
}
Bukkit.getPluginManager().callEvent(new NPCDespawnEvent(this));
boolean keepSelected = getTrait(Spawned.class).shouldSpawn();
if (!keepSelected)
removeMetadata("selectors", CitizensAPI.getPlugin());
getBukkitEntity().remove();
mcEntity = null;
CitizensAPI.getServer().callEvent(new NPCDespawnEvent(this));
getEntity().remove();
controller = null;
return true;
}
@Override
public CitizensAI getAI() {
return ai;
}
@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);
public LivingEntity getEntity() {
return (LivingEntity) controller.getEntity();
}
@Override
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) {
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
for (DataKey traitKey : root.getRelative("traits").getSubKeys()) {
Trait trait = traitManager.getTrait(traitKey.name(), this);
for (DataKey attachmentKey : root.getRelative("traits").getSubKeys()) {
Attachment trait = attachmentFactory.getTrait(attachmentKey.name(), this);
if (trait == null) {
Messaging.severeF("Skipped missing trait '%s' while loading NPC ID: '%d'. Has the name changed?",
traitKey.name(), getId());
Messaging.severeF("Skipped missing attachment '%s' while loading NPC ID: '%d'. Has the name changed?",
attachmentKey.name(), getId());
continue;
}
addTrait(trait);
addAttachment(trait);
try {
getTrait(trait.getClass()).load(traitKey);
getAttachment(trait.getClass()).load(attachmentKey);
} 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());
}
}
// Spawn the NPC
if (getTrait(Spawned.class).shouldSpawn()) {
Location spawnLoc = getTrait(CurrentLocation.class).getLocation();
if (getAttachment(Spawned.class).shouldSpawn()) {
WorldVector spawnLoc = getAttachment(CurrentLocation.class).getLocation();
if (spawnLoc != null)
spawn(spawnLoc);
}
}
@Override
public void remove() {
super.remove();
CitizensAPI.getNPCRegistry().deregister(this);
}
public void save(DataKey root) {
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
for (Trait trait : traits.values()) {
for (Attachment trait : attachments.values()) {
trait.save(root.getRelative("traits." + trait.getName()));
}
}
@Override
public void setName(String name) {
super.setName(name);
}
@Override
public boolean spawn(Location loc) {
Validate.notNull(loc, "location cannot be null");
public boolean spawn(WorldVector at) {
if (at == null)
throw new IllegalArgumentException("location cannot be null");
if (isSpawned()) {
Messaging.debug("NPC (ID: " + getId() + ") is already spawned.");
return false;
}
NPCSpawnEvent spawnEvent = new NPCSpawnEvent(this, loc);
Bukkit.getPluginManager().callEvent(spawnEvent);
NPCSpawnEvent spawnEvent = new NPCSpawnEvent(this, at);
CitizensAPI.getServer().callEvent(spawnEvent);
if (spawnEvent.isCancelled())
return false;
mcEntity = createHandle(loc);
mcEntity.world.addEntity(mcEntity);
mcEntity.world.players.remove(mcEntity);
controller.spawn(at);
// Set the spawned state
getTrait(CurrentLocation.class).setLocation(loc);
getTrait(Spawned.class).setSpawned(true);
getAttachment(CurrentLocation.class).setLocation(at);
getAttachment(Spawned.class).setSpawned(true);
// Modify NPC using traits after the entity has been created
for (Trait trait : traits.values())
trait.onNPCSpawn();
for (Attachment attached : attachments.values())
attached.onSpawn();
return true;
}
@ -191,7 +116,6 @@ public abstract class CitizensNPC extends AbstractNPC {
public void update() {
try {
super.update();
ai.update();
} catch (Exception ex) {
Messaging.logF("Exception while updating %d: %s.", getId(), ex.getMessage());
ex.printStackTrace();

View File

@ -1,145 +1,29 @@
package net.citizensnpcs.npc;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
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.NPCRegistry;
import net.citizensnpcs.api.npc.character.Character;
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 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 {
private final ByIdArray<NPC> npcs = new ByIdArray<NPC>();
private final Storage saves;
private final Map<EntityType, Class<? extends CitizensNPC>> types = new EnumMap<EntityType, Class<? extends CitizensNPC>>(
EntityType.class);
public CitizensNPCRegistry(Storage 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
public NPC createNPC(EntityType type, String name) {
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) {
public NPC getById(int id) {
if (id < 0)
throw new IllegalArgumentException("invalid 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
public Iterator<NPC> iterator() {
return npcs.iterator();
@ -153,24 +37,15 @@ public class CitizensNPCRegistry implements NPCRegistry {
}
@Override
public void deregisterAll() {
Iterator<NPC> itr = iterator();
while (itr.hasNext()) {
NPC npc = itr.next();
itr.remove();
npc.despawn();
saves.getKey("npc").removeKey(String.valueOf(npc.getId()));
}
public NPC createAndSpawn(String name, WorldVector at, MobType type) {
NPC npc = new CitizensNPC(this, name);
npc.setEntityController(null); // TODO;
npc.spawn(at);
return npc;
}
private CitizensNPC getByType(EntityType type, int id, String name) {
Class<? extends CitizensNPC> npcClass = types.get(type);
if (npcClass == null)
throw new IllegalArgumentException("Invalid EntityType: " + type);
try {
return npcClass.getConstructor(int.class, String.class).newInstance(id, name);
} catch (Exception ex) {
return null;
}
@Override
public int register(NPC npc) {
return npcs.add(npc);
}
}

View File

@ -6,9 +6,7 @@ import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.NPCRemoveEvent;
import net.citizensnpcs.api.event.NPCRightClickEvent;
import net.citizensnpcs.api.event.NPCSelectEvent;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.util.Messaging;
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.CitizensNPC;
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;

View File

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

View File

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

View File

@ -1,22 +1,19 @@
package net.citizensnpcs.trait;
import net.citizensnpcs.api.attachment.Attachment;
import net.citizensnpcs.api.event.NPCRightClickEvent;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
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.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
//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 boolean enabled;

View File

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

View File

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

View File

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

View File

@ -8,17 +8,15 @@ import java.util.Map;
import java.util.Random;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.attachment.Attachment;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.trait.Toggleable;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.Paginator;
import net.minecraft.server.EntityHuman;
import net.minecraft.server.EntityLiving;
import org.bukkit.Bukkit;
import org.bukkit.conversations.Conversation;
@ -28,7 +26,7 @@ import org.bukkit.conversations.ConversationFactory;
import org.bukkit.entity.Player;
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 int currentIndex;
private final NPC npc;
@ -93,7 +91,7 @@ public class Text extends Trait implements Runnable, Toggleable, ConversationAba
}
@Override
public void onNPCSpawn() {
public void onSpawn() {
if (text.isEmpty())
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 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.trait.trait.Owner;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.google.common.base.Joiner;
@ -68,7 +68,7 @@ public class Messaging {
send = send.replace("<player>", player.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("<id>", Integer.toString(npc.getId()));

View File

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