Minecraft 1.12 modding with forge – 7 – custom ore generation

Hello everyone, in this part we will make our custom ore generate in the overworld. I will also show how you could make a block generate in other dimensions and in other blocks then stone.

EDIT: Because a bug was found (Thanks to mortem5282!) I remade this part!

To keep the code organized create a new package called gen (or worldgen, or something like that). In this package I will create a class called OreGen. By instantiating this class we will be able to register custom ore generating. Make this class implement IWorldGenerator. Eclipse will automatically complain because we haven’t implemented the generate method. Just hover over the error and click “add unimplemented methods“. If that for some reason doesn’t work or you can’t do that for some reason, add a public method called generate. It doesn’t return anything:

 public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator,public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider) {} 

Now we just need 1 more method: It is private, returns nothing and I will call it runGenerator. This method will choose the position based on the pseudo-random number generator (based on the world seed) and pass the position to the oreGenerator, this will automatically generate an ore vein at the position.
This method takes in several variables:

  1. The block to generate. (IBlockState)
  2. The amount of blocks to generate. (int)
  3. The spawnChance. (int)
  4. The minimumHeight. (int)
  5. The maximumHeight. (int)
  6. The block to replace. (Predicate<IBlockState>)
  7. The world that is being generated. (World)
  8. The random object. (Random)
  9. The chunk’s x position. (int)
  10. The chunk’s z position. (int)

Now we have all of our methods setup and we can start making them do something.

The generate method will do 1 thing: it will call the runGenerator method with different arguments depending on the dimension. To choose in which dimension we want our ores to generate we are gonna implement a switch statement for every vanilla dimension. Dimensions are represented by integers:

  • Nether: -1 (Ores mostly replace Netherrack)
  • Overworld: 0 (Ores mostly replace Stone)
  • The End: 1 (No ores normally spawn but you should probably replace Endstone)

When the generator is run it will try to generate your block between minHeight and maxHeight. For every chunk it will try spawnChance times to generate your block, and it will replace the block you said.

Inside of the case with the dimension id you want to generate in you need to call runGenerator with the variables you want. For example this could be a line:

 runGenerator(ModBlocks.tutorialOre.getDefaultState(), 7, 10, 12, 50, BlockMatcher.forBlock(Blocks.STONE), world, random, chunkX, chunkZ); 

This will generate the tutorialOre with a max size of 7 and a spawnChance of 10. Between y12 and y50. This line was made for the overworld and thus will replace stone. The other variables are the inputs of the runGenerator method. I’ll also make it generate brick blocks in the end (Because why not!)

  runGenerator(Blocks.BRICK_BLOCK.getDefaultState(), 7, 10, 0, 255, BlockMatcher.forBlock(Blocks.END_STONE), world, random, chunkX, chunkZ); 

Now the runGenerator method, the first thing you should do is check if minHeight isn’t smaller then 0, maxHeight isn’t bigger then 256 and minHeight isn’t bigger then maxHeight. If one of those things is wrong you can throw an IllegalArgumentException. We can then calculate the difference between min- and maxHeight. This will be used to generate a random int between min– and maxHeight. Then create a loop from 0 to spawnChance. In every iteration we will generate a random x, y and z position. Then with those values call generate on the generator and pass it the world, random object and BlockPosition. We also need to create a WorldGenMinable variable, we need to pass the block we are gonna generate, the amount of blocks we are gonna generate and the blocks we need to replace.

Now we just have to register our OreGen. In your main mod class’ init method register the generator by calling GameRegistry.registerWorldGenerator, this method needs 2 variables, our generator and a weight. For the generator instatiate our OreGen.  The weight is used to determine when the generator is ran. The higher the later (and thus less chance your blocks will be removed). I will just used 0.

 GameRegistry.registerWorldGenerator(new OreGen(), 0); 

You have to make sure you don’t make the size way to big, this could lead to cascading worldgeneration. This means that extra chunks keep getting generated by eachothers to generate your ore. Mezz posted an amazing explanation on reddit.

I hope this was useful and as always if you have any question don’t hesitate to ask in the comments! Also if you saw any errors in the tutorial please let me know so I can fix it!

~suppergerrie2

 

Posted in Forge tutorial, Forge Tutorial 1.12.

