Войти или зарегистрироваться
  • Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.

Стартап Обработка столкновения лодки с блоком

Energy warrior

Активный участник
Пользователь
Баллы
76
Предисловие:
Хз понадобится или нет, но факт остаётся фактом, VehicleBlockCollisionEvent не работает для лодок.
Поэтому мне пришлось пилить свой говнокод, чтобы это заработало, сразу говорю, я не знаю как пользоваться Collision боксами, поэтому сделал, как умею, выкладываю потому что хочется поделиться. Эта тема пригодится новичкам, которым прям позарез нужен VehiclBlockCollisionEvent для лодок. Если ты прям оч крутой программист и работаешь в Google, вместо обсираний можешь подсказать как сделать код лучше.

Начало работы:
для работы сеего чуда понадобится ProtocolLib

Код:
@Override
    public void onPacketReceiving(PacketEvent event) {
        if(event.getPacketType()!=PacketType.Play.Client.BOAT_MOVE) return;
        Bukkit.getScheduler().runTask(this.plugin,()->{ //Запускаем поиск лодок в радиусе 1x1x1 в основном потоке
            ArrayList<Boat> boats = event.getPlayer().getNearbyEntities(1,1,1).stream().filter(entity -> entity instanceof Boat).map(entity -> (Boat)entity).filter(boat -> boat.getPassengers().contains(event.getPlayer())).collect(Collectors.toCollection(ArrayList::new));
            if(boats.size()==1){
                Boat boat = boats.get(0); //Получаем найденую лодку
                Block loc = boat.getLocation().getBlock();
                Block block = checkCollision(loc,boat.getLocation(),boat); //Проверка на столкновение
                if(block == null) return;
                VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(boat,block);
                Bukkit.getPluginManager().callEvent(event);
    }

Код:
private Block checkCollision(Location bloc, Boat boat){
    System.out.println(bloc.getYaw());
    Block b = VectorUtils.getDirBlock(bloc);
    if(b == null) return null;
    if(!b.getType().isSolid(b.getType())) return null;
    if(isPlayerOnHalf(boat)){
        if(bloc.getBlockY()==NumberConversions.ceil(bloc.getY())) return b;
        return null;
    }
    return b;
}
}

Код:
private static List<Material> halfBlockTypes = Arrays.stream(Material.values()).filter(m->m.name().endsWith("_SLAB")||m.name().endsWith("_STAIRS")).collect(Collectors.toCollection(ArrayList::new));

    public boolean isPlayerOnHalf(Player player) {
        return (!player.isFlying() && (player.getLocation().getY() + "").endsWith(".5")) || halfBlockTypes.contains(player.getLocation().getBlock().getType());
    }
 
Последнее редактирование:
А к чему тут протоколлиб? VehicleMoveEvent не хватило? Да и не слишком большой овехед то, каждый тик лодки искать.
 
А к чему тут протоколлиб? VehicleMoveEvent не хватило? Да и не слишком большой овехед то, каждый тик лодки искать.
С протоколом не тупит! Кста, есть ли нормальные способы проверить столкновения ентити с блоком. Через Баундинг бокс пробовал, не катит!
 
С протоколом не тупит! Кста, есть ли нормальные способы проверить столкновения ентити с блоком. Через Баундинг бокс пробовал, не катит!
Проверка есть, но она выключена на лодках, да и в той проверке вада не учитывается как проходимый блок. Тебе лучше озвучить на spigotms свою идею. Может добавят бросание ивента с лодкой.
 
Проверка есть, но она выключена на лодках, да и в той проверке вада не учитывается как проходимый блок. Тебе лучше озвучить на spigotms свою идею. Может добавят бросание ивента с лодкой.
Уже писал как ошибку, вроде сказали, что сделают! Но чёт не делают! А пока я хз как это сделать, есть ли кусок кода где это обрабатывается?
 
Я всё конечно понимаю, 5 лет там, но скинь класс VectorUtils) Не понятно откуда это брать
 
Я всё конечно понимаю, 5 лет там, но скинь класс VectorUtils) Не понятно откуда это брать
Вообще не смутило?
upload_2024-6-3_13-33-44.png
Можно по смыслу догадаться, что происходит в этом VectorUtils.

Но, скорее всего, и с VehicleMoveEvent всё прекрасно работает
 
Вообще не смутило?
Посмотреть вложение 67262
Можно по смыслу догадаться, что происходит в этом VectorUtils.

Но, скорее всего, и с VehicleMoveEvent всё прекрасно работает
Не, не работает с VehicleMoveEvent. Я с ним и пробовал, но функционал воссоздать не удалось. Я попытался сделать с рэйтрейсом блоков, но наверное я так и не понял функционал его метода. + Интересное замечание, если игрок не в лодке, дефолтный VehicleBlockCollisionEevent вызывается.

Вот код который я сделал, и ноль результата.
Код:
@EventHandler public void onVehicleMove(VehicleMoveEvent event) {
        if(event.getVehicle() instanceof Boat boat) {
            Vector vector = event.getTo().toVector().subtract(event.getFrom().toVector()).normalize();

            Block block = checkCollision(boat.getLocation(), boat, vector);
            if(block != null) {
                Bukkit.getPluginManager().callEvent(
                        new VehicleBlockCollisionEvent(boat, block, event.getVehicle().getVelocity())
                );
            }
        }
    }

@SuppressWarnings("deprecation")
    private Block checkCollision(Location bloc, Boat boat, Vector vector){
        RayTraceResult result = bloc.getBlock().rayTrace(bloc, vector, 3, FluidCollisionMode.NEVER);
        if(result == null) return null;

        Block b = result.getHitBlock();
        if(b == null) return null;
        if(!b.getType().isSolid()) return null;

        Entity entity = boat.getPassenger();
        if(entity instanceof Player player && isPlayerOnHalf(player)) {
            if(bloc.getBlockY() == NumberConversions.ceil(bloc.getY())) return b;
            return null;
        }
        return b;
    }

    private static final List<Material> halfBlockTypes = Arrays.stream(Material.values()).filter(m->m.name().endsWith("_SLAB")||m.name().endsWith("_STAIRS")).collect(Collectors.toList());

    public boolean isPlayerOnHalf(Player player) {
        return (!player.isFlying() && (new DecimalFormat("#.#").format(player.getLocation().y())).endsWith("5")) || halfBlockTypes.contains(player.getLocation().getBlock().getType());
    }
 
Я более чем уверен что кому-то поможет, вот работающий код.
Код:
@EventHandler public void onPlayerMove(PlayerMoveEvent event) {
        Player player = event.getPlayer();
        if(player.getVehicle() instanceof Boat boat) {
            double boatWidth = 1.5;
            double halfWidth = boatWidth / 2;

            double boatX = boat.getLocation().getX();
            double boatY = boat.getLocation().getY();
            double boatZ = boat.getLocation().getZ();

            double[][] corners = {
                    {boatX - halfWidth, boatZ - halfWidth},
                    {boatX - halfWidth, boatZ + halfWidth},
                    {boatX + halfWidth, boatZ - halfWidth},
                    {boatX + halfWidth, boatZ + halfWidth}
            };

            for (double[] corner : corners) {
                Block block = boat.getWorld().getBlockAt((int) Math.floor(corner[0]), (int) Math.floor(boatY), (int) Math.floor(corner[1]));
                if (!block.isPassable()) {
                    VehicleBlockCollisionEvent collisionEvent = new VehicleBlockCollisionEvent(boat, block);
                    Bukkit.getServer().getPluginManager().callEvent(collisionEvent);
                    return;
                }
            }
        }
    }
 

Поделиться этой страницей

Назад
Верх