Is it possible to manipulate the block data directly?

Hello!

I have a piece of code, in which I import a schematics file into a Minecraft world using JNBT. It allows you to read “raw” block IDs and block data from a schematics file.

val file = File(instr.fileName)
var fis: FileInputStream? = null
var nbt: NBTInputStream? = null

try {
    fis = FileInputStream(file)
    nbt = NBTInputStream(fis)
    val backupTag: CompoundTag = nbt.readTag() as CompoundTag
    val tagCollection:Map<String, Tag> = backupTag.value

    val width:Short =
            getChildTag(tagCollection, "Width").getValue() as Short
    val height:Short =
            getChildTag(tagCollection, "Height").getValue() as Short
    val length:Short =
            getChildTag(tagCollection, "Length").getValue() as Short
    val blocks: ByteArray? =
            (getChildTag(tagCollection, "Blocks") as ByteArrayTag).value
    val blockData: ByteArray? =
            (getChildTag(tagCollection, "Data") as ByteArrayTag).value
    for (x in 0..(width - 1)) {
        for (y in 0..(height - 1)) {
            for (z in 0..(length - 1)) {
                val index = y * width * length + z * width + x
                val blockId:Int = blocks[index].toPositiveInt()
                // Here we have the ID of the block at location (x, y, z) in the schematics file file

Is it possible to use these block ID and block data to modify a given block in a Sponge world, i. e. without analyzing, what block this?

For example, there is a block ID 197 (dark wooden door). Currently, if I detect this block ID, I run code like this:

override fun createDoor(
      door: Door,
      coords: McCoords
) {
    // Lower half
    val lowerLoc = createSpongeLocation(
          x = coords.x + door.x,
          y = coords.y + door.elevation,
          z = coords.z + door.z
    )
    setBlockType(lowerLoc, getBlockType(door.blockType))
    offer(lowerLoc, Keys.PORTION_TYPE, PortionTypes.BOTTOM)
    offer(lowerLoc, Keys.HINGE_POSITION, Hinges.LEFT)

    // Upper half
    val upperLoc = createSpongeLocation(
          x = coords.x + door.x,
          y = coords.y + door.elevation + 1,
          z = coords.z + door.z
    )
    setBlockType(upperLoc, getBlockType(door.blockType))
    offer(upperLoc, Keys.PORTION_TYPE, PortionTypes.TOP)
    offer(upperLoc, Keys.HINGE_POSITION, Hinges.LEFT)
}

This means that I need to write custom piece of code for every block type, which needs special treatment (such as doors, or any blocks, which have directions e. g. slabs).

It would save me a lot of time, if I could just put the binary data into some Sponge method, which will then manipulate that block accordingly. For example, in case of a door I assume that the information about portion types and hinge position is stored in its block data (relevant portion of the blockData array above).

Is it possible? If yes, how?

Thanks in advance

Dmitri Pisarenko

You can rely on the base game through ForgeGradle and look up the block states from the registry. There is little to no support from the base game to just dump using raw data values. SpongeAPI doesn’t allow using raw data values either, so can’t help you there.

There is a feature that is hopefully going to be merged into API 5.0.0-SNAPSHOT that adds API support for Schematics and allows for reading from a few different formats.

I would warn you though that if you take the implementation route, there’s a lot of things that you should consider with the implementation of Sponge, namely CauseTracking, that handles mass block changes to throw events for plugins to use.

2 Likes