Skip to content

Instantly share code, notes, and snippets.

@misode
Last active May 15, 2023 00:18
Show Gist options
  • Star 44 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save misode/45559d34627755ecaa52497daea83544 to your computer and use it in GitHub Desktop.
Save misode/45559d34627755ecaa52497daea83544 to your computer and use it in GitHub Desktop.

Custom data pack structures in 1.18.2

This guide will showcase how to create a data pack that adds a custom structure to the world. There is also a data pack download of this complete example.

Always leave the world and rejoin to apply the new changes!

⚠️ This guide has moved ⚠️

Updates for both 1.18.2 and 1.19 can be found at https://misode.github.io/guides/adding-custom-structures/

Pack.mcmeta

Like every data pack, we need a pack.mcmeta. In this version, the pack format is 9!

{
  "pack": {
    "pack_format": 9,
    "description": "A tall tower"
  }
}

The structure set

A structure set is where the placement starts. It defines where in the world the structure should be placed, and how rare it is. It takes a weighted list of different structures, allowing structure variants (for example the vanilla nether has a structure set with both the bastion and fortress).

data/example/worldgen/structure_set/tall_towers.json

{
  "structures": [
    {
      "structure": "example:tall_tower",
      "weight": 1
    }
  ],
  "placement": {
    "type": "minecraft:random_spread",
    "spacing": 5,
    "separation": 2,
    "salt": 1646207470
  }
}

Structure sets are made up of two parts:

  • structures: A weighted list of configured structure features (see next step).
  • placement: The structure placement
    • placement.type: Either random_spread or concentric_rings. The latter is only used by strongholds in vanilla, so we'll focus on random_spread
    • placement.spacing: Roughly the average distance in chunks between two structures in this set.
    • placement.separation: The minimum distance in chunks. Needs to be smaller than spacing.
    • placement.salt: A random number that is combined with the world seed. Always use a different random number for different structures, otherwise they will end up being placed in the same spot!

When using the random_spread placement type, it generates structures grid-based. Here's an illustration of the above example with spacing = 5, separation = 2. There will be one structure attempt in each 5x5 chunk grid, and only at X a structure can spawn.

.............
..XXX..XXX..X
..XXX..XXX..X
..XXX..XXX..X
.............
.............
..XXX..XXX..X
..XXX..XXX..X
..XXX..XXX..X

The configured structure

The configured structure (feature) is the ID you will be able to reference in /locate.

data/example/worldgen/configured_structure_feature/tall_tower.json

{
  "type": "minecraft:village",
  "config": {
    "start_pool": "example:tall_tower",
    "size": 1
  },
  "biomes": "#minecraft:has_structure/mineshaft",
  "adapt_noise": true,
  "spawn_overrides": {}
}

Let's go over all the fields.

  • type: This is the structure feature type. When making custom structures, you almost always want to set this to village or bastion_remnant. There is one important difference between the two: using village will spawn the structure on the surface, while bastion_remnant will always spawn the structure at Y=33.
  • config.start_pool: This is a reference to the template pool (see next step).
  • config.size: This is a number between 1 and 7. This is important if your structure uses jigsaw. In this simple example, we'll leave it at 1.
  • biomes: This controls in which biomes this structure is allowed to generate. You can give it any biome tag, a list of biomes, or a single biome. For easy testing we'll set it to every biome with mineshafts.
  • adapt_noise: When true, it will add extra terrain below each structure piece.
  • spawn_overrides: This field allows you to override mob spawning inside the structure bounding boxes. This is currently outside the scope of this guide, but you could look at the vanilla monument structure feature as a reference.

The template pool

The template pool defines how to build up your structure. Since we're not using jigsaw, this is quite straight forward: we want to place a single NBT structure.

data/example/worldgen/template_pool/tall_tower.json

{
  "name": "example:tall_tower",
  "fallback": "minecraft:empty",
  "elements": [
    {
      "weight": 1,
      "element": {
        "element_type": "minecraft:single_pool_element",
        "location": "example:stone_tall_tower",
        "projection": "rigid",
        "processors": "minecraft:empty"
      }
    }
  ]
}

Again, let's go over the fields:

  • name: For some reason, the game needs the name of this template pool. Just set this to the ID of the template pool.
  • fallback: Used in jigsaw structures, but we can simply use minecraft:empty.
  • elements: A weighted list of pool elements to choose from. You can add multiple elements here if your structure has different starting structure files. For example in vanilla a plains village has different town center variants.
    • element_type: The type of this element. One of empty_pool_element (placing nothing), feature_pool_element (placing a placed feature), legacy_single_pool_element, list_pool_element, and single_pool_element (placing a structure).
    • location: The path to the structure NBT file. (see next step).
    • projection: Either rigid or terrain_matching. Use the latter if you want the structure to match the terrain, just like village paths do.
    • processors: If you want to run any processor lists, this is quite complicated so again we'll skip this for now and set it to minecraft:empty.

