Copy Part of 1.12 to 1.13 world

Discussion in 'Spigot Plugin Development' started by Bean900, Aug 4, 2018.

Thread Status:
Not open for further replies.
  1. Hi
    Since there is a new world generator in 1.13, I would like to automatically transfer all grounds from my old world into the new one. I only need a copy function for all typs of blocks. Does anyone have an answer how to copy a block with its metadata in the new spigot version?

    Thanks for your Help :)
     
  2. You'd have to wait for 1.13 to be stable, so you can do with the right plugins.
     
  3. Right now your best choice would be to load the old 1.12 world into an 1.13 server and let mojang convert it.
    This would probably be your best choice even somewhen in future.

    Then use structures to copy / move it.
    You could also make structures on a 1.12 server, copy them into a 1.13 server and paste them there, but this isn't as safe as let the world loader do the thing (i already got a structure mojang can't load on 1.13, but the world successfully loads the same area, problem was a flower pot...).

    It's 1.13 - use structures, say goodbye to schematics and stuff.
     
  4. I have over 1000 plots and would like to develop a plugin myself which copies the houses of these plots into the newly generated world. Of course I wait until the 1.13 is stable. Both worlds (the old one with the houses) and the new one with the newly generated world will run simultaneously on the 1.13 server. Therefore the question how to copy the metadata of blocks with the new spigot.
     
  5. One word: STRUCTURES

    Solves all your problems.
    Also see Thread#331243.
     
  6. thanks that sounds like what I'm looking for. But it is so much that I can read it only in the next few days :)
     
  7. When I execute your method via a command, I always get the following error:

    Code (Java):
    [18:26:04 ERROR]: Couldn't load chunk
    java.lang.IllegalStateException: primary thread
        at com.google.common.base.Preconditions.checkState(Preconditions.java:444) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkRegionLoader.check(ChunkRegionLoader.java:54) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkRegionLoader.a(ChunkRegionLoader.java:96) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkRegionLoader.a(ChunkRegionLoader.java:48) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkRegionLoader.loadChunk(ChunkRegionLoader.java:148) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkRegionLoader.a(ChunkRegionLoader.java:133) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkProviderServer.getChunkAt(ChunkProviderServer.java:95) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkProviderServer.a(ChunkProviderServer.java:142) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.StructureGenerator.a(StructureGenerator.java:207) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.StructureGenerator.generate(StructureGenerator.java:43) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.WorldGenDecoratorEmpty.a(SourceFile:16) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.WorldGenDecoratorEmpty.a(SourceFile:13) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.WorldGenFeatureComposite.a(SourceFile:27) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.BiomeBase.a(SourceFile:504) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkGeneratorAbstract.addDecorations(ChunkGeneratorAbstract.java:98) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at org.bukkit.craftbukkit.v1_13_R2.generator.NormalChunkGenerator.addDecorations(NormalChunkGenerator.java:59) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkTaskDecorate.a(SourceFile:12) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkTask.a(SourceFile:35) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkStatus.a(SourceFile:95) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkTaskScheduler.a(ChunkTaskScheduler.java:78) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkTaskScheduler.a(ChunkTaskScheduler.java:1) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:147) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:602) ~[?:1.8.0_131]
        at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:577) ~[?:1.8.0_131]
        at java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:442) ~[?:1.8.0_131]
        at com.google.common.util.concurrent.MoreExecutors$DirectExecutorService.execute(MoreExecutors.java:260) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at java.util.concurrent.CompletableFuture$UniCompletion.claim(CompletableFuture.java:529) ~[?:1.8.0_131]
        at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:599) ~[?:1.8.0_131]
        at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:577) ~[?:1.8.0_131]
        at java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:617) ~[?:1.8.0_131]
        at java.util.concurrent.CompletableFuture.thenApplyAsync(CompletableFuture.java:1993) ~[?:1.8.0_131]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:147) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at java.util.Map.computeIfAbsent(Map.java:957) ~[?:1.8.0_131]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:137) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:143) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkStatus.a(SourceFile:105) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkStatus.a(SourceFile:22) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:143) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at java.util.Map.computeIfAbsent(Map.java:957) ~[?:1.8.0_131]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:137) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:143) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkStatus.a(SourceFile:105) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkStatus.a(SourceFile:22) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:143) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at java.util.Map.computeIfAbsent(Map.java:957) ~[?:1.8.0_131]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:137) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:143) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkStatus.a(SourceFile:105) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkStatus.a(SourceFile:22) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:143) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at java.util.Map.computeIfAbsent(Map.java:957) ~[?:1.8.0_131]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:137) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.Scheduler$a.a(SourceFile:115) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.Scheduler.a(SourceFile:61) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590) ~[?:1.8.0_131]
        at com.google.common.util.concurrent.MoreExecutors$DirectExecutorService.execute(MoreExecutors.java:260) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at java.util.concurrent.CompletableFuture.asyncSupplyStage(CompletableFuture.java:1604) ~[?:1.8.0_131]
        at java.util.concurrent.CompletableFuture.supplyAsync(CompletableFuture.java:1830) ~[?:1.8.0_131]
        at net.minecraft.server.v1_13_R2.Scheduler.a(SourceFile:62) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.SchedulerBatch.a(SourceFile:39) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.ChunkProviderServer.getChunkAt(ChunkProviderServer.java:112) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.World.getChunkAt(World.java:272) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.World.getChunkAtWorldCoords(World.java:268) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.World.getType(World.java:657) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at net.minecraft.server.v1_13_R2.DefinedStructure.a(SourceFile:92) ~[spigot-1.13.1-R0.1-SNAPSHOT.jar:git-Spigot-2440e18-d0bb0a1]
        at de.thebohne.command.Copy.createSingleStructure(Copy.java:140) ~[?:?]
        at de.thebohne.command.Copy.copyChunk(Copy.java:118) ~[?:?]
        at de.thebohne.command.Copy.copy(Copy.java:90) ~[?:?]
        at de.thebohne.command.Copy.lambda$onCommand$0(Copy.java:50) ~[?:?]
        at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]
    So i lode the chunk:
    Code (Java):
     Object syncObject = new Object();
            Bukkit.getScheduler().runTask(BeanProject.getPlugin(), () -> {
                chunkFrom.load();
                chunkTo.load();
                synchronized (syncObject) {
                    syncObject.notify();
                }
            });

            synchronized (syncObject) {
                try {
                    syncObject.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    maybe someone can help me :D
     
  8. I didn't test on 1.13.1 yet. Does it work for 1.13?

    Is the chunk you're trying to write to already generated?
     
  9. It did not work in version 1.13.1 and 1.13 prev 7.
    The chunk is not generated when the plugin is used productively.
    But in this test it was generated: D
    Maybe I'm doing something wrong.
    So here's the code for the copy function that contains your code sample (it's not fancy at this time: D):
    Code (Java):
    private void copyChunk(Chunk chunkFrom, Chunk chunkTo) {
            Object syncObject = new Object();
            Bukkit.getScheduler().runTask(BeanProject.getPlugin(), () -> {
                chunkFrom.load();
                chunkTo.load();
                synchronized (syncObject) {
                    syncObject.notify();
                }
            });

            synchronized (syncObject) {
                try {
                    syncObject.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            Location start = new Location(chunkFrom.getWorld(), chunkFrom.getX() * 16, 0, chunkFrom.getZ() * 16);
            Location end = new Location(chunkFrom.getWorld(), (chunkFrom.getX() * 16) + 16, 0, (chunkFrom.getZ() * 16) + 16);
            DefinedStructure structure = createSingleStructure(new Location[]{start, end}, "Bean900");
            insertSingleStructure(structure, new Location(chunkTo.getWorld(), chunkTo.getX() * 16, 0, chunkTo.getZ() * 16), EnumBlockRotation.NONE);
        }
     
  10. Your structure has a height of 0 blocks?
     
  11. hah :D typical copy paste error
    now the methods go through without mistakes ...
    However, nothing changes when copying in the world: /
     
  12. Where / what is chunkFrom and chunkTo?
    If they're identical, you won't see a difference.
     
  13. md_5

    Administrator Developer

    You can't use Bukkit in threads !!!
     
  14. For small structures you could probably loop through all the blocks and save the material of the block for all the block locations and then start the server in 1.13 and paste x amount of blocks each tick so it won't lag the server. Just an idea I don't know if it will work or not because of material changes or anything like that.
     
  15. chunkFrom is the chunk from the 1.12 World and chunkTo the chunk in the new generated 1.13 world, where the content of chunkfrom is to be copied.

    Since everything is a thread where can I use it then... :D

    I also had the idea at the beginning.
    But I extrapolated it and it takes much too long :(
     
    #15 Bean900, Aug 28, 2018
    Last edited: Aug 28, 2018
  16. Both worlds are loaded on the server and the 1.12 world has already been converted to 1.13?
    The 1.12 world looks all right at the area you're trying to copy (if you enter it on the 1.13 server)?
    The 1.13 world has just some default terrain at the area you're trying to paste?
    Add some debug output to console (e.g. "Trying to paste from <..posFrom..> to <..posTo..>") before calling #insertSingleStructure.
     
  17. After the start of the server i jump from world to OldWorld. So i gues it is converted.
    And there are no bugs in the 1.12 world.
    The new 1.13 world is just a default terraint.
    Here the code with the Sys:
    Code (Java):
    private void copy(World from, World to) {
            System.out.println("Start: Copy World " + from.getName() + " to " + to.getName());
            Bukkit.broadcastMessage(SIGNATUR + ChatColor.WHITE + "Starte Kopiervorgang");
            Set<String> copiedChunks = new HashSet<>();
            List<Ground> groundList = Ground.find.all();
            index = 0;
            new Thread(() -> {
                while (index < groundList.size()) {
                    try {
                        Thread.sleep(30000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    Bukkit.broadcastMessage(SIGNATUR + ChatColor.WHITE + " " + ((index * 100.0) / groundList.size()) + "% Kopierte: " + blocks);
                }
                Bukkit.broadcastMessage(SIGNATUR + ChatColor.GOLD + "Kopiervorgang beendet");
            }).start();

            for (; index < groundList.size(); index++) {
                Ground ground = groundList.get(index);
                for (double x = ground.getX(); x < (ground.getX() + ground.getHeight()); x++) {
                    for (double z = ground.getZ(); z < (ground.getZ() + ground.getWidth()); z++) {
                        final double zFinal = z;
                        final double xFinal = x;
                        Chunk chunkFrom = loadChunk(x, z, from);
                        String chunkCode = chunkFrom.getX() + "-" + chunkFrom.getZ();
                        if (!copiedChunks.contains(chunkCode)) {
                            copiedChunks.add(chunkCode);
                            Chunk chunkTo = loadChunk(x, z, to);
                            copyChunk(chunkFrom, chunkTo);
                        }
                    }
                }
            }
            copy = false;
            System.out.println("Finished: Copy World " + from.getName() + " to " + to.getName());
        }

        private void copyChunk(Chunk chunkFrom, Chunk chunkTo) {
            System.out.println("Start: Copy Chunk (" + chunkFrom.getWorld().getName() + "|" + chunkFrom.getX() + "|" + chunkFrom.getZ() + ") to (" + chunkTo.getWorld().getName() + "|" + chunkTo.getX() + "|" + chunkTo.getZ() + ")");
            Object syncObject = new Object();
            Bukkit.getScheduler().runTask(BeanProject.getPlugin(), () -> {
                chunkFrom.load();
                chunkTo.load();
                System.out.println("Load Chunk (" + chunkFrom.getWorld().getName() + "|" + chunkFrom.getX() + "|" + chunkFrom.getZ() + ") and (" + chunkTo.getWorld().getName() + "|" + chunkTo.getX() + "|" + chunkTo.getZ() + ")");
                synchronized (syncObject) {
                    syncObject.notify();
                }
            });

            synchronized (syncObject) {
                try {
                    syncObject.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            for (int index = 0; index < (255 / 31); index++) {
                copyChunkBlock(chunkFrom, chunkTo, index);
            }
            System.out.println("Finished: Copy Chunk (" + chunkFrom.getWorld().getName() + "|" + chunkFrom.getX() + "|" + chunkFrom.getZ() + ") to (" + chunkTo.getWorld().getName() + "|" + chunkTo.getX() + "|" + chunkTo.getZ() + ")");
        }

        private void copyChunkBlock(Chunk chunkFrom, Chunk chunkTo, int hight) {
            System.out.println("Start: Copy Chunk (" + chunkFrom.getWorld().getName() + "|" + chunkFrom.getX() + "|" + chunkFrom.getZ() + ") to (" + chunkTo.getWorld().getName() + "|" + chunkTo.getX() + "|" + chunkTo.getZ() + ") hight: " + hight);
            Location start = new Location(chunkFrom.getWorld(), chunkFrom.getX() * 16, hight * 31, chunkFrom.getZ() * 16);
            Location end = new Location(chunkFrom.getWorld(), (chunkFrom.getX() * 16) + 16, (hight * 31) + 31, (chunkFrom.getZ() * 16) + 16);
            DefinedStructure structure = createSingleStructure(new Location[]{start, end}, "Bean900");
            insertSingleStructure(structure, new Location(chunkTo.getWorld(), chunkTo.getX() * 16, 0, chunkTo.getZ() * 16), EnumBlockRotation.NONE);
            System.out.println("Finished: Copy Chunk (" + chunkFrom.getWorld().getName() + "|" + chunkFrom.getX() + "|" + chunkFrom.getZ() + ") to (" + chunkTo.getWorld().getName() + "|" + chunkTo.getX() + "|" + chunkTo.getZ() + ") hight: " + hight);
        }

        /**
         * Creates a single structure of maximum 32x32x32 blocks.
         *
         * @param corners - The edges of the are (order doesn't matter)
         * @param author  - The listed author of the structure
         * @return DefinedStructure - The new structure instance
         */

        private DefinedStructure createSingleStructure(Location[] corners, String author) {
            System.out.println("Create Structure");
            if (corners.length != 2)
                throw new IllegalArgumentException("An area needs to be set up by exactly 2 opposite edges!");
            Location[] normalized = normalizeEdges(corners[0], corners[1]); // find this method at the end of the tutorial
            // ^^ This is juggling the coordinates, so the first is the Corner with lowest x, y, z and the second has the highest x, y, z.
            WorldServer world = ((CraftWorld) normalized[0].getWorld()).getHandle();
            int[] dimensions = getDimensions(normalized); // find this method at the end of the tutorial
            if (dimensions[0] > 32 || dimensions[1] > 32 || dimensions[2] > 32)
                throw new IllegalArgumentException("A single structure can only be 32x32x32!");
            DefinedStructure structure = new DefinedStructure();
            structure.a(world, new BlockPosition(normalized[0].getBlockX(), normalized[0].getBlockY(), normalized[0].getBlockZ()), new BlockPosition(dimensions[0], dimensions[1], dimensions[2]), true, Blocks.STRUCTURE_VOID);
            structure.a(author); // may not be saved to file anymore since 1.13
            System.out.println("Finish Create Structure");
            return structure;
        }

        /**
         * Pastes a single structure into the world
         *
         * @param structure - The structure to be pasted
         * @param startEdge - The starting corner with the lowest x, y, z coordinates
         * @param rotation  - You may rotate the structure by 90 degrees steps
         */

        public static void insertSingleStructure(DefinedStructure structure, Location startEdge, EnumBlockRotation rotation) {
            System.out.println("Insert Structure ");
            Object syncObject = new Object();

            Bukkit.getScheduler().runTask(BeanProject.getPlugin(), () -> {
                WorldServer world = ((CraftWorld) startEdge.getWorld()).getHandle();
                DefinedStructureInfo structInfo = new DefinedStructureInfo().a(EnumBlockMirror.NONE).a(rotation).a(false).a((ChunkCoordIntPair) null).a((Block) null).c(false).a(1.0f).a(new Random());
                // false sets ignore entities to false (so it does NOT ignore them)
                // 1.0f sets the amout of to be pasted blocks to 100%
                // mirror & rortation are self explaining
                // the block does the thing like the block does, which can be set in the ingame structure block GUI
                // no idea at the moment, what the coord pair, the random and the second false does
                // If you want to find out more about it, see net.minecraft.server.v1_13_R1.TileEntityStructure.c(boolean), there mojang calls the method and compare it with the ingame GUI
                structure.a(world, new BlockPosition(startEdge.getBlockX(), startEdge.getBlockY(), startEdge.getBlockZ()), structInfo);
                synchronized (syncObject) {
                    syncObject.notify();
                }
                System.out.println("Finished insert Structure");
            });

            synchronized (syncObject) {
                try {
                    syncObject.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(" Finished insert Structure method");
        }

        /**
         * Get the amount of blocks along x axis (width), y axis (height), z axis (length)
         *
         * @param corners - The 2 opposite edges, in best case the first has the lowest coordinates in x, y, z
         * @return int[3] - Width, height, length
         */

        private int[] getDimensions(Location[] corners) {
            if (corners.length != 2)
                throw new IllegalArgumentException("An area needs to be set up by exactly 2 opposite edges!");
            return new int[]{corners[1].getBlockX() - corners[0].getBlockX() + 1, corners[1].getBlockY() - corners[0].getBlockY() + 1, corners[1].getBlockZ() - corners[0].getBlockZ() + 1};
        }

        /**
         * Swaps the edge corners if necessary, so the first edge will be at the lowest coordinates and the highest will be at the edge with the highest coordinates
         *
         * @param startBlock - Any corner
         * @param endBlock   - The other corner
         * @return Location[2] array - [0] = lowest edge, [1] = highest edge
         */

        private Location[] normalizeEdges(Location startBlock, Location endBlock) {
            int xMin, xMax, yMin, yMax, zMin, zMax;
            if (startBlock.getBlockX() <= endBlock.getBlockX()) {
                xMin = startBlock.getBlockX();
                xMax = endBlock.getBlockX();
            } else {
                xMin = endBlock.getBlockX();
                xMax = startBlock.getBlockX();
            }
            if (startBlock.getBlockY() <= endBlock.getBlockY()) {
                yMin = startBlock.getBlockY();
                yMax = endBlock.getBlockY();
            } else {
                yMin = endBlock.getBlockY();
                yMax = startBlock.getBlockY();
            }
            if (startBlock.getBlockZ() <= endBlock.getBlockZ()) {
                zMin = startBlock.getBlockZ();
                zMax = endBlock.getBlockZ();
            } else {
                zMin = endBlock.getBlockZ();
                zMax = startBlock.getBlockZ();
            }
            return new Location[]{new Location(startBlock.getWorld(), xMin, yMin, zMin), new Location(startBlock.getWorld(), xMax, yMax, zMax)};
        }
    and here the log:
    Code (Text):
    [23:25:13 INFO]: Bean900 issued server command: /copy
    [23:25:13 INFO]: Start: Copy World OldWorld to world
    [23:25:13 INFO]: Start: Copy Chunk (OldWorld|0|0) to (world|0|0)
    [23:25:14 INFO]: Load Chunk (OldWorld|0|0) and (world|0|0)
    [23:25:14 INFO]: Start: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 0
    [23:25:14 INFO]: Create Structure
    [23:25:14 INFO]: Finish Create Structure
    [23:25:14 INFO]: Insert Structure
    [23:25:14 INFO]: Finished insert Structure
    [23:25:14 INFO]:  Finished insert Structure method
    [23:25:14 INFO]: Finished: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 0
    [23:25:14 INFO]: Start: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 1
    [23:25:14 INFO]: Create Structure
    [23:25:14 INFO]: Finish Create Structure
    [23:25:14 INFO]: Insert Structure
    [23:25:14 INFO]: Finished insert Structure
    [23:25:14 INFO]:  Finished insert Structure method
    [23:25:14 INFO]: Finished: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 1
    [23:25:14 INFO]: Start: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 2
    [23:25:14 INFO]: Create Structure
    [23:25:14 INFO]: Finish Create Structure
    [23:25:14 INFO]: Insert Structure
    [23:25:14 INFO]: Finished insert Structure
    [23:25:14 INFO]:  Finished insert Structure method
    [23:25:14 INFO]: Finished: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 2
    [23:25:14 INFO]: Start: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 3
    [23:25:14 INFO]: Create Structure
    [23:25:14 INFO]: Finish Create Structure
    [23:25:14 INFO]: Insert Structure
    [23:25:14 INFO]: Finished insert Structure
    [23:25:14 INFO]:  Finished insert Structure method
    [23:25:14 INFO]: Finished: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 3
    [23:25:14 INFO]: Start: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 4
    [23:25:14 INFO]: Create Structure
    [23:25:14 INFO]: Finish Create Structure
    [23:25:14 INFO]: Insert Structure
    [23:25:14 INFO]:  Finished insert Structure method
    [23:25:14 INFO]: Finished: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 4
    [23:25:14 INFO]: Start: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 5
    [23:25:14 INFO]: Create Structure
    [23:25:14 INFO]: Finished insert Structure
    [23:25:14 INFO]: Finish Create Structure
    [23:25:14 INFO]: Insert Structure
    [23:25:14 INFO]: Finished insert Structure
    [23:25:14 INFO]:  Finished insert Structure method
    [23:25:14 INFO]: Finished: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 5
    [23:25:14 INFO]: Start: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 6
    [23:25:14 INFO]: Create Structure
    [23:25:14 INFO]: Finish Create Structure
    [23:25:14 INFO]: Insert Structure
    [23:25:14 INFO]:  Finished insert Structure method
    [23:25:14 INFO]: Finished: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 6
    [23:25:14 INFO]: Start: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 7
    [23:25:14 INFO]: Create Structure
    [23:25:14 INFO]: Finished insert Structure
    [23:25:14 INFO]: Finish Create Structure
    [23:25:14 INFO]: Insert Structure
    [23:25:14 INFO]: Finished insert Structure
    [23:25:14 INFO]:  Finished insert Structure method
    [23:25:14 INFO]: Finished: Copy Chunk (OldWorld|0|0) to (world|0|0) hight: 7
    [23:25:14 INFO]: Finished: Copy Chunk (OldWorld|0|0) to (world|0|0)
    [23:25:14 INFO]: Start: Copy Chunk (OldWorld|0|1) to (world|0|1)
    [23:25:14 INFO]: Load Chunk (OldWorld|0|1) and (world|0|1)
    ...
    (And so on)
     
  18. After all i'm pretty sure the thread stuff is the problem.

    To eliminate possible causes of the problem, please try copying within the sync server thread.
    Copying 1 structure (maybe each second) per tick shouldn't cause too much lag.
     
  19. So i pack the hole
    copyChunkBlock
    Method in a sync Thread with:
    Code (Java):
    BeanProject.getPlugin().getServer().getScheduler().runTask(BeanProject.getPlugin(), () -> {
    ...
    }
    and have tried this too (if that makes a difference)
    Code (Text):
    Bukkit.getScheduler().runTask(BeanProject.getPlugin(),()->{
    In addition, I have adapted the method so that you place the property in the same world just 50 blocks farther away. Unfortunately, nothing happened here.
    Do you have a small exemplary class where everything works?
     
  20. @Bean900 sorry for the late reply, i'm pretty busy lately.
    I never tried copy and paste an area without saving it to a file, so i needed to make some adjustments to my test plugin.
    Now i did and tested. Succeed.

    Within my test plugin i can specify 2 opposite corners of an area (set1 & set2), create an structure object without saving it (buffer) and paste this object (pasteBuffer).
    I tested it by copying a 16x16x16 area on "defaultworld", and pasted it on world "a" somewhere. Works flawlessly.
    World changes and chunk borders are no problem.

    Following source is approved to be working as intended on git-Spigot-69774b3-a9c796f (MC: 1.13) (Implementing API version 1.13-R0.1-SNAPSHOT).
    I used #createSingleStructure and #insertSingleStructure like you did. But i attached them afterwards.
    The cases "buffer" and "pastebuffer" are relevant only for you.
    Code (Java):
    package minecraft.spigot.community.michel_0.structures.cmd;
    import java.io.File;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.UUID;
    import org.bukkit.Location;
    import org.bukkit.Material;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.LivingEntity;
    import org.bukkit.entity.Player;
    import org.bukkit.plugin.java.JavaPlugin;
    import minecraft.spigot.community.michel_0.api.structure.StructureService;
    import minecraft.spigot.community.michel_0.structures.CoordPair;
    import net.minecraft.server.v1_13_R1.DefinedStructure;
    import net.minecraft.server.v1_13_R1.EnumBlockRotation;
    public class Struct implements CommandExecutor {
        private Map<UUID, CoordPair> points;
        private Map<UUID, DefinedStructure> buffered;
        private JavaPlugin main;
        public Struct(JavaPlugin main) {
            this.main = main;
            this.points = new HashMap<>();
            this.buffered = new HashMap<>();
        }
        @Override
        public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
            if (sender instanceof Player) {
                if (sender.isOp()) {
                    UUID pUid = ((Player) sender).getUniqueId();
                    if (args.length >= 1) {
                        switch (args[0].toLowerCase()) {
                        case "set1":
                            if (this.points.containsKey(pUid)) {
                                this.points.put(pUid, this.points.get(pUid).setStart(((LivingEntity) sender).getTargetBlock(null, 20).getLocation()));
                            } else {
                                this.points.put(pUid, new CoordPair(((LivingEntity) sender).getTargetBlock(new HashSet<>(Arrays.asList(new Material[] {Material.AIR})), 10).getLocation()));
                            }
                            sender.sendMessage(this.points.get(pUid).toString());
                            break;
                        case "set2":
                            if (this.points.containsKey(pUid)) {
                                this.points.put(pUid, this.points.get(pUid).setEnd(((LivingEntity) sender).getTargetBlock(null, 20).getLocation()));
                            } else {
                                this.points.put(pUid, new CoordPair(null, ((LivingEntity) sender).getTargetBlock(new HashSet<>(Arrays.asList(new Material[] {Material.AIR})), 10).getLocation()));
                            }
                            sender.sendMessage(this.points.get(pUid).toString());
                            break;
                        case "save":
                            if (args.length >= 2) {
                                if (this.points.containsKey(pUid)) {
                                    if (this.points.get(pUid).isStartSet() && this.points.get(pUid).isEndSet()) {
                                        CoordPair area = this.points.get(pUid);
                                        try {
                                            StructureService.createAndSaveAny(new Location[] { area.getStart(), area.getEnd() }, sender.getName(), new File(this.main.getDataFolder(), args[1]));
                                            sender.sendMessage("Saved");
                                        } catch (IOException e) {
                                            sender.sendMessage("Something went wrong: " + e.getMessage());
                                        }
                                    } else sender.sendMessage("You need to set point 1 and 2 first");
                                } else sender.sendMessage("You need to set point 1 and 2 first");
                            } else sender.sendMessage("/struct save <name>");
                            break;
                        case "load":
                            if (args.length >= 2) {
                                if (this.points.containsKey(pUid)) {
                                    if (this.points.get(pUid).isStartSet()) {
                                        try {
                                            StructureService.loadAndInsertAny(new File(this.main.getDataFolder(), args[1]), this.points.get(pUid).getStart());
                                            sender.sendMessage("Loaded");
                                        } catch (IOException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                                            sender.sendMessage("Something went wrong: " + e.getMessage());
                                        }
                                    } else sender.sendMessage("You need to set point 1 first");
                                } else sender.sendMessage("You need to set point 1 first");
                            } else sender.sendMessage("/struct load <name>");
                            break;
                        case "buffer":
                            if (this.points.containsKey(pUid)) {
                                if (this.points.get(pUid).isStartSet() && this.points.get(pUid).isEndSet()) {
                                    CoordPair area = this.points.get(pUid);
                                    this.buffered.put(((Player) sender).getUniqueId(), StructureService.createSingleStructure(new Location[] { area.getStart(), area.getEnd() }, sender.getName()));
                                    sender.sendMessage("Buffered");
                                } else sender.sendMessage("You need to set point 1 and 2 first");
                            } else sender.sendMessage("You need to set point 1 and 2 first");
                            break;
                        case "pastebuffer":
                            if (this.points.containsKey(pUid)) {
                                if (this.points.get(pUid).isStartSet()) {
                                    if (this.buffered.containsKey(((Player) sender).getUniqueId())) {
                                        StructureService.insertSingleStructure(this.buffered.get(((Player) sender).getUniqueId()), this.points.get(pUid).getStart(), EnumBlockRotation.NONE);
                                        sender.sendMessage("Pasted");
                                    } else sender.sendMessage("You need to buffer an area first");
                                } else sender.sendMessage("You need to set point 1 first");
                            } else sender.sendMessage("You need to set point 1 first");
                            break;
                        default:
                            sender.sendMessage("/struct <set1|set2|load|save>");
                        }
                    } else sender.sendMessage("/struct <set1|set2|load|save>");
                } else sender.sendMessage("This is a prototype testing plugin. OPs only!");
            } else sender.sendMessage("Only players can use this command");
            return true;
        }
    }
    Code (Java):
    public static void insertSingleStructure(DefinedStructure structure, Location startEdge, EnumBlockRotation rotation) {
        WorldServer world = ((CraftWorld) startEdge.getWorld()).getHandle();
        DefinedStructureInfo structInfo = new DefinedStructureInfo().a(EnumBlockMirror.NONE).a(rotation).a(false).a((ChunkCoordIntPair) null).a((Block) null).c(false).a(1.0f).a(new Random());
        structure.a(world, new BlockPosition(startEdge.getBlockX(), startEdge.getBlockY(), startEdge.getBlockZ()), structInfo);
    }
    public static DefinedStructure createSingleStructure(Location[] corners, String author) {
        if (corners.length != 2) throw new IllegalArgumentException("An area needs to be set up by exactly 2 opposite edges!");
        Location[] normalized = StructureService.normalizeEdges(corners[0], corners[1]);
        WorldServer world = ((CraftWorld) normalized[0].getWorld()).getHandle();
        int[] dimensions = StructureService.getDimensions(normalized);
        if (dimensions[0] > 32 || dimensions[1] > 32 || dimensions[2] > 32) throw new IllegalArgumentException("A single structure can only be 32x32x32! If you need more, use #createStructuresArea.");
        DefinedStructure structure = new DefinedStructure();
        structure.a(world, new BlockPosition(normalized[0].getBlockX(), normalized[0].getBlockY(), normalized[0].getBlockZ()), new BlockPosition(dimensions[0], dimensions[1], dimensions[2]), true, Blocks.STRUCTURE_VOID);
        structure.a(author);
        return structure;
    }
     
    • Winner Winner x 1
Thread Status:
Not open for further replies.