The Meaning of Life, the Universe, and Everything.
Location:
Ohio
Join Date:
6/13/2015
Posts:
66
Minecraft:
ToadallyTerrific
Xbox:
Captain Skiller
Member Details
Hey, I'm trying to create a randomly generated volcano that will appear in random places in the world made out of a block I added called Basalt. I also want to add two ores inside of it, lithium and sulfur, but I don't want them to appear on the visible part of the volcano.
And once every few Minecraft days, I would like the volcano to trigger an eruption event, which I can do the code for that myself.
I just can't figure out how to make this! Can someone please help?
Hey, I'm trying to create a randomly generated volcano that will appear in random places in the world made out of a block I added called Basalt. I also want to add two ores inside of it, lithium and sulfur, but I don't want them to appear on the visible part of the volcano.
And once every few Minecraft days, I would like the volcano to trigger an eruption event, which I can do the code for that myself.
I just can't figure out how to make this! Can someone please help?
First, you will need to program the generation of the volcano. Does it have its own biome? Does it just generate in a random spot?
What shape is it? I'm sure you can use some randomness and possibly trigonometric functions to decide the height of the basalt blocks, based on the horizontal distance from the center.
If you don't know anything about world generation, I recently posted two tutorials in the Modding Tutorials section (here and here)
For the ore generation, re-create something like WorldGenMinable but have a segment that checks if the block is touching air. That will indicate whether it is visible without mining.
For the eruption, make a TileEntity somewhere in the volcano, probably the center, that is indestructible (unless you want the player to be able to completely remove a volcano). That TileEntity would check the world time occasionally, remember the time of the last eruption, and use whatever code you like to decide when to trigger a new eruption. When an eruption occurs, lava can randomly appear around the sides of the volcano and the top. Maybe add fire blocks randomly on the surface as well.
Rollback Post to RevisionRollBack
Click this banner for a list of illegal mod distributors -- only download from legal sites!
The Meaning of Life, the Universe, and Everything.
Location:
Ohio
Join Date:
6/13/2015
Posts:
66
Minecraft:
ToadallyTerrific
Xbox:
Captain Skiller
Member Details
Hi, thanks for the response! I want it to generate in random locations with its own small biome that only includes the volcano itself. I plan on making the volcano either composite or cinder cone shaped, but I can't seem to find any equations to achieve this. I'll reply if I find one. And also once I've got the equation, I do want to add a bit of randomness, which I don't know how to do.
I was thinking of a cosine function that relates the center of the volcano to its radius.
Specifically, use cosine and adjust its period so you are only using 1/4 of a period. That will make its return values go from 1 to 0 and not 1 to -1 to 1 like a full period does.
the psuedocode is something like this:
final int RADIUS = 16; // or whatever
final int BASE_HEIGHT = 32; // will multiply this by the cosine function to get height
final int HEIGHT_VARIANCE = 24; // or whatever
BlockPos center = parCenter; // this would be passed in the parameters of your generate method
int centerY = center.getY();
for(int x = -RADIUS; x <= RADIUS; x++)
{
for(int z = -RADIUS; z <= RADIUS; z++)
{
int disSquare = center.distanceSq(x, centerY, z);
startY = // get the surface height at that x,z
// calculate and assign the peak height to alpha
double alpha = BASE_HEIGHT + random.nextInt(HEIGHT_VARIANCE) - random.nextInt(HEIGHT_VARIANCE);
// calculate and assign the volcano width-height ratio to omega
// changing this adjusts cosine's period. period -> steepness
double omega = 0.25D * Math.PI * RADIUS // relate it to the radius. this may be the wrong way to do it :/
final int MAX_VARIANCE = 8;
int variance = random.nextInt(MAX_VARIANCE) - random.nextInt(MAX_VARIANCE); // this will return number in range -7 to 7
// HEIGHT FUNCTION
int numBlocks = alpha * Math.cos(disSquare * omega) + variance; // THE IMPORTANT PART
for(numSet = 0; numSet < numBlocks; numSet++)
{
// set blocks at (x, startY + numSet, z)
}
}
}
Okay, so it's not strictly psuedocode. But the general idea is that since cosine is 1 at 0, and cosine is 0 at (π / 2) , you can transform the function into one that has your radius as its period,
I got a random variance by simply adding a random number to the suggested height outputted by a non-random formula (cosine)
Maybe this picture will help. I overlaid the cosine function (the top half, as we don't want anything negative) on the picture of a volcano you provided:
Although, you won't be inputting negative numbers into cosine because the distanceSquared function always returns a positive. So just imagine that right half of my graph swinging around to form the entire volcano.
Now, for the random spread at the bottom, your biome can take care of that by using your basalt block for its top and filler. You can mess with its height and variance as well.
Anyway, that's my idea. What are your thoughts on this?
Rollback Post to RevisionRollBack
Click this banner for a list of illegal mod distributors -- only download from legal sites!
Okay, I've refined the code I posted earlier. I've succeeded in getting a big steep "bump" using cosine and the distance formula. I tried shifting the cosine function to get a hole in the middle, but it didn't seem steep enough using the same formula.
Here's a picture of my earliest try:
strict (no randomness or variance)
This is my latest attempt, complete with a crater and block blobs:
Loose (randomness and variance)
Crater:
This is my current code:
public class StructureVolcano extends WorldGenerator
{
final int VARIANCE_RADIUS = 3; // increase to have more variety in volcano radius (min=1)
final int VARIANCE_TOTAL_HEIGHT = 4; // increase for more extremely tall and short volcanoes (min=1)
final int VARIANCE_COLUMN_HEIGHT = 3; // increase for more randomness in column height (min=1)
final double VARIANCE_INCLINE = 0.1D; // increase for more wider and steeper volcanoes
final int BASE_RADIUS = 12; // increase for wider volcanoes
final int BASE_HEIGHT = 15; // increase for taller volcanoes
final double BASE_INCLINE = 0.65D; // increase for a steeper volcano
@Override
public boolean generate(World worldIn, Random random, BlockPos center)
{
// debug:
System.out.println("volcano centered at " + center);
// the volcano block
final IBlockState volcanoBlock = Blocks.obsidian.getDefaultState();
// size factors calculated using base and variances
int RADIUS = BASE_RADIUS + random.nextInt(VARIANCE_RADIUS) - random.nextInt(VARIANCE_RADIUS);
double INCLINE = BASE_INCLINE + (random.nextDouble() - 0.5D) * VARIANCE_INCLINE;
// peak height
double alpha = BASE_HEIGHT + random.nextInt(VARIANCE_TOTAL_HEIGHT) - random.nextInt(VARIANCE_TOTAL_HEIGHT);
// this number will make cosine's period equal to the twice the radius (I hope)
double omega = INCLINE / ((double)RADIUS * Math.PI);
// BUILD THE VOLCANO
// for every location in the volcano's radius
for(int dx = -RADIUS; dx <= RADIUS; dx++)
{
for(int dz = -RADIUS; dz <= RADIUS; dz++)
{
int x = center.getX() + dx;
int z = center.getZ() + dz;
double disSquare = center.distanceSq(x, center.getY(), z);
// if it's actually within the CIRCULAR radius, place blocks there
// without this, I get spikes near the corners where cosine peaks again
if(disSquare < RADIUS * RADIUS / INCLINE)
{
int startY = this.getNonAirNonLiquidFromAbove(worldIn, x, z) - 3;
// this prevents replacing bedrock
if(startY <= 0) startY = 1;
int colVariance = random.nextInt(VARIANCE_COLUMN_HEIGHT) - random.nextInt(VARIANCE_COLUMN_HEIGHT);
// this prevents 'spiky' areas on top
if(disSquare < (RADIUS * RADIUS) / 2) colVariance = 0;
// HEIGHT FUNCTION
double targetHeight = alpha * Math.cos(BASE_INCLINE * disSquare * omega) + colVariance;
// this forms the crater, which always takes up a 5-block radius
if(disSquare < 26.0D) targetHeight -= (26.0D - disSquare) * 0.35D;
// begin placing the blocks:
int numSet = 0;
int maxY = center.getY() + MathHelper.ceiling_double_int(targetHeight);
while(startY + numSet < maxY)
{
BlockPos setPos = new BlockPos(x, startY + numSet, z);
worldIn.setBlockState(setPos, volcanoBlock);
numSet++;
}
}
}
}
// PLACE LAVA
for(int y = -10; y < alpha + 2; y++)
{
worldIn.setBlockState(center.up(y), Blocks.lava.getDefaultState());
}
final double LAVA_SPREAD = 1.7D;
for(int numLava = 4 + random.nextInt(6); numLava > 0; numLava--)
{
double randX = center.getX() + (random.nextInt(RADIUS) - random.nextInt(RADIUS)) * LAVA_SPREAD;
double randZ = center.getZ() + (random.nextInt(RADIUS) - random.nextInt(RADIUS)) * LAVA_SPREAD;
int groundY = this.getNonAirNonLiquidFromAbove(worldIn, (int)randX, (int)randZ);
BlockPos lava = new BlockPos((int)randX, groundY, (int)randZ);
worldIn.setBlockState(lava.down(1), Blocks.lava.getDefaultState());
worldIn.setBlockState(lava, Blocks.lava.getDefaultState());
worldIn.setBlockState(lava.up(1), Blocks.lava.getDefaultState());
}
// PLACE BLOCK NOISE
for(int numBlobs = 2 + random.nextInt(6); numBlobs > 0; numBlobs--)
{
double randX = center.getX() + (random.nextInt(RADIUS * 2) - random.nextInt(RADIUS * 2)) / LAVA_SPREAD;
double randZ = center.getZ() + (random.nextInt(RADIUS * 2) - random.nextInt(RADIUS * 2)) / LAVA_SPREAD;
int groundY = this.getNonAirNonLiquidFromAbove(worldIn, (int)randX, (int)randZ);
WorldGenerator blobs = new WorldGenBlockBlob(volcanoBlock.getBlock(), 2 + random.nextInt(7));
blobs.generate(worldIn, random, new BlockPos(randX, groundY - random.nextInt(3), randZ));
}
return true;
}
public int getNonAirNonLiquidFromAbove(World world, int x, int z)
{
int y = 255;
boolean foundGround = false;
while(!foundGround && y-- >= 0)
{
Block blockAt = world.getBlockState(new BlockPos(x,y,z)).getBlock();
foundGround = blockAt != Blocks.air && blockAt.getMaterial() != Material.water && blockAt.getMaterial() != Material.lava;
}
return y;
}
}
Rollback Post to RevisionRollBack
Click this banner for a list of illegal mod distributors -- only download from legal sites!
How can I make the crater only around 3-4 blocks wide and the top part of the volcano slightly higher?
This section controls the crater width
// this forms the crater, which always takes up a 5-block radius
if(disSquare < 26.0D) targetHeight -= (26.0D - disSquare) * 0.35D;
To make it more controllable, I could do this.
// this controls the crater width and depth
double craterRadius = 2.1D; // why not 2.0D? because doubles are never exactly equal, so no point in <=
double craterRadiusSq = craterRadius * craterRadius;
double craterDepthFactor = 0.35D; // increase to make a deeper crater (does not affect radius)
// actually change targetHeight if it's within the crater radius
if(disSquare < craterRadiusSq) targetHeight -= (craterRadiusSq - disSquare) * craterDepthFactor;
I'm not certain how to make the top taller without some hard-coded stuff, but you can mess with omega and the radius to make the whole thing steeper, then combine those changes with a deeper crater
Edit:
I found two ways to make it steeper in the center
you can easily make some sections taller by checking if disSquare is between the crater radius and another number, then adding to targetHeight
// make a steeper area just around the crater
// using 2 here means the steeper border area is 2 blocks wide
double steepRadius = craterRadius + 2.1D; // again, using 2.1 instead of 2.0
double steepRadiusSq = steepRadius * steepRadius;
double borderHeightFactor = 0.25D; // increase for steeper border around crater
if(disSquare > craterRadiusSq && disSquare < steepRadiusSq)
{
targetHeight *= borderHeightFactor;
}
This would be added just after the section that adds the crater, and could even be modified into an if-else statement there.
Alternatively you can shift the cosine function to the left so the smooth, flat peak on top is cut off sooner. This would be done by adding a positive constant to disSquare before passing it to the cosine function. While simpler than the manual adjustment, I had to be careful to add the same constant when calculating which areas were within the volcano radius or else I got a "ring" around the volcano. You can see some of that in the first picture of my previous post
Hmm... I think everything will be the same except for 1) making a distance formula to use 2) changing the method that detects world height and 3) changing where blocks are set.
I could get started on that, but I think you will get a lot more users if you make this for 1.8.x or 1.9 first. As hard as it is to get rendering to work right (at least for me ) it's worth it for future updates.
Rollback Post to RevisionRollBack
Click this banner for a list of illegal mod distributors -- only download from legal sites!
The Meaning of Life, the Universe, and Everything.
Location:
Ohio
Join Date:
6/13/2015
Posts:
66
Minecraft:
ToadallyTerrific
Xbox:
Captain Skiller
Member Details
Okay, so I managed to fix what was wrong in 1.8, moving back to that. The only problem is: I've configured everything, but I can't seem to figure out how to actually get the volcano to generate! Sorry, I have little experience with world generators
The Meaning of Life, the Universe, and Everything.
Location:
Ohio
Join Date:
6/13/2015
Posts:
66
Minecraft:
ToadallyTerrific
Xbox:
Captain Skiller
Member Details
Okay, so what are two codes I should make inside the generateOverworld() method inside the IWorldGenerator class? I've been tinkering around with it, but it keeps crashing my game because it generated way too many volcanoes, and I can't fix it.
The Meaning of Life, the Universe, and Everything.
Location:
Ohio
Join Date:
6/13/2015
Posts:
66
Minecraft:
ToadallyTerrific
Xbox:
Captain Skiller
Member Details
Thank you so much for keeping up with me! You've been such a big help so far!
So, I tried out the generation code, and it worked... but with some slight issues.
When the volcanoes generate in my world, they form extremely derpily.
CONFIGURATION:
final int VARIANCE_RADIUS = 3; // increase to have more variety in volcano radius (min=1)
final int VARIANCE_TOTAL_HEIGHT = 4; // increase for more extremely tall and short volcanoes (min=1)
final int VARIANCE_COLUMN_HEIGHT = 3; // increase for more randomness in column height (min=1)
final double VARIANCE_INCLINE = 0.3D; // increase for more wider and steeper volcanoes
final int BASE_RADIUS = 30; // increase for wider volcanoes
final int BASE_HEIGHT = 30; // increase for taller volcanoes
final double BASE_INCLINE = 0.7D; // increase for a steeper volcano
Interesting... the "spikes" surrounding the volcano are due to miscalculating the radius. I thought my distance check accounted for that, but apparently not quite perfectly.
You want to be careful setting the radius, because at the time of chunk decoration you only have access to 1 chunk and its adjacent (not diagonal) chunks. That means that a radius of 30 will become a diameter of 60, which will try to fill 4 chunks. That's more than you have access to, which is why some volcanoes seem to cut off at chunk borders.
I don't know why there are obsidian blocks if you changed this line
final IBlockState volcanoBlock = Blocks.obsidian.getDefaultState();
to use your block instead. Because even the block blobs generation uses volcanoBlock instead of hard-coding a block.
Long story short... you'll have to tweak things like the radius calculation on your own to customize it. Hopefully I added enough comments to let you know which sections control what.
Also, if you really want the diameter to be so much larger than the height, I would recommend a different function entirely. The code I wrote out was customized to make a cone volcano by transforming the cosine function. If you want a dome volcano you should use an ellipsoid function instead.
Rollback Post to RevisionRollBack
Click this banner for a list of illegal mod distributors -- only download from legal sites!
Hey, I'm trying to create a randomly generated volcano that will appear in random places in the world made out of a block I added called Basalt. I also want to add two ores inside of it, lithium and sulfur, but I don't want them to appear on the visible part of the volcano.
And once every few Minecraft days, I would like the volcano to trigger an eruption event, which I can do the code for that myself.
I just can't figure out how to make this! Can someone please help?
EDIT: Like the old RedPower volcanoes
http://vignette1.wikia.nocookie.net/technicpack/images/6/61/2012-02-29_18.53.47.png/revision/latest/scale-to-width-down/220?cb=20120229185603
First, you will need to program the generation of the volcano. Does it have its own biome? Does it just generate in a random spot?
What shape is it? I'm sure you can use some randomness and possibly trigonometric functions to decide the height of the basalt blocks, based on the horizontal distance from the center.
If you don't know anything about world generation, I recently posted two tutorials in the Modding Tutorials section (here and here)
For the ore generation, re-create something like WorldGenMinable but have a segment that checks if the block is touching air. That will indicate whether it is visible without mining.
For the eruption, make a TileEntity somewhere in the volcano, probably the center, that is indestructible (unless you want the player to be able to completely remove a volcano). That TileEntity would check the world time occasionally, remember the time of the last eruption, and use whatever code you like to decide when to trigger a new eruption. When an eruption occurs, lava can randomly appear around the sides of the volcano and the top. Maybe add fire blocks randomly on the surface as well.
Hi, thanks for the response! I want it to generate in random locations with its own small biome that only includes the volcano itself. I plan on making the volcano either composite or cinder cone shaped, but I can't seem to find any equations to achieve this. I'll reply if I find one. And also once I've got the equation, I do want to add a bit of randomness, which I don't know how to do.
What about a limpet torus with a smaller hole in the middle? What would be the formula for that?
I was thinking of a cosine function that relates the center of the volcano to its radius.
Specifically, use cosine and adjust its period so you are only using 1/4 of a period. That will make its return values go from 1 to 0 and not 1 to -1 to 1 like a full period does.
the psuedocode is something like this:
Okay, so it's not strictly psuedocode. But the general idea is that since cosine is 1 at 0, and cosine is 0 at (π / 2) , you can transform the function into one that has your radius as its period,
I got a random variance by simply adding a random number to the suggested height outputted by a non-random formula (cosine)
Maybe this picture will help. I overlaid the cosine function (the top half, as we don't want anything negative) on the picture of a volcano you provided:
Although, you won't be inputting negative numbers into cosine because the distanceSquared function always returns a positive. So just imagine that right half of my graph swinging around to form the entire volcano.
Now, for the random spread at the bottom, your biome can take care of that by using your basalt block for its top and filler. You can mess with its height and variance as well.
Anyway, that's my idea. What are your thoughts on this?
Update:
Okay, I've refined the code I posted earlier. I've succeeded in getting a big steep "bump" using cosine and the distance formula. I tried shifting the cosine function to get a hole in the middle, but it didn't seem steep enough using the same formula.
Here's a picture of my earliest try:
strict (no randomness or variance)
This is my latest attempt, complete with a crater and block blobs:
Loose (randomness and variance)
Crater:
This is my current code:
Thanks! I'll try this after school is done. Do you think you can re-upload the pictures though? I can't see them.
EDIT: Nevermind, it's my school wi-fi blocking them.
How can I make the crater only around 3-4 blocks wide and the top part of the volcano slightly higher?
This section controls the crater width
To make it more controllable, I could do this.
I'm not certain how to make the top taller without some hard-coded stuff, but you can mess with omega and the radius to make the whole thing steeper, then combine those changes with a deeper crater
Edit:
I found two ways to make it steeper in the center
you can easily make some sections taller by checking if disSquare is between the crater radius and another number, then adding to targetHeight
This would be added just after the section that adds the crater, and could even be modified into an if-else statement there.
Alternatively you can shift the cosine function to the left so the smooth, flat peak on top is cut off sooner. This would be done by adding a positive constant to disSquare before passing it to the cosine function. While simpler than the manual adjustment, I had to be careful to add the same constant when calculating which areas were within the volcano radius or else I got a "ring" around the volcano. You can see some of that in the first picture of my previous post
Thanks! Could you provide a code for 1.7 so I can create my mod on it? I am sticking to 1.7 because for whatever reason, 1.8 or 1.9 hates me.
EDIT: Changed tag from 1.9 to 1.7.10
Hmm... I think everything will be the same except for 1) making a distance formula to use 2) changing the method that detects world height and 3) changing where blocks are set.
I could get started on that, but I think you will get a lot more users if you make this for 1.8.x or 1.9 first. As hard as it is to get rendering to work right (at least for me ) it's worth it for future updates.
Thanks! And thanks for the quick response, too!
I'll see if I can get it working for 1.8.
Okay, so I managed to fix what was wrong in 1.8, moving back to that. The only problem is: I've configured everything, but I can't seem to figure out how to actually get the volcano to generate! Sorry, I have little experience with world generators
I have a tutorial for that here
Okay, so what are two codes I should make inside the generateOverworld() method inside the IWorldGenerator class? I've been tinkering around with it, but it keeps crashing my game because it generated way too many volcanoes, and I can't fix it.
Yeah, a for loop would be way too much.
In this tutorial I have an example where I use a random number generator instead.
Do this:
Thank you so much for keeping up with me! You've been such a big help so far!
So, I tried out the generation code, and it worked... but with some slight issues.
When the volcanoes generate in my world, they form extremely derpily.
CONFIGURATION:
Interesting... the "spikes" surrounding the volcano are due to miscalculating the radius. I thought my distance check accounted for that, but apparently not quite perfectly.
You want to be careful setting the radius, because at the time of chunk decoration you only have access to 1 chunk and its adjacent (not diagonal) chunks. That means that a radius of 30 will become a diameter of 60, which will try to fill 4 chunks. That's more than you have access to, which is why some volcanoes seem to cut off at chunk borders.
I don't know why there are obsidian blocks if you changed this line
to use your block instead. Because even the block blobs generation uses volcanoBlock instead of hard-coding a block.
Long story short... you'll have to tweak things like the radius calculation on your own to customize it. Hopefully I added enough comments to let you know which sections control what.
Also, if you really want the diameter to be so much larger than the height, I would recommend a different function entirely. The code I wrote out was customized to make a cone volcano by transforming the cosine function. If you want a dome volcano you should use an ellipsoid function instead.
Oh, sorry. The second image I sent you was one without any changes made to the code. Woops!
Tweaked around with it a little, and, what do you know it works how I wanted it to! Thank you so much!