The structure

Creating the structure NBT file is entirely up to you. In this example I'm going to use a tower structure from Gamemode 4.

data/example/structures/stone_tall_tower.nbt

(binary NBT file) Download the structure from this example

Result

stone tower close-up a bunch of towers in a forest

@0x000006
Copy link

How can i make the structure generate in the end? (like end cities)

@Ohponopono
Copy link

Thanks a lot

@mageowl
Copy link

mageowl commented Mar 1, 2022

How can i make the structure generate in the end? (like end cities)

I think you would put a biome that generates in the end for the biome tag

@misode
Copy link
Author

misode commented Mar 1, 2022

How can i make the structure generate in the end? (like end cities)

@0x000006 Make a biome tag that contains the end biomes that you want, and set it as the biomes field in the configured structure feature.

@RaxoDev
Copy link

RaxoDev commented Mar 1, 2022

@ianmhuff I am probably wrong and I haven't tested this but try setting your spacing low and separation high. I think that by having separation high you prevent anything from spawning near it.

@fishh333
Copy link

fishh333 commented Mar 1, 2022

I was pretty sure that I did everything correctly but the pack wont validate in the world creation menu. I originally wanted it toonly generate in the plains biome, but I dont know how to specify that yet, so I used the "#minecraft:has_structure/mineshaft" from the example. would anyone be so kind and look over it?
(theres also other stuff in the pack but I dont think that it fucks with anything)

https://www.mediafire.com/file/h76206qwv5yallx/items%252B.zip/file

@RaxoDev
Copy link

RaxoDev commented Mar 1, 2022

I originally wanted it toonly generate in the plains biome, but I dont know how to specify that yet, so I used the "#minecraft:has_structure/mineshaft" from the example.

@fishh333 I think you can just change it to "minecraft:plains" without the hash.
If you do /locatebiome in game you get a list of all the biomes and biometags!

@0x000006
Copy link

0x000006 commented Mar 1, 2022

I think you would put a biome that generates in the end for the biome tag

@0x000006 Make a biome tag that contains the end biomes that you want, and set it as the biomes field in the configured structure feature.

Thanks for the answers!

@fishh333
Copy link

fishh333 commented Mar 1, 2022

Good to know, thank you!
But as I said, I didn't play with that yet, so that doesn't really solve my problem. Something in the code is wrong, so the world won't let me put the datapack in it and Idk what it is

@PyxGames
Copy link

PyxGames commented Mar 2, 2022

Hello I have a question how do I add Multiple structures to generate

@fishh333
Copy link

fishh333 commented Mar 2, 2022

Hello I have a question how do I add Multiple structures tI'm pretty sure that you just need to keep adding files to the different folders in the worldgen folder and corresponding nbt files in the structure folder.
but thats only for single structures. for complex ones with random rooms and shit youll need to use jigsaw blocks

@Sponssteel
Copy link

any way to put your custom structure in caves only?

@PyxGames
Copy link

PyxGames commented Mar 5, 2022

Does this also work on servers?

@MattDraftGH
Copy link

What is the proper syntax for making the structure generate in multiple biomes?

@Gamingbarn The configured structure feature has a biomes field, which can reference a biome tag (in tags/worldgen/biome)
could you give an example of what's in the biome json file

@Gamingbarn
Copy link

Gamingbarn commented Mar 6, 2022

@Gamingbarn The configured structure feature has a biomes field, which can reference a biome tag (in tags/worldgen/biome)
could you give an example of what's in the biome json file
@MattDraftGH
{ "values":[ "#minecraft:has_structure/village_plains", "#minecraft:has_structure/village_desert" ] }
Like this

@mcneds
Copy link

mcneds commented Mar 13, 2022

