@Override
 public void collide(net.minecraft.server.v1_6_R2.Entity entity) {
   // this method is called by both the entities involved - cancelling
   // it will not stop the NPC from moving.
   super.collide(entity);
   if (npc != null) Util.callCollisionEvent(npc, entity.getBukkitEntity());
 }
 public static void startWithCallback(
     Callback callback,
     NPCRegistry npcRegistry,
     CommandSender sender,
     CommandContext args,
     String raw)
     throws CommandException {
   try {
     int id = Integer.parseInt(raw);
     callback.run(npcRegistry.getById(id));
     return;
   } catch (NumberFormatException ex) {
     String name = args.getString(1);
     List<NPC> possible = Lists.newArrayList();
     double range = -1;
     if (args.hasValueFlag("r")) {
       range = Math.abs(args.getFlagDouble("r"));
     }
     for (NPC test : npcRegistry) {
       if (test.getName().equalsIgnoreCase(name)) {
         if (range > 0
             && test.isSpawned()
             && !Util.locationWithinRange(
                 args.getSenderLocation(), test.getEntity().getLocation(), range)) continue;
         possible.add(test);
       }
     }
     if (possible.size() == 1) {
       callback.run(possible.get(0));
     } else if (possible.size() > 1) {
       NPCCommandSelector.start(callback, (Conversable) sender, possible);
       return;
     }
   }
 }
  @Override
  public void j_() {
    super.j_();
    if (npc == null) return;
    boolean navigating = npc.getNavigator().isNavigating();
    updatePackets(navigating);
    if (gravity
        && !navigating
        && getBukkitEntity() != null
        && Util.isLoaded(getBukkitEntity().getLocation(LOADED_LOCATION))
        && !NMS.inWater(getBukkitEntity())) {
      move(0, -0.2, 0);
      // gravity. also works around an entity.onGround not updating issue
      // (onGround is normally updated by the client)
    }
    if (!npc.data().get("removefromplayerlist", true)) g();
    if (Math.abs(motX) < EPSILON && Math.abs(motY) < EPSILON && Math.abs(motZ) < EPSILON)
      motX = motY = motZ = 0;

    NMS.updateSenses(this);
    if (navigating) {
      Navigation navigation = getNavigation();
      if (!navigation.f()) navigation.e();
      moveOnCurrentHeading();
    } else if (motX != 0 || motZ != 0 || motY != 0) {
      e(0, 0); // is this necessary? it does controllable but sometimes
      // players sink into the ground
    }

    if (noDamageTicks > 0) --noDamageTicks;
    npc.update();
  }
  @Override
  public void A_() {
    super.A_();
    if (npc == null) return;
    if (updateCounter + 1 > Setting.PACKET_UPDATE_DELAY.asInt()) {
      updateEffects = true;
    }
    livingEntityBaseTick();

    boolean navigating = npc.getNavigator().isNavigating();
    updatePackets(navigating);
    if (!navigating
        && getBukkitEntity() != null
        && npc.getTrait(Gravity.class).hasGravity()
        && Util.isLoaded(getBukkitEntity().getLocation(LOADED_LOCATION))) {
      g(0, 0);
    }
    if (Math.abs(motX) < EPSILON && Math.abs(motY) < EPSILON && Math.abs(motZ) < EPSILON) {
      motX = motY = motZ = 0;
    }
    if (navigating) {
      if (!NMSImpl.isNavigationFinished(navigation)) {
        NMSImpl.updateNavigation(navigation);
      }
      moveOnCurrentHeading();
    }
    NMSImpl.updateAI(this);

    if (noDamageTicks > 0) {
      --noDamageTicks;
    }

    npc.update();
  }
 @Override
 public void g(double x, double y, double z) {
   if (npc == null) {
     super.g(x, y, z);
     return;
   }
   if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
     if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) super.g(x, y, z);
     return;
   }
   Vector vector = new Vector(x, y, z);
   NPCPushEvent event = Util.callPushEvent(npc, vector);
   if (!event.isCancelled()) {
     vector = event.getCollisionVector();
     super.g(vector.getX(), vector.getY(), vector.getZ());
   }
   // when another entity collides, this method is called to push the
   // NPC so we prevent it from doing anything if the event is
   // cancelled.
 }