예제 #1
0
  /**
   * Various corner cases that would cause this check to fail or require special treatment
   *
   * @param player
   * @param data
   * @param from
   * @param to
   * @return
   */
  public boolean shouldBeApplied(
      final Player player, final MovingData data, final Location from, final Location to) {

    if (player.isDead() || player.isInsideVehicle() || data.insideVehicle) return false;

    if (data.wasTeleported) {
      // Remember this location
      data.teleportedTo = from.clone();
      data.wasTeleported = false;
      data.jumpPhase = 0;
    }

    if (data.teleportedTo != null && data.teleportedTo.getWorld().equals(from.getWorld())) {
      // As long as the from-Location doesn't change, the player didn't accept the teleport
      if (data.teleportedTo.distanceSquared(from) < 0.01D) {
        // Event after Teleport ignored
        return false;
      } else {
        // The player finally accepted the teleport with the previous event
        data.teleportedTo = null;
      }
    }

    // If the target is a bed, don't check (going to bed is a kind of mini teleport...)
    if (to.getWorld().getBlockTypeIdAt(to) == Material.BED_BLOCK.getId()) {
      return false;
    }

    return true;
  }
예제 #2
0
  /**
   * Update the cached values for players velocity to be prepared to give them additional movement
   * freedom in their next move events
   *
   * @param v
   * @param data
   */
  public void updateVelocity(Vector v, MovingData data) {

    // Compare the velocity vector to the existing movement freedom that we've from previous events
    double tmp = (Math.abs(v.getX()) + Math.abs(v.getZ())) * 3D;
    if (tmp > data.horizFreedom) data.horizFreedom = tmp;

    if (v.getY() > data.maxYVelocity) {
      data.maxYVelocity = v.getY();
    }
  }
예제 #3
0
  /**
   * Register a task with bukkit that will be run a short time from now, displaying how many
   * violations happened in that timeframe
   *
   * @param p
   * @param data
   */
  private void setupSummaryTask(final Player p, final MovingData data) {
    // Setup task to display summary later
    if (data.summaryTask == -1) {
      Runnable r =
          new Runnable() {

            @Override
            public void run() {
              if (data.highestLogLevel != null) {
                String logString =
                    String.format(
                        summaryMessage,
                        p.getName(),
                        ticksBeforeSummary / 20,
                        data.violationsInARow[0],
                        data.violationsInARow[1],
                        data.violationsInARow[2]);
                plugin.log(data.highestLogLevel, logString);

                data.highestLogLevel = Level.ALL;
              }
              // deleting its own reference
              data.summaryTask = -1;

              data.violationsInARow[0] = 0;
              data.violationsInARow[1] = 0;
              data.violationsInARow[2] = 0;
            }
          };

      // Give a summary in x ticks. 20 ticks ~ 1 second
      data.summaryTask =
          plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, r, ticksBeforeSummary);
    }
  }
예제 #4
0
  /**
   * Call this when a player got successfully teleported with the corresponding event to adjust
   * stored data to the new situation
   *
   * @param event
   */
  public void teleported(PlayerTeleportEvent event) {

    MovingData data = MovingData.get(event.getPlayer());

    // We can enforce a teleport, if that flag is explicitly set (but I'd rather have other plugins
    // not arbitrarily cancel teleport events in the first place...
    if (data.teleportInitializedByMe != null
        && event.isCancelled()
        && enforceTeleport
        && event.getTo().equals(data.teleportInitializedByMe)) {
      event.setCancelled(false);
      data.teleportInitializedByMe = null;
    }

    if (!event.isCancelled()) {
      data.wasTeleported = true;
      data.setBackPoint = event.getTo().clone();
      // data.lastLocation = event.getTo().clone();
    }

    // reset anyway - if another plugin cancelled our teleport it's no use to try and be precise
    data.jumpPhase = 0;
  }
