tutorial:ores
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
tutorial:ores [2020/02/26 15:23] – Change to new format supercoder79 | tutorial:ores [2023/12/18 00:52] – solidblock | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Adding Ores to the World ====== | + | If you are looking |
- | A lot of mods add their own ores, and you'll need a way to place them in existing biomes | + | |
- | * Iterate over the biome registry to add your ores to existing biomes. | + | |
- | * Use the RegistryEntryAddedCallback to ensure your ore gets added into any biomes added by mods. | + | |
- | We' | + | ====== Generating Custom Ores [1.19.3+] ====== |
+ | A lot of mods add their own ores, and you' | ||
+ | * Make worldgen Features in JSON that define how and where the ore block is spawned. | ||
+ | * Use [[https:// | ||
- | ==== Adding ores to a biome ==== | + | To simplify, we use vanilla end rod as ore, because it can be easily found and seen underground in spectator mode. |
- | First we need to create | + | ==== Adding to the overworld biomes ==== |
+ | In this section, our goal will be spawning the ore in the overworld. | ||
+ | |||
+ | First, create two new JSON files in your mod's data directory: | ||
+ | |||
+ | <code JavaScript src\main\resources\data\tutorial\worldgen\configured_feature\ore_custom.json> | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | }, | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | }, | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | }, | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | This Configured Feature tells the game the size of the ore veins, what fraction of the ore blocks should be removed due to air exposure, and, importantly, | ||
+ | |||
+ | <code JavaScript src\main\resources\data\tutorial\worldgen\placed_feature\ore_custom.json> | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | }, | ||
+ | { | ||
+ | " | ||
+ | }, | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | }, | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | } | ||
+ | }, | ||
+ | { | ||
+ | " | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | This Placed Feature tells the game how many ore veins to place in a chunk, what shape the ore veins are placed in, and at what y-levels the ore veins are placed in. Note that the first line of the Placed Feature references the Configured Feature that was created a moment ago. | ||
+ | |||
+ | Writing these JSON files by hand is strenuous and inefficient. Note that the bulk of the work can be skipped by using tools like this [[https:// | ||
+ | |||
+ | Now that our data is created, it's time for code! Thanks to the changes in Minecraft 1.19.3, adding ore to world generation requires much less Java code. All we need to do is register the feature, | ||
+ | |||
+ | First, at the class level, let's create a new '' | ||
+ | |||
+ | <code Java src/ | ||
+ | public class ExampleMod implements ModInitializer { | ||
+ | |||
+ | public static final RegistryKey< | ||
+ | |||
+ | @Override | ||
+ | public void onInitialize() { | ||
+ | |||
+ | //Your other code here... | ||
- | <code java [enable_line_numbers=" | ||
- | private void handleBiome(Biome biome) { | ||
- | if(biome.getCategory() != Biome.Category.NETHER && biome.getCategory() != Biome.Category.THEEND) { | ||
- | biome.addFeature( | ||
- | GenerationStep.Feature.UNDERGROUND_ORES, | ||
- | Feature.ORE.configure( | ||
- | new OreFeatureConfig( | ||
- | OreFeatureConfig.Target.NATURAL_STONE, | ||
- | Blocks.NETHER_QUARTZ_ORE.getDefaultState(), | ||
- | 8 //Ore vein size | ||
- | | ||
- | Decorator.COUNT_RANGE.configure(new RangeDecoratorConfig( | ||
- | 8, //Number of veins per chunk | ||
- | 0, //Bottom Offset | ||
- | 0, //Min y level | ||
- | 64 //Max y level | ||
- | )))); | ||
} | } | ||
} | } | ||
</ | </ | ||
- | This method adds your ore to the overworld, with the provided spawn settings. Feel free to change | + | Notice 2 things: |
+ | * '' | ||
+ | * our identifier uses the name " | ||
- | ==== Iterating Biome Registry ==== | + | Now to add the Feature to a biome: |
- | What we need to do next is process all biomes that have been registered as well as all biomes that will be registered in the future (as added by other mods). We first iterate over the current registry, then register a listener that will be called for future additions. | + | <code Java src/ |
- | <code java [enable_line_numbers=" | ||
@Override | @Override | ||
- | public void onInitialize() { | + | public void onInitialize() { |
- | //Loop over existing biomes | + | |
- | Registry.BIOME.forEach(this:: | + | //Your other code here... |
+ | BiomeModifications.addFeature(BiomeSelectors.foundInOverworld(), GenerationStep.Feature.UNDERGROUND_ORES, | ||
+ | } | ||
- | //Listen for other biomes being registered | + | </code> |
- | RegistryEntryAddedCallback.event(Registry.BIOME).register((i, identifier, biome) -> handleBiome(biome)); | + | |
+ | ==== Testing ==== | ||
+ | |||
+ | To test your new ore, generate a new world. You can also open existing world but have to go to new chunks. In this example of end rod, the ores can be directly seen underground in spectator mode. | ||
+ | |||
+ | ==== Adding to the Nether or End ==== | ||
+ | |||
+ | Adding your ore to the other dimensions is very similar to adding ore to the Overworld. This section assumes you have already created an ore block for the Nether and End. | ||
+ | |||
+ | As with the Overworld, we begin with the JSON files. Using vanilla' | ||
+ | |||
+ | <code JavaScript src/ | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | }, | ||
+ | { | ||
+ | " | ||
+ | }, | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | }, | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | } | ||
+ | }, | ||
+ | { | ||
+ | " | ||
+ | } | ||
+ | ] | ||
} | } | ||
</ | </ | ||
- | ==== Conclusion ==== | + | Notice how the only real difference is that the height ranges are described differently, |
- | You should see quartz ore spawning | + | |
- | {{https://i.imgur.com/ | + | As before, we add a Configured Feature as well. |
+ | <code JavaScript src/ | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | }, | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | In the Configured Feature, remember that the '' | ||
+ | |||
+ | Finally, back in our Java code, right after our other BiomeModification line, | ||
+ | |||
+ | <code Java src/ | ||
+ | BiomeModifications.addFeature(BiomeSelectors.foundInNether(), | ||
+ | </ | ||
+ | |||
+ | Extrapolating this process to add ore to the End is left as an exercise for the reader. | ||
+ | |||
+ | ====== Generating Custom Ores [1.18.2 / 1.19.2] ====== | ||
+ | A lot of mods add their own ores, and you'll need a way to place them in existing biomes for players to find. In this tutorial, we'll look at adding ores to existing biomes. There are 2 steps that are required to add ores to biomes. | ||
+ | * Make a ConfiguredFeature. This defines how your ore block is spawned. | ||
+ | * Use [[https:// | ||
+ | |||
+ | Note that the Biome Modification API is marked as experimental. | ||
+ | If the API doesn' | ||
+ | |||
+ | We'll assume you've already created your own ore block at this point. Wool block will serve as our replacement throughout this tutorial. Replace references to wool with your ore when appropriate. | ||
+ | |||
+ | ==== Adding to the overworld biomes ==== | ||
+ | In this section, our goal will be spawning the ore in the overworld. | ||
+ | |||
+ | We need to create a ConfiguredFeature. | ||
+ | Make sure to register your ConfiguredFeature at '' | ||
+ | Feel free to change the values to suit your mod. | ||
+ | |||
+ | <code java> | ||
+ | public class ExampleMod implements ModInitializer { | ||
+ | private static ConfiguredFeature<?, | ||
+ | (Feature.ORE, | ||
+ | OreConfiguredFeatures.STONE_ORE_REPLACEABLES, | ||
+ | Blocks.WHITE_WOOL.getDefaultState(), | ||
+ | 9)); // vein size | ||
+ | |||
+ | public static PlacedFeature OVERWORLD_WOOL_ORE_PLACED_FEATURE = new PlacedFeature( | ||
+ | RegistryEntry.of(OVERWORLD_WOOL_ORE_CONFIGURED_FEATURE), | ||
+ | Arrays.asList( | ||
+ | CountPlacementModifier.of(20), | ||
+ | SquarePlacementModifier.of(), | ||
+ | HeightRangePlacementModifier.uniform(YOffset.getBottom(), | ||
+ | )); // height | ||
+ | |||
+ | @Override | ||
+ | public void onInitialize() { | ||
+ | Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, | ||
+ | new Identifier(" | ||
+ | Registry.register(BuiltinRegistries.PLACED_FEATURE, | ||
+ | OVERWORLD_WOOL_ORE_PLACED_FEATURE); | ||
+ | BiomeModifications.addFeature(BiomeSelectors.foundInOverworld(), | ||
+ | RegistryKey.of(Registry.PLACED_FEATURE_KEY, | ||
+ | new Identifier(" | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | === Result === | ||
+ | Always create a new world when you check the world generation result. You should see wool spawning in the overworld. You can use the command below to remove stone blocks surrounding you. | ||
+ | < | ||
+ | /fill ~-8 0 ~-8 ~8 ~ ~8 minecraft: | ||
+ | </ | ||
+ | |||
+ | {{tutorial: | ||
+ | |||
+ | ==== Adding to the nether biomes ==== | ||
+ | In this section, based on the code in the previous section, we will add the ore to the nether biomes. | ||
+ | |||
+ | We need to replace '' | ||
+ | because the ore has to replace different blocks in the nether than in the overworld. | ||
+ | |||
+ | <code java> | ||
+ | public class ExampleMod implements ModInitializer { | ||
+ | private static ConfiguredFeature<?, | ||
+ | (Feature.ORE, | ||
+ | OreConfiguredFeatures.NETHERRACK, | ||
+ | Blocks.WHITE_WOOL.getDefaultState(), | ||
+ | 9)); | ||
+ | |||
+ | public static PlacedFeature NETHER_WOOL_ORE_PLACED_FEATURE = new PlacedFeature( | ||
+ | RegistryEntry.of(NETHER_WOOL_ORE_CONFIGURED_FEATURE), | ||
+ | Arrays.asList( | ||
+ | CountPlacementModifier.of(20), | ||
+ | SquarePlacementModifier.of(), | ||
+ | HeightRangePlacementModifier.uniform(YOffset.getBottom(), | ||
+ | |||
+ | @Override | ||
+ | public void onInitialize() { | ||
+ | Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, | ||
+ | new Identifier(" | ||
+ | Registry.register(BuiltinRegistries.PLACED_FEATURE, | ||
+ | NETHER_WOOL_ORE_PLACED_FEATURE); | ||
+ | BiomeModifications.addFeature(BiomeSelectors.foundInTheNether(), | ||
+ | RegistryKey.of(Registry.PLACED_FEATURE_KEY, | ||
+ | new Identifier(" | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== Adding to the end biomes ==== | ||
+ | In this section, based on the code in the overworld section, we will add the ore to the end biomes. | ||
+ | |||
+ | We replace '' | ||
+ | |||
+ | <code java> | ||
+ | public class ExampleMod implements ModInitializer { | ||
+ | private static ConfiguredFeature<?, | ||
+ | (Feature.ORE, | ||
+ | new BlockMatchRuleTest(Blocks.END_STONE), | ||
+ | Blocks.WHITE_WOOL.getDefaultState(), | ||
+ | 9)); | ||
+ | |||
+ | public static PlacedFeature END_WOOL_ORE_PLACED_FEATURE = new PlacedFeature( | ||
+ | RegistryEntry.of(END_WOOL_ORE_CONFIGURED_FEATURE), | ||
+ | Arrays.asList( | ||
+ | CountPlacementModifier.of(20), | ||
+ | SquarePlacementModifier.of(), | ||
+ | HeightRangePlacementModifier.uniform(YOffset.getBottom(), | ||
+ | |||
+ | @Override | ||
+ | public void onInitialize() { | ||
+ | Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, | ||
+ | new Identifier(" | ||
+ | Registry.register(BuiltinRegistries.PLACED_FEATURE, | ||
+ | END_WOOL_ORE_PLACED_FEATURE); | ||
+ | BiomeModifications.addFeature(BiomeSelectors.foundInTheEnd(), | ||
+ | RegistryKey.of(Registry.PLACED_FEATURE_KEY, | ||
+ | new Identifier(" | ||
+ | } | ||
+ | } | ||
+ | </ | ||
tutorial/ores.txt · Last modified: 2023/12/18 01:03 by solidblock