6b69d3d138
Modified RiftGenerator to correct for the rarity of Rift Gateways in the Nether. Our config settings allow us to set the probability that we will attempt to generate a gateway in a given chunk. However, that doesn't guarantee that a gateway will generate. I collected a lot of data and determined that generation succeeds in the Nether only about 15% of the time. That's compared to 30% in the Overworld when counting oceans (which always fail) and about 75% (sometimes higher) when traveling mainly on land. RiftGenerator now corrects for this by multiplying the chance of attempting to generate gateways in the Nether by 4. Gateways in the Nether are still relatively rare and hard to find, but you'll occasionally come across them now. Also reorganized the code a little for clarify.
233 lines
9.1 KiB
Java
233 lines
9.1 KiB
Java
package StevenDimDoors.mod_pocketDim;
|
|
|
|
import java.util.Random;
|
|
|
|
import net.minecraft.block.Block;
|
|
import net.minecraft.block.material.Material;
|
|
import net.minecraft.world.World;
|
|
import net.minecraft.world.chunk.IChunkProvider;
|
|
import net.minecraftforge.common.DimensionManager;
|
|
import StevenDimDoors.mod_pocketDim.helpers.dimHelper;
|
|
import StevenDimDoors.mod_pocketDim.items.itemDimDoor;
|
|
import StevenDimDoors.mod_pocketDim.world.LimboProvider;
|
|
import StevenDimDoors.mod_pocketDim.world.PocketProvider;
|
|
import cpw.mods.fml.common.IWorldGenerator;
|
|
|
|
public class RiftGenerator implements IWorldGenerator
|
|
{
|
|
public static final int MAX_GATEWAY_GENERATION_CHANCE = 10000;
|
|
public static final int MAX_CLUSTER_GENERATION_CHANCE = 10000;
|
|
private static final int CLUSTER_GROWTH_CHANCE = 80;
|
|
private static final int MAX_CLUSTER_GROWTH_CHANCE = 100;
|
|
private static final int MIN_RIFT_Y = 4;
|
|
private static final int MAX_RIFT_Y = 250;
|
|
private static final int CHUNK_LENGTH = 16;
|
|
private static final int GATEWAY_RADIUS = 4;
|
|
private static final int MAX_GATEWAY_GENERATION_ATTEMPTS = 10;
|
|
private static final int NETHER_CHANCE_CORRECTION = 4;
|
|
private static final int OVERWORLD_DIMENSION_ID = 0;
|
|
private static final int NETHER_DIMENSION_ID = -1;
|
|
private static DDProperties properties = null;
|
|
|
|
public RiftGenerator()
|
|
{
|
|
if (properties == null)
|
|
properties = DDProperties.instance();
|
|
}
|
|
|
|
@Override
|
|
public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider)
|
|
{
|
|
//Don't generate rifts or gateways if the rift generation flag is disabled,
|
|
//the current world is a pocket dimension, or the world is remote.
|
|
if ((!properties.WorldRiftGenerationEnabled && !(world.provider instanceof LimboProvider)) ||
|
|
world.provider instanceof PocketProvider || world.isRemote)
|
|
{
|
|
return;
|
|
}
|
|
//This check prevents a crash related to superflat worlds not loading World 0
|
|
if (dimHelper.getWorld(OVERWORLD_DIMENSION_ID) == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int x, y, z;
|
|
int attempts;
|
|
int correction;
|
|
boolean valid;
|
|
LinkData link;
|
|
|
|
//Check if we're generating things in the Nether
|
|
if (world.provider.dimensionId == NETHER_DIMENSION_ID)
|
|
{
|
|
//The terrain in the Nether makes it much harder for our gateway spawning algorithm to find a spot to place a gateway.
|
|
//Tests show that only about 15% of attempts succeed. Compensate for this by multiplying the chance of generation
|
|
//by a correction factor.
|
|
correction = NETHER_CHANCE_CORRECTION;
|
|
}
|
|
else
|
|
{
|
|
//No correction
|
|
correction = 1;
|
|
}
|
|
|
|
//Randomly decide whether to place a cluster of rifts here
|
|
if (random.nextInt(MAX_CLUSTER_GENERATION_CHANCE) < properties.ClusterGenerationChance)
|
|
{
|
|
link = null;
|
|
do
|
|
{
|
|
//Pick a random point on the surface of the chunk
|
|
x = chunkX * CHUNK_LENGTH + random.nextInt(CHUNK_LENGTH);
|
|
z = chunkZ * CHUNK_LENGTH + random.nextInt(CHUNK_LENGTH);
|
|
y = world.getHeightValue(x, z);
|
|
|
|
//If the point is within the acceptable altitude range, the block above is empty, and we're
|
|
//not building on bedrock, then generate a rift there
|
|
if (y >= MIN_RIFT_Y && y <= MAX_RIFT_Y && world.isAirBlock(x, y + 1, z) &&
|
|
world.getBlockId(x, y, z) != Block.bedrock.blockID && //<-- Stops Nether roof spawning. DO NOT REMOVE!
|
|
world.getBlockId(x, y - 1, z) != Block.bedrock.blockID &&
|
|
world.getBlockId(x, y - 2, z) != Block.bedrock.blockID)
|
|
{
|
|
//Create a link. If this is the first time, create a dungeon pocket and create a two-way link.
|
|
//Otherwise, create a one-way link and connect to the destination of the first link.
|
|
if (link == null)
|
|
{
|
|
link = new LinkData(world.provider.dimensionId, 0, x, y + 1, z, x, y + 1, z, true, 0);
|
|
link = dimHelper.instance.createPocket(link, true, true);
|
|
}
|
|
else
|
|
{
|
|
link = dimHelper.instance.createLink(link.locDimID, link.destDimID, x, y + 1, z, link.destXCoord, link.destYCoord, link.destZCoord);
|
|
}
|
|
}
|
|
}
|
|
//Randomly decide whether to repeat the process and add another rift to the cluster
|
|
while (random.nextInt(MAX_CLUSTER_GROWTH_CHANCE) < CLUSTER_GROWTH_CHANCE);
|
|
}
|
|
|
|
//Check if generating structures is enabled and randomly decide whether to place a Rift Gateway here.
|
|
//This only happens if a rift cluster was NOT generated.
|
|
else if (random.nextInt(MAX_GATEWAY_GENERATION_CHANCE) < properties.GatewayGenerationChance * correction &&
|
|
isStructureGenerationAllowed())
|
|
{
|
|
valid = false;
|
|
x = y = z = 0; //Stop the compiler from freaking out
|
|
|
|
//Check locations for the gateway until we are satisfied or run out of attempts.
|
|
for (attempts = 0; attempts < MAX_GATEWAY_GENERATION_ATTEMPTS && !valid; attempts++)
|
|
{
|
|
//Pick a random point on the surface of the chunk and check its materials
|
|
x = chunkX * CHUNK_LENGTH + random.nextInt(CHUNK_LENGTH);
|
|
z = chunkZ * CHUNK_LENGTH + random.nextInt(CHUNK_LENGTH);
|
|
y = world.getHeightValue(x, z);
|
|
valid = checkGatewayLocation(world, x, y, z);
|
|
}
|
|
|
|
//Build the gateway if we found a valid location
|
|
if (valid)
|
|
{
|
|
//Create a two-way link between the upper block of the gateway and a pocket dimension
|
|
//That pocket dimension is where we'll start a dungeon!
|
|
link = new LinkData(world.provider.dimensionId, 0, x, y + 1, z, x, y + 1, z, true, 0);
|
|
link = dimHelper.instance.createPocket(link, true, true);
|
|
|
|
//If the current dimension isn't Limbo, build a Rift Gateway out of Stone Bricks
|
|
if (world.provider.dimensionId != properties.LimboDimensionID)
|
|
{
|
|
createStoneGateway(world, x, y, z, random);
|
|
}
|
|
else
|
|
{
|
|
createLimboGateway(world, x, y, z);
|
|
}
|
|
|
|
//Place the shiny transient door into a dungeon
|
|
itemDimDoor.placeDoorBlock(world, x, y + 1, z, 0, mod_pocketDim.transientDoor);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void createStoneGateway(World world, int x, int y, int z, Random random)
|
|
{
|
|
final int blockID = Block.stoneBrick.blockID;
|
|
|
|
//Replace some of the ground around the gateway with bricks
|
|
for (int xc = -GATEWAY_RADIUS; xc <= GATEWAY_RADIUS; xc++)
|
|
{
|
|
for (int zc= -GATEWAY_RADIUS; zc <= GATEWAY_RADIUS; zc++)
|
|
{
|
|
//Check that the block is supported by an opaque block.
|
|
//This prevents us from building over a cliff, on the peak of a mountain,
|
|
//or the surface of the ocean or a frozen lake.
|
|
if (world.isBlockOpaqueCube(x + xc, y - 2, z + zc))
|
|
{
|
|
//Randomly choose whether to place bricks or not. The math is designed so that the
|
|
//chances of placing a block decrease as we get farther from the gateway's center.
|
|
if (Math.abs(xc) + Math.abs(zc) < random.nextInt(2) + 3)
|
|
{
|
|
//Place Stone Bricks
|
|
world.setBlock(x + xc, y - 1, z + zc, blockID, 0, 3);
|
|
}
|
|
else if (Math.abs(xc) + Math.abs(zc) < random.nextInt(3) + 3)
|
|
{
|
|
//Place Cracked Stone Bricks
|
|
world.setBlock(x + xc, y - 1, z + zc, blockID, 2, 3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Use Chiseled Stone Bricks to top off the pillars around the door
|
|
world.setBlock(x, y + 2, z + 1, blockID, 3, 3);
|
|
world.setBlock(x, y + 2, z - 1, blockID, 3, 3);
|
|
//Build the columns around the door
|
|
world.setBlock(x, y + 1, z - 1, blockID, 0, 3);
|
|
world.setBlock(x, y + 1, z + 1, blockID, 0, 3);
|
|
world.setBlock(x, y, z - 1, blockID, 0, 3);
|
|
world.setBlock(x, y, z + 1, blockID, 0, 3);
|
|
}
|
|
|
|
private static void createLimboGateway(World world, int x, int y, int z)
|
|
{
|
|
//Build the gateway out of Unraveled Fabric. Since nearly all the blocks in Limbo are of
|
|
//that type, there is no point replacing the ground.
|
|
final int blockID = properties.LimboBlockID;
|
|
world.setBlock(x, y + 2, z + 1, blockID, 0, 3);
|
|
world.setBlock(x, y + 2, z - 1, blockID, 0, 3);
|
|
|
|
//Build the columns around the door
|
|
world.setBlock(x, y + 1, z - 1, blockID, 0, 3);
|
|
world.setBlock(x, y + 1, z + 1, blockID, 0, 3);
|
|
world.setBlock(x, y, z - 1, blockID, 0, 3);
|
|
world.setBlock(x, y, z + 1, blockID, 0, 3);
|
|
}
|
|
|
|
private static boolean checkGatewayLocation(World world, int x, int y, int z)
|
|
{
|
|
//Check if the point is within the acceptable altitude range, the block above that point is empty,
|
|
//and the block two levels down is opaque and has a reasonable material. Plus that we're not building
|
|
//on top of bedrock.
|
|
return (y >= MIN_RIFT_Y &&
|
|
y <= MAX_RIFT_Y &&
|
|
world.isAirBlock(x, y + 1, z) &&
|
|
world.getBlockId(x, y, z) != Block.bedrock.blockID && //<-- Stops Nether roof spawning. DO NOT REMOVE!
|
|
world.getBlockId(x, y - 1, z) != Block.bedrock.blockID &&
|
|
checkFoundationMaterial(world, x, y - 2, z));
|
|
}
|
|
|
|
private static boolean checkFoundationMaterial(World world, int x, int y, int z)
|
|
{
|
|
//We check the material and opacity to prevent generating gateways on top of trees or houses,
|
|
//or on top of strange things like tall grass, water, slabs, or torches.
|
|
//We also want to avoid generating things on top of the Nether's bedrock!
|
|
Material material = world.getBlockMaterial(x, y, z);
|
|
return (material != Material.leaves && material != Material.wood && material != Material.pumpkin
|
|
&& world.isBlockOpaqueCube(x, y, z) && world.getBlockId(x, y, z) != Block.bedrock.blockID);
|
|
}
|
|
|
|
private static boolean isStructureGenerationAllowed()
|
|
{
|
|
return DimensionManager.getWorld(OVERWORLD_DIMENSION_ID).getWorldInfo().isMapFeaturesEnabled();
|
|
}
|
|
}
|