A breakdown of a CoFH World generation entry.

This information is specific to the 1.12.2 version of CoFH World. Some of this is portable to older versions of the mod, but I cannot promise how much. And in July 2020, the new versions of thermal/CoFH mods aren't out yet, so it's hard to anticipate how applicable this will be in the future versions.

So you wanna generate ores, and everybody seems unable to shut up about CoFH World. But oh my gosh your brain is melting. Well, never fear, I'm here to waste your time and do a bad job of explaining its format. So get ready!

https://teamcofh.com/docs/1.12/cofh-world/ are the official documents of the mod, but are written in a way that assumes you are comfortable building a json file from scratch, whole cloth. And as optimistic and cheery as that assumption is, that doesn't even describe me, and I've been using this mod for years. So, I'm gonna attack the teaching of this mod with a more direct approach, by showing an example, and walking through it step by step.

First off, lets show a complete, valid CoFH World json with one ore generation entry in it.

{
	"priority": 1000000000000,
	"populate": {
		"cool_ore_entry_name": {
			"distribution": "uniform",
			"generator": {
				"block": [
					  {
						  "name": "thermalfoundation:ore",
						  "properties": {
  							"type": "silver"
	  					},
		  				"weight": 80
			  		},
				  	{
  						"name": "thermalfoundation:ore",
	  					"properties": {
		  					"type": "lead"
			  			},
				  		"weight": 10
					  }
				  ],
				"material": [
					"earthworks:block_slate_green",
					"earthworks:block_slate",
					"earthworks:block_slate_purple",
					"earthworks:block_chalk",
					"minecraft:stone",
					"quark:marble",
					"quark:limestone",
					"rustic:slate"
				],
				"cluster-size": 9
			},
      			"chunk-chance": 2,
			"cluster-count": 7,
			"min-height": 0,
			"max-height": 64,
			"retrogen": false,
			"biome": {
				"restriction": "whitelist",
				"value": [
					{
						"type": "dictionary",
						"entry": [
							"MOUNTAIN",
							"MESA"
						]
					}
				]
			},
			"dimension": {
				"restriction": "blacklist",
				"value": [
					-1,
					1
				]
			}
		}
	}
}

Oh god that is a nightmare and it's huge what was I thinking this is so much. But we can beat this!

Let's break it down bit by bit.

"priority": 1000000000000,

This bit is simple: It tells CoFH World which order to run its files in. Higher numbers = More firster.

"populate": {
...
}

The populate object surrounds all of your world-generation entries. It's basically just a box that has entries in it. We're not to worried about this. That closing curly-brace is the 2nd to last one in the file. The populate object encompasses nearly everything.

"cool_ore_entry_name": {
...
}

This is the name of, and the beginning of the object that encompasses the specific generation entry we're creating! In a more typical json, you'll have multiple such entries, each with a unique name. Generation entry names have to be unique across your whole modpack, not just within the files. It's usually useful to give your entry a name that describes what it is. cool_ore_entry_name works, but is not terribly helpful to you. For this entry, silver_with_lead_in_it or something descriptive would be better. I don't actually know the naming rules, but keeping it all lowercase, no spaces, has always worked for me.

"distribution": "uniform",

This describes how the ore is going to be placed in the world. uniform is "an equal chance to be at any x y or z coordinate in this entry's range". There are other options, detailed here: https://teamcofh.com/docs/1.12/cofh-world/world-generator-configuration/distribution-types/ , but uniform is usually the one you want for "boring old normal ores". The other options exist though, if you wanna get fancy.

"generator": {
...
},

This just encompasses the section of the entry that details what blocks are going to be placed in the world, and inside of which blocks they will be placed. This is one of the meatier sections of the entry, so get ready for it.

				"block": [
					  {
						  "name": "thermalfoundation:ore",
						  "properties": {
  							"type": "silver"
	  					},
		  				"weight": 80
			  		},
				  	{
  						"name": "thermalfoundation:ore",
	  					"properties": {
		  					"type": "lead"
			  			},
				  		"weight": 10
					  }
				  ]

Okay, so this is where things get a touch intense. A block object defines a block, or, in this case, an array of blocks (inside a pair of [] brackets), that will be generated. If it is a list of blocks, for each block generated, one of the blocks on the list will be randomly selected.

These blocks are ores from thermal foundation! Let's break down one of the entries:

"name": "thermalfoundation:ore",

The name is the modid:block_id of the block you want to generate. You can see this by looking at either the item's tooltip in your inventory with F3+H Advanced Tooltips enabled, or by opening the F3 debug info and looking at it in-world. (The info is on the middle right of the screen, roughly)

						  "properties": {
  							"type": "silver"
	  					},

For blocks with multiple sub-blocks based on different metadata, like thermal's ores, or minecraft's wool, you will need to know their properties : this information is ALSO available from turning on the F3 debug screen and looking at it in world. In this case, the block has one property, named type, and the type property has the value silver. Property names aren't always named type. I've seen all kinds of stuff, including varient, mispelling and all. Use the property name as it appears in the f3 menu, and the name for the property, also as it appears.

"weight": 80

This number just represents "How likely this block will be randomly selected". Since the 2 values in this block entry are 80 and 10, that means 8/9 of the time, the silver block will be selected, and 1/9 of the time the lead block will be selected.

},

