4

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?

  • I made a system (more a framework) before that would let you do something like that, but it also lags a lot. Try only filling one layer with them and using that as a placeholder, then teleporting them all up (or to the side or whatever). – Fabian Röling Jul 16 '19 at 5:59
  • What kind of blocks should the area be filled with? Should they be evenly distibuted, or one more often than the others? How would the system know what spaces not to fill? or should it just replace everything that isn't air? Or is air one of the random blocks? Is a datapack with a function acceptable for you? How do the area effect clouds that you use pick a random block? What are you going to use this for (In case there is a better thing to do, though it looks like you know what you want)? – user232393 Jul 16 '19 at 13:26
  • bearb001 I have created a datapack that "digs" a random maze in a stone brick area, creating air blocks. This must be done before the blocks are randomized, since the generator relies on stone_bricks to path. After it is finished, I want to replace all stone bricks with some of its variants (ex. Mossy_stone_brick.) My system uses /fill ~ ~ ~ ~ ~ ~ <block> replace stone_brick" instead of "/setblock ~ ~ ~ <block>" because /setblock can't replace a specified block. – ginkgo Jul 16 '19 at 13:40
  • @ginkgo So basically all stone_brick blocks in that area should be replaced by a random block, chosen from this list: stone bricks (regular, so some would stay the same), cracked stone bricks, mossy stone bricks, and chiseled stone bricks. Is that correct? How many % are allowed to remain regular stone bricks? You could just use one, or multiple armor stands to randomly replace bricks. (And just to be sure, you use 1.14.3, right?) – user232393 Jul 16 '19 at 18:25
  • @ bearb001 My "block pool," if you will, includes 2 stone_bricks, 1 mossy-stone_bricks, 1 cracked_stone_bricks, and 1 polished_andesite. So 33% remain stone_brick. (Yes, I am using 1.14.3.) I assume by "one, or multiple armor stands to randomly replace bricks" you mean something similar to this: Repeatedly using /spreadplayers to randomly teleport an armor_stand(s) and wherever the armor_stand(s) lands, it replaces the block beneath it? – ginkgo Jul 16 '19 at 22:28
4

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
  • 1
    I edited this to increase the performance. This now works with one layer at a time, so the armor stands don't have to teleport up and down every tick anymore, every armor stand only changes the x value, there is one armor stand per z value. It is also a little bit more flexible. – user232393 Jul 18 '19 at 15:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.