Resource Structure Util: NMS Schematics

Discussion in 'Spigot Plugin Development' started by MiniDigger, Dec 8, 2016.

  1. MiniDigger

    Supporter

    disclaimer: this uses nms. if you don't know what that means and what consequences that has, move on and use the worldedit api.
    disclaimer2: this util uses structures, NOT schematics. they are two different things. structures are officially supported by mojang, schematics are not. most tools like worldedit or mcedit do not support structures yet, so you can only use the util so save and load stuff from within your own plugin (like if you want to copy something from A to B or build a arena that gets reset every time)

    Hey Guys,
    I created this a while back and it seems like it could be useful to ppl.
    after @ysl3000 changed some stuff I uploaded this to gist so that everybody can enjoy it:
    https://gist.github.com/MiniDigger/e10fdb52db509f4b82980ea9b4040e60
    its pretty straight forward: save saves a structure (similarly to a schematic, but officially supported by mojang) into the world folder and load loads it back from there and pastes it in.
    you can also modify some stuff (eg: line 40: you can toggle if it should include entities there, same for line 61, where you can do all kind of stuff) but I did that util for a contest and didn't had time to properly do it, so you need to change it in the code. this whole thing is a mess, I basically ripped it out of the code for the structure block.

    UPDATE: I went ahead and created a reflection version (with more options, like mirror, rotate and includeEntitites), you can find that here: https://gist.github.com/MiniDigger/ce2b0b0446d53d3bb94f24f1c708c657
    it is only tested with 1.10 and 1.11, if you find out that it does work for other versions or find out the right names for another version, let me know so I can add them here!
     
    #1 MiniDigger, Dec 8, 2016
    Last edited: Dec 8, 2016
    • Like Like x 5
    • Winner Winner x 3
    • Useful Useful x 2
  2. Neat! Schematic loading with no world edit! Will use I ever need schematic loading without world edit.
     
  3. I might try to recreate this with reflection later. Idk

    But good resource
     
  4. Wouldn't be of much use, due obfuscation.
     
  5. Good one, even if it uses nms, we can still use reflection/abstraction
     
  6. It can be used to save Structures, not Schematics? Or did i mix up something?
     
  7. MiniDigger

    Supporter

    I didn't know if they are same or not, sorry to cause confusion: this uses the offical mojang structure format
     
    • Like Like x 1
  8. MiniDigger

    Supporter

    I went ahead and created a reflection version (with more options, like mirror, rotate and includeEntitites), you can find that here: https://gist.github.com/MiniDigger/ce2b0b0446d53d3bb94f24f1c708c657
    it is only tested with 1.10, if you find out that it does work for other versions or find out the right names for another version, let me know so I can add them here!
     
    • Like Like x 1
  9. Schematics and Structures where 2 completely different things based on completely different specifications.

    The structure specification is specified by mojang and as far as i know a minecraft server is the only "software", which is able to handle this format, since structures always has been a server internal thing.

    Whereas the schematic specification is created by the community. Mojang never used it and won't ever use schematics. But the big advantage is, that there is a huge nuber of tools and other software, which can handle the schematic file format.

    The only common thing is, both specifications where based on NBT and save NBT files.

    This is why you should at least modify the thread title from "schematics" to "structures", this shouldn't be mixed up.

    I don't know if this is the right place to discuss about schematics / structures, but i think using schematics is prefered, because it always has been a open source standard used by many tools, this is why plugins should use it.
    Using such an "internal" format like structures doesn't give plugin users the opportunity to modify / create structures by other external tools.
     
  10. MiniDigger

    Supporter

    ah I see, thank you for the clarification.
    this util is targeted at ppl who want to save and load stuff from within their plugin, without external modification.
    I cleared up the first post to make that more clear.
     
    • Like Like x 1
  11. @MiniDigger you should use enums instead of raw strings, where applicable. Heck, might be nice if you'd OO this (constructor taking a name, setters for properties such as rotation and entities, and a save/load method with appropriate parameters).

    Time to update my Spigot jar and peek around, might be possible to delegate a lot of the reflection work to blocks / commands
     
  12. MiniDigger

    Supporter

    added support for 1.11 and updated the gist, it will now work on 1.10 and 1.11, have fun!

    you are right about that. as mentioned above, I just ripped this out of nms, for a contest. someone brought that util up again and I created this thread. someone brought up reflection and I slapped that on too. I didn't design a proper api (mostly because I am way to tired currently :D)
    you are very welcome to make this a proper api and share it here, or even pr it into spigot.
     
    • Like Like x 1
  13. MiniDigger

    Supporter

    • Like Like x 1
  14. This is over an year old? GG... i really ignored structures until 1.13.
    However, i got a little different approach to handle structures, that's why i'm bumping this thread.

    Seems like you all guys are using the DefinedStructureManager to receive an DefinedStructure instance and seems like you also let it save and load your structures… just why?

    I want structures to be easily copied, moved, deleted,... or even modified by any end-user. So why hide it deeply inside of the world folder (i assume the DefinedStructureManager does this)? I think it's more suitable to save structures at the plugin folder and make it not bound to a world and to vanilla.
    Long story short: I want to manage my structures, not NMS.

    So this is my solution (and i wonder why i haven't seen something yet):
    Code (Java):
    // Out of API imports:
    import org.bukkit.craftbukkit.v1_13_R1.CraftWorld;
    import net.minecraft.server.v1_13_R1.BlockPosition;
    import net.minecraft.server.v1_13_R1.Blocks;
    import net.minecraft.server.v1_13_R1.DefinedStructure;
    import net.minecraft.server.v1_13_R1.NBTCompressedStreamTools;
    import net.minecraft.server.v1_13_R1.NBTTagCompound;
    import net.minecraft.server.v1_13_R1.WorldServer;
    public void saveStructure(Location start, Location end, String author, File destination) {
        // Calculate the width, height, length
        int[] dimensions = this.getDimensions(new Location[] { start, end });
        // Common way to receive the NMS world instance
        WorldServer world = ((CraftWorld) start.getWorld()).getHandle();
        // Seems to work well to instantiate it by myself
        DefinedStructure structure = new DefinedStructure();
        // Serialize the world with parameters 1: the corresponding world; 2: starting Edge; 3: relative width, height, length; 4: including entities; 5: ignored blocks when placed
        structure.a(world, new BlockPosition(start.getBlockX(), start.getBlockY(), start.getBlockZ()), new BlockPosition(dimensions[0], dimensions[1], dimensions[2]), true, Blocks.STRUCTURE_VOID);
        // Didn't test this yet… but it can only be the author tag.
        structure.a(author);
        // Common way to handle NBT tags
        NBTTagCompound fileTag = new NBTTagCompound();
        // This serializes a DefinedStructure to an NBTTagCompound
        fileTag = structure.a(fileTag);
        // Finally save the structure
        NBTCompressedStreamTools.a(fileTag, new FileOutputStream(destination));
    }
    public static 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 };
    }
    I puzzeled something together above, on my test project it's a little more structured and separated.
    However it works like that.

    Only disadvantage: You might not be able to paste the structure ingame by a structure block. But i don't want this to be possible, so it's no problem. When someone got a plugin like this to save structures, this plugin can also paste structures so there is no need for structure blocks anymore.

    The names of the NMS methods seems to be highly dynamic (changes on updates often). I tested on spigot dev build for 1.13 (Implementing API version 1.13-R0.1-SNAPSHOT).

    Outlook:
    With a logic like posted above you got the complete control to create structures dynamically and independent. This is what i need to make a workaround to bypass the 32x32x32 limit. I'm splitting up a region of any size in 32x32x32 (or less at the corners) parts, pack them into a one dimensional array, and safe them all into an new generated, empty folder, with names containing the array index. Additionally a file to save the original absolute with, length, height (so i know how to puzzle them together again).

    You reported on JIRA at 8.12.16??? Still no reaction from administration? Is there any hope, that this will be part of the spigot API anytime?
     
    • Like Like x 2