This closes up our entry for the silver block. If there's no more blocks in your block entry, ditch the comma. But since we have the lead entry coming up next, we have a comma here. .json files hate trailing commas on lists.

				"material": [
					"earthworks:block_slate_green",
					"earthworks:block_slate",
					"earthworks:block_slate_purple",
					"earthworks:block_chalk",
					"minecraft:stone",
					"quark:marble",
					"quark:limestone",
					"rustic:slate"
				],

This is our material entry of the generator object! It is a list of blocks that the blocks in the block entry will be generated in! You can type any block you want here! In this example, it's a bunch of stone types, to make sure that the stone types generating in the world don't "block" the ore from generating. If you put minecraft:air on this list, the ore will generate in floating clusters in mid-air. minecraft:water and you'll potentially see it in lakes, rivers, and oceans! You can get properly jiggy with this, if you want.

"cluster-size": 9

This is a simple little bit of info: How "big" is the blob of blocks generated by this generator entry? At lower values (10 and under) it's approximately "how many blocks in each ore vein", but, as the number gets larger, the number of blocks actually generated grows even quicker. So a cluster-size of 16 results in clusters with 20 - 24 blocks. And bigger numbers result in the number of blocks being even-higher-than the number you typed. Typical "vanilla minecraft" sized veins are in the 4 to 9 range, with coal being a notable exception for having much larger veins.

"chunk-chance": 2,

This is the chance, each chunk, that the mod will even try to generate this entry. It's a 1/n chance, so in this case, 1/2, or one half of all chunks. A value of 1 would be 1/1 chunks, or all of them.

"cluster-count": 7,

Cluster count is a bit simpler: When the entry tries to generate in a chunk, how many times will it generate? For perspective, vanilla Iron generates 20 times per chunk, and diamonds and lapis generate once per chunk.

			"min-height": 0,
			"max-height": 64,

This one is pretty straightforward too: These are the Y level ranges within which the feature will be generated. For perspective, vanilla Iron generates from 0 to 64, and Diamonds from 0 to 16.

"retrogen": false,

This turns on or off whether this entry will be retroactively generated into already-explored terrain, when the config.cfg setting for B:RetroactiveGeneration= is set to true. For a modpack you're making, you probably don't need this true, but, if you update your pack and add new ore generation later on, this might be relevant to your interests.

			"biome": {
				"restriction": "whitelist",
				"value": [
					{
						"type": "dictionary",
						"entry": [
							"MOUNTAIN",
							"MESA"
						]
					}
				]
			},

A biome restriction entry! This can look a few different ways, depending on what you want. This particular entry is a whitelist of the forge biome dictionary tag of MOUNTAIN, meaning the feature will try to generate in biomes that have that biome dictionary tag! The list of tags can have multiple entries, or just one. A list of these tags can be found at this very very official pastebin link: https://pastebin.com/raw/0NH383ps

But let's look at the other ways this section could look:

"biome": "all",

This is probably what you will put on 95% of your ore entries! It lets the feature generate in any biome at all!

			"biome": {
				"restriction": "whitelist",
				"value": [
					{
						"type": "id",
						"entry": [
							"minecraft:mesa",
							"minecraft:mesa_rock"
						]
					}
				]
			},

You can also use the biome's registry ID to specify. Maybe you don't want ALL mesas, maybe you only want 2 very super specific mesa biomes. The id type is here for you. Again, it can be a whole list, or just one entry. To get a list of the biome registry names in your modpack, I reccomend the mod Tell Me, which has commands to dump a wide variety of info about your minecraft modpack to text files: https://www.curseforge.com/minecraft/mc-mods/tellme

			"dimension": {
				"restriction": "blacklist",
				"value": [
					-1,
					1
				]
			}

Dimensions! We can be super specific about what dimensions it spawns in! It can be a blacklist or whitelist, and you just use the numerical dimension ID to be specific. The value can be a whole list, or just one number. If you need to know the dimension ID, https://www.curseforge.com/minecraft/mc-mods/tellme can get you that info too, as well as the /forge dimensions command.

"dimension": "all"

Much like the biome restriction, we can just use all if we want it to generate in all dimensions!

}

And you close up the whole cool_ore_entry_name with a closing brace, and, if it's the last one in the file, don't put a comma, otherwise, do. When building .json files, I firmly reccomend using a "good" text editor that has syntax highlighting. Notepad++ (https://notepad-plus-plus.org/downloads/) Is a fairly simple one that's not too alien for a beginner, while still being a huge step up from windows notepad. Coolcat programmer-types will say it's lame and that they've got all kinds of better editors to suggest, and they're probably right. But I'm not them!

And, once you're done doing surgery on your .json file, a tool like https://jsonlint.com/ Can doublecheck that you didn't screw up your {}, [], or leave a dangling , hanging around somewhere or fail to put "" marks around an object / parameter name.

Generally, my approach to creating ore entries is to take one of the default CoFH World files (like 00_minecraft.json) and make a copy of it, and do science and surgery on the copy until it's been transformed to do the ores I want done.

Finally: CoFH World can do a lot more than put ores in rocks, as you probably guessed if you clicked on the link to the official documents at any time. This is a lovely reddit thread provided by worldgeneration maestro Fluke, with examples of some of the more specialized or exotic generation methods the mod offers: https://www.reddit.com/r/feedthebeast/comments/818y32/the_cofh_word_cookbook_a_huge_list_of_examples/ . The possibilities get pretty wild, and having an example to work from and pick apart to understand really helps.

Hopefully this all helped!