public void followUpdate() {
   ObjectStub followObj = (ObjectStub) followTarget.getEntity(Namespace.MOB);
   Point followLoc = followObj.getWorldNode().getLoc();
   InterpolatedWorldNode node = obj.getWorldNode();
   Point myLoc = node.getLoc();
   long oid = obj.getOid();
   float fdist = Point.distanceTo(followLoc, destLoc);
   float dist = Point.distanceTo(followLoc, myLoc);
   if (Log.loggingDebug)
     Log.debug(
         "BaseBehavior.followUpdate: oid = "
             + oid
             + "; myLoc = "
             + myLoc
             + "; followLoc = "
             + followLoc
             + "; fdist = "
             + fdist
             + "; dist = "
             + dist);
   long msToSleep = (long) 500;
   // If the new target location is more than a meter from
   // the old one, create a new path.
   if (fdist > 1000) {
     long msToDest = setupPathInterpolator(oid, myLoc, followLoc, true, node.getFollowsTerrain());
     destLoc = followLoc;
     msToSleep = msToDest == 0 ? (long) 500 : Math.min((long) 500, msToDest);
   }
   // Else if we're interpolating, interpolate the current path
   else if (interpolatingPath) {
     interpolatePath();
     if (Log.loggingDebug)
       Log.debug(
           "baseBehavior.followUpdate: oid = "
               + oid
               + "; interpolated myLoc = "
               + obj.getWorldNode().getLoc());
   }
   scheduleMe(interpolatingPath ? msToSleep : pathState.pathTimeRemaining());
 }
    protected void update() {
      Log.debug("Updater.update: in update");

      List<Long> perceiverOids = null;
      lock.lock();
      try {
        perceiverOids = new ArrayList<Long>(perceiverDataMap.keySet());
      } finally {
        lock.unlock();
      }
      // We loop over the copied perceiverOids causing
      // interpolation to happen, and capturing the location in
      // the PerceiverData, so we can later do comparisons
      // cheaply.  Note that underlying map can change while
      // we're doing so, so we don't raise errors if it happens.
      for (long perceiverOid : perceiverOids) {
        PerceiverData perceiverData = perceiverDataMap.get(perceiverOid);
        if (perceiverData != null) {
          perceiverData.previousLoc = perceiverData.lastLoc;
          //                    long lastInterp = perceiverData.wnode.getLastInterp();
          perceiverData.lastLoc = perceiverData.wnode.getLoc();
          //                     if (Log.loggingDebug)
          //                         Log.debug("Updater.update: perceiverOid " + perceiverOid + ",
          // previousLoc " + perceiverData.previousLoc +
          //                             ", lastLoc " + perceiverData.lastLoc + ", time since interp
          // " + (System.currentTimeMillis() - lastInterp));
        }
      }
      // Now actually do the double loop to check if inRange has
      // changed
      for (long perceiverOid : perceiverOids) {
        PerceiverData perceiverData = perceiverDataMap.get(perceiverOid);
        if (perceiverData == null) continue;
        // If the perceiver hasn't moved much, no need to
        // iterate over it's perceived entities
        if (perceiverData.previousLoc != null
            && Point.distanceToSquared(perceiverData.previousLoc, perceiverData.lastLoc) < 100f)
          continue;
        ArrayList<Long> perceivedOids = new ArrayList<Long>(perceiverData.perceivedOids);
        for (long perceivedOid : perceivedOids) {
          PerceiverData perceivedData = perceiverDataMap.get(perceivedOid);
          if (perceivedData == null) continue;
          // Invoke the testProximity method but tell it not
          // to interpolate, but instead get its location
          // from the PerceptionData.lastLoc members
          testProximity(perceiverData, perceivedData, false, false);
        }
      }
    }
 /**
  * Test if the perceived object has come in or out of range of the perceiver object; if so, we
  * change the inRangeOids set for the perceiver, and notify the perceiver.
  */
 protected void testProximity(
     PerceiverData perceiverData,
     PerceiverData perceivedData,
     boolean interpolatePerceiver,
     boolean interpolatePerceived) {
   Point perceiverLoc =
       interpolatePerceiver ? perceiverData.wnode.getLoc() : perceiverData.lastLoc;
   Point perceivedLoc =
       interpolatePerceived ? perceivedData.wnode.getLoc() : perceivedData.lastLoc;
   float distance = Point.distanceTo(perceiverLoc, perceivedLoc);
   float reactionRadius = perceiverData.reactionRadius;
   long perceiverInstance = perceiverData.wnode.getInstanceOid();
   long perceivedInstance = perceivedData.wnode.getInstanceOid();
   boolean sameInstance = perceiverInstance == perceivedInstance;
   boolean inRadius = sameInstance && (distance < reactionRadius);
   boolean wasInRadius = perceiverData.inRangeOids.contains(perceivedData.perceiverOid);
   //         if (Log.loggingDebug)
   //             Log.debug("ProximityTracker.testProximity: perceiver " +
   // perceiverData.perceiverOid + ", perceiverLoc = " + perceiverLoc +
   //                 ", perceived " + perceivedData.perceiverOid + ", perceivedLoc = " +
   // perceivedLoc +
   //                 ", distance " + distance + ", reactionRadius " + reactionRadius + ",
   // perceiverInstance " + perceiverInstance +
   //                 ", perceivedInstance " + perceivedInstance + ", inRadius " + inRadius + ",
   // wasInRadius " + wasInRadius);
   if (inRadius == wasInRadius) return;
   if (sameInstance && hystericalMargin != 0f) {
     if (wasInRadius) inRadius = distance < (reactionRadius + hystericalMargin);
     else inRadius = distance < (reactionRadius - hystericalMargin);
     // If they are the same after hysteresis was applied, skip.
     if (inRadius == wasInRadius) return;
   }
   if (inRadius) {
     perceiverData.inRangeOids.add(perceivedData.perceiverOid);
     perceivedData.inRangeOids.add(perceiverData.perceiverOid);
   } else {
     perceiverData.inRangeOids.remove(perceivedData.perceiverOid);
     perceivedData.inRangeOids.remove(perceiverData.perceiverOid);
   }
   performNotification(
       perceiverData.perceiverOid, perceivedData.perceiverOid, inRadius, wasInRadius);
 }