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

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

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, но это так же не привело к успеху
 
Последнее редактирование:
Поломав голову я понял, что схематика вставляется правильно и чтобы она была вставлена в сторону, куда смотрит игрок, её придется крутить. Поискав в интернете, я нашел способ как применить 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();
            }
        }
    }

Помогите разобраться
 
Разобрался. Моя ошибка была в том, что я устанавливал радиусы в радианах.
Вот готовый метод, который вставляет схематик с поворотом на 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();
            }
        }
    }
 
Код:
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();
    }
}
Открываю тему снова, т.к. уже зашел в тупик.
В общем, как выяснилось, мое решение выше работает только если схематик был скопирован, пока игрок смотрел в определенную сторону, а все остальные стороны этот код не учитывал.

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

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

Назад
Верх