예제 #5
0
  public PreciseLocation check(NoCheatPlayer player, MovingData data, CCMoving ccmoving) {

    final PreciseLocation setBack = data.runflySetBackPoint;
    final PreciseLocation from = data.from;
    final PreciseLocation to = data.to;

    if (!setBack.isSet()) {
      setBack.set(from);
    }

    final double yDistance = to.y - from.y;

    // Calculate some distances
    final double xDistance = to.x - from.x;
    final double zDistance = to.z - from.z;
    final double horizontalDistance = Math.sqrt((xDistance * xDistance + zDistance * zDistance));

    double resultHoriz = 0;
    double resultVert = 0;
    double result = 0;
    PreciseLocation newToLocation = null;

    // In case of creative gamemode, give at least 0.60 speed limit
    // horizontal
    double speedLimitHorizontal =
        player.isCreative()
            ? Math.max(creativeSpeed, ccmoving.flyingSpeedLimitHorizontal)
            : ccmoving.flyingSpeedLimitHorizontal;

    speedLimitHorizontal *= player.getSpeedAmplifier();

    resultHoriz = Math.max(0.0D, horizontalDistance - data.horizFreedom - speedLimitHorizontal);

    boolean sprinting = player.isSprinting();

    data.bunnyhopdelay--;

    // Did he go too far?
    if (resultHoriz > 0 && sprinting) {

      // Try to treat it as a the "bunnyhop" problem
      if (data.bunnyhopdelay <= 0 && resultHoriz < 0.4D) {
        data.bunnyhopdelay = 3;
        resultHoriz = 0;
      }
    }

    resultHoriz *= 100;

    // super simple, just check distance compared to max distance
    resultVert =
        Math.max(0.0D, yDistance - data.vertFreedom - ccmoving.flyingSpeedLimitVertical) * 100;

    result = resultHoriz + resultVert;

    if (result > 0) {

      // Increment violation counter
      data.runflyVL += result;
      if (resultHoriz > 0) {
        data.runflyRunningTotalVL += resultHoriz;
        data.runflyRunningFailed++;
      }

      if (resultVert > 0) {
        data.runflyFlyingTotalVL += resultVert;
        data.runflyFlyingFailed++;
      }

      boolean cancel = executeActions(player, ccmoving.flyingActions.getActions(data.runflyVL));

      // Was one of the actions a cancel? Then really do it
      if (cancel) {
        newToLocation = setBack;
      }
    }

    // Slowly reduce the level with each event
    data.runflyVL *= 0.97;

    // Some other cleanup 'n' stuff
    if (newToLocation == null) {
      setBack.set(to);
    }

    return newToLocation;
  }
예제 #6
0
  /**
   * The actual check. First find out if the event needs to be handled at all Second check if the
   * player moved too far horizontally Third check if the player moved too high vertically Fourth
   * treat any occured violations as configured
   *
   * @param event
   */
  public Location check(Player player, Location from, Location to, MovingData data) {

    updateVelocity(player.getVelocity(), data);

    Location newToLocation = null;

    final long startTime = System.nanoTime();

    /** *********** DECIDE WHICH CHECKS NEED TO BE RUN ************ */
    final boolean flyCheck =
        !allowFlying && !plugin.hasPermission(player, PermissionData.PERMISSION_FLYING, checkOPs);
    final boolean runCheck = true;

    /** *************** REFINE EVENT DATA FOR CHECKS ************** */
    if (flyCheck || runCheck) {

      // In both cases it will be interesting to know the type of underground the player
      // is in or goes to
      final int fromType =
          helper.isLocationOnGround(from.getWorld(), from.getX(), from.getY(), from.getZ(), false);
      final int toType =
          helper.isLocationOnGround(to.getWorld(), to.getX(), to.getY(), to.getZ(), false);

      final boolean fromOnGround = fromType != MovingEventHelper.NONSOLID;
      final boolean toOnGround = toType != MovingEventHelper.NONSOLID;

      // Distribute data to checks in the form needed by the checks

      /** ******************* EXECUTE THE CHECKS ******************* */
      double result = 0.0D;

      if (flyCheck) {
        result += Math.max(0D, flyingCheck.check(player, from, fromOnGround, to, toOnGround, data));
      }

      if (runCheck) {
        result +=
            Math.max(
                0D,
                runningCheck.check(
                    from,
                    to,
                    !allowFakeSneak && player.isSneaking(),
                    !allowFastSwim && (fromType & toType & MovingEventHelper.LIQUID) > 0,
                    data));
      }

      /** ******* HANDLE/COMBINE THE RESULTS OF THE CHECKS ********** */
      data.jumpPhase++;

      if (result <= 0) {
        if (fromOnGround) {
          data.setBackPoint = from;
          data.jumpPhase = 0;
        } else if (toOnGround) {
          data.jumpPhase = 0;
        }
      } else if (result > 0) {
        // Increment violation counter
        data.violationLevel += result;
        if (data.setBackPoint == null) data.setBackPoint = from;
      }

      if (result > 0 && data.violationLevel > 1) {

        setupSummaryTask(player, data);

        int level = limitCheck(data.violationLevel - 1);

        data.violationsInARow[level]++;

        newToLocation =
            action(player, from, to, actions[level], data.violationsInARow[level], data);
      }
    }

    // Slowly reduce the level with each event
    data.violationLevel *= 0.97;
    data.horizFreedom *= 0.97;

    statisticElapsedTimeNano += System.nanoTime() - startTime;
    statisticTotalEvents++;

    return newToLocation;
  }
