1

我正在创建一个自定义的反作弊。然而,我已经到了一个让我很困惑的地步。我试图检测玩家是否可以在所述位置放置块,但随着我试图使其对非作弊玩家更可靠,它变得越来越复杂。目前,每当玩家与AxisAllignedBB块(我相信,问题在于玩家的方向每秒只更新 20 次,而他们的帧速率可能会高得多。这通常会导致(在我的测试中大约每 15 个左右的块位置一次)被错误地取消。PlayerInteractEventBlockBlockFacePlayerInteractEvent

用于查找 Block 的 Raycast 算法

 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;
}

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

想法:靠近街区

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

想法:A* 寻路算法

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

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

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

4

3 回答 3

2

我建议创建一个方法来通知 Player 和 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;
}
于 2017-07-31T16:18:51.590 回答
0

我不确定这是否有效。但是我考虑过使用 BlockPlaceEvent 并检查如果玩家正在查看该块,则何时放置块。

@EventHandler
public void blockplace(BlockPlaceEvent event){
    Player p = event.getPlayer();
    int x = p.getLocation().getDirection().getBlockX();
    int y = p.getLocation().getDirection().getBlockY();
    int z = p.getLocation().getDirection().getBlockZ();

    Location lookingLoc = new Location(p.getWorld(),x,y,z);

    if (!event.getBlockPlaced().getLocation().equals(lookingLoc)){
        //flag player...
    }

}

随意留下建议。

于 2017-07-31T09:17:45.413 回答
0

我读了几次这个问题以确定。如果我理解这个前提,您希望验证何时发生玩家正在查看正在与之交互的块的交互。我认为您想阻止可能伪造此类事件的“自动构建”模块等。

使用Player.getTargetBlock()验证应该很简单。如果返回的方块与您getTargetBlock()报告的方块相同,PlayerInteractEvent您应该有理由相信玩家正在查看方块。

于 2017-08-05T23:47:20.293 回答