Проверьте, может ли игрок разместить блок в указанном месте
Я создаю собственный анти-чит. Тем не менее, я дошел до того, что я весьма озадачен. Я пытаюсь определить, может ли игрок разместить блок в указанном месте, но это становится все более запутанным, поскольку я пытаюсь сделать его более надежным для игроков, не обманывающих. В настоящее время я включаю алгоритм Raycast (используяAxisAllignedBB
) всякий раз, когда игрок взаимодействует с блоком (PlayerInteractEvent
) чтобы увидеть, действительно ли игрок смотрит на Block
а также BlockFace
событие говорит, что они были. Проблема, я считаю, заключается в том, что направление игрока обновляется только 20 раз в секунду, где его частота кадров может быть намного выше. Это часто вызывает (примерно один раз каждые 15 или около того блоков места из моего тестирования) PlayerInteractEvent
быть неправильно отмененным.
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 блока (или, возможно, короче, если я смотрю на самое близкое расстояние, чтобы блокировать от луча) блока, найденного из лучевой передачи, но это создает слишком много проблем. Если игрок перемещает курсор от барьера к дальней зоне, ложное срабатывание за обман будет срабатывать. С другой стороны, игроки могли бы строить в полностью закрытом пространстве, если бы у них были блокпосты Север, Восток, Юг, Запад, но не Северо-Запад, Северо-Восток и т. Д.
Идея: Алгоритм поиска пути
Если бы я сделал точки на луче в лучевой трансляции с 0 G-Cost, причем G-Cost увеличивается с удалением от луча, а H-Cost - самое близкое расстояние до блока нацеливания, я чувствую, что это может решить эту дилемму. Я мог бы установить максимальный порог G-Cost до PlayerInteractEvent
отменено Проблема, однако, заключается в том, что объединение A* с различными блоками AxisAllignedBB кажется трудным. Возможно, мне удастся создать сетку, состоящую из 100x100x100 точек на блок, но я не уверен, что это будет эффективно и не будет лучшей практикой.
Идея: посмотреть, может ли игрок увидеть блок
Это было бы очень эффективно, но я не уверен, будет ли это реалистичным. Для этого каждый раз, когда игрок помещает блок, мне нужно было бы определить, какие блоки будут полностью перекрывать другие блоки в радиусе взаимодействия игрока. Взяв все последние неперекрывающиеся блоки, я мог видеть, содержит ли их во взаимодействующем блоке. Если нет, взаимодействие будет отменено. Кажется, что это может повлиять на производительность, и я мог видеть, как могут быть ложные срабатывания для мошенничества.
3 ответа
Я бы предложил создать метод, который информирует, пересекаются ли Player и блок.
Образец кода
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;
}
Я не уверен, что это работает. Но я подумал об использовании 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...
}
}
Не стесняйтесь оставлять рекомендации.
Я прочитал вопрос пару раз, чтобы быть уверенным. Если я понимаю предпосылку, вы хотите проверить, когда происходит взаимодействие, когда игрок смотрит на блок, с которым взаимодействует. Я полагаю, что вы хотите предотвратить "автоматическую сборку" модов или тому подобное, которые могут имитировать такие события.
Проверка должна быть простой, используя Player.getTargetBlock (). Если блок возвращен getTargetBlock()
то же самое, что сообщается PlayerInteractEvent
Вы должны быть достаточно уверены, что игрок смотрит на блок.