How to apply a schematic without air blocks?

How to apply a schematic without air blocks replacing the blocks on the map ?

You can manually place the blocks using BlockWorker which then you can filter out the air blocks

How to use a BlockWorker ?

Here is code I wrote that shows how to do mostly what your trying to do

I have a problem…
I created this function

public static void apply(String name, World world, Vector3i position, Collection filter) {

  getSchematic(name).getBlockWorker().iterate((v, x, y, z) -> {
  	Vector3i max = v.getBlockMax();
  	Vector3i min = v.getBlockMin();
  	for(int x1 = min.getX(); x1 < max.getX(); x1++){
  		for(int y1 = min.getY(); y1 < max.getY(); y1++){
  			for(int z1 = min.getZ(); z1 < max.getZ(); z1++){
  				if (!filter.contains(v.getBlock(x1, y1, z1).getType())) world.setBlock(x1, y1, z1, v.getBlock(x1, y1, z1));
  			}
  		}
  	}
  });

}

And when I run it with the argument:

world = default world
position = (0, 200, 0)
filter = Arrays.asList(BlockTypes.AIR)

I’ve got an error in the console:

org.spongepowered.api.util.PositionOutOfBoundsException: Position is out of bounds: expected in range (-30000000, 0, -30000000) to (29999999, 255, 29999999) but got (-1, -1, -1)

Can you help me?

Just tried my own code out, its similar to yours but mine works

Vector3i min = v.getBlockMin();
Vector3i max = v.getBlockMax();
for(int X = min.getX(); X < max.getX(); X++){
    for(int Y = min.getY(); Y < max.getY(); Y++){
        for(int Z = min.getZ(); Z < max.getZ(); Z++){
            Location<World> loc = world.getLocation(X, Y, Z).add(position);
            BlockState state = v.getBlock(X, Y, Z);
            if(state.getType().equals(BlockTypes.AIR)){
                continue;
            }
            loc.setBlock(state, BlockChangeFlags.NONE);
        }
    }
}

It seems to be the position of your location that your not taking into account

It works, but when I apply my structure the blocks inside don’t have NBT.
How to apply them too?

Personally never delt with NBT, I know it means modifying the Container of the object to set and get NBT. You maybe able to get the NBT data you wish from the following (as it part of the Container api) but not too sure

DataView view = v.getMetaData();

But that is likely only to hold things such as the name, date and author of the schematic

I’ve found a solution!

Vector3i min = schematic.getBlockMin();
Vector3i max = schematic.getBlockMax();
for(int x = min.getX(); x <= max.getX(); x++){
	for(int y = min.getY(); y <= max.getY(); y++){
		for(int z = min.getZ(); z <= max.getZ(); z++){
			BlockState block = schematic.getBlock(x, y, z);
			if (!filter.contains(block.getType())) {
				Optional<TileEntityArchetype> optional = schematic.getTileEntityArchetype(x, y, z);
				if (optional.isPresent()) optional.get().apply(world.getLocation(x, y, z).add(position).add(min));
				else world.setBlock(position.add(x, y, z), block);
			}
		}
	}
}

Oh you meant TileEntity not just NBT