how would you access a block's NBT?

Discussion in 'Spigot Plugin Development' started by Quezler, Apr 24, 2016.

  1. How would you edit a block's NBT data through spigot? (like: /blockdata ~ ~-1 ~ {})
    I've tried everything i could find, but nothing worked yet.

    My eventual goal, getting the level NBT tag of a beacon block.
     
  2. The Bukkit / Spigot API doesn't support NBT, so you should cast the Block to a CraftBlock and get the NMS block with the getNMSBlock() method.
     
  3. I can't find an easy way around:
    Code (Text):
    The method getNMSBlock() from the type CraftBlock is not visible
    From what i could find on the internet it needs to be the same package or something.
     
  4. @Quezler why not just run the commands?
     
    • Informative Informative x 1
  5. Well i would assume spigot has some sort of faster way to do it ;)

    I've also looked into the worldedit API, but i understand to little of that sadly.

    Does anyone know how to do it without commands by any chance?
     
  6. Here's an example of using the WorldEdit API:
    Code (Text):
    WorldEditPlugin plugin = (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit");
    World bukkitWorld = Bukkit.getWorld("world");
    WorldEdit we = WorldEdit.getInstance();
    BukkitWorld world = new BukkitWorld(bukkitWorld);
    /*
    Note: You can get/set blocks through the BukkitWorld as well but an EditSession may be better if you're doing a large number of changes
        - If you are using FAWE you could use this code from an async thread
        - If you are using AWE you would want to use the ThreadSafeEditSession class
    */
    EditSession edit = we.getEditSessionFactory().getEditSession(world, -1, (BlockBag) null, (Player) null);
    Vector pos = new Vector(x, y, z);
    { // Do as many changes as you want with the EditSession before flushing the queue
        BaseBlock block = edit.getBlock(pos);
        CompoundTag nbt = block != null ? block.getNbtData() : null;
        if (nbt != null) {
            /*
            Do stuff with the nbt here.

            Some tags are immutable:
             - Either replace it with a new tag (e.g. new ListTag(...)) (safer)
             - Or use reflection to change values (faster as it avoids recreating large compound tags)
             */
        }
        // Setting the nbt to another CompoundTag
        block.setNbtData(other);
        try {
            edit.setBlock(pos, block, EditSession.Stage.BEFORE_CHANGE);
        } catch (WorldEditException e) {
            // Something went wrong!
            e.printStackTrace();
        }
    }
    // If you made any changes
    edit.flushQueue();
     
    • Like Like x 2
  7. I'm using spigot 1.9 and can get nbts using:
    Code (Text):
    CraftWorld ws = (CraftWorld) w; //W is your normal bukkit world . . . I'm using player.getWorld()
    NBTTagCompound ntc = null;
    TileEntity te = ws.getTileEntityAt(x, y, z);
    if (te != null)
    {
        ntc = new NBTTagCompound();
        te.save(ntc);
    }
    This is what I use for my schematic system and just apply it to the entity if the tile entity exists while pasteing. . .

    Hope this is anything close to what you wanted.
     
    #7 Lightspeed360, Apr 24, 2016
    Last edited: Apr 25, 2016
    • Useful Useful x 1
  8. Blocks dont have NBT. What you are looking for is called a TileEntity, And it requires NMS, or a library that uses NMS internally (just do it yourself).
     
  9. Any example/link to point me in the right direction? :oops:
     
  10. Tfw people try to use WE for block modifications
     
    • Funny Funny x 1
  11. This will check if the block is a tile entity and if so grab the nbt and set ntc to it.

    Im using normal spigot so this should work for you?
     
  12. I went with
    empire92
    's solution, but i just cannot figure out how to change NBT (reading works)

    Right now i have:
    Code (Java):
                    Map<String, Tag> map = new HashMap<String, Tag>();
                    List<Integer> i = new ArrayList<Integer>();
                    i.add(15);
                    Tag tag = new ListTag(int.class, i);
                    map.put("SuccessCount", tag);
                    nbt.setValue(map);
    it gives me the error The constructor ListTag(Class<Integer>, List<Integer>) is undefined

    i tried to use this page as best as i could, any help?
     
  13. Update:

    i finally managed to get rid of the error, but now any value (integer/string/etc) that i set are not to be found with the /blockdata command, or with any known method to read block data.

    Code (Java):
        private CompoundTag blockdata(BlockState tile) {
            World bukkitWorld = Bukkit.getWorld(tile.getWorld().getName());
            WorldEdit we = WorldEdit.getInstance();
            BukkitWorld world = new BukkitWorld(bukkitWorld);
            CompoundTag nbt = null;
            /*
            Note: You can get/set blocks through the BukkitWorld as well but an EditSession may be better if you're doing a large number of changes
                - If you are using FAWE you could use this code from an async thread
                - If you are using AWE you would want to use the ThreadSafeEditSession class
            */

            EditSession edit = we.getEditSessionFactory().getEditSession((com.sk89q.worldedit.world.World) world, -1);
            Vector pos = new Vector(tile.getX(), tile.getY(), tile.getZ());
            { // Do as many changes as you want with the EditSession before flushing the queue
                BaseBlock block = edit.getBlock(pos);
                nbt = block != null ? block.getNbtData() : null;
                if (nbt != null) {
                    /*
                    Do stuff with the nbt here.

                    Some tags are immutable:
                     - Either replace it with a new tag (e.g. new ListTag(...)) (safer)
                     - Or use reflection to change values (faster as it avoids recreating large compound tags)
                     */

                    Map<String, Tag> map = new HashMap<String, Tag>();
                    map.put("SuccessCount", new IntTag(15));
                    nbt.setValue(map);
                }
                // Setting the nbt to another CompoundTag
                block.setNbtData(nbt);
                try {
                    edit.setBlock(pos, block, EditSession.Stage.BEFORE_CHANGE);
                } catch (WorldEditException e) {
                    // Something went wrong!
                    e.printStackTrace();
                }
            }
            // If you made any changes
            edit.flushQueue();
            return nbt;
        }
     
  14. Another update:

    Apparently this way overrides the values, does someone here know how to use "Reflection" to change 1 NBT value of a block?