I can't get mine to work, it says failed to validate datapack, here is my log and the namespace I have everything in. help would be appreciatedFailed to validate datapack java.util.concurrent.CompletionException: com.google.gson.JsonParseException: Error loading registry data: Not a JSON object: null at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:332) at java.base/java.util.concurrent.CompletableFuture.uniAcceptNow(CompletableFuture.java:747) at java.base/java.util.concurrent.CompletableFuture.uniAcceptStage(CompletableFuture.java:735) at java.base/java.util.concurrent.CompletableFuture.thenAcceptAsync(CompletableFuture.java:2191) at net.minecraft.class_525.method_29682(class_525.java:490) at net.minecraft.class_5369.method_29642(class_5369.java:49) at net.minecraft.class_5375.method_25419(class_5375.java:80) at net.minecraft.class_5375.method_29982(class_5375.java:97) at net.minecraft.class_4185.method_25306(class_4185.java:40) at net.minecraft.class_4264.method_25348(class_4264.java:16) at net.minecraft.class_339.method_25402(class_339.java:121) at net.minecraft.class_4069.method_25402(class_4069.java:27) at net.minecraft.class_312.method_1611(class_312.java:94) at net.minecraft.class_437.method_25412(class_437.java:492) at net.minecraft.class_312.method_1601(class_312.java:94) at net.minecraft.class_312.method_22686(class_312.java:165) at net.minecraft.class_1255.execute(class_1255.java:103) at net.minecraft.class_312.method_22684(class_312.java:165) at org.lwjgl.glfw.GLFWMouseButtonCallbackI.callback(GLFWMouseButtonCallbackI.java:36) at org.lwjgl.system.JNI.invokeV(Native Method) at org.lwjgl.glfw.GLFW.glfwWaitEventsTimeout(GLFW.java:3174) at com.mojang.blaze3d.systems.RenderSystem.limitDisplayFPS(RenderSystem.java:222) at net.minecraft.class_310.method_1523(class_310.java:1150) at net.minecraft.class_310.method_1514(class_310.java:737) at net.minecraft.client.main.Main.main(Main.java:236) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at net.fabricmc.loader.impl.game.minecraft.MinecraftGameProvider.launch(MinecraftGameProvider.java:416) at net.fabricmc.loader.impl.launch.knot.Knot.launch(Knot.java:77) at net.fabricmc.loader.impl.launch.knot.KnotClient.main(KnotClient.java:23) Caused by: com.google.gson.JsonParseException: Error loading registry data: Not a JSON object: null at net.minecraft.class_5455.method_34849(class_5455.java:296) at java.base/java.util.Optional.ifPresent(Optional.java:178) at net.minecraft.class_5455.method_30526(class_5455.java:296) at net.minecraft.class_5455.method_30519(class_5455.java:290) at net.minecraft.class_6903.method_40413(class_6903.java:32) at net.minecraft.class_6903.method_40412(class_6903.java:25) at net.minecraft.class_525.method_40209(class_525.java:482) at net.minecraft.class_6904.method_40431(class_6904.java:40) at net.minecraft.class_525.method_29682(class_525.java:474) ... 27 more

And here is all of my code in worldgen:

structure_set/minimonument:
{
"structures": [
{
"structure": "mobstructures:mini_monument",
"weight": 1
}
],
"placement": {
"spread_type": "triangular",
"salt": 10387313,
"spacing": 32,
"separation": 5,
"type": "minecraft:random_spread"
}
}

structures/mini_monument
mini_monument.nbt

template_pool/mini_monument
{
"name": "mobstructures:mini_monument",
"fallback": "minecraft:empty",
"elements": [
{
"weight": 1,
"element": {
"element_type": "minecraft:single_pool_element",
"location": "mobstructures:mini_monument",
"projection": "rigid",
"processors": "minecraft:empty"
}
}
]
}

configured_structure_feature/mini_monument
{
"config": {
"start_pool": "mobstructures:mini_monument",
"size": 7
},
"biomes": "minecraft:plains",
"spawn_overrides": {
"monster": {
"bounding_box": "full",
"spawns": [
{
"type": "minecraft:guardian",
"weight": 1,
"minCount": 2,
"maxCount": 4
}
]
},
"axolotls": {
"bounding_box": "full",
"spawns": []
},
"underground_water_creature": {
"bounding_box": "full",
"spawns": []
}
},
"type": "minecraft:village"
}

IDK WHY ITS DOING THIS MSVSCODE ISNT RETURNING ANY ERRORS BESIDES ME PUTTING PACK.MCMETA TO 9 FOR 1.18.2 AAAAA

@mcneds
Copy link

mcneds commented Mar 15, 2022

