java - 检查玩家是否可以在所述位置放置方 block

标签 java algorithm bukkit a-star anti-cheat

我正在创建自定义反作弊。但是,我已经到了让我很困惑的地步。我正在尝试检测玩家是否可以在所述位置放置方 block ,但它变得越来越复杂,因为我试图让它对非作弊玩家更可靠。目前,每当玩家与方 block (PlayerInteractEvent) 交互时,我都会采用光线转换算法(使用AxisAllignedBB)来查看玩家是否真的在看方 block BlockFace 事件表明它们是。我认为,问题在于玩家的方向每秒仅更新 20 次,而他们的帧速率可能要高得多。这通常会导致(在我的测试中大约每 15 个左右的 block 位置一次)PlayerInteractEvent 被错误地取消。

寻找区 block 的光线转换算法

 public static Block getTargetBlock(Location location, Vector direction, double rangeSquared, int maxTrials, TargetMethod targetMethod) {


    Location loc = location.clone();

    Vector dir = direction.normalize();

    final double directionX = direction.getX();
    final double directionY = direction.getY();
    final double directionZ = direction.getZ();

    Block block = loc.getBlock();

    for (int i = 0; i <= maxTrials; i++) {


        final double locX = loc.getX();
        final double locY = loc.getY();
        final double locZ = loc.getZ();

        double wholeMoreX = wholeMore(locX,directionX);
        double moreX = Math.abs(wholeMoreX /directionX);

        double wholeMoreY = wholeMore(locY,directionY);
        double moreY = Math.abs(wholeMoreY /directionY);

        double wholeMoreZ = wholeMore(locZ,directionZ);
        double moreZ = Math.abs(wholeMoreZ /directionZ);

        if(moreX < moreY && moreX < moreZ){
            if(directionX > 0)
                block = block.getRelative(BlockFace.EAST);
            else {
                block = block.getRelative(BlockFace.WEST);
            }
        }
        else if(moreY < moreX && moreY < moreZ){
            if(directionY > 0){
                block = block.getRelative(BlockFace.UP);
            }
            else{
                block = block.getRelative(BlockFace.DOWN);
            }
        }
        else{
            if(directionZ > 0){
                block = block.getRelative(BlockFace.SOUTH);
            }
            else{
                block = block.getRelative(BlockFace.NORTH);
            }
        }

        final double scalar = Math.min(Math.min(moreX,moreY),moreZ);

        Vector addAmount = dir.clone().multiply(scalar);
        loc.add(addAmount);

        if(loc.distanceSquared(location) > rangeSquared)
            return null;

        AxisAlignedBB boundry = getBoundry(block,targetMethod);
        if(boundry != null)
            if(blockFaceCollide(location,direction,boundry) != null)
                return block;
    }
    return null;
}

但是,我怀疑这是问题所在。根据我的测试,它工作得很好。因此,我认为我必须依靠替代​​方法。这里有一些想法,但我不太确定它们是否令人满意。

想法:近街区

我曾考虑过查看放置的方 block 是否在从光线转换中找到的方 block 的 1 个方 block 半径内(如果我正在查看距射线最近的方 block 距离,则可能更短),但这带来了太多问题。如果玩家将光标从障碍物移到更远的区域,则会触发作弊误报。另一方面,如果玩家有北、东、南、西但西北、东北等方 block 支柱,他们仍然可以在完全封闭的区域中 build 。

思想:A*寻路算法

如果我在光线转换中使光线上的点具有 0 G 成本,G 成本随着与光线的距离而增加,而 H 成本是离目标 block 最近的距离,我觉得这可以解决这个难题.我可以在取消 PlayerInteractEvent 之前设置最大 G-Cost 阈值。然而,问题是将 A* 与各种 AxisAllignedBB block 合并似乎很困难。我也许能够创建一个由每个 block 100x100x100 点组成的网格,但我不确定这是否有效也不是最佳实践。

思路:看玩家能不能看到方 block

这会非常有效,但我不确定它是否现实。为此,每次玩家放置一个方 block 时,我都需要检测哪些方 block 会与玩家交互半径内的其他方 block 完全重叠。获取所有最终的非重叠 block ,我可以查看交互 block 是否包含这些 block 。如果不是,则交互将被取消。这似乎可能会影响性能,而且我可以看到如何也可能存在一些误报作弊。

最佳答案

我建议创建一个方法来通知玩家和方 block 是否相交。

示例代码

public static final double ONE_UNIT = 1.0;
public static final double ZERO_UNIT = 0.0;


public static Location getPlayerBlockIntersection(Player player, Block target) {
    if (player == null || target == null) {
        return null;
    }


    double minX = target.getX();
    double minY = target.getY();
    double minZ = target.getZ();

    double maxX = minX + ONE_UNIT;
    double maxY = minY + ONE_UNIT;
    double maxZ = minZ + ONE_UNIT;


    Location origin = player.getEyeLocation();
    double originX = origin.getX();
    double originY = origin.getY();
    double originZ = origin.getZ();


    Vector dir = origin.getDirection();
    double dirX = dir.getX();
    double dirY = dir.getY();
    double dirZ = dir.getZ();


    double divX = ONE_UNIT / dirX;
    double divY = ONE_UNIT / dirY;
    double divZ = ONE_UNIT / dirZ;

    double t0 = ZERO_UNIT;
    double t1 = Double.MAX_VALUE;

    double imin, imax, iymin, iymax, izmin, izmax;

    if (dirX >= ZERO_UNIT) {
        imin = (minX - originX) * divX;
        imax = (maxX - originX) * divX;
    } else {
        imin = (maxX - originX) * divX;
        imax = (minX - originX) * divX;
    }


    if (dirY >= ZERO_UNIT) {
        iymin = (minY - originY) * divY;
        iymax = (maxY - originY) * divY;
    } else {
        iymin = (maxY - originY) * divY;
        iymax = (minY - originY) * divY;
    }

    if ((imin > iymax) || (iymin > imax)) {
        return null;
    }

    if (iymin > imin) {
        imin = iymin;
    }

    if (iymax < imax) {
        imax = iymax;
    }

    if (dirZ >= ZERO_UNIT) {
        izmin = (minZ - originZ) * divZ;
        izmax = (maxZ - originZ) * divZ;
    } else {
        izmin = (maxZ - originZ) * divZ;
        izmax = (minZ - originZ) * divZ;
    }

    if ((imin > izmax) || (izmin > imax)) {
        return null;
    }

    if (izmin > imin) {
        imin = izmin;
    }
    if (izmax < imax) {
        imax = izmax;
    }

    if ((imin >= t1) || (imax <= t0)) {
        return null;
    }

    // check this baby and see if both objects represent an intersection:
    Location intersection = origin.add(dir.multiply(imin));
    return intersection;
}

关于java - 检查玩家是否可以在所述位置放置方 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45386306/

相关文章:

java - 使用 Stream API 填充 Collection

algorithm - 像key->value_count这样形式化的10个文件的海量数据如何获取Top 10?

java - 如何使用noteblockapi bukkit?

java - MailChimp API java 集成

java - 哪个更快?(来自CTCI书)

objective-c - 将数据流解析为记录的优雅算法

python - n 个数以下素数之和需要解释

Java:通过构造函数初始化和通过静态方法初始化之间的区别?

java - 在 Bukkit/Spigot 中生成世界时删除某些生物群落

java - IBM MQ - NoSuchMethodError - getQmgrSplCapability()