public static boolean SingleLineCheckForProjectile(@NotNull Vector vector, int x, int y, int z, int dest_x, int dest_y, int dest_z) {
long time = System.nanoTime();
boolean r1 = false;
boolean r2 = false;
boolean r3 = false;
boolean r4 = false;
try {
if (IPoint.isEmptyPoint(x, y, World.WORLD_MAP_MIN_X, World.WORLD_MAP_MAX_X, World.WORLD_MAP_MIN_Y, World.WORLD_MAP_MAX_Y)) {
return false;
}
if (IPoint.isEmptyPoint(dest_x, dest_y, World.WORLD_MAP_MIN_X, World.WORLD_MAP_MAX_X, World.WORLD_MAP_MIN_Y, World.WORLD_MAP_MAX_Y)) {
return false;
}
IPoint pos;
IPoint vTo;
boolean direct = dest_z < z;
//Смещение на верх применяется для самой высокой точки.
if (direct) {
pos = new Location(x, y, z);
vTo = new Location(dest_x, dest_y, dest_z);
} else {
pos = new Location(dest_x, dest_y, dest_z);
vTo = new Location(x, y, z);
}
//Вычисление разницы координат
double deltaX = vTo.getX() - pos.getX();
double deltaY = vTo.getY() - pos.getY();
double deltaZ = vTo.getZ() - pos.getZ();
double xyLengthSquared = deltaX * deltaX + deltaY * deltaY;
//Если расстояние между точками слишком мало, возвращаем true
if (deltaZ * deltaZ + xyLengthSquared < 0.5) {
return true;
}
double lengthXY = Math.sqrt(xyLengthSquared);
double v10 = 64.0;
if (lengthXY < 64.0) {
v10 = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);
}
if (DebugConfig.DEBUG_SIGHT) {
Debug.getInstance().newPrimitive("CAN_SEE");
}
pos.setZ(GetVerticalLimit(pos));
vTo.setZ(GetVerticalLimit(vTo));
if (DebugConfig.DEBUG_SIGHT) {
Debug.getInstance().getPrimitive("CAN_SEE").addPoint("", Color.MAGENTA, true, pos);
}
double length2D = Math.sqrt((deltaX * deltaX) + (deltaY * deltaY));
if (length2D > 0.0) {
deltaX = deltaX / length2D;
deltaY = deltaY / length2D;
deltaZ = deltaZ / length2D;
}
Location v = new Location((int) (deltaX * v10) + pos.getX(), (int) (deltaY * v10) + pos.getY(), pos.getZ() + 16);
//Проверка видимости по прямым линиям
//Проверка досягаемости точки v от pos(например, чтобы над персонажем не было потолка)
r1 = SingleLineCheckWithFlyTopDown(vector.change3DWithoutCollision(v, pos, IGeoCell.SIZE), 0);
r2 = SingleLineCheckWithFlyTopDown(vector.change3DWithoutCollision(pos, v, IGeoCell.SIZE), 0);
//Проверка видимости удаленной точки vTo от v(если direct, то это проверка видимости цели, если нет, то это обратная проверка от цели к смотрящему)
r3 = !direct && !GeoDataConfig.REQUIRE_VISIBILITY_BOTH_FOR_SUCCESS || SingleLineCheckWithFlyTopDown(vector.change3DWithoutCollision(v, vTo, IGeoCell.SIZE), 0);
//Проверка видимости удаленной точки v от vTo(если direct, то это обратная проверка видимости, от цели к смотрящему, а если нет, то это проверка видимости цели)
r4 = direct && !GeoDataConfig.REQUIRE_VISIBILITY_BOTH_FOR_SUCCESS || SingleLineCheckWithFlyTopDown(vector.change3DWithoutCollision(vTo, v, IGeoCell.SIZE), 0);
if (DebugConfig.DEBUG_SIGHT) {
Debug.getInstance().getPrimitive("CAN_SEE").addLine("", r1 & r2 ? Color.GREEN : Color.RED, true, v, pos);
Debug.getInstance().getPrimitive("CAN_SEE").addArrow("", r3 & r4 ? Color.GREEN : Color.RED, r3 ? Color.GREEN : Color.RED, r3 ? Color.GREEN : Color.RED, true, vTo, v, direct ? 0 : 8, direct ? 8 : 0);
Debug.getInstance().getPrimitive("CAN_SEE").addArrow("", r3 & r4 ? Color.GREEN : Color.RED, r4 ? Color.GREEN : Color.RED, r4 ? Color.GREEN : Color.RED, true, v, vTo, direct ? 8 : 0, direct ? 0 : 8);
}
return r1 && r2 && r3 && r4;
} catch (Exception e) {
log.warn("Error while CanSee()", e);
} finally {
if (DebugConfig.DEBUG_SIGHT) {
boolean success = r1 && r2 && r3 && r4;
Debug.getInstance().chat("CanSeeTime: " + (r1 ? "T" : "F") + (r2 ? "T" : "F") + (r3 ? "T" : "F") + (r4 ? "T " : "F ") + (System.nanoTime() - time) / 1_000_000. + "ms", success ? ESayPacketType.PARTY : ESayPacketType.TELL);
Debug.getInstance().sendPrimitive("CAN_SEE");
}
}
return false; //Если же нет, то это фейл и цель не видно.
}