How can I quickly fill a large space with random blocks?
Solution 1:
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