I can't get mine to work, it says failed to validate datapack, here is my log and the namespace I have everything in. help would be appreciatedFailed to validate datapack java.util.concurrent.CompletionException: com.google.gson.JsonParseException: Error loading registry data: Not a JSON object: null at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:332) at java.base/java.util.concurrent.CompletableFuture.uniAcceptNow(CompletableFuture.java:747) at java.base/java.util.concurrent.CompletableFuture.uniAcceptStage(CompletableFuture.java:735) at java.base/java.util.concurrent.CompletableFuture.thenAcceptAsync(CompletableFuture.java:2191) at net.minecraft.class_525.method_29682(class_525.java:490) at net.minecraft.class_5369.method_29642(class_5369.java:49) at net.minecraft.class_5375.method_25419(class_5375.java:80) at net.minecraft.class_5375.method_29982(class_5375.java:97) at net.minecraft.class_4185.method_25306(class_4185.java:40) at net.minecraft.class_4264.method_25348(class_4264.java:16) at net.minecraft.class_339.method_25402(class_339.java:121) at net.minecraft.class_4069.method_25402(class_4069.java:27) at net.minecraft.class_312.method_1611(class_312.java:94) at net.minecraft.class_437.method_25412(class_437.java:492) at net.minecraft.class_312.method_1601(class_312.java:94) at net.minecraft.class_312.method_22686(class_312.java:165) at net.minecraft.class_1255.execute(class_1255.java:103) at net.minecraft.class_312.method_22684(class_312.java:165) at org.lwjgl.glfw.GLFWMouseButtonCallbackI.callback(GLFWMouseButtonCallbackI.java:36) at org.lwjgl.system.JNI.invokeV(Native Method) at org.lwjgl.glfw.GLFW.glfwWaitEventsTimeout(GLFW.java:3174) at com.mojang.blaze3d.systems.RenderSystem.limitDisplayFPS(RenderSystem.java:222) at net.minecraft.class_310.method_1523(class_310.java:1150) at net.minecraft.class_310.method_1514(class_310.java:737) at net.minecraft.client.main.Main.main(Main.java:236) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at net.fabricmc.loader.impl.game.minecraft.MinecraftGameProvider.launch(MinecraftGameProvider.java:416) at net.fabricmc.loader.impl.launch.knot.Knot.launch(Knot.java:77) at net.fabricmc.loader.impl.launch.knot.KnotClient.main(KnotClient.java:23) Caused by: com.google.gson.JsonParseException: Error loading registry data: Not a JSON object: null at net.minecraft.class_5455.method_34849(class_5455.java:296) at java.base/java.util.Optional.ifPresent(Optional.java:178) at net.minecraft.class_5455.method_30526(class_5455.java:296) at net.minecraft.class_5455.method_30519(class_5455.java:290) at net.minecraft.class_6903.method_40413(class_6903.java:32) at net.minecraft.class_6903.method_40412(class_6903.java:25) at net.minecraft.class_525.method_40209(class_525.java:482) at net.minecraft.class_6904.method_40431(class_6904.java:40) at net.minecraft.class_525.method_29682(class_525.java:474) ... 27 more

And here is all of my code in worldgen:

structure_set/minimonument: { "structures": [ { "structure": "mobstructures:mini_monument", "weight": 1 } ], "placement": { "spread_type": "triangular", "salt": 10387313, "spacing": 32, "separation": 5, "type": "minecraft:random_spread" } }

structures/mini_monument mini_monument.nbt

template_pool/mini_monument { "name": "mobstructures:mini_monument", "fallback": "minecraft:empty", "elements": [ { "weight": 1, "element": { "element_type": "minecraft:single_pool_element", "location": "mobstructures:mini_monument", "projection": "rigid", "processors": "minecraft:empty" } } ] }

configured_structure_feature/mini_monument { "config": { "start_pool": "mobstructures:mini_monument", "size": 7 }, "biomes": "minecraft:plains", "spawn_overrides": { "monster": { "bounding_box": "full", "spawns": [ { "type": "minecraft:guardian", "weight": 1, "minCount": 2, "maxCount": 4 } ] }, "axolotls": { "bounding_box": "full", "spawns": [] }, "underground_water_creature": { "bounding_box": "full", "spawns": [] } }, "type": "minecraft:village" }

IDK WHY ITS DOING THIS MSVSCODE ISNT RETURNING ANY ERRORS BESIDES ME PUTTING PACK.MCMETA TO 9 FOR 1.18.2 AAAAA

i got it to sorta work, but now just nothing generates when i tp to it

YYYYYYYYYYYYYYY

@misode
Copy link
Author

misode commented Mar 15, 2022

@mcneds I answered this on discord, but for anyone else wondering. If you want structures in a flat world, you need to specify the structure_overrides field in the dimension. For example:

