1. Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.
    Скрыть объявление
Скрыть объявление
В преддверии глобального обновления, мы проводим исследования, которые помогут нам сделать опыт пользования форумом ещё удобнее. Помогите нам, примите участие!

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

Тема в разделе "Разработка плагинов для новичков", создана пользователем Energy warrior, 30 дек 2019.

  1. Автор темы
    Energy warrior

    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());
        }
     
    Последнее редактирование: 30 дек 2019
  2. alexandrage

    alexandrage Старожил Пользователь

    Баллы:
    173
    А к чему тут протоколлиб? VehicleMoveEvent не хватило? Да и не слишком большой овехед то, каждый тик лодки искать.
     
  3. Автор темы
    Energy warrior

    Energy warrior Активный участник Пользователь

    Баллы:
    76
    С протоколом не тупит! Кста, есть ли нормальные способы проверить столкновения ентити с блоком. Через Баундинг бокс пробовал, не катит!
     
  4. alexandrage

    alexandrage Старожил Пользователь

    Баллы:
    173
    Проверка есть, но она выключена на лодках, да и в той проверке вада не учитывается как проходимый блок. Тебе лучше озвучить на spigotms свою идею. Может добавят бросание ивента с лодкой.
     
  5. Автор темы
    Energy warrior

    Energy warrior Активный участник Пользователь

    Баллы:
    76
    Уже писал как ошибку, вроде сказали, что сделают! Но чёт не делают! А пока я хз как это сделать, есть ли кусок кода где это обрабатывается?
     
  6. just_lofe

    just_lofe Активный участник Пользователь

    Баллы:
    66
    Имя в Minecraft:
    just_l0fe
    Я всё конечно понимаю, 5 лет там, но скинь класс VectorUtils) Не понятно откуда это брать
     
  7. Dymeth

    Dymeth Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Вообще не смутило?
    upload_2024-6-3_13-33-44.png
    Можно по смыслу догадаться, что происходит в этом VectorUtils.

    Но, скорее всего, и с VehicleMoveEvent всё прекрасно работает
     
  8. just_lofe

    just_lofe Активный участник Пользователь

    Баллы:
    66
    Имя в Minecraft:
    just_l0fe
    Не, не работает с 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());
        }
     
  9. just_lofe

    just_lofe Активный участник Пользователь

    Баллы:
    66
    Имя в Minecraft:
    just_l0fe
    Я более чем уверен что кому-то поможет, вот работающий код.
    Код:
    @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;
                    }
                }
            }
        }
     

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