29 Comments

  1. Hello,

    Following this tutorial now in 2020 and found myself stuck on a little problem.
    You’re talking about a switch statement, but I didn’t understand where to put it, and looking at github it seems like the code for this part wasn’t updated after you changed it.

    Can someone help me with that or have the full code for this part ?

    Thanks

  2. You should specify that the Predicate parameter in the runGenerator method is a call to the import com.google.common.base.Predicate not java.util.function.Predicate, that will cause an error (at least it did for me in intellij.)

  3. Great Tutorial! I have my ores generating fine in my world, but I would like to know how I can generate ores in specific biomes, like emeralds.

    • Just before you call generator.generate you can check the biome. You can get the biome using world.getBiome(BlockPos).

      ~suppergerrie2

    • Hello!

      If you look in your log do you see any messages about cascading world lag?

      ~suppergerrie2

    • My world generation is extremly slow too, and no mention of cascading world lag. I did everything the same way as the tutorial :/

      • Hmmm, maybe I missed something. Can you post your code on github so I can take a look at it? If you want to you can also join the discord (join using the widget on the right).

        ~suppergerrie2

  4. There’s one thing in this that really annoys me, and that’s the fact that the vein amount seems so random and unpredictable, or makes no sense to me. People say it’s supposed to be a max vein amount. But when I specify it to be 3, I only seem to get ore veins of 1. And when I specify it to be 4, I get ore veins of 5.

    I apologise if I’m getting off sounding rude, but I was wondering how I would create a method which is not only accurate to all the arguments I put in. But would also implement a minimum and maximum ore vein amount, so I had more control over the vein amount.

    • I don’t have time to look now but I’ll investigate later. It’s difficult to make sure an exact amount of ores spawn because you are using random to choose the amount, while checking a random spot in random terrain. (A lot of random!). It could also happen that 2 veins spawn at the same position.

      ~suppergerrie2

    • Ah, I understand. Lots of random. XP
      Was just wondering how I would generate an ore vein in-between 2 values, rather than 1 – that clearly from my experience didn’t quite do what I expected it to.

      Also, I was wondering but is it possible to generate an ore that only spawned 1 vein less than every chunk? Like 1 every 2 chunks. Maybe even in-between, like 1.5 chunks. Would you supposedly change the Chunk_X and Chunk_Z multipliers? If it is, could you possibly show what you changed.

    • Corrections:
      ‘an ore vein size that is in-between 2 values’.
      ‘that spawns 1 vein less than every chunk’

      I’m never usually this bad at English. I almost didn’t understand what I meant then. XD

      • If you want to use 2 values you’d need to implement a custom WorldGenerator I think, in this tutorial we are using WorldGenMinable which only uses 1 value. You could look in the code of WorldGenMinable (found in net.minecraft.world.gen.feature.WorldGenMinable). And reimplement it with 2 values in some way.

        The best way I can think of for implementing less is either lowering the spawnchance so it fails more, or generating a random int between 0 and x and checking if that is lower than some value to make it only generate sometimes and thus not in every chunk.

        You should never generate in between chunks except if both chunks are already generated, else you could cause cascading lag.

        ~suppergerrie2

      • I know it’s been a little while since then. But I’ve honestly just started modding and when looking into the WorldGenMinable class, I am pretty clueless on what most of this even does. So I feel like trying to then adapt that into something that I want is pretty out of my league without tons of help.

        • Do you know java? If not you should probably learn java first before you start making mods, you should at least know what for loops are, if/else/elseif statements, how variables work, what the difference is between static and not static etc. (But ofcourse the more you know the better). You could use codecademy (Not sponsored :P) or find a tutorial yourself. But try to make stuff yourself instead of just copying other people (Not saying you do know just a tip I think helps when you learn!)

          Then when you know java you can start messing around in the minecraft code. Guess what something does, place a breakpoint and check if you are correct, or copy the class if possible, guess what something does and what happens when you ex. replace a number somewhere and check if your guess is correct.

          I don’t want to make the code and give it to you because this website is to help people learn, and I believe you learn by making and messing around yourself.

          If you have questions about specific parts I’d love to help! (Or strange errors you don’t understand :P).
          I didn’t mean to say anything negative in this comment so if you read something negative it is probably because this is not my first language ;P

          ~suppergerrie2

    • Hello, please put your code on pastebin/GitHub so I can look at it. What errors do you get? ~suppergerrie2

  5. Hey suppergerrie!

    I really like your tutorials since the forge doc and also the minecraft wiki is not helpful at all. Keep doing tutorials please!
    Just a question: In order to check for the dimension… where do I get the dimension from? Ther is no variable for that in the constructor or the other method…

    • Hello!

      It seems like I forgot to add that part to the tutorial when I remade it, sorry! It indeed isn’t in the passed when the method is called, but the world is, by calling world.provider.getDimension() you get the dimension that is being generated. I hope this helps and I’ll add this to my to-do list to fix! (Also sorry for the late reaction, I’ve been sick and haven’t been able to access my pc because of that!)

      ~suppergerrie2

  6. I tried doing this with 2 ores but only 1 ore spawns per dimension. Lets say i have two ores one called Steel one called Copper, the Copper generates only in the Overworld and Nether but the Steel does not, while the Steel generates only in the End and the Copper does not. Is there a way i can fix this somehow?

    • Hello,

      If I understand your question correctly you want to spawn copper ore in the overworld and nether and steel in the end.
      You can do that by registering the OreGen 3 times, 1 time with the copper ore but with a dimension id of 0 (Overworld), 1 time with copper ore but with dimension id of -1 (nether) and 1 time with the steel ore and a dimension id of 1 (the end). For the nether and end dimenions you also need to BlockMatcher.forBlock(Blocks.NETHERRACK) (or Blocks.END_STONE) to make sure it replaces the correct block.

      Replace the words in caps with your values.

      ~suppergerrie2

      • Sorry i didn’t explain myself well. I meant i want Copper and Steel Ores to spawn together in all dimensions, i tried registering the OreGen for all dimensions for both Copper and Steel ores but only 1 of those ores spawn in each dimension. is there a way i can spawn both ores in all dimensions somehow?

        • Ah, I think I’ve found the problem. I’m looking into how to fix it as I’m writing it! For some reason I never noticed it, but it is kinda random which one will generate. If you restart the game the other ore can start generating instead! Thanks for pointing it out and I’ll update when I find the fix!

        • Okay so it should be fixed in the tutorial now, you will need to redo the whole tutorial to make sure everything is correct, the problem was because it tried generating at the same place as the last ore and that broke the generation.

          ~suppergerrie2

Comments are closed.