예제 #7
0
  /**
   * Perform actions that were specified in the config file
   *
   * @param event
   * @param action
   * @return
   */
  private Location action(
      Player player,
      Location from,
      Location to,
      Action[] actions,
      int violations,
      MovingData data) {

    Location newToLocation = null;

    if (actions == null) return newToLocation;
    boolean cancelled = false;

    for (Action a : actions) {
      if (a.firstAfter <= violations) {
        if (a.firstAfter == violations || a.repeat) {
          if (a instanceof LogAction) {
            // prepare log message if necessary
            String log =
                String.format(
                    Locale.US,
                    logMessage,
                    player.getName(),
                    from.getWorld().getName(),
                    to.getWorld().getName(),
                    from.getX(),
                    from.getY(),
                    from.getZ(),
                    to.getX(),
                    to.getY(),
                    to.getZ(),
                    Math.abs(from.getX() - to.getX()),
                    to.getY() - from.getY(),
                    Math.abs(from.getZ() - to.getZ()));

            plugin.log(((LogAction) a).level, log);

            // Remember the highest log level we encountered to determine what level the summary log
            // message should have
            if (data.highestLogLevel == null) data.highestLogLevel = Level.ALL;
            if (data.highestLogLevel.intValue() < ((LogAction) a).level.intValue())
              data.highestLogLevel = ((LogAction) a).level;
          } else if (!cancelled && a instanceof CancelAction) {
            // Make a modified copy of the setBackPoint to prevent other plugins from accidentally
            // modifying it
            // and keep the current pitch and yaw (setbacks "feel" better that way). Plus try to
            // adapt the Y-coord
            // to place the player close to ground

            double y = data.setBackPoint.getY();

            // search for the first solid block up to 5 blocks below the setbackpoint and teleport
            // the player there
            int i = 0;
            for (; i < 20; i++) {
              if (playerIsOnGround(data.setBackPoint, -0.5 * i) != MovingData.NONSOLID) {
                break;
              }
            }
            y -= 0.5 * i;

            data.setBackPoint.setY(y);

            // Remember the location we send the player to, to identify teleports that were started
            // by us
            data.teleportInitializedByMe =
                new Location(
                    data.setBackPoint.getWorld(),
                    data.setBackPoint.getX(),
                    y,
                    data.setBackPoint.getZ(),
                    to.getYaw(),
                    to.getPitch());

            newToLocation = data.teleportInitializedByMe;

            cancelled =
                true; // just prevent us from treating more than one "cancel" action, which would
            // make no sense
          } else if (a instanceof CustomAction) plugin.handleCustomAction((CustomAction) a, player);
        }
      }
    }

    return newToLocation;
  }