Remove/consolidate some NMS usage

This commit is contained in:
fullwall 2012-12-07 23:04:31 +08:00
parent bc870189aa
commit 40a74a4630
10 changed files with 127 additions and 116 deletions

View File

@ -31,28 +31,22 @@ import net.citizensnpcs.command.command.ScriptCommands;
import net.citizensnpcs.command.command.TemplateCommands;
import net.citizensnpcs.command.command.TraitCommands;
import net.citizensnpcs.command.command.WaypointCommands;
import net.citizensnpcs.command.exception.CommandException;
import net.citizensnpcs.command.exception.CommandUsageException;
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.CitizensNPCRegistry;
import net.citizensnpcs.npc.CitizensTraitFactory;
import net.citizensnpcs.npc.NPCSelector;
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.StringHelper;
import net.citizensnpcs.util.Util;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.v1_4_5.CraftServer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginLoadOrder;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
@ -108,7 +102,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
ex.printStackTrace();
}
}
((CraftServer) Bukkit.getServer()).enablePlugins(PluginLoadOrder.POSTWORLD);
NMS.loadPlugins();
}
public CommandInfo getCommandInfo(String rootCommand, String modifier) {
@ -140,40 +134,17 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
@Override
public boolean onCommand(CommandSender sender, Command command, String cmdName, String[] args) {
try {
String modifier = args.length > 0 ? args[0] : "";
if (!commands.hasCommand(command, modifier) && !modifier.isEmpty()) {
return suggestClosestModifier(sender, command.getName().toLowerCase(), modifier);
}
NPC npc = selector.getSelected(sender);
// TODO: change the args supplied to a context style system for
// flexibility (ie. adding more context in the future without
// changing everything)
try {
commands.execute(command, args, sender, sender, npc);
} catch (ServerCommandException ex) {
Messaging.sendTr(sender, Messages.COMMAND_MUST_BE_INGAME);
} catch (CommandUsageException ex) {
Messaging.sendError(sender, ex.getMessage());
Messaging.sendError(sender, ex.getUsage());
} catch (WrappedCommandException ex) {
throw ex.getCause();
} catch (UnhandledCommandException ex) {
return false;
} catch (CommandException ex) {
Messaging.sendError(sender, ex.getMessage());
}
} catch (NumberFormatException ex) {
Messaging.sendErrorTr(sender, Messages.COMMAND_INVALID_NUMBER);
} catch (Throwable ex) {
ex.printStackTrace();
if (sender instanceof Player) {
Messaging.sendErrorTr(sender, Messages.COMMAND_REPORT_ERROR);
Messaging.sendError(sender, ex.getClass().getName() + ": " + ex.getMessage());
}
String modifier = args.length > 0 ? args[0] : "";
if (!commands.hasCommand(command, modifier) && !modifier.isEmpty()) {
return suggestClosestModifier(sender, command.getName(), modifier);
}
return true;
NPC npc = selector.getSelected(sender);
// TODO: change the args supplied to a context style system for
// flexibility (ie. adding more context in the future without
// changing everything)
return commands.executeSafe(command, args, sender, sender, npc);
}
@Override
@ -196,7 +167,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
public void onEnable() {
CitizensAPI.setImplementation(this);
// Disable if the server is not using the compatible Minecraft version
String mcVersion = ((CraftServer) getServer()).getServer().getVersion();
String mcVersion = Util.getMinecraftVersion();
compatible = mcVersion.startsWith(COMPATIBLE_MC_VERSION);
if (!compatible) {
Messaging.severeTr(Messages.CITIZENS_INCOMPATIBLE, getDescription().getVersion(), mcVersion);

View File

@ -21,6 +21,7 @@ import net.citizensnpcs.command.exception.ServerCommandException;
import net.citizensnpcs.command.exception.UnhandledCommandException;
import net.citizensnpcs.command.exception.WrappedCommandException;
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.StringHelper;
import org.bukkit.command.CommandSender;
@ -86,11 +87,11 @@ public class CommandManager {
Object[] newMethodArgs = new Object[methodArgs.length + 1];
System.arraycopy(methodArgs, 0, newMethodArgs, 1, methodArgs.length);
executeMethod(null, newArgs, sender, newMethodArgs);
executeMethod(newArgs, sender, newMethodArgs);
}
// Attempt to execute a command.
private void executeMethod(Method parent, String[] args, CommandSender sender, Object[] methodArgs)
private void executeMethod(String[] args, CommandSender sender, Object[] methodArgs)
throws CommandException {
String cmdName = args[0];
String modifier = args.length > 1 ? args[1] : "";
@ -99,7 +100,7 @@ public class CommandManager {
if (method == null)
method = commands.get(cmdName.toLowerCase() + " *");
if (method == null && parent == null)
if (method == null)
throw new UnhandledCommandException();
if (!serverCommands.contains(method) && sender instanceof ConsoleCommandSender)
@ -140,11 +141,47 @@ public class CommandManager {
} catch (InvocationTargetException e) {
if (e.getCause() instanceof CommandException)
throw (CommandException) e.getCause();
throw new WrappedCommandException(e.getCause());
}
}
/**
* A safe version of <code>execute</code> which catches and logs all errors
* that occur. Returns whether the command handler should print usage or
* not.
*
* @see #execute(Command, String[], CommandSender, Object...)
* @return Whether further usage should be printed
*/
public boolean executeSafe(org.bukkit.command.Command command, String[] args, CommandSender sender,
Object... methodArgs) {
try {
try {
execute(command, args, sender, methodArgs);
} catch (ServerCommandException ex) {
Messaging.sendTr(sender, Messages.COMMAND_MUST_BE_INGAME);
} catch (CommandUsageException ex) {
Messaging.sendError(sender, ex.getMessage());
Messaging.sendError(sender, ex.getUsage());
} catch (UnhandledCommandException ex) {
return false;
} catch (WrappedCommandException ex) {
throw ex.getCause();
} catch (CommandException ex) {
Messaging.sendError(sender, ex.getMessage());
} catch (NumberFormatException ex) {
Messaging.sendErrorTr(sender, Messages.COMMAND_INVALID_NUMBER);
}
} catch (Throwable ex) {
ex.printStackTrace();
if (sender instanceof Player) {
Messaging.sendErrorTr(sender, Messages.COMMAND_REPORT_ERROR);
Messaging.sendError(sender, ex.getClass().getName() + ": " + ex.getMessage());
}
}
return true;
}
/**
* Searches for the closest modifier using Levenshtein distance to the given
* top level command and modifier.

View File

@ -1,11 +1,11 @@
package net.citizensnpcs.npc;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.Map;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.util.NMS;
import net.minecraft.server.v1_4_5.Block;
import net.minecraft.server.v1_4_5.EntityLiving;
import net.minecraft.server.v1_4_5.World;
@ -16,18 +16,19 @@ import org.bukkit.craftbukkit.v1_4_5.CraftWorld;
import com.google.common.collect.Maps;
public abstract class CitizensMobNPC extends CitizensNPC {
private final Constructor<? extends EntityLiving> constructor;
private final Constructor<?> constructor;
protected CitizensMobNPC(int id, String name, Class<? extends EntityLiving> clazz) {
protected CitizensMobNPC(int id, String name, Class<?> clazz) {
super(id, name);
this.constructor = getConstructor(clazz);
NMS.registerEntityClass(clazz);
}
private EntityLiving createEntityFromClass(World world) {
private EntityLiving createEntityFromClass(Object... args) {
try {
return constructor.newInstance(world, this);
Object[] newArgs = Arrays.copyOf(args, args.length + 1);
newArgs[args.length] = this;
return (EntityLiving) constructor.newInstance(newArgs);
} catch (Exception ex) {
ex.printStackTrace();
return null;
@ -42,20 +43,15 @@ public abstract class CitizensMobNPC extends CitizensNPC {
// entity.onGround isn't updated right away - we approximate here so
// that things like pathfinding still work *immediately* after spawn.
org.bukkit.Material beneath = loc.getBlock().getRelative(BlockFace.DOWN).getType();
if (beneath.isBlock()) {
Block block = Block.byId[beneath.getId()];
if (block != null && block.material != null) {
entity.onGround = block.material.isSolid();
}
}
if (beneath.isBlock())
entity.onGround = true;
return entity;
}
private static final Map<Class<? extends EntityLiving>, Constructor<? extends EntityLiving>> CONSTRUCTOR_CACHE = Maps
.newHashMap();
private static final Map<Class<?>, Constructor<?>> CONSTRUCTOR_CACHE = Maps.newHashMap();
private static Constructor<? extends EntityLiving> getConstructor(Class<? extends EntityLiving> clazz) {
Constructor<? extends EntityLiving> constructor = CONSTRUCTOR_CACHE.get(clazz);
private static Constructor<?> getConstructor(Class<?> clazz) {
Constructor<?> constructor = CONSTRUCTOR_CACHE.get(clazz);
if (constructor != null)
return constructor;
try {

View File

@ -75,9 +75,9 @@ public abstract class CitizensNPC extends AbstractNPC {
@Override
public LivingEntity getBukkitEntity() {
if (getHandle() == null)
if (mcEntity == null)
return null;
return (LivingEntity) getHandle().getBukkitEntity();
return (LivingEntity) mcEntity.getBukkitEntity();
}
public EntityLiving getHandle() {
@ -221,7 +221,7 @@ public abstract class CitizensNPC extends AbstractNPC {
try {
super.update();
if (isSpawned()) {
NMS.trySwim(getHandle());
NMS.trySwim(getBukkitEntity());
navigator.run();
}
} catch (Exception ex) {

View File

@ -51,13 +51,13 @@ public class AStarNavigationStrategy extends AbstractPathStrategy {
return true;
if (plan == null || plan.isComplete())
return true;
if (NMS.distanceSquared(npc.getHandle(), vector) <= params.distanceMargin()) {
if (npc.getBukkitEntity().getVelocity().distanceSquared(vector) <= params.distanceMargin()) {
plan.update(npc);
if (plan.isComplete())
return true;
vector = plan.getCurrentVector();
}
npc.getHandle().getControllerMove().a(vector.getX(), vector.getY(), vector.getZ(), params.speed());
NMS.setDestination(npc.getBukkitEntity(), vector.getX(), vector.getY(), vector.getZ(), params.speed());
return false;
}

View File

@ -17,7 +17,6 @@ import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.util.NMS;
import net.minecraft.server.v1_4_5.EntityLiving;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -34,7 +33,6 @@ public class CitizensNavigator implements Navigator, Runnable {
private NavigatorParameters localParams = defaultParams;
private final CitizensNPC npc;
private int stationaryTicks;
private boolean updatedAvoidWater = false;
public CitizensNavigator(CitizensNPC npc) {
this.npc = npc;
@ -100,11 +98,6 @@ public class CitizensNavigator implements Navigator, Runnable {
if (defaultParams.baseSpeed() == UNINITIALISED_SPEED)
defaultParams.baseSpeed(NMS.getSpeedFor(npc));
updatePathfindingRange();
if (!updatedAvoidWater) {
boolean defaultAvoidWater = npc.getHandle().getNavigation().a();
defaultParams.avoidWater(defaultAvoidWater);
updatedAvoidWater = true;
}
}
@Override

View File

@ -3,28 +3,31 @@ package net.citizensnpcs.npc.ai;
import net.citizensnpcs.api.ai.NavigatorParameters;
import net.citizensnpcs.api.ai.TargetType;
import net.citizensnpcs.api.ai.event.CancelReason;
import net.citizensnpcs.npc.CitizensNPC;
import net.minecraft.server.v1_4_5.EntityPlayer;
import net.citizensnpcs.api.npc.NPC;
import net.minecraft.server.v1_4_5.EntityHuman;
import net.minecraft.server.v1_4_5.EntityLiving;
import net.minecraft.server.v1_4_5.Navigation;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_4_5.entity.CraftLivingEntity;
public class MCNavigationStrategy extends AbstractPathStrategy {
private final Navigation navigation;
private final NavigatorParameters parameters;
private final Location target;
MCNavigationStrategy(final CitizensNPC npc, Location dest, NavigatorParameters params) {
MCNavigationStrategy(final NPC npc, Location dest, NavigatorParameters params) {
super(TargetType.LOCATION);
this.target = dest;
this.parameters = params;
if (npc.getHandle() instanceof EntityPlayer) {
npc.getHandle().onGround = true;
EntityLiving handle = ((CraftLivingEntity) npc.getBukkitEntity()).getHandle();
if (handle instanceof EntityHuman) {
handle.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 = npc.getHandle().getNavigation();
navigation = handle.getNavigation();
navigation.a(parameters.avoidWater());
navigation.a(dest.getX(), dest.getY(), dest.getZ(), parameters.speed());
if (navigation.f())

View File

@ -5,7 +5,7 @@ import net.citizensnpcs.api.ai.EntityTarget;
import net.citizensnpcs.api.ai.NavigatorParameters;
import net.citizensnpcs.api.ai.TargetType;
import net.citizensnpcs.api.ai.event.CancelReason;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.PlayerAnimation;
import net.minecraft.server.v1_4_5.EntityLiving;
@ -24,8 +24,8 @@ public class MCTargetStrategy implements PathStrategy, EntityTarget {
private final Navigation navigation;
private final NavigatorParameters parameters;
public MCTargetStrategy(CitizensNPC handle, LivingEntity target, boolean aggro, NavigatorParameters params) {
this.handle = handle.getHandle();
public MCTargetStrategy(NPC handle, LivingEntity target, boolean aggro, NavigatorParameters params) {
this.handle = ((CraftLivingEntity) handle.getBukkitEntity()).getHandle();
this.target = ((CraftLivingEntity) target).getHandle();
this.navigation = this.handle.getNavigation();
this.aggro = aggro;

View File

@ -9,7 +9,6 @@ import java.util.Set;
import java.util.WeakHashMap;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.npc.CitizensNPC;
import net.minecraft.server.v1_4_5.ControllerLook;
import net.minecraft.server.v1_4_5.DamageSource;
import net.minecraft.server.v1_4_5.EnchantmentManager;
@ -25,10 +24,12 @@ import net.minecraft.server.v1_4_5.Packet;
import net.minecraft.server.v1_4_5.PathfinderGoalSelector;
import net.minecraft.server.v1_4_5.World;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_4_5.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_4_5.CraftServer;
import org.bukkit.craftbukkit.v1_4_5.CraftWorld;
import org.bukkit.craftbukkit.v1_4_5.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_4_5.entity.CraftLivingEntity;
import org.bukkit.craftbukkit.v1_4_5.entity.CraftPlayer;
import org.bukkit.entity.EntityType;
@ -36,7 +37,7 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.material.Stairs;
import org.bukkit.material.Step;
import org.bukkit.util.Vector;
import org.bukkit.plugin.PluginLoadOrder;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@ -48,9 +49,9 @@ public class NMS {
}
private static final float DEFAULT_SPEED = 0.4F;
private static Map<Class<? extends Entity>, Integer> ENTITY_CLASS_TO_INT;
private static final Map<Class<? extends Entity>, Constructor<? extends Entity>> ENTITY_CONSTRUCTOR_CACHE = new WeakHashMap<Class<? extends Entity>, Constructor<? extends Entity>>();
private static Map<Integer, Class<? extends Entity>> ENTITY_INT_TO_CLASS;
private static Map<Class<?>, Integer> ENTITY_CLASS_TO_INT;
private static final Map<Class<?>, Constructor<?>> ENTITY_CONSTRUCTOR_CACHE = new WeakHashMap<Class<?>, Constructor<?>>();
private static Map<Integer, Class<?>> ENTITY_INT_TO_CLASS;
private static Field GOAL_FIELD;
private static Field LAND_SPEED_MODIFIER_FIELD;
private static final Map<EntityType, Float> MOVEMENT_SPEEDS = Maps.newEnumMap(EntityType.class);
@ -125,18 +126,9 @@ public class NMS {
}
}
public static double distance(EntityLiving handle, Vector vector) {
return Math.sqrt(distanceSquared(handle, vector));
}
public static double distanceSquared(EntityLiving handle, Vector vector) {
return Math.pow(handle.locX - vector.getX(), 2) + Math.pow(handle.locY - vector.getY(), 2)
+ Math.pow(handle.locZ - vector.getZ(), 2);
}
private static Constructor<? extends Entity> getCustomEntityConstructor(Class<? extends Entity> clazz,
EntityType type) throws SecurityException, NoSuchMethodException {
Constructor<? extends Entity> constructor = ENTITY_CONSTRUCTOR_CACHE.get(clazz);
private static Constructor<?> getCustomEntityConstructor(Class<?> clazz, EntityType type)
throws SecurityException, NoSuchMethodException {
Constructor<?> constructor = ENTITY_CONSTRUCTOR_CACHE.get(clazz);
if (constructor == null) {
constructor = clazz.getConstructor(World.class);
constructor.setAccessible(true);
@ -167,7 +159,7 @@ public class NMS {
return DEFAULT_SPEED;
}
try {
float speed = SPEED_FIELD.getFloat(((CraftEntity)npc.getBukkitEntity()).getHandle());
float speed = SPEED_FIELD.getFloat(((CraftEntity) npc.getBukkitEntity()).getHandle());
MOVEMENT_SPEEDS.put(entityType, speed);
return speed;
} catch (IllegalAccessException ex) {
@ -176,10 +168,14 @@ public class NMS {
}
}
public static boolean inWater(EntityLiving mcEntity) {
public static boolean inWater(Entity mcEntity) {
return mcEntity.I() || mcEntity.J();
}
public static void loadPlugins() {
((CraftServer) Bukkit.getServer()).enablePlugins(PluginLoadOrder.POSTWORLD);
}
public static void look(ControllerLook controllerLook, EntityLiving handle, EntityLiving target) {
controllerLook.a(target, 10.0F, handle.bp());
}
@ -189,7 +185,7 @@ public class NMS {
handle.pitch = pitch;
}
public static void registerEntityClass(Class<? extends Entity> clazz) {
public static void registerEntityClass(Class<?> clazz) {
if (ENTITY_CLASS_TO_INT.containsKey(clazz))
return;
Class<?> search = clazz;
@ -208,6 +204,10 @@ public class NMS {
((CraftPlayer) player).getHandle().netServerHandler.sendPacket(packet);
}
public static void setDestination(LivingEntity bukkitEntity, double x, double y, double z, float speed) {
((CraftLivingEntity) bukkitEntity).getHandle().getControllerMove().a(x, y, z, speed);
}
public static void setHeadYaw(EntityLiving handle, float yaw) {
handle.ay = yaw;
}
@ -227,8 +227,8 @@ public class NMS {
World handle = ((CraftWorld) world).getHandle();
Entity entity = null;
try {
Constructor<? extends Entity> constructor = getCustomEntityConstructor(clazz, type);
entity = constructor.newInstance(handle);
Constructor<?> constructor = getCustomEntityConstructor(clazz, type);
entity = (Entity) constructor.newInstance(handle);
} catch (Exception e) {
Messaging.logTr(Messages.ERROR_SPAWNING_CUSTOM_ENTITY, e.getMessage());
return null;
@ -248,16 +248,16 @@ public class NMS {
}
}
public static void trySwim(EntityLiving handle) {
trySwim(handle, 0.04F);
}
public static void trySwim(EntityLiving handle, float power) {
public static void trySwim(Entity handle, float power) {
if (RANDOM.nextFloat() < 0.8F && inWater(handle)) {
handle.motY += power;
}
}
public static void trySwim(org.bukkit.entity.Entity handle) {
trySwim(((CraftEntity) handle).getHandle(), 0.04F);
}
public static void updateAI(EntityLiving entity) {
updateSenses(entity);
entity.getNavigation().e();
@ -278,10 +278,10 @@ public class NMS {
}
}
public static void updatePathfindingRange(CitizensNPC npc, float pathfindingRange) {
public static void updatePathfindingRange(NPC npc, float pathfindingRange) {
if (PATHFINDING_RANGE == null)
return;
Navigation navigation = npc.getHandle().getNavigation();
Navigation navigation = ((CraftLivingEntity) npc.getBukkitEntity()).getHandle().getNavigation();
try {
PATHFINDING_RANGE.set(navigation, pathfindingRange);
} catch (Exception e) {
@ -318,9 +318,9 @@ public class NMS {
try {
Field field = getField(EntityTypes.class, "d");
ENTITY_INT_TO_CLASS = (Map<Integer, Class<? extends Entity>>) field.get(null);
ENTITY_INT_TO_CLASS = (Map<Integer, Class<?>>) field.get(null);
field = getField(EntityTypes.class, "e");
ENTITY_CLASS_TO_INT = (Map<Class<? extends Entity>, Integer>) field.get(null);
ENTITY_CLASS_TO_INT = (Map<Class<?>, Integer>) field.get(null);
} catch (Exception e) {
Messaging.logTr(Messages.ERROR_GETTING_ID_MAPPING, e.getMessage());
}

View File

@ -75,6 +75,16 @@ public class Util {
}
}
public static String getMinecraftVersion() {
String raw = Bukkit.getVersion();
int start = raw.indexOf("MC:");
if (start == -1)
return raw;
start += 4;
int end = raw.indexOf(')', start);
return raw.substring(start, end);
}
public static boolean isLoaded(Location location) {
if (location.getWorld() == null)
return false;
@ -145,6 +155,7 @@ public class Util {
}
}
}
static {
try {
RNG_CLASS = Class.forName("org.uncommons.maths.random.XORShiftRNG");