{
  "type": "minecraft:overworld",
  "generator": {
    "type": "minecraft:flat",
    "settings": {
      "biome": "minecraft:plains",
      "layers": [
        {
          "block": "minecraft:grass_block",
          "height": 1
        }
      ],
      "structure_overrides": [
        "example:tall_towers"
      ]
    }
  }
}

@wolly01
Copy link

wolly01 commented Mar 24, 2022

Thanks for the tutorial, super helpful! Are you planning to produce an example for 1.19, as settings are changing somewhat?

@ZergHeureux
Copy link

Very nice tuto ! However when im loading my map (in a custom dimension) my stuctures never generates ? the "/locate" point on weird sphere... Im quit new sorry but any idea from where this is coming from ?
i tried adding structure_overrides in generator>biome_source>biomes>, unfortunatly its still not working...

@mcneds
Copy link

mcneds commented Mar 26, 2022

Very nice tuto ! However when im loading my map (in a custom dimension) my stuctures never generates ? the "/locate" point on weird sphere... Im quit new sorry but any idea from where this is coming from ?
i tried adding structure_overrides in generator>biome_source>biomes>, unfortunatly its still not working...

If it doesn’t autocomplete when typing ur namespace u did one of the structure files wrong in some random way, (ie referencing wrong file name like I did the first time) or you need to add it to the biome file of your dimension. Another thing is that structure override is not a separate file it is part of the dimension json

@RobotLuca37
Copy link

I have a question. Im trying to make a datapack with a custom dimension for my smp, and me and my friends made a structure for it to spawn. I have everything done, and it works. But is there any way to put the structure a couple of blocks in the ground. Because below the structure, there is redstone, and we covered this up with black concrete. But the black concrete spawns above the ground. How can i put the black concrete with the redstone below the ground

@Gamingbarn
Copy link

Gamingbarn commented Apr 3, 2022

What do you need to change for jigsaw blocks to work correctly?
Edit: Nevermind! I got it to work.

@Gamingbarn
Copy link

Gamingbarn commented Apr 3, 2022

I have a question. Im trying to make a datapack with a custom dimension for my smp, and me and my friends made a structure for it to spawn. I have everything done, and it works. But is there any way to put the structure a couple of blocks in the ground. Because below the structure, there is redstone, and we covered this up with black concrete. But the black concrete spawns above the ground. How can i put the black concrete with the redstone below the ground

You'll have to use jigsaws for that.
https://gist.github.com/GentlemanRevvnar/387f9ee28613715c187a36dbc1dff35d
I follow this tutorial, it's very helpful.
@RobotLuca37

@Syhix
Copy link

Syhix commented Apr 6, 2022

Tutorial on version 1.19 planned?

@kittech0
Copy link

kittech0 commented Apr 7, 2022

how could i generate structures under water?

@misode
Copy link
Author

misode commented Apr 7, 2022

how could i generate structures under water?

@JustFoxx You can do this, but only in the 1.19 snapshots. There is a field project_start_to_heightmap that allows you to configure the heightmap that the structure should spawn at, one option is OCEAN_FLOOR_WG. For example: https://misode.github.io/worldgen/structure/?share=3ac3e684-b360-413d-8d9b-3be17f106fdc

@Syhix
Copy link

Syhix commented Apr 12, 2022

When I try to spawn a cat with spawn_overrides it doesn't work. This is exactly the same configuration as swamp_hut.

"spawn_overrides": {
        "creature": {
            "bounding_box": "piece",
            "spawns": [
                {
                    "type": "minecraft:cat",
                    "weight": 1,
                    "minCount": 1,
                    "maxCount": 1
                }
            ]
        }
    }

@rzerdik
Copy link

rzerdik commented May 5, 2022

I was pretty sure that I did everything correctly but the pack wont validate in the world creation menu. I originally wanted it toonly generate in the plains biome, but I dont know how to specify that yet, so I used the "#minecraft:has_structure/mineshaft" from the example. would anyone be so kind and look over it? (theres also other stuff in the pack but I dont think that it fucks with anything)

https://www.mediafire.com/file/h76206qwv5yallx/items%252B.zip/file

your zip file contains also folder with the same name as the zip, it's because you ziped the folder, not it's contents.
you have this structure:

.zip

  • item+
    • data
    • pack.mcmeta

instead, it should be:

.zip

  • data
  • pack.mcmeta

@fishh333
Copy link

fishh333 commented May 5, 2022

Thanks but I only zipped it at all so I could upload it. I did the testing without ever tipping it and it still failed to validate

PS: Also validating isn't the same as showing up in the datapack selection

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment