我正在创建自定义反作弊。但是,我已经到了让我很困惑的地步。我正在尝试检测玩家是否可以在所述位置放置方 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/