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

Помогите Вставить схематик перед лицом игрока

Тема в разделе "Разработка плагинов для новичков", создана пользователем Yourbreath, 10 янв 2023.

  1. Автор темы
    Yourbreath

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

    Баллы:
    61
    Всем привет. Мне нужно вставлять схематик перед лицом игрока. Но так как схематик сохраняется относительно позиции игрока, мне нужно как-то избавиться от этого, чтобы вставлять схематик без этой относительности всегда туда, куда нужно.

    К слову, схематик я сохранил, стоя передом к лицевой части постройки, посередине.
    Код:
    @EventHandler
        public void onInteract(BlockPlaceEvent event) throws IOException {
            if (event.getBlockPlaced().getType() == Material.DIAMOND_BLOCK) {
                Player player = event.getPlayer();
                event.getBlockPlaced().setType(Material.AIR);
                File schematicFile = new File("/home/house.schem");
                Location location = calculateLocation(player);
                paste(location, schematicFile);     
            }
        }
    
        private Location calculateLocation(Player player) {
            org.bukkit.World world = player.getWorld();
            Location playerLocation = player.getLocation();
            double x = playerLocation.getX();
            double y = playerLocation.getY();
            double z = playerLocation.getZ();
            float yaw = playerLocation.getYaw();
            float pitch = playerLocation.getPitch();
    
            // рассчитываем новую координату Х, находясь на той же плоскости
            x = x + (4 * Math.cos(Math.toRadians(-yaw - 90)) * Math.cos(Math.toRadians(-pitch)));
            // рассчитываем новую координату Y
            //y = y + (4 * Math.sin(Math.toRadians(-pitch)));
            // рассчитываем новую координату Z, находясь на той же плоскости
            z = z + (4 * Math.sin(Math.toRadians(-yaw - 90)) * Math.cos(Math.toRadians(-pitch)));
    
            // изменяем направление игрока, чтобы он смотрел назад
            yaw = yaw + 180;
    
            return new Location(world, x, y, z, yaw, pitch);
        }
    
        public void paste(Location location, File file) {
    
            ClipboardFormat clipboardFormat = ClipboardFormats.findByFile(file);
            Clipboard clipboard;
    
            BlockVector3 blockVector3 = BlockVector3.at(location.getBlockX(), location.getBlockY(), location.getBlockZ());
    
            if (clipboardFormat != null) {
                try (ClipboardReader clipboardReader = clipboardFormat.getReader(new FileInputStream(file))) {
    
                    if (location.getWorld() == null)
                        throw new NullPointerException("Failed to paste schematic due to world being null");
    
                    World world = BukkitAdapter.adapt(location.getWorld());
    
                    EditSession editSession = WorldEdit.getInstance().newEditSessionBuilder().world(world).build();
    
                    clipboard = clipboardReader.read();
    
                    BlockVector3 originVector = clipboard.getOrigin();
    
                    int dx = location.getBlockX() - originVector.getBlockX();
                    int dy = location.getBlockY() - originVector.getBlockY();
                    int dz = location.getBlockZ() - originVector.getBlockZ();
    
                    clipboard.setOrigin(BlockVector3.at(dx, dy, dz));
    
                    Operation operation = new ClipboardHolder(clipboard)
                            .createPaste(editSession)
                            .to(blockVector3)
                            .ignoreAirBlocks(true)
                            .build();
    
                    try {
                        Operations.complete(operation);
                        editSession.close();
                    } catch (WorldEditException e) {
                        e.printStackTrace();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    Если я убираю строчку "clipboard.setOrigin(BlockVector3.at(dx, dy, dz));", тогда схематик спавнится, но опять же так, как я его сохранял, а не перед лицом.
    А если я оставляю эту строчку, схематик вообще рядом не появляется (скорее всего, где-то вне поле моего зрения).
    Также пробовал убирать эту строчку и создавать BlockVector3.at(dx, dy, dz) в аргументе функции to() билдера PasteBuilder, но это так же не привело к успеху
     
    Последнее редактирование: 10 янв 2023
  2. Автор темы
    Yourbreath

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

    Баллы:
    61
    Поломав голову я понял, что схематика вставляется правильно и чтобы она была вставлена в сторону, куда смотрит игрок, её придется крутить. Поискав в интернете, я нашел способ как применить rotate к ClipBoard, но схематика всё равно вставляется обычная, а не повернутая, хотя у людей, чей код я взял, этот способ работал.


    Код:
    AffineTransform affineTransform = new AffineTransform();
    affineTransform = affineTransform.rotateX(Math.toRadians(90));
    affineTransform = affineTransform.rotateY(Math.toRadians(90));
    affineTransform = affineTransform.rotateZ(Math.toRadians(90));
    
    ClipboardHolder clipboardHolder = new ClipboardHolder(clipboard);
    clipboardHolder.setTransform(clipboardHolder.getTransform().combine(affineTransform));
    Код:
    public void paste(Location location, File file) {
    
            ClipboardFormat clipboardFormat = ClipboardFormats.findByFile(file);
            Clipboard clipboard;
    
            BlockVector3 blockVector3 = BlockVector3.at(location.getBlockX(), location.getBlockY(), location.getBlockZ());
    
            if (clipboardFormat != null) {
                try (ClipboardReader clipboardReader = clipboardFormat.getReader(new FileInputStream(file))) {
    
                    if (location.getWorld() == null)
                        throw new NullPointerException("Failed to paste schematic due to world being null");
    
                    World world = BukkitAdapter.adapt(location.getWorld());
    
                    EditSession editSession = WorldEdit.getInstance().newEditSessionBuilder().world(world).build();
    
                    clipboard = clipboardReader.read();
    
                    AffineTransform affineTransform = new AffineTransform();
                    affineTransform = affineTransform.rotateX(Math.toRadians(90));
                    affineTransform = affineTransform.rotateY(Math.toRadians(90));
                    affineTransform = affineTransform.rotateZ(Math.toRadians(90));
    
                    ClipboardHolder clipboardHolder = new ClipboardHolder(clipboard);
                    clipboardHolder.setTransform(clipboardHolder.getTransform().combine(affineTransform));
    
                    Operation operation = clipboardHolder
                            .createPaste(editSession)
                            .copyBiomes(false)
                            .copyEntities(true)
                            .ignoreAirBlocks(false)
                            .to(blockVector3)
                            .build();
                    try {
                        Operations.complete(operation);
                        editSession.close();
                    } catch (WorldEditException e) {
                        e.printStackTrace();
                    }
    
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    Помогите разобраться
     
  3. Автор темы
    Yourbreath

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

    Баллы:
    61
    Разобрался. Моя ошибка была в том, что я устанавливал радиусы в радианах.
    Вот готовый метод, который вставляет схематик с поворотом на 90 градусов.
    Код:
    public void paste(Location location, File file) {
    
            ClipboardFormat clipboardFormat = ClipboardFormats.findByFile(file);
            Clipboard clipboard;
    
            BlockVector3 blockVector3 = BlockVector3.at(location.getBlockX(), location.getBlockY(), location.getBlockZ());
    
            if (clipboardFormat != null) {
                try (ClipboardReader clipboardReader = clipboardFormat.getReader(new FileInputStream(file))) {
    
                    if (location.getWorld() == null)
                        throw new NullPointerException("Failed to paste schematic due to world being null");
    
                    World world = BukkitAdapter.adapt(location.getWorld());
    
                    EditSession editSession = WorldEdit.getInstance().newEditSessionBuilder().world(world).build();
    
                    clipboard = clipboardReader.read();
    
                    AffineTransform affineTransform = new AffineTransform();
                    affineTransform = affineTransform.rotateX(90);
                    affineTransform = affineTransform.rotateY(-90);
                    affineTransform = affineTransform.rotateZ(90);
    
                    ClipboardHolder clipboardHolder = new ClipboardHolder(clipboard);
                    clipboardHolder.setTransform(clipboardHolder.getTransform().combine(affineTransform));
    
                    Operation operation = clipboardHolder
                            .createPaste(editSession)
                            .copyBiomes(false)
                            .copyEntities(true)
                            .ignoreAirBlocks(true)
                            .to(blockVector3)
                            .build();
                    try {
                        Operations.complete(operation);
                        editSession.close();
                    } catch (WorldEditException e) {
                        e.printStackTrace();
                    }
    
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
     
  4. Автор темы
    Yourbreath

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

    Баллы:
    61
    Код:
    private Location calculateLocation(Player player) {
        org.bukkit.World world = player.getWorld();
        Location location = player.getLocation();
        double x = location.getX();
        double y = location.getY();
        double z = location.getZ();
        float yaw = location.getYaw();
        float pitch = location.getPitch();
        String face = player.getFacing().name();
    
        double frst = 4 * Math.cos(Math.toRadians(-yaw - 90)) * Math.cos(Math.toRadians(-pitch));
        double scnd = 4 * Math.sin(Math.toRadians(-yaw - 90)) * Math.cos(Math.toRadians(-pitch));
        if (face.contains("SOUTH") || face.contains("NORTH")) {
            x = x + frst;
            z = z - scnd;
        } else if (face.contains("EAST") || face.contains("WEST")) {
            x = x + frst;
            z = z + scnd;
        }
    
        // изменяем направление игрока, чтобы он смотрел назад
        yaw = yaw + 180;
    
        return new Location(world, x, y, z, yaw, pitch);
    }
    
    public void transform(Player player, File file) {
        
        Location location = calculateLocation(player);
        ClipboardFormat clipboardFormat = ClipboardFormats.findByFile(file);
        Clipboard clipboard;
    
        BlockVector3 blockVector3 = BlockVector3.at(location.getBlockX(), location.getBlockY(), location.getBlockZ());
    
        if (clipboardFormat != null) {
            try (ClipboardReader clipboardReader = clipboardFormat.getReader(new FileInputStream(file))) {
    
                if (location.getWorld() == null)
                    throw new NullPointerException("Failed to paste schematic due to world being null");
    
                World world = BukkitAdapter.adapt(location.getWorld());
    
                EditSession editSession = WorldEdit.getInstance().newEditSessionBuilder().world(world).build();
    
                clipboard = clipboardReader.read();
    
                AffineTransform affineTransform = new AffineTransform();
    
                double angle = Math.round(-location.getYaw() / 90.0D) * 90.0D;
    
                while (angle < 0) {
                    angle += 360;
                }
                while (angle > 360) {
                    angle -= 360;
                }
    
                affineTransform = affineTransform.rotateY(angle);
    
                ClipboardHolder clipboardHolder = new ClipboardHolder(clipboard);
                clipboardHolder.setTransform(affineTransform);
    
                pasteSchem(clipboardHolder, editSession, blockVector3);
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    private void pasteSchem(ClipboardHolder clipboardHolder, EditSession editSession, BlockVector3 blockVector3) {
        Operation operation = clipboardHolder
                .createPaste(editSession)
                .ignoreAirBlocks(true)
                .to(blockVector3)
                .build();
        try {
            Operations.complete(operation);
            editSession.close();
        } catch (WorldEditException e) {
            e.printStackTrace();
        }
    }
    Открываю тему снова, т.к. уже зашел в тупик.
    В общем, как выяснилось, мое решение выше работает только если схематик был скопирован, пока игрок смотрел в определенную сторону, а все остальные стороны этот код не учитывал.

    Мне нужно сделать так, чтобы схематик спавнился перед лицом игрока таким образом, чтобы лицевая часть схематика (получается, это та, в которую смотрел игрок при копировании схематика) смотрела прямо на игрока.
    У меня есть говнокод, с которым это работает, но я не знаю, как адаптировать его так, чтобы он учитывал разные стороны. Помогите, пожалуйста
     
  5. Автор темы
    Yourbreath

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

    Баллы:
    61
  6. Автор темы
    Yourbreath

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

    Баллы:
    61
    нашел тему https://rubukkit.org/threads/vstavljaem-sxematik.173909/
    там человку посоветовали устанавливать origin для схематики перед вставкой. сделал по совету, но теперь схематика вообще не появляется (скорее всего, она где-то в вне поля зрения). Думаю, что это из-за того, что вставка выполняется относительно origin, но никак не пойму, как это пофиксить
     
  7. Автор темы
    Yourbreath

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

    Баллы:
    61
    помогите
     

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