WARNING: IF YOU DO NOT KNOW ANYTHING ABOUT JAVA, PLEASE LEARN THE BASICS BEFORE ATTEMPTING TO FOLLOW ANY MODDING TUTORIALS!!!!!
In this tutorial, we will be looking at how ore generation works. We will be generating our block/ore that we created back in the blocks tutorial. Let's start by creating a package called "com.<yourname>.tut.world". In here we will create a class called "WorldGenOre". We will implement IWorldGenerator and add the unimplemented method, generate. In this method we will have a switch method, that switches through the different dimensions.
1 2 3 4 5 | public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider) { switch(world.provider.getDimension()){ } } |
We get the dimension type through world.provider.getDimension(). This is an integer that is given to each dimension as a unique ID. Nether is -1, Overworld is 0, and End is 1. So we need to specify what happens in each of these cases.
We want to create a method for each of these dimensions, genSurface, genNether, and genEnd.
Within each of these, let's start with genSurface, we want to call a method, that we will make, called addOreSpawn.
1 2 3 | private void genSurface(World world, Random random, int chunkX, int chunkZ){ addOreSpawn(BlockHandler.tutBlock.getDefaultState(), world, random, chunkX, chunkZ, 16, 16, 50, 20, 10, 100, BlockMatcher.forBlock(Blocks.STONE)); } |
It takes in 12 arguments: block to spawn, the world, random, chunkX, chunkZ, maxX, maxZ, the chance of it spawning, minimum Y spawn, max Y spawn, and block to generate in.
Block to spawn is the block that we are generating, obviously.
The World is self explanatory, and so is random.
ChunkX is the chunk on the X axis that is being generated. It is often a 16 X 256 X 16 cube of cubes. 256 is the highest Y value a block can be placed in the world. 16 is the max size of the chunk on the X and Z axis.
MaxX and MaxZ are the max size of the chunk that the ore can be generated in. The maths goes like this:
16 + rand.nextInt(16)
So technically, the max X spawn can be generated anywhere along the X axis in a chunk between 16 and 32. The same goes for the Z spawn.
MaxVeinSize is the max number of blocks that will be spawned in a vein.
Chance is the chance that the block will be spawned. It iterates through a for loop and the lower the number, the rarer, because it goes through the entire chunk and generates that many times in the chunk. If you put 1, it will only generate 1 vein in a chunk.
MinY and MaxY are are the Y spawn coords for the vein. We work out a random number between the two parameters.
BlocksToSpawnIn is the block that the ore will be found in. We will choose STONE for this.
Let's create the addOreSpawn method and implement our for loop and generate our ores.
1 2 3 4 5 6 7 8 9 | private void addOreSpawn(IBlockState block, World world, Random random, int blockXPos, int blockZPos, int maxX, int maxZ, int maxVeinSize, int chance, int minY, int maxY, Predicate<IBlockState> blockToSpawnIn){ int diffMinMaxY = maxY - minY; for(int x = 0; x < chance; x++){ int posX = blockXPos + random.nextInt(maxX); int posY = minY + random.nextInt(diffMinMaxY); int posZ = blockZPos + random.nextInt(maxZ); (new WorldGenMinable(block, maxVeinSize, blockToSpawnIn)).generate(world, random, new BlockPos(posX, posY, posZ)); } } |
First, we get the range of the min and max Y values. Then we iterate through our chance, and iterate through it. Next we created a posX, posY, and posZ. The posX is a random number between the chunk boundary and a random number of the other chunk boundary, being 16 + rand(16). The same applies for the Z axis. The posY is a random number between the min Y and a random number of the difference of the min and max Y. Then we instantiate a new WorldGenMinable which is how we generate our ore in the world. We give it the arguments of the block state, max vein size, and the block to spawn in. We then call the WorldGenMinable.generate method, and give it the arguments world, random, and a new BlockPos, given the posX, posY, and posZ values.
Our blockToSpawnIn is a predicate of a block state. I don't know too much about it, so I can't discuss it too much.
We get the block state of the block we want to generate because some blocks have different state. For example: redstone. It has lit and unlit blockstates It generates the default blockstate, being unlit, so that it can change between lit and unlit within the world.
Now we need to register our world generator. Go into your CommonProxy and register the World Generator we created.
1 | GameRegistry.registerWorldGenerator(new WorldGenOre(), 0); |
The 0 is the weight of the generator. We will make it 0 for simplicity, so it is loaded first every time, after the vanilla generator.
Once you have gotten it registered, go ahead and run the game and CREATE A NEW WORLD EVERY TIME YOU MAKE A CHANGE TO WORLD GENERATION!!!!!!
This comment has been removed by the author.
ReplyDeleteHi, I'm programming a mod for minecraft 1.11.2 and I follow your tutorial to do that. Can you help me in my issue ?
ReplyDeleteThe problem is ore generation works but only from coordinate[x=0,y=0,z=0] so when I create a new world if I'm on [300,65,600] for example I cannot see my ore
Can you help me to figure this out please
By the way, your tutorial is really great
Can you make a github with your code and link me to your ore gen code please?
DeleteI don't have gitHub but I put my file on my dropbox, sorry for the late answer ^^ and thank you for your help
Deletehttps://www.dropbox.com/s/2jjbhhap8cow5en/WorldGenOre.java?dl=0
Alright, I think I spotted an error on my part. Instead of "maxX" and "maxZ", take those away and replace them in "rand.nextInt" with "16". You should only be spawning the vein within a chunk of 16X16, and this way, you are not. I don't know how I didn't catch it before.
DeleteThank you for your reply, your answer guide me on the right way, so to generate ore when you calculate posX or posZ, you did "int posX = blockXPos + random.nextInt(maxX);" but when I wrote "int posX = blockXPos * 16 + random.nextInt(16);" it's work. It's the same logic for posZ
DeleteThank you ^^
I know it's a pretty late response, but if someone else finds this tutorial and has the same problem, actually change "int posX = blockXPos + random.nextInt(maxX)" to "int posX = blockXPos * maxX + random.nextInt(maxX)" and not "int posX = blockXPos * 16 + random.nextInt(16);" Otherwise changing the maxX and maxZ values will have no effect
DeleteEhm... I don't know why, but I can't find my ore. Anywhere. It's just non-existent in the world. Anyone have an idea? (I have my spawn chance on 80, so it shouldn't be hard to find, right?
ReplyDeleteNevermind. I never added the case to the switch statement xD
Delete