Minecraft – How to quickly fill a large space with random blocks

minecraft-commandsminecraft-java-edition

I want to fill a large area (approximately 40000 blocks in volume, 100x 4y 100z) with random blocks, and as quickly as possible. The area is not solid; it has air blocks which are not intended to be filled. I currently have a method to do so, but it is slow and it crunches TPS. My current method is to use a wall made up of individual area_effect_clouds. Each one chooses a random block to place at its position, and when all the clouds have done so, the wall moves 1 block forward.

Are there any better ways to do this?

Best Answer

You can solve this with a datapack, I used the namespace maze.

For this to know where to replace blocks you need to place a root armor stand with these ({Marker:1,Tags:[root,rootTwo,rootThree,stoneBricks],Invisible:1}) NBT tags at the position with the lowest x, y, and z values. This setup may replace any non-air block that is in a 100x4x100 block and about 33% stay the same as they were originally. You can change the amount of layers in the third command.

The command to place the root armor stand should look like this:

/summon minecraft:armor_stand ~ ~ ~ {Marker:1,Tags:[root,rootTwo,rootThree,stoneBricks],Invisible:1}

The main function (call this after placing the root armor stand):

#set up a scoreboard objective, increase placementsPerLayer for fewer regular stone bricks
scoreboard objectives add repeats dummy
scoreboard players set placementsPerLayer repeats 36
scoreboard players set layers repeats 4

#summon 99 tagged armor stands in a diagonal line based on the position of the root armor stand
execute at @e[tag=stoneBricks] run summon minecraft:armor_stand ~10 ~ ~10 {Marker:1,Tags:[rootThree,rootTwo,stoneBricks],Invisible:1}
execute at @e[tag=stoneBricks] run summon minecraft:armor_stand ~20 ~ ~20 {Marker:1,Tags:[rootThree,rootTwo,stoneBricks],Invisible:1}
execute at @e[tag=stoneBricks] run summon minecraft:armor_stand ~40 ~ ~40 {Marker:1,Tags:[rootThree,rootTwo,stoneBricks],Invisible:1}
execute at @e[tag=root] run summon minecraft:armor_stand ~80 ~ ~80 {Marker:1,Tags:[rootThree,rootTwo,stoneBricks],Invisible:1}
execute at @e[tag=root] run summon minecraft:armor_stand ~90 ~ ~90 {Marker:1,Tags:[rootThree,rootTwo,stoneBricks],Invisible:1}
execute at @e[tag=stoneBricks] run summon minecraft:armor_stand ~1 ~ ~1 {Marker:1,Tags:[rootThree,stoneBricks],Invisible:1}
execute at @e[tag=stoneBricks] run summon minecraft:armor_stand ~2 ~ ~2 {Marker:1,Tags:[rootThree,stoneBricks],Invisible:1}
execute at @e[tag=stoneBricks] run summon minecraft:armor_stand ~4 ~ ~4 {Marker:1,Tags:[rootThree,stoneBricks],Invisible:1}
execute at @e[tag=rootTwo] run summon minecraft:armor_stand ~8 ~ ~8 {Marker:1,Tags:[rootThree,stoneBricks],Invisible:1}
execute at @e[tag=rootTwo] run summon minecraft:armor_stand ~9 ~ ~9 {Marker:1,Tags:[rootThree,stoneBricks],Invisible:1}

#summon 100 armor stands that should be used to determin where to put blocks
execute as @e[tag=stoneBricks] at @s run summon minecraft:armor_stand ~ ~ ~ {Marker:1,Tags:[stoneBricks],Invisible:1}

#set a score for how many more placements should be made in this layer
scoreboard players operation placements repeats = placementsPerLayer repeats

#call the function responsible for replacing blocks
function maze:place

The maze:place function (called by the main function):

#teleport all armor stands to a random location within the 100x100 square of the current layer
#only along the x axis, there is one armor stand per z value
execute as @e[tag=stoneBricks,tag=!rootThree] run data modify entity @s Pos[0] set from entity @e[tag=rootThree,sort=random,limit=1] Pos[0]
#set all non-air blocks at the location of an armor stand to a mossy stone bricks block
execute as @e[tag=stoneBricks,tag=!rootThree] at @s unless block ~ ~ ~ minecraft:air run setblock ~ ~ ~ minecraft:mossy_stone_bricks

#repeat for cracked stone bricks blocks
execute as @e[tag=stoneBricks,tag=!rootThree] run data modify entity @s Pos[0] set from entity @e[tag=rootThree,sort=random,limit=1] Pos[0]
execute as @e[tag=stoneBricks,tag=!rootThree] at @s unless block ~ ~ ~ minecraft:air run setblock ~ ~ ~ minecraft:cracked_stone_bricks

#repeat for polished andesite
execute as @e[tag=stoneBricks,tag=!rootThree] run data modify entity @s Pos[0] set from entity @e[tag=rootThree,sort=random,limit=1] Pos[0]
execute as @e[tag=stoneBricks,tag=!rootThree] at @s unless block ~ ~ ~ minecraft:air run setblock ~ ~ ~ minecraft:polished_andesite

#keep track of how many more placements to make on this layer
scoreboard players remove placements repeats 1

#teleport the placing armor stands one block up if the current layer is finished
execute if score placements repeats matches ..0 as @e[tag=stoneBricks,tag=!rootThree] at @s run tp ~ ~1 ~
#keep track of how many more layers there are
execute if score placements repeats matches ..0 run scoreboard players remove layers repeats 1
#reset the placements value to the placementsPerLayer value
execute if score placements repeats matches ..0 run scoreboard players operation placements repeats = placementsPerLayer repeats

#schedule the next iteration to the next tick (repeats this function)
execute if score layers repeats matches 1.. run schedule function maze:place 1t
#kills all armor stands used for this after this function is done
execute if score layers repeats matches ..0 run kill @e[tag=stoneBricks]
#remove the scoreboard objective
execute if score layers repeats matches ..0 run scoreboard objectives remove repeats

It took my computer 10 seconds to run this, though I was able to continue playing smoothly with still acceptable fps. It is possible to tweak this to go faster, but the performance may suffer.

In a sample of 10000 blocks there were

  • 3390 stone bricks
  • 2252 polished andesite
  • 2203 cracked stone bricks
  • 2155 mossy stone bricks