Пример #1
0
 /**
  * Feed lower-case inputs. Adds versions with "/" if missing, also adds input without the first
  * "/". Trimming from the left side is used, but the original input is also added.
  *
  * @param tree
  * @param inputs
  * @param clear If to clear the tree, before feeding.
  */
 public static void feedCommands(
     SimpleCharPrefixTree tree, Collection<String> inputs, boolean clear) {
   if (clear) {
     tree.clear();
   }
   for (String input : inputs) {
     if (input == null) {
       continue;
     }
     if (!input.isEmpty()) {
       // Do feed the original input.
       tree.feed(input);
     }
     input = StringUtil.leftTrim(input).toLowerCase();
     if (input.isEmpty()) {
       continue;
     }
     tree.feed(input);
     if (!input.startsWith("/")) {
       // Add version with '/'.
       tree.feed("/" + input);
     } else {
       // Add version without the first '/'.
       // TODO: Consider removing all leading '/' here.
       input = input.substring(1);
       if (!input.isEmpty()) {
         tree.feed(input);
       }
     }
   }
 }
Пример #2
0
 public ReflectBlock(ReflectBase base, ReflectBlockPosition blockPosition)
     throws ClassNotFoundException {
   final Class<?> clazz = Class.forName(base.nmsPackageName + ".Block");
   // byID (static)
   nmsGetById = ReflectionUtil.getMethod(clazz, "getById", int.class);
   // getMaterial
   nmsGetMaterial = ReflectionUtil.getMethodNoArgs(clazz, "getMaterial");
   // updateShape
   Method method = null;
   Class<?> clazzIBlockAccess = Class.forName(base.nmsPackageName + ".IBlockAccess");
   if (blockPosition != null) {
     method =
         ReflectionUtil.getMethod(clazz, "updateShape", clazzIBlockAccess, blockPosition.nmsClass);
   }
   if (method == null) {
     method =
         ReflectionUtil.getMethod(
             clazz, "updateShape", clazzIBlockAccess, int.class, int.class, int.class);
     useBlockPosition = false;
   } else {
     useBlockPosition = true;
   }
   nmsUpdateShape = method;
   // Block bounds fetching. The array uses the order the methods (used to) appear in the nms
   // class.
   String[] names =
       new String[] {
         "getMinX", "getMaxX", "getMinY", "getMaxY", "getMinZ", "getMaxZ"
       }; // FUTURE GUESS.
   Method[] methods = tryBoundsMethods(clazz, names);
   if (methods == null) {
     names = guessBoundsMethodNames(clazz);
     if (names != null) {
       methods = tryBoundsMethods(clazz, names);
     }
     if (methods == null) {
       methods = new Method[] {null, null, null, null, null, null};
     }
   }
   // TODO: Test which is which [ALLOW to configure and also save used ones to config, by mc
   // version].
   // TODO: Dynamically test these ? [needs an extra world/space to place blocks inside of...]
   if (ConfigManager.getConfigFile().getBoolean(ConfPaths.LOGGING_EXTENDED_STATUS)) {
     NCPAPIProvider.getNoCheatPlusAPI()
         .getLogManager()
         .debug(
             Streams.INIT,
             "[NoCheatPlus] ReflectBlock: Use methods for shape: "
                 + StringUtil.join(Arrays.asList(names), ", "));
   }
   this.nmsGetMinX = methods[0];
   this.nmsGetMaxX = methods[1];
   this.nmsGetMinY = methods[2];
   this.nmsGetMaxY = methods[3];
   this.nmsGetMinZ = methods[4];
   this.nmsGetMaxZ = methods[5];
 }
Пример #3
0
 private void outpuDebugMove(
     final Player player,
     final double hDistance,
     final double limitH,
     final double yDistance,
     final double limitV,
     final ModelFlying model,
     final List<String> tags,
     final MovingData data) {
   final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove();
   StringBuilder builder = new StringBuilder(350);
   final String dHDist =
       lastMove.toIsValid ? " (" + StringUtil.formatDiff(hDistance, lastMove.hDistance) + ")" : "";
   final String dYDist =
       lastMove.toIsValid ? " (" + StringUtil.formatDiff(yDistance, lastMove.yDistance) + ")" : "";
   builder.append(
       "hDist: "
           + hDistance
           + dHDist
           + " / "
           + limitH
           + " , vDist: "
           + yDistance
           + dYDist
           + " / "
           + limitV);
   final PlayerMoveData thisMove = data.playerMoves.getCurrentMove();
   if (lastMove.toIsValid) {
     builder.append(
         " , fdsq: "
             + StringUtil.fdec3.format(thisMove.distanceSquared / lastMove.distanceSquared));
   }
   if (thisMove.verVelUsed != null) {
     builder.append(" , vVelUsed: " + thisMove.verVelUsed);
   }
   builder.append(" , model: " + model.id);
   if (!tags.isEmpty()) {
     builder.append(" , tags: ");
     builder.append(StringUtil.join(tags, "+"));
   }
   builder.append(" , jumpphase: " + data.sfJumpPhase);
   thisMove.addExtraProperties(builder, " , ");
   debug(player, builder.toString());
 }
