buildcraft/common/buildcraft/energy/worldgen/OilPopulate.java
AlexIIL 3668dc883a Fix #3283, fix #3395, fix #3283.
Just a few fixes for 7.1.18, whenever it comes out.
2016-07-15 12:56:02 +01:00

389 lines
11 KiB
Java

/**
* Copyright (c) 2011-2015, SpaceToad and the BuildCraft Team
* http://www.mod-buildcraft.com
* <p/>
* BuildCraft is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* http://www.mod-buildcraft.com/MMPL-1.0.txt
*/
package buildcraft.energy.worldgen;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFlower;
import net.minecraft.block.BlockStaticLiquid;
import net.minecraft.block.material.Material;
import net.minecraft.init.Blocks;
import net.minecraft.world.World;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.chunk.Chunk;
import cpw.mods.fml.common.eventhandler.Event.Result;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.common.util.EnumHelper;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.event.terraingen.PopulateChunkEvent;
import net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType;
import net.minecraftforge.event.terraingen.TerrainGen;
import net.minecraftforge.fluids.BlockFluidBase;
import net.minecraftforge.fluids.IFluidBlock;
import buildcraft.BuildCraftCore;
import buildcraft.BuildCraftEnergy;
public final class OilPopulate {
public static final OilPopulate INSTANCE = new OilPopulate();
public static final EventType EVENT_TYPE = EnumHelper.addEnum(EventType.class, "BUILDCRAFT_OIL", new Class[0], new Object[0]);
private static final byte LARGE_WELL_HEIGHT = 16;
private static final byte MEDIUM_WELL_HEIGHT = 6;
public final Set<Integer> excessiveBiomes = new HashSet<Integer>();
public final Set<Integer> surfaceDepositBiomes = new HashSet<Integer>();
public final Set<Integer> excludedBiomes = new HashSet<Integer>();
private enum GenType {
LARGE, MEDIUM, LAKE, NONE
}
private OilPopulate() {
// BuildCraftCore.debugWorldgen = true;
}
@SubscribeEvent
public void populate(PopulateChunkEvent.Pre event) {
boolean doGen = TerrainGen.populate(event.chunkProvider, event.world, event.rand, event.chunkX, event.chunkZ, event.hasVillageGenerated, EVENT_TYPE);
if (!doGen) {
event.setResult(Result.ALLOW);
return;
}
generateOil(event.world, event.rand, event.chunkX, event.chunkZ);
}
public void generateOil(World world, Random rand, int chunkX, int chunkZ) {
// shift to world coordinates
int x = chunkX * 16 + 8 + rand.nextInt(16);
int z = chunkZ * 16 + 8 + rand.nextInt(16);
BiomeGenBase biome = world.getBiomeGenForCoords(x, z);
// Do not generate oil in the End or Nether
if (excludedBiomes.contains(biome.biomeID)) {
return;
}
boolean oilBiome = surfaceDepositBiomes.contains(biome.biomeID);
double bonus = oilBiome ? 3.0 : 1.0;
bonus *= BuildCraftEnergy.oilWellScalar;
if (excessiveBiomes.contains(biome.biomeID)) {
bonus *= 30.0;
} else if (BuildCraftCore.debugWorldgen) {
bonus *= 20.0;
}
GenType type = GenType.NONE;
if (rand.nextDouble() <= 0.0004 * bonus) {
// 0.04%
type = GenType.LARGE;
} else if (rand.nextDouble() <= 0.001 * bonus) {
// 0.1%
type = GenType.MEDIUM;
} else if (oilBiome && rand.nextDouble() <= 0.02 * bonus) {
// 2%
type = GenType.LAKE;
}
if (type == GenType.NONE) {
return;
}
// Find ground level
int groundLevel = getTopBlock(world, x, z);
if (groundLevel < 5) {
return;
}
double deviation = surfaceDeviation(world, x, groundLevel, z, 8);
if (deviation > 0.45) {
return;
}
// Generate a Well
if (type == GenType.LARGE || type == GenType.MEDIUM) {
int wellX = x;
int wellZ = z;
int wellHeight = MEDIUM_WELL_HEIGHT;
if (type == GenType.LARGE) {
wellHeight = LARGE_WELL_HEIGHT;
}
int maxHeight = groundLevel + wellHeight;
if (maxHeight >= world.getHeight() - 1) {
return;
}
// Generate a spherical cave deposit
int wellY = 20 + rand.nextInt(10);
int radius;
if (type == GenType.LARGE) {
radius = 8 + rand.nextInt(9);
} else {
radius = 4 + rand.nextInt(4);
}
int radiusSq = radius * radius;
for (int poolX = -radius; poolX <= radius; poolX++) {
for (int poolY = -radius; poolY <= radius; poolY++) {
for (int poolZ = -radius; poolZ <= radius; poolZ++) {
int distance = poolX * poolX + poolY * poolY + poolZ * poolZ;
if (distance <= radiusSq) {
world.setBlock(poolX + wellX, poolY + wellY, poolZ + wellZ, BuildCraftEnergy.blockOil, 0, distance == radiusSq ? 3 : 2);
}
}
}
}
// Generate Lake around Spout
int lakeRadius;
if (type == GenType.LARGE) {
lakeRadius = 25 + rand.nextInt(20);
// if (BuildCraftCore.debugMode) {
// lakeRadius += 40;
// }
} else {
lakeRadius = 5 + rand.nextInt(10);
}
generateSurfaceDeposit(world, rand, biome, wellX, groundLevel, wellZ, lakeRadius);
boolean makeSpring = type == GenType.LARGE && BuildCraftEnergy.spawnOilSprings && BuildCraftCore.springBlock != null && (BuildCraftCore.debugWorldgen || rand.nextDouble() <= 0.25);
// Generate Spout
int baseY;
if (makeSpring) {
baseY = 0;
} else {
baseY = wellY;
}
if (makeSpring && world.getBlock(wellX, baseY, wellZ) == Blocks.bedrock) {
world.setBlock(wellX, baseY, wellZ, BuildCraftCore.springBlock, 1, 3);
}
for (int y = baseY + 1; y <= maxHeight; ++y) {
world.setBlock(wellX, y, wellZ, BuildCraftEnergy.blockOil, 0, 3);
}
if (type == GenType.LARGE) {
for (int y = wellY; y <= maxHeight - wellHeight / 2; ++y) {
world.setBlock(wellX + 1, y, wellZ, BuildCraftEnergy.blockOil, 0, 3);
world.setBlock(wellX - 1, y, wellZ, BuildCraftEnergy.blockOil, 0, 3);
world.setBlock(wellX, y, wellZ + 1, BuildCraftEnergy.blockOil, 0, 3);
world.setBlock(wellX, y, wellZ - 1, BuildCraftEnergy.blockOil, 0, 3);
}
}
} else if (type == GenType.LAKE) {
// Generate a surface oil lake
int lakeX = x;
int lakeZ = z;
int lakeY = groundLevel;
Block block = world.getBlock(lakeX, lakeY, lakeZ);
if (block == biome.topBlock) {
generateSurfaceDeposit(world, rand, biome, lakeX, lakeY, lakeZ, 5 + rand.nextInt(10));
}
}
}
public void generateSurfaceDeposit(World world, Random rand, int x, int y, int z, int radius) {
BiomeGenBase biome = world.getBiomeGenForCoords(x, z);
generateSurfaceDeposit(world, rand, biome, x, y, z, radius);
}
private void generateSurfaceDeposit(World world, Random rand, BiomeGenBase biome, int x, int y, int z, int radius) {
int depth = rand.nextDouble() < 0.5 ? 1 : 2;
// Center
setOilColumnForLake(world, biome, x, y, z, depth, 2);
// Generate tendrils, from the center outward
for (int w = 1; w <= radius; ++w) {
float proba = (float) (radius - w + 4) / (float) (radius + 4);
setOilWithProba(world, biome, rand, proba, x, y, z + w, depth);
setOilWithProba(world, biome, rand, proba, x, y, z - w, depth);
setOilWithProba(world, biome, rand, proba, x + w, y, z, depth);
setOilWithProba(world, biome, rand, proba, x - w, y, z, depth);
for (int i = 1; i <= w; ++i) {
setOilWithProba(world, biome, rand, proba, x + i, y, z + w, depth);
setOilWithProba(world, biome, rand, proba, x + i, y, z - w, depth);
setOilWithProba(world, biome, rand, proba, x + w, y, z + i, depth);
setOilWithProba(world, biome, rand, proba, x - w, y, z + i, depth);
setOilWithProba(world, biome, rand, proba, x - i, y, z + w, depth);
setOilWithProba(world, biome, rand, proba, x - i, y, z - w, depth);
setOilWithProba(world, biome, rand, proba, x + w, y, z - i, depth);
setOilWithProba(world, biome, rand, proba, x - w, y, z - i, depth);
}
}
// Fill in holes
for (int dx = x - radius; dx <= x + radius; ++dx) {
for (int dz = z - radius; dz <= z + radius; ++dz) {
if (isOil(world, dx, y, dz)) {
continue;
}
if (isOilSurrounded(world, dx, y, dz)) {
setOilColumnForLake(world, biome, dx, y, dz, depth, 2);
}
}
}
}
private boolean isReplaceableFluid(World world, int x, int y, int z) {
Block block = world.getBlock(x, y, z);
return (block instanceof BlockStaticLiquid || block instanceof BlockFluidBase || block instanceof IFluidBlock) && block.getMaterial() != Material.lava;
}
private boolean isOil(World world, int x, int y, int z) {
Block block = world.getBlock(x, y, z);
return block == BuildCraftEnergy.blockOil;
}
private boolean isReplaceableForLake(World world, BiomeGenBase biome, int x, int y, int z) {
if (world.isAirBlock(x, y, z)) {
return true;
}
Block block = world.getBlock(x, y, z);
if (block == biome.fillerBlock || block == biome.topBlock) {
return true;
}
if (!block.getMaterial().blocksMovement()) {
return true;
}
if (block.isReplaceableOreGen(world, x, y, z, Blocks.stone)) {
return true;
}
if (block instanceof BlockFlower) {
return true;
}
if (!block.isOpaqueCube()) {
return true;
}
return false;
}
private boolean isOilAdjacent(World world, int x, int y, int z) {
return isOil(world, x + 1, y, z)
|| isOil(world, x - 1, y, z)
|| isOil(world, x, y, z + 1)
|| isOil(world, x, y, z - 1);
}
private boolean isOilSurrounded(World world, int x, int y, int z) {
return isOil(world, x + 1, y, z)
&& isOil(world, x - 1, y, z)
&& isOil(world, x, y, z + 1)
&& isOil(world, x, y, z - 1);
}
private void setOilWithProba(World world, BiomeGenBase biome, Random rand, float proba, int x, int y, int z, int depth) {
if (rand.nextFloat() <= proba && !world.isAirBlock(x, y - depth - 1, z)) {
if (isOilAdjacent(world, x, y, z)) {
setOilColumnForLake(world, biome, x, y, z, depth, 3);
}
}
}
private void setOilColumnForLake(World world, BiomeGenBase biome, int x, int y, int z, int depth, int update) {
if (isReplaceableForLake(world, biome, x, y + 1, z)) {
if (!world.isAirBlock(x, y + 2, z)) {
return;
}
if (isReplaceableFluid(world, x, y, z) || world.isSideSolid(x, y - 1, z, ForgeDirection.UP)) {
world.setBlock(x, y, z, BuildCraftEnergy.blockOil, 0, update);
} else {
return;
}
if (!world.isAirBlock(x, y + 1, z)) {
world.setBlock(x, y + 1, z, Blocks.air, 0, update);
}
for (int d = 1; d <= depth - 1; d++) {
if (isReplaceableFluid(world, x, y - d, z) || !world.isSideSolid(x, y - d - 1, z, ForgeDirection.UP)) {
return;
}
world.setBlock(x, y - d, z, BuildCraftEnergy.blockOil, 0, 2);
}
}
}
private int getTopBlock(World world, int x, int z) {
Chunk chunk = world.getChunkFromBlockCoords(x, z);
int y = chunk.getTopFilledSegment() + 15;
int trimmedX = x & 15;
int trimmedZ = z & 15;
for (; y > 0; --y) {
Block block = chunk.getBlock(trimmedX, y, trimmedZ);
if (block.isAir(world, x, y, z)) {
continue;
}
if (block instanceof BlockStaticLiquid) {
return y;
}
if (block instanceof BlockFluidBase) {
return y;
}
if (block instanceof IFluidBlock) {
return y;
}
if (!block.getMaterial().blocksMovement()) {
continue;
}
if (block instanceof BlockFlower) {
continue;
}
return y - 1;
}
return -1;
}
private double surfaceDeviation(World world, int x, int y, int z, int radius) {
int diameter = radius * 2;
double centralTendancy = y;
double deviation = 0;
for (int i = 0; i < diameter; i++) {
for (int k = 0; k < diameter; k++) {
deviation += getTopBlock(world, x - radius + i, z - radius + k) - centralTendancy;
}
}
return Math.abs(deviation / centralTendancy);
}
}