147 lines
5.7 KiB
Markdown
147 lines
5.7 KiB
Markdown
```
|
||
metadata.title = "World Generation: Ore"
|
||
metadata.date = "2016-10-10 11:28:42 -0400"
|
||
metadata.series = "forge-modding-112"
|
||
metadata.seriesName = "Forge Mods for 1.12"
|
||
```
|
||
|
||
We've got our copper ore block, but it doesn't generate in the world so it's not very useful to players. Let's fix that.
|
||
|
||
The first thing we'll need to do is create a class called `ModWorldGeneration` in the `world` sub-package in our mod. This class will implement Forge's `IWorldGenerator` interface which is used to hook into Minecraft's world generation.
|
||
|
||
```java
|
||
package net.shadowfacts.tutorial.world;
|
||
|
||
import net.minecraft.world.World;
|
||
import net.minecraft.world.chunk.IChunkGenerator;
|
||
import net.minecraft.world.chunk.IChunkProvider;
|
||
import net.minecraftforge.fml.common.IWorldGenerator;
|
||
|
||
import java.util.Random;
|
||
|
||
public class ModWorldGen implements IWorldGenerator {
|
||
|
||
@Override
|
||
public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider) {
|
||
|
||
}
|
||
|
||
}
|
||
```
|
||
|
||
The `generate` method is called by Forge for every chunk that's generated and is our entry point into MC's world generation. Inside the `generate` method, we'll check if `world.provider.getDimension() == 0` because we only want our ore to generate in the overworld. If that's true, we'll call a separate method called `generateOverworld` that takes the same parameters as `generate`. In this method we'll have our generation code that's specific to the overworld.
|
||
|
||
```java
|
||
// ...
|
||
public class ModWorldGen implements IWorldGenerator {
|
||
|
||
@Override
|
||
public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider) {
|
||
if (world.provider.getDimension() == 0) { // the overworld
|
||
generateOverworld(random, chunkX, chunkZ, world, chunkGenerator, chunkProvider);
|
||
}
|
||
}
|
||
|
||
private void generateOverworld(Random random, int chunkX, int chunkY, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider) {
|
||
|
||
}
|
||
|
||
}
|
||
```
|
||
|
||
Before we write the code that will actually add our Copper Ore into the world, let's write a little helper method to make our lives a bit easier.
|
||
|
||
This method will take a couple of things:
|
||
|
||
1. The `IBlockState` to generate.
|
||
2. The `World` to generate in.
|
||
3. The `Random` to use for generation.
|
||
4. The X and Z positions to generate the block at.
|
||
5. The minimum and maximum Y positions for which the ore can be generated.
|
||
6. The size of each ore vein.
|
||
7. The number of veins per chunk.
|
||
|
||
```java
|
||
// ...
|
||
public class ModWorldGen implements IWorldGenerator {
|
||
|
||
// ...
|
||
|
||
private void generateOre(IBlockState ore, World world, Random random, int x, int z, int minY, int maxY, int size, int chances) {
|
||
int deltaY = maxY - minY;
|
||
|
||
for (int i = 0; i < chances; i++) {
|
||
BlockPos pos = new BlockPos(x + random.nextInt(16), minY + random.nextInt(deltaY), z + random.nextInt(16));
|
||
|
||
WorldGenMinable generator = new WorldGenMinable(ore, size);
|
||
generator.generate(world, random, pos);
|
||
}
|
||
}
|
||
|
||
}
|
||
```
|
||
|
||
This method does a couple of things:
|
||
|
||
1. Calculate the difference between the maximum Y and minimum Y values.
|
||
2. Create a `BlockPos` with X, minimum Y, and Z values passed into the method and offset by:
|
||
1. A random number from 0 to 15
|
||
2. A random number from 0 to the difference between the min and max Y values (so that the ore is generated somewhere in between)
|
||
3. A random number from 0 to 15
|
||
3. Creates a new `WorldGenMinable` instance.
|
||
4. Calls the `generate` method on it to generate our ore in the world.
|
||
5. Repeats steps 2 through 4 `chances` times.
|
||
|
||
This results in our ore being generated `chanes` times per chunk with each chance having a different position inside the chunk and in between the specificed Y values.
|
||
|
||
```java
|
||
// ...
|
||
public class ModWorldGen implements IWorldGenerator {
|
||
|
||
// ...
|
||
|
||
private void generateOverworld(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider) {
|
||
generateOre(ModBlocks.oreCopper.getDefaultState(), world, random, chunkX * 16, chunkZ * 16, 16, 64, 4 + random.nextInt(4), 6);
|
||
}
|
||
|
||
private void generateOre(IBlockState ore, World world, Random random, int x, int z, int minY, int maxY, int size, int chances) {
|
||
// ...
|
||
}
|
||
|
||
}
|
||
```
|
||
|
||
We call the `generateOre` method with:
|
||
|
||
1. The block state we want to generate (the default block state of our copper ore block).
|
||
2. The world we want generate in (the `World` we've been passed).
|
||
3. The random we want to use to generate (the `Random` we've been passed).
|
||
4. The X position we want to generate at (the `chunkX` value multipled by 16, because chunks are 16x16).
|
||
5. The Z position we want to generate at (the `chunkZ` value multiplied by 16, because chunks are 16x16).
|
||
6. The minimum Y position we want to generate at (16).
|
||
7. The maximum Y position we want to generate at (64).
|
||
8. The size of the vein to generate (a random number from 4 to 7).
|
||
9. The number of times per chunk to generate (6).
|
||
|
||
Lastly, in the `preInit` of our main mod class, we'll need to register our world generator.
|
||
|
||
```java
|
||
// ...
|
||
public class TutorialMod {
|
||
// ...
|
||
public void preInit(FMLPreInitializationEvent event) {
|
||
// ...
|
||
GameRegistry.registerWorldGenerator(new ModWorldGen(), 3);
|
||
}
|
||
// ...
|
||
}
|
||
```
|
||
|
||
The `int` parameter of `GameRegistry.registerWorldGenerator` is the weight of our mod's world generator. This usually doens't matter, however, if you're experiencing issues with other mods interfering with your world generation, you may want to change this.
|
||
|
||
Now, if you create a new world and search around for a bit, you'll bet able to find a deposit of our Copper Ore!
|
||
|
||
You may want to play around with the vein size and chances settings until you achieve the desired concentration of ore per chunk.
|
||
|
||
![Copper Ore generating in the world](https://i.imgur.com/jfeYvi0.png)
|