Пример #4
0
  /**
   * Handle the '/nocheatplus reload' command.
   *
   * @param sender the sender
   * @return true, if successful
   */
  private void handleReloadCommand(final CommandSender sender) {
    final LogManager logManager = NCPAPIProvider.getNoCheatPlusAPI().getLogManager();
    if (!sender.equals(Bukkit.getConsoleSender())) {
      sender.sendMessage(TAG + "Reloading configuration...");
    }
    logManager.info(Streams.INIT, TAG + "Reloading configuration...");

    // Do the actual reload.
    ConfigManager.cleanup();
    ConfigManager.init(access);
    if (logManager instanceof INotifyReload) { // TODO: This is a band-aid.
      ((INotifyReload) logManager).onReload();
    }

    // Remove all cached configs.
    DataManager.clearConfigs(); // There you have to add XConfig.clear() form now on.

    // Remove some checks data.
    // TODO: Better concept (INotifyReload).
    for (final CheckType checkType :
        new CheckType[] {
          CheckType.BLOCKBREAK, CheckType.FIGHT,
        }) {
      DataManager.clearData(checkType);
    }

    // Reset debug flags to default (temp, heavy).
    DataManager.restoreDefaultDebugFlags();

    // Tell the registered listeners to adapt to new config, first sort them (!).
    Collections.sort(notifyReload, Order.cmpSetupOrder);
    for (final INotifyReload component : notifyReload) {
      component.onReload();
    }

    // Say to the other plugins that we've reloaded the configuration.
    Bukkit.getPluginManager().callEvent(new NCPReloadEvent());

    // Log reloading done.
    if (!sender.equals(Bukkit.getConsoleSender())) {
      sender.sendMessage(TAG + "Configuration reloaded!");
    }
    logManager.info(Streams.INIT, TAG + "Configuration reloaded.");
    logManager.info(
        Streams.DEFAULT_FILE,
        StringUtil.join(VersionCommand.getVersionInfo(), "\n")); // Queued (!).
  }
Пример #5
0
  @Override
  public void checkConsistency(final Player[] onlinePlayers) {
    // Check online player tracking consistency.
    int missing = 0;
    int changed = 0;
    int expectedSize = 0;
    for (int i = 0; i < onlinePlayers.length; i++) {
      final Player player = onlinePlayers[i];
      final String name = player.getName();
      //			if (player.isOnline()){
      expectedSize += 1 + (name.equals(name.toLowerCase()) ? 0 : 1);
      if (!this.onlinePlayers.containsKey(name)) {
        missing++;
        // TODO: Add the player [problem: messy NPC plugins?]?
      }
      if (player != this.onlinePlayers.get(name)) {
        changed++;
        // Update the reference.
        addOnlinePlayer(player);
        //				}
      }
    }

    // TODO: Consider checking lastLogout for too long gone players.

    final int storedSize = this.onlinePlayers.size();
    if (missing != 0 || changed != 0 || expectedSize != storedSize) {
      final List<String> details = new LinkedList<String>();
      if (missing != 0) {
        details.add("missing online players (" + missing + ")");
      }
      if (expectedSize != storedSize) {
        // TODO: Consider checking for not online players and remove them.
        details.add(
            "wrong number of online players (" + storedSize + " instead of " + expectedSize + ")");
      }
      if (changed != 0) {
        details.add("changed player instances (" + changed + ")");
      }

      LogUtil.logWarning(
          "[NoCheatPlus] DataMan inconsistencies: " + StringUtil.join(details, " | "));
    }
  }
Пример #6
0
 /**
  * Output information specific to player-move events.
  *
  * @param player
  * @param from
  * @param to
  * @param mcAccess
  */
 public static void outputMoveDebug(
     final Player player,
     final PlayerLocation from,
     final PlayerLocation to,
     final double maxYOnGround,
     final MCAccess mcAccess) {
   final StringBuilder builder = new StringBuilder(250);
   final Location loc = player.getLocation();
   // TODO: Differentiate debug levels (needs setting up some policy + document in
   // BuildParamteres)?
   if (BuildParameters.debugLevel > 0) {
     builder.append("\n-------------- MOVE --------------\n");
     builder.append(player.getName() + " " + from.getWorld().getName() + ":\n");
     addMove(from, to, loc, builder);
   } else {
     builder.append(player.getName() + " " + from.getWorld().getName() + " ");
     addFormattedMove(from, to, loc, builder);
   }
   final double jump = mcAccess.getJumpAmplifier(player);
   final double speed = mcAccess.getFasterMovementAmplifier(player);
   final double strider = BridgeEnchant.getDepthStriderLevel(player);
   if (BuildParameters.debugLevel > 0) {
     try {
       // TODO: Check backwards compatibility (1.4.2). Remove try-catch
       builder.append(
           "\n(walkspeed=" + player.getWalkSpeed() + " flyspeed=" + player.getFlySpeed() + ")");
     } catch (Throwable t) {
     }
     if (player.isSprinting()) {
       builder.append("(sprinting)");
     }
     if (player.isSneaking()) {
       builder.append("(sneaking)");
     }
     if (player.isBlocking()) {
       builder.append("(blocking)");
     }
     final Vector v = player.getVelocity();
     if (v.lengthSquared() > 0.0) {
       builder.append("(svel=" + v.getX() + "," + v.getY() + "," + v.getZ() + ")");
     }
   }
   if (speed != Double.NEGATIVE_INFINITY) {
     builder.append("(e_speed=" + (speed + 1) + ")");
   }
   final double slow = PotionUtil.getPotionEffectAmplifier(player, PotionEffectType.SLOW);
   if (slow != Double.NEGATIVE_INFINITY) {
     builder.append("(e_slow=" + (slow + 1) + ")");
   }
   if (jump != Double.NEGATIVE_INFINITY) {
     builder.append("(e_jump=" + (jump + 1) + ")");
   }
   if (strider != 0) {
     builder.append("(e_depth_strider=" + strider + ")");
   }
   // Print basic info first in order
   NCPAPIProvider.getNoCheatPlusAPI()
       .getLogManager()
       .debug(Streams.TRACE_FILE, builder.toString());
   // Extended info.
   if (BuildParameters.debugLevel > 0) {
     builder.setLength(0);
     // Note: the block flags are for normal on-ground checking, not with yOnGrond set to 0.5.
     from.collectBlockFlags(maxYOnGround);
     if (from.getBlockFlags() != 0)
       builder.append(
           "\nfrom flags: "
               + StringUtil.join(BlockProperties.getFlagNames(from.getBlockFlags()), "+"));
     if (from.getTypeId() != 0) addBlockInfo(builder, from, "\nfrom");
     if (from.getTypeIdBelow() != 0) addBlockBelowInfo(builder, from, "\nfrom");
     if (!from.isOnGround() && from.isOnGround(0.5)) builder.append(" (ground within 0.5)");
     to.collectBlockFlags(maxYOnGround);
     if (to.getBlockFlags() != 0)
       builder.append(
           "\nto flags: "
               + StringUtil.join(BlockProperties.getFlagNames(to.getBlockFlags()), "+"));
     if (to.getTypeId() != 0) addBlockInfo(builder, to, "\nto");
     if (to.getTypeIdBelow() != 0) addBlockBelowInfo(builder, to, "\nto");
     if (!to.isOnGround() && to.isOnGround(0.5)) builder.append(" (ground within 0.5)");
     NCPAPIProvider.getNoCheatPlusAPI()
         .getLogManager()
         .debug(Streams.TRACE_FILE, builder.toString());
   }
 }
Пример #7
0
  /**
   * @param player
   * @param from
   * @param to
   * @param data
   * @param cc
   * @param time Milliseconds.
   * @return
   */
  public Location check(
      final Player player,
      final PlayerLocation from,
      final PlayerLocation to,
      final MovingData data,
      final MovingConfig cc,
      final long time,
      final boolean useBlockChangeTracker) {

    // Reset tags, just in case.
    tags.clear();

    // Some edge data for this move.
    final GameMode gameMode = player.getGameMode();
    final ModelFlying model = cc.getModelFlying(player, from);
    final PlayerMoveData thisMove = data.playerMoves.getCurrentMove();
    //        if (!data.thisMove.from.extraPropertiesValid) {
    //            // TODO: Confine by model config flag or just always do [if the latter: do it in
    // the listener]?
    //            data.thisMove.setExtraProperties(from, to);
    //        }
    thisMove.modelFlying = model;
    final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove();

    // Calculate some distances.
    final double yDistance = thisMove.yDistance;
    final double hDistance = thisMove.hDistance;

    final boolean flying = gameMode == BridgeMisc.GAME_MODE_SPECTATOR || player.isFlying();
    final boolean sprinting = time <= data.timeSprinting + cc.sprintingGrace;

    // Lost ground, if set so.
    if (model.ground) {
      MovingUtil.prepareFullCheck(from, to, thisMove, Math.max(cc.yOnGround, cc.noFallyOnGround));
      if (!thisMove.from.onGroundOrResetCond) {
        if (from.isSamePos(to)) {
          if (lastMove.toIsValid
              && lastMove.hDistance > 0.0
              && lastMove.yDistance < -0.3 // Copy and paste from sf.
              && LostGround.lostGroundStill(
                  player, from, to, hDistance, yDistance, sprinting, lastMove, data, cc, tags)) {
            // Nothing to do.
          }
        } else if (LostGround.lostGround(
            player,
            from,
            to,
            hDistance,
            yDistance,
            sprinting,
            lastMove,
            data,
            cc,
            useBlockChangeTracker ? blockChangeTracker : null,
            tags)) {
          // Nothing to do.
        }
      }
    }

    // Horizontal distance check.
    double[] resH =
        hDist(
            player, from, to, hDistance, yDistance, sprinting, flying, lastMove, time, model, data,
            cc);
    double limitH = resH[0];
    double resultH = resH[1];

    // Check velocity.
    if (resultH > 0) {
      double hFreedom = data.getHorizontalFreedom();
      if (hFreedom < resultH) {
        // Use queued velocity if possible.
        hFreedom += data.useHorizontalVelocity(resultH - hFreedom);
      }
      if (hFreedom > 0.0) {
        resultH = Math.max(0.0, resultH - hFreedom);
        if (resultH <= 0.0) {
          limitH = hDistance;
        }
        tags.add("hvel");
      }
    } else {
      data.clearActiveHorVel(); // TODO: test/check !
    }

    resultH *= 100.0; // Normalize to % of a block.
    if (resultH > 0.0) {
      tags.add("hdist");
    }

    // Vertical move.
    double limitV = 0.0; // Limit.
    double resultV = 0.0; // Violation (normalized to 100 * 1 block, applies if > 0.0).

    // Distinguish checking method by y-direction of the move.
    if (yDistance > 0.0) {
      // Ascend.
      double[] res = vDistAscend(from, to, yDistance, flying, thisMove, lastMove, model, data, cc);
      resultV = Math.max(resultV, res[1]);
      limitV = res[0];
    } else if (yDistance < 0.0) {
      // Descend.
      double[] res = vDistDescend(from, to, yDistance, flying, lastMove, model, data, cc);
      resultV = Math.max(resultV, res[1]);
      limitV = res[0];
    } else {
      // Keep altitude.
      double[] res = vDistZero(from, to, yDistance, flying, lastMove, model, data, cc);
      resultV = Math.max(resultV, res[1]);
      limitV = res[0];
    }

    // Velocity.
    if (resultV > 0.0 && data.getOrUseVerticalVelocity(yDistance) != null) {
      resultV = 0.0;
      tags.add("vvel");
    }

    // Add tag for maximum height check (silent set back).
    final double maximumHeight = model.maxHeight + player.getWorld().getMaxHeight();
    if (to.getY() > maximumHeight) {
      // TODO: Allow use velocity there (would need a flag to signal the actual check below)?
      tags.add("maxheight");
    }

    resultV *= 100.0; // Normalize to % of a block.
    if (resultV > 0.0) {
      tags.add("vdist");
    }

    final double result = Math.max(0.0, resultH) + Math.max(0.0, resultV);

    if (data.debug) {
      outpuDebugMove(player, hDistance, limitH, yDistance, limitV, model, tags, data);
    }

    // Violation handling.
    Location setBack = null; // Might get altered below.
    if (result > 0.0) {
      // Increment violation level.
      data.creativeFlyVL += result;

      // Execute whatever actions are associated with this check and the violation level and find
      // out if we
      // should cancel the event.
      final ViolationData vd =
          new ViolationData(this, player, data.creativeFlyVL, result, cc.creativeFlyActions);
      if (vd.needsParameters()) {
        vd.setParameter(
            ParameterName.LOCATION_FROM,
            String.format(Locale.US, "%.2f, %.2f, %.2f", from.getX(), from.getY(), from.getZ()));
        vd.setParameter(
            ParameterName.LOCATION_TO,
            String.format(Locale.US, "%.2f, %.2f, %.2f", to.getX(), to.getY(), to.getZ()));
        vd.setParameter(
            ParameterName.DISTANCE, String.format(Locale.US, "%.2f", TrigUtil.distance(from, to)));
        if (!tags.isEmpty()) {
          vd.setParameter(ParameterName.TAGS, StringUtil.join(tags, "+"));
        }
      }
      if (executeActions(vd).willCancel()) {
        // Compose a new location based on coordinates of "newTo" and viewing direction of
        // "event.getTo()"
        // to allow the player to look somewhere else despite getting pulled back by NoCheatPlus.
        setBack = data.getSetBack(to);
      }
    } else {
      // Maximum height check (silent set back).
      if (to.getY() > maximumHeight) {
        setBack = data.getSetBack(to);
      }
      if (setBack == null) {
        // Slowly reduce the violation level with each event.
        data.creativeFlyVL *= 0.97;
      }
    }

    // Return setBack, if set.
    if (setBack != null) {
      // Check for max height of the set-back.
      if (setBack.getY() > maximumHeight) {
        // Correct the y position.
        setBack.setY(getCorrectedHeight(maximumHeight, setBack.getWorld()));
        if (data.debug) {
          debug(player, "Maximum height exceeded by set-back, correct to: " + setBack.getY());
        }
      }
      data.sfJumpPhase = 0;
      return setBack;
    } else {
      // Adjust the set-back and other last distances.
      data.setSetBack(to);
      // Adjust jump phase.
      if (!thisMove.from.onGroundOrResetCond && !thisMove.to.onGroundOrResetCond) {
        data.sfJumpPhase++;
      } else if (thisMove.touchedGround && !thisMove.to.onGroundOrResetCond) {
        data.sfJumpPhase = 1;
      } else {
        data.sfJumpPhase = 0;
      }
      return null;
    }
  }
  /**
   * This will be called from within the plugin in onEnable, after registration of all core
   * listeners and components. After each components addition processQueuedSubComponentHolders()
   * will be called to allow registries for further optional components.
   *
   * @param plugin
   * @return
   */
  public Collection<Object> getAvailableComponentsOnEnable(NoCheatPlus plugin) {
    final List<Object> available = new LinkedList<Object>();

    // Add components (try-catch).
    // TODO: catch ClassNotFound, incompatibleXY rather !?

    // Check: inventory.fastconsume.
    try {
      // TODO: Static test methods !?
      FastConsume.testAvailability();
      available.add(new FastConsume());
      NCPAPIProvider.getNoCheatPlusAPI()
          .addFeatureTags("checks", Arrays.asList(FastConsume.class.getSimpleName()));
    } catch (Throwable t) {
      StaticLog.logInfo("Inventory checks: FastConsume is not available.");
    }

    // Check: inventory.gutenberg.
    try {
      Gutenberg.testAvailability();
      available.add(new Gutenberg());
      NCPAPIProvider.getNoCheatPlusAPI()
          .addFeatureTags("checks", Arrays.asList(Gutenberg.class.getSimpleName()));
    } catch (Throwable t) {
      StaticLog.logInfo("Inventory checks: Gutenberg is not available.");
    }

    // Hot fix: falling block end portal.
    try {
      HotFixFallingBlockPortalEnter.testAvailability();
      available.add(new HotFixFallingBlockPortalEnter());
      NCPAPIProvider.getNoCheatPlusAPI()
          .addFeatureTags(
              "checks", Arrays.asList(HotFixFallingBlockPortalEnter.class.getSimpleName()));
    } catch (RuntimeException e) {
    }

    // ProtocolLib dependencies.
    if (protocolLibPresent.isAvailable()) {
      // Check conditions.
      boolean protocolLibAvailable = false;
      for (final IActivation condition : protocolLibActivation) {
        if (condition.isAvailable()) {
          protocolLibAvailable = true;
          break;
        }
      }
      // Attempt to react.
      if (protocolLibAvailable) {
        try {
          available.add(new ProtocolLibComponent(plugin));
        } catch (Throwable t) {
          StaticLog.logWarning("Failed to set up packet level access with ProtocolLib.");
          if (ConfigManager.getConfigFile().getBoolean(ConfPaths.LOGGING_EXTENDED_STATUS)) {
            NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.INIT, t);
          }
        }
      } else {
        List<String> parts = new LinkedList<String>();
        parts.add("Packet level access via ProtocolLib not available, supported configurations: ");
        for (IDescriptiveActivation cond : protocolLibActivation) {
          parts.add(cond.getNeutralDescription());
        }
        StaticLog.logWarning(StringUtil.join(parts, " | "));
      }
    } else {
      StaticLog.logInfo("Packet level access: ProtocolLib is not available.");
    }

    return available;
  }