CommandConfigurable interface, range/realistic looking settings added to LookClose and Text

This commit is contained in:
fullwall 2012-08-04 12:48:07 +08:00
parent 461d102107
commit 288bcf5e9f
9 changed files with 136 additions and 61 deletions

View File

@ -52,9 +52,12 @@ public class Settings {
DATABASE_USERNAME("storage.database.username", ""), DATABASE_USERNAME("storage.database.username", ""),
DEBUG_MODE("general.debug-mode", false), DEBUG_MODE("general.debug-mode", false),
DEFAULT_LOOK_CLOSE("npc.default.look-close", false), DEFAULT_LOOK_CLOSE("npc.default.look-close", false),
DEFAULT_LOOK_CLOSE_RANGE("npc.default.look-close.range", 5),
DEFAULT_PATHFINDING_RANGE("npc.pathing.default-pathfinding-range", 25F), DEFAULT_PATHFINDING_RANGE("npc.pathing.default-pathfinding-range", 25F),
DEFAULT_RANDOM_TALKER("npc.default.random-talker", true), DEFAULT_RANDOM_TALKER("npc.default.random-talker", true),
DEFAULT_REALISTIC_LOOKING("npc.default.realistic-looking", false),
DEFAULT_TALK_CLOSE("npc.default.talk-close", false), DEFAULT_TALK_CLOSE("npc.default.talk-close", false),
DEFAULT_TALK_CLOSE_RANGE("npc.default.talk-close.range", 5),
DEFAULT_TEXT("npc.default.text.0", "Hi, I'm <npc>!") { DEFAULT_TEXT("npc.default.text.0", "Hi, I'm <npc>!") {
@Override @Override
public void loadFromKey(DataKey root) { public void loadFromKey(DataKey root) {

View File

@ -0,0 +1,5 @@
package net.citizensnpcs.command;
public interface CommandConfigurable {
void configure(CommandContext args);
}

View File

@ -135,9 +135,11 @@ public class CommandManager {
if (cmd.max() != -1 && context.argsLength() > cmd.max()) if (cmd.max() != -1 && context.argsLength() > cmd.max())
throw new CommandUsageException("Too many arguments.", getUsage(args, cmd)); throw new CommandUsageException("Too many arguments.", getUsage(args, cmd));
if (!context.getFlags().contains('*')) {
for (char flag : context.getFlags()) for (char flag : context.getFlags())
if (cmd.flags().indexOf(String.valueOf(flag)) == -1) if (cmd.flags().indexOf(String.valueOf(flag)) == -1)
throw new CommandUsageException("Unknown flag: " + flag, getUsage(args, cmd)); throw new CommandUsageException("Unknown flag: " + flag, getUsage(args, cmd));
}
methodArgs[0] = context; methodArgs[0] = context;
Object instance = instances.get(method); Object instance = instances.get(method);

View File

@ -13,6 +13,7 @@ import net.citizensnpcs.api.trait.trait.MobType;
import net.citizensnpcs.api.trait.trait.Owner; import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.api.trait.trait.Spawned; import net.citizensnpcs.api.trait.trait.Spawned;
import net.citizensnpcs.command.Command; import net.citizensnpcs.command.Command;
import net.citizensnpcs.command.CommandConfigurable;
import net.citizensnpcs.command.CommandContext; import net.citizensnpcs.command.CommandContext;
import net.citizensnpcs.command.Requirements; import net.citizensnpcs.command.Requirements;
import net.citizensnpcs.command.exception.CommandException; import net.citizensnpcs.command.exception.CommandException;
@ -557,4 +558,27 @@ public class NPCCommands {
Messaging.sendF(sender, ChatColor.GREEN + "Trait %s added successfully.", Messaging.sendF(sender, ChatColor.GREEN + "Trait %s added successfully.",
StringHelper.wrap(traitName)); StringHelper.wrap(traitName));
} }
@Command(
aliases = { "npc" },
usage = "traitc|tc [trait name] [flags]",
desc = "Configures a trait",
modifiers = { "traitc", "tc" },
min = 2,
flags = "*",
permission = "npc.trait-configure")
public void traitConfigure(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
String traitName = args.getString(1);
if (!sender.hasPermission("citizens.npc.trait-configure." + traitName))
throw new NoPermissionsException();
Class<? extends Trait> clazz = CitizensAPI.getTraitFactory().getTraitClass(args.getString(1));
if (clazz == null)
throw new CommandException("Trait not found.");
if (!clazz.isAssignableFrom(CommandConfigurable.class))
throw new CommandException("That trait is not configurable");
if (!npc.hasTrait(clazz))
throw new CommandException("The NPC doesn't have that trait.");
CommandConfigurable trait = (CommandConfigurable) npc.getTrait(clazz);
trait.configure(args);
}
} }

View File

@ -5,64 +5,59 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import net.citizensnpcs.Settings.Setting; import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.exception.NPCLoadException; import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import net.minecraft.server.EntityLiving; import net.citizensnpcs.command.CommandConfigurable;
import net.citizensnpcs.command.CommandContext;
import net.citizensnpcs.util.Util;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.entity.CraftLivingEntity;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class LookClose extends Trait implements Toggleable { public class LookClose extends Trait implements Toggleable, CommandConfigurable {
private boolean enabled = Setting.DEFAULT_LOOK_CLOSE.asBoolean(); private boolean enabled = Setting.DEFAULT_LOOK_CLOSE.asBoolean();
private Player lookingAt; private Player lookingAt;
private double range = Setting.DEFAULT_LOOK_CLOSE_RANGE.asDouble();
private boolean realisticLooking = Setting.DEFAULT_REALISTIC_LOOKING.asBoolean();
public LookClose() { public LookClose() {
super("lookclose"); super("lookclose");
} }
private void faceEntity(Entity from, Entity at) { private boolean canSeeTarget() {
if (from.getWorld() != at.getWorld()) return realisticLooking ? Util.rayTrace(npc.getBukkitEntity(), lookingAt) : true;
return;
Location loc = from.getLocation();
double xDiff = at.getLocation().getX() - loc.getX();
double yDiff = at.getLocation().getY() - loc.getY();
double zDiff = at.getLocation().getZ() - loc.getZ();
double distanceXZ = Math.sqrt(xDiff * xDiff + zDiff * zDiff);
double distanceY = Math.sqrt(distanceXZ * distanceXZ + yDiff * yDiff);
double yaw = (Math.acos(xDiff / distanceXZ) * 180 / Math.PI);
double pitch = (Math.acos(yDiff / distanceY) * 180 / Math.PI) - 90;
if (zDiff < 0.0) {
yaw = yaw + (Math.abs(180 - yaw) * 2);
} }
EntityLiving handle = ((CraftLivingEntity) from).getHandle(); @Override
handle.yaw = (float) yaw - 90; public void configure(CommandContext args) {
handle.pitch = (float) pitch; range = args.getFlagDouble("range", range);
handle.as = handle.yaw; range = args.getFlagDouble("r", range);
realisticLooking = args.hasFlag('r');
} }
private void findNewTarget() { private void findNewTarget() {
List<Entity> nearby = npc.getBukkitEntity().getNearbyEntities(2.5, 5, 2.5); List<Entity> nearby = npc.getBukkitEntity().getNearbyEntities(range / 2, range, range / 2);
final Location npcLocation = npc.getBukkitEntity().getLocation();
Collections.sort(nearby, new Comparator<Entity>() { Collections.sort(nearby, new Comparator<Entity>() {
@Override @Override
public int compare(Entity o1, Entity o2) { public int compare(Entity o1, Entity o2) {
double d1 = o1.getLocation().distanceSquared(npc.getBukkitEntity().getLocation()); double d1 = o1.getLocation().distanceSquared(npcLocation);
double d2 = o2.getLocation().distanceSquared(npc.getBukkitEntity().getLocation()); double d2 = o2.getLocation().distanceSquared(npcLocation);
return Double.compare(d1, d2); return Double.compare(d1, d2);
} }
}); });
for (Entity entity : nearby) { for (Entity entity : nearby) {
if (entity instanceof Player) { if (entity.getType() != EntityType.PLAYER)
continue;
if (CitizensAPI.getNPCRegistry().getNPC(entity) != null)
continue;
lookingAt = (Player) entity; lookingAt = (Player) entity;
return; return;
} }
}
lookingAt = null; lookingAt = null;
} }
@ -70,33 +65,34 @@ public class LookClose extends Trait implements Toggleable {
if (lookingAt == null) if (lookingAt == null)
return true; return true;
if (!lookingAt.isOnline() || lookingAt.getWorld() != npc.getBukkitEntity().getWorld() if (!lookingAt.isOnline() || lookingAt.getWorld() != npc.getBukkitEntity().getWorld()
|| lookingAt.getLocation().distanceSquared(npc.getBukkitEntity().getLocation()) > 5) { || lookingAt.getLocation().distanceSquared(npc.getBukkitEntity().getLocation()) > range) {
lookingAt = null; lookingAt = null;
return true;
} }
return false; return lookingAt == null;
} }
@Override @Override
public void load(DataKey key) throws NPCLoadException { public void load(DataKey key) throws NPCLoadException {
enabled = key.getBoolean(""); enabled = key.getBoolean("");
range = key.getDouble("range", range);
realisticLooking = key.getBoolean("realistic-looking", false);
} }
@Override @Override
public void run() { public void run() {
if (!enabled || npc.getNavigator().isNavigating()) if (!enabled || npc.getNavigator().isNavigating())
return; return;
if (hasInvalidTarget()) { if (hasInvalidTarget())
findNewTarget(); findNewTarget();
} if (lookingAt != null && canSeeTarget())
if (lookingAt != null) { Util.faceEntity(npc.getBukkitEntity(), lookingAt);
faceEntity(npc.getBukkitEntity(), lookingAt);
}
} }
@Override @Override
public void save(DataKey key) { public void save(DataKey key) {
key.setBoolean("", enabled); key.setBoolean("", enabled);
key.setDouble("range", range);
key.setBoolean("realistic-looking", realisticLooking);
} }
@Override @Override

View File

@ -3,6 +3,7 @@ package net.citizensnpcs.trait.text;
import net.citizensnpcs.util.Messaging; import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.StringHelper; import net.citizensnpcs.util.StringHelper;
import org.bukkit.command.CommandSender;
import org.bukkit.conversations.ConversationContext; import org.bukkit.conversations.ConversationContext;
import org.bukkit.conversations.Prompt; import org.bukkit.conversations.Prompt;
import org.bukkit.conversations.StringPrompt; import org.bukkit.conversations.StringPrompt;
@ -24,10 +25,14 @@ public class StartPrompt extends StringPrompt {
else if (input.equalsIgnoreCase("remove")) else if (input.equalsIgnoreCase("remove"))
return new TextRemovePrompt(text); return new TextRemovePrompt(text);
else if (input.equalsIgnoreCase("random")) else if (input.equalsIgnoreCase("random"))
Messaging.send((Player) context.getForWhom(), "<e>Random talker <a>set to <e>" + text.toggleRandomTalker() Messaging.send((Player) context.getForWhom(),
+ "<a>."); "<e>Random talker <a>set to <e>" + text.toggleRandomTalker() + "<a>.");
else if (input.equalsIgnoreCase("realistic looking"))
Messaging.send((CommandSender) context.getForWhom(),
"<e>Realistic looking <a>set to <e>" + text.toggleRealisticLooking() + "<a>.");
else if (input.equalsIgnoreCase("close")) else if (input.equalsIgnoreCase("close"))
Messaging.send((Player) context.getForWhom(), "<e>Close talker <a>set to <e>" + text.toggle() + "<a>."); Messaging.send((Player) context.getForWhom(), "<e>Close talker <a>set to <e>" + text.toggle()
+ "<a>.");
else else
Messaging.sendError((Player) context.getForWhom(), "Invalid edit type."); Messaging.sendError((Player) context.getForWhom(), "Invalid edit type.");

View File

@ -37,6 +37,8 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
private int currentIndex; private int currentIndex;
private final Plugin plugin; private final Plugin plugin;
private boolean randomTalker = Setting.DEFAULT_RANDOM_TALKER.asBoolean(); private boolean randomTalker = Setting.DEFAULT_RANDOM_TALKER.asBoolean();
private double range = Setting.DEFAULT_TALK_CLOSE_RANGE.asDouble();
private boolean realisticLooker = Setting.DEFAULT_REALISTIC_LOOKING.asBoolean();
private boolean talkClose = Setting.DEFAULT_TALK_CLOSE.asBoolean(); private boolean talkClose = Setting.DEFAULT_TALK_CLOSE.asBoolean();
private final List<String> text = new ArrayList<String>(); private final List<String> text = new ArrayList<String>();
@ -59,9 +61,9 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
} }
public Editor getEditor(final Player player) { public Editor getEditor(final Player player) {
final Conversation conversation = new ConversationFactory(plugin).addConversationAbandonedListener(this) final Conversation conversation = new ConversationFactory(plugin)
.withLocalEcho(false).withEscapeSequence("/npc text").withModality(false) .addConversationAbandonedListener(this).withLocalEcho(false).withEscapeSequence("/npc text")
.withFirstPrompt(new StartPrompt(this)).buildConversation(player); .withModality(false).withFirstPrompt(new StartPrompt(this)).buildConversation(player);
return new Editor() { return new Editor() {
@Override @Override
@ -89,10 +91,10 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
if (text.isEmpty()) if (text.isEmpty())
populateDefaultText(); populateDefaultText();
if (key.keyExists("talk-close")) talkClose = key.getBoolean("talk-close", talkClose);
talkClose = key.getBoolean("talk-close"); realisticLooker = key.getBoolean("realistic-looking", realisticLooker);
if (key.keyExists("random-talker")) randomTalker = key.getBoolean("random-talker", randomTalker);
randomTalker = key.getBoolean("random-talker"); range = key.getDouble("range", range);
} }
@EventHandler @EventHandler
@ -147,6 +149,8 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
public void save(DataKey key) { public void save(DataKey key) {
key.setBoolean("talk-close", talkClose); key.setBoolean("talk-close", talkClose);
key.setBoolean("random-talker", randomTalker); key.setBoolean("random-talker", randomTalker);
key.setBoolean("realistic-looking", realisticLooker);
key.setDouble("range", range);
for (int i = 0; i < text.size(); i++) for (int i = 0; i < text.size(); i++)
key.setString(String.valueOf(i), text.get(i)); key.setString(String.valueOf(i), text.get(i));
} }
@ -183,13 +187,15 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
@Override @Override
public boolean toggle() { public boolean toggle() {
talkClose = !talkClose; return (talkClose = !talkClose);
return talkClose;
} }
public boolean toggleRandomTalker() { public boolean toggleRandomTalker() {
randomTalker = !randomTalker; return (randomTalker = !randomTalker);
return randomTalker; }
public boolean toggleRealisticLooking() {
return (realisticLooker = !realisticLooker);
} }
@Override @Override

View File

@ -37,6 +37,11 @@ public class WanderingWaypointProvider implements WaypointProvider, Iterable<Loc
return currentGoal.isPaused(); return currentGoal.isPaused();
} }
@Override
public Iterator<Location> iterator() {
return iterator;
}
@Override @Override
public void load(DataKey key) { public void load(DataKey key) {
} }
@ -59,9 +64,4 @@ public class WanderingWaypointProvider implements WaypointProvider, Iterable<Loc
public void setPaused(boolean paused) { public void setPaused(boolean paused) {
currentGoal.setPaused(paused); currentGoal.setPaused(paused);
} }
@Override
public Iterator<Location> iterator() {
return iterator;
}
} }

View File

@ -4,6 +4,7 @@ import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.event.NPCCollisionEvent; import net.citizensnpcs.api.event.NPCCollisionEvent;
import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.event.NPCPushEvent;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.minecraft.server.EntityLiving;
import net.minecraft.server.Packet; import net.minecraft.server.Packet;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
@ -11,8 +12,11 @@ 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.CraftLivingEntity;
import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
@ -34,6 +38,30 @@ public class Util {
return event; return event;
} }
public static void faceEntity(Entity from, Entity at) {
if (from.getWorld() != at.getWorld())
return;
Location loc = from.getLocation();
double xDiff = at.getLocation().getX() - loc.getX();
double yDiff = at.getLocation().getY() - loc.getY();
double zDiff = at.getLocation().getZ() - loc.getZ();
double distanceXZ = Math.sqrt(xDiff * xDiff + zDiff * zDiff);
double distanceY = Math.sqrt(distanceXZ * distanceXZ + yDiff * yDiff);
double yaw = (Math.acos(xDiff / distanceXZ) * 180 / Math.PI);
double pitch = (Math.acos(yDiff / distanceY) * 180 / Math.PI) - 90;
if (zDiff < 0.0) {
yaw = yaw + (Math.abs(180 - yaw) * 2);
}
EntityLiving handle = ((CraftLivingEntity) from).getHandle();
handle.yaw = (float) yaw - 90;
handle.pitch = (float) pitch;
handle.as = handle.yaw;
}
public static boolean isSettingFulfilled(Player player, Setting setting) { public static boolean isSettingFulfilled(Player player, Setting setting) {
String parts = setting.asString(); String parts = setting.asString();
if (parts.contains("*")) if (parts.contains("*"))
@ -59,6 +87,12 @@ public class Util {
return type; return type;
} }
public static boolean rayTrace(LivingEntity entity, LivingEntity entity2) {
EntityLiving from = ((CraftLivingEntity) entity).getHandle();
EntityLiving to = ((CraftLivingEntity) entity2).getHandle();
return from.l(to);
}
public static void sendPacketNearby(Location location, Packet packet, double radius) { public static void sendPacketNearby(Location location, Packet packet, double radius) {
radius *= radius; radius *= radius;
final World world = location.getWorld(); final World world = location.getWorld();