diff --git a/src/main/java/com/hbm/lib/HbmWorld.java b/src/main/java/com/hbm/lib/HbmWorld.java index 537309fb7..f563e7bb1 100644 --- a/src/main/java/com/hbm/lib/HbmWorld.java +++ b/src/main/java/com/hbm/lib/HbmWorld.java @@ -1,13 +1,22 @@ package com.hbm.lib; +import com.hbm.blocks.ModBlocks; +import com.hbm.config.GeneralConfig; +import com.hbm.config.WorldConfig; +import com.hbm.world.gen.MapGenChainloader; import com.hbm.world.gen.MapGenNTMFeatures; import com.hbm.world.gen.NTMWorldGenerator; import com.hbm.world.gen.component.*; import com.hbm.world.gen.component.BunkerComponents.BunkerStart; import com.hbm.world.gen.nbt.NBTStructure; +import com.hbm.world.gen.terrain.MapGenBedrockOil; +import com.hbm.world.gen.terrain.MapGenBubble; +import com.hbm.world.gen.terrain.MapGenCrater; import cpw.mods.fml.common.IWorldGenerator; import cpw.mods.fml.common.registry.GameRegistry; +import net.minecraft.init.Blocks; +import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.gen.structure.MapGenStructureIO; import net.minecraftforge.common.MinecraftForge; @@ -31,6 +40,9 @@ public class HbmWorld { MinecraftForge.EVENT_BUS.register(worldGenerator); NBTStructure.register(); + + MapGenChainloader.register(); + registerNTMTerrain(); } private static void registerWorldGen(IWorldGenerator nukerWorldGen, int weightedProbability) { @@ -45,4 +57,40 @@ public class HbmWorld { BunkerComponents.registerComponents(); MapGenStructureIO.func_143031_a(SiloComponent.class, "NTMSiloComponent"); } + + /** Register multi-chunk spanning terrain features using chainloader */ + private static void registerNTMTerrain() { + if(GeneralConfig.enableRad && WorldConfig.radfreq > 0) { + MapGenCrater sellafieldCrater = new MapGenCrater(WorldConfig.radfreq); + sellafieldCrater.regolith = sellafieldCrater.rock = ModBlocks.sellafield_slaked; + sellafieldCrater.targetBiome = BiomeGenBase.desert; + MapGenChainloader.addOverworldGenerator(sellafieldCrater); + } + + if(WorldConfig.oilSpawn > 0) { + MapGenBubble oilBubble = new MapGenBubble(WorldConfig.oilSpawn); + oilBubble.block = ModBlocks.ore_oil; + oilBubble.setSize(8, 16); + MapGenChainloader.addOverworldGenerator(oilBubble); + } + + if(WorldConfig.bedrockOilSpawn > 0) { + MapGenBedrockOil bedrockBubble = new MapGenBedrockOil(WorldConfig.bedrockOilSpawn); + MapGenChainloader.addOverworldGenerator(bedrockBubble); + } + + int sandBubbleSpawn = 200; + if(sandBubbleSpawn > 0) { + MapGenBubble sandOilBubble = new MapGenBubble(sandBubbleSpawn); + sandOilBubble.replace = Blocks.sand; + sandOilBubble.block = ModBlocks.ore_oil_sand; + sandOilBubble.canSpawn = biome -> !biome.canSpawnLightningBolt() && biome.temperature >= 1.5F; + sandOilBubble.minY = 56; + sandOilBubble.rangeY = 16; + sandOilBubble.setSize(16, 48); + sandOilBubble.fuzzy = true; + MapGenChainloader.addOverworldGenerator(sandOilBubble); + } + } + } diff --git a/src/main/java/com/hbm/lib/HbmWorldGen.java b/src/main/java/com/hbm/lib/HbmWorldGen.java index dd7af4b60..b5dac1bcd 100644 --- a/src/main/java/com/hbm/lib/HbmWorldGen.java +++ b/src/main/java/com/hbm/lib/HbmWorldGen.java @@ -223,18 +223,6 @@ public class HbmWorldGen implements IWorldGenerator { } } -// if(biome == BiomeGenBase.plains || biome == BiomeGenBase.desert) { -// if(WorldConfig.radioStructure > 0 && rand.nextInt(WorldConfig.radioStructure) == 0) { -// for(int a = 0; a < 1; a++) { -// int x = i + rand.nextInt(16); -// int z = j + rand.nextInt(16); -// int y = world.getHeightValue(x, z); -// -// new Radio01().generate(world, rand, x, y, z); -// } -// } -// } - if(biome.temperature >= 0.4F && biome.rainfall <= 0.6F) { if(WorldConfig.antennaStructure > 0 && rand.nextInt(WorldConfig.antennaStructure) == 0) { for(int a = 0; a < 1; a++) { @@ -278,26 +266,6 @@ public class HbmWorldGen implements IWorldGenerator { } } - if(!biome.canSpawnLightningBolt() && biome.temperature >= 1.5F) { - if(rand.nextInt(200) == 0) { - for(int a = 0; a < 1; a++) { - int x = i + rand.nextInt(16); - int z = j + rand.nextInt(16); - int y = world.getHeightValue(x, z); - - OilSandBubble.spawnOil(world, x, y, z, 15 + rand.nextInt(31)); - } - } - } - -// if(WorldConfig.factoryStructure > 0 && rand.nextInt(WorldConfig.factoryStructure) == 0) { -// int x = i + rand.nextInt(16); -// int z = j + rand.nextInt(16); -// int y = world.getHeightValue(x, z); -// -// new Factory().generate(world, rand, x, y, z); -// } - if(WorldConfig.dudStructure > 0 && rand.nextInt(WorldConfig.dudStructure) == 0) { int x = i + 8 + rand.nextInt(16); int z = j + 8 + rand.nextInt(16); @@ -386,24 +354,6 @@ public class HbmWorldGen implements IWorldGenerator { } } - if(WorldConfig.radfreq > 0 && GeneralConfig.enableRad && rand.nextInt(WorldConfig.radfreq) == 0 && biome == BiomeGenBase.desert) { - - for (int a = 0; a < 1; a++) { - int x = i + rand.nextInt(16); - int z = j + rand.nextInt(16); - - double r = rand.nextInt(15) + 10; - - if(rand.nextInt(50) == 0) - r = 50; - - new Sellafield().generate(world, x, z, r, r * 0.35D); - - if(GeneralConfig.enableDebugMode) - MainRegistry.logger.info("[Debug] Successfully spawned raditation hotspot at " + x + " " + z); - } - } - if (WorldConfig.geyserChlorine > 0 && biome == BiomeGenBase.plains && rand.nextInt(WorldConfig.geyserWater) == 0) { int x = i + rand.nextInt(16); int z = j + rand.nextInt(16); @@ -545,36 +495,6 @@ public class HbmWorldGen implements IWorldGenerator { } } - if(WorldConfig.oilSpawn > 0 && rand.nextInt(WorldConfig.oilSpawn) == 0) { - int randPosX = i + rand.nextInt(16); - int randPosY = rand.nextInt(25); - int randPosZ = j + rand.nextInt(16); - - OilBubble.spawnOil(world, randPosX, randPosY, randPosZ, 10 + rand.nextInt(7)); - } - - if(WorldConfig.bedrockOilSpawn > 0 && rand.nextInt(WorldConfig.bedrockOilSpawn) == 0) { - int randPosX = i + rand.nextInt(16); - int randPosZ = j + rand.nextInt(16); - - for(int x = -4; x <= 4; x++) { - for(int y = 0; y <= 4; y++) { - for(int z = -4; z <= 4; z++) { - - if(Math.abs(x) + Math.abs(y) + Math.abs(z) <= 6) { - Block b = world.getBlock(randPosX + x, y, randPosZ + z); - if(b.isReplaceableOreGen(world, randPosX + x, y, randPosZ + z, Blocks.stone) || b.isReplaceableOreGen(world, randPosX + x, y, randPosZ + z, Blocks.bedrock)) { - world.setBlock(randPosX + x, y, randPosZ + z, ModBlocks.ore_bedrock_oil); - } - } - } - } - } - - DungeonToolbox.generateOre(world, rand, i, j, 16, 8, 10, 50, ModBlocks.stone_porous); - OilSpot.generateOilSpot(world, randPosX, randPosZ, 5, 50, true); - } - if(WorldConfig.meteoriteSpawn > 0 && rand.nextInt(WorldConfig.meteoriteSpawn) == 0) { int x = i + rand.nextInt(16) + 8; int z = j + rand.nextInt(16) + 8; diff --git a/src/main/java/com/hbm/world/feature/OilBubble.java b/src/main/java/com/hbm/world/feature/OilBubble.java deleted file mode 100644 index e122d9d98..000000000 --- a/src/main/java/com/hbm/world/feature/OilBubble.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.hbm.world.feature; - -import com.hbm.blocks.ModBlocks; - -import net.minecraft.init.Blocks; -import net.minecraft.world.World; - -public class OilBubble { - - public static void spawnOil(World world, int x, int y, int z, int radius) { - int r = radius; - int r2 = r * r; - int r22 = r2 / 2; - - for (int xx = -r; xx < r; xx++) { - int X = xx + x; - int XX = xx * xx; - for (int yy = -r; yy < r; yy++) { - int Y = yy + y; - int YY = XX + yy * yy * 3; - for (int zz = -r; zz < r; zz++) { - int Z = zz + z; - int ZZ = YY + zz * zz; - if (ZZ < r22) { - if(world.getBlock(X, Y, Z) == Blocks.stone) - world.setBlock(X, Y, Z, ModBlocks.ore_oil); - } - } - } - } - } - -} diff --git a/src/main/java/com/hbm/world/feature/OilSandBubble.java b/src/main/java/com/hbm/world/feature/OilSandBubble.java deleted file mode 100644 index 45e5c804f..000000000 --- a/src/main/java/com/hbm/world/feature/OilSandBubble.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.hbm.world.feature; - -import java.util.Random; - -import com.hbm.blocks.ModBlocks; - -import net.minecraft.init.Blocks; -import net.minecraft.world.World; - -public class OilSandBubble { - - private final static Random field_149933_a = new Random(); - - public static void spawnOil(World world, int x, int y, int z, int radius) { - int r = radius; - int r2 = r * r; - int r22 = r2 / 2; - - for (int xx = -r; xx < r; xx++) { - int X = xx + x; - int XX = xx * xx; - for (int yy = -r; yy < r; yy++) { - int Y = yy + y; - int YY = XX + yy * yy * 3; - for (int zz = -r; zz < r; zz++) { - int Z = zz + z; - int ZZ = YY + zz * zz; - if (ZZ < r22 + field_149933_a.nextInt(r22 / 3)) { - if(world.getBlock(X, Y, Z) == Blocks.sand) - world.setBlock(X, Y, Z, ModBlocks.ore_oil_sand); - } - } - } - } - } - -} diff --git a/src/main/java/com/hbm/world/feature/Sellafield.java b/src/main/java/com/hbm/world/feature/Sellafield.java deleted file mode 100644 index 98a6d615d..000000000 --- a/src/main/java/com/hbm/world/feature/Sellafield.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.hbm.world.feature; - -import java.util.Random; - -import com.hbm.blocks.ModBlocks; - -import net.minecraft.block.Block; -import net.minecraft.world.World; - -public class Sellafield { - - private double depthFunc(double x, double rad, double depth) { - - return -Math.pow(x, 2) / Math.pow(rad, 2) * depth + depth; - } - - public void generate(World world, int x, int z, double radius, double depth) { - - if(world.isRemote) - return; - - Random rand = new Random(); - - int iRad = (int)Math.round(radius); - - for(int a = -iRad - 5; a <= iRad + 5; a++) { - - for(int b = -iRad - 5; b <= iRad + 5; b++) { - - double r = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2)); - - if(r - rand.nextInt(3) <= radius) { - - int dep = (int)depthFunc(r, radius, depth); - dig(world, x + a, z + b, dep); - - if(r + rand.nextInt(3) <= radius / 3D) { - place(world, x + a, z + b, 3, ModBlocks.sellafield, 1); - } else if(r - rand.nextInt(3) <= radius / 3D * 2D) { - place(world, x + a, z + b, 3, ModBlocks.sellafield); - } else { - place(world, x + a, z + b, 3, ModBlocks.sellafield_slaked); - } - } - } - } - } - - private void dig(World world, int x, int z, int depth) { - - int y = world.getHeightValue(x, z) - 1; - - if(y < depth * 2) - return; - - for(int i = 0; i < depth; i++) - world.setBlockToAir(x, y - i, z); - } - - private void place(World world, int x, int z, int depth, Block block) { place(world, x, z, depth, block, 0); } - - private void place(World world, int x, int z, int depth, Block block, int meta) { - - int y = world.getHeightValue(x, z) - 1; - - for(int i = 0; i < depth; i++) - world.setBlock(x, y - i, z, block, meta, 2); - } - - //private void placeCore(World world, int x, int z, double rad) { } -} diff --git a/src/main/java/com/hbm/world/gen/MapGenBaseMeta.java b/src/main/java/com/hbm/world/gen/MapGenBaseMeta.java new file mode 100644 index 000000000..fe2aaf728 --- /dev/null +++ b/src/main/java/com/hbm/world/gen/MapGenBaseMeta.java @@ -0,0 +1,13 @@ +package com.hbm.world.gen; + +import net.minecraft.world.gen.MapGenBase; + +public class MapGenBaseMeta extends MapGenBase { + + protected byte[] metas; + + public void setMetas(byte[] metas) { + this.metas = metas; + } + +} diff --git a/src/main/java/com/hbm/world/gen/MapGenChainloader.java b/src/main/java/com/hbm/world/gen/MapGenChainloader.java new file mode 100644 index 000000000..93dbc96e5 --- /dev/null +++ b/src/main/java/com/hbm/world/gen/MapGenChainloader.java @@ -0,0 +1,92 @@ +package com.hbm.world.gen; + +import java.util.ArrayList; +import java.util.List; + +import cpw.mods.fml.common.eventhandler.EventPriority; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import net.minecraft.block.Block; +import net.minecraft.world.World; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.gen.MapGenBase; +import net.minecraftforge.event.terraingen.InitMapGenEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.terraingen.ChunkProviderEvent.ReplaceBiomeBlocks; +import net.minecraftforge.event.terraingen.InitMapGenEvent.EventType; + +public class MapGenChainloader extends MapGenBase { + + /** + * There is no way - with existing forge hooks - to add entirely new `MapGenBase` generators to existing dimensions (overworld, nether). + * So, in order to fix that (while not breaking mods like Greg's Caves), we chainload our own MapGenBase into the existing cave generator + */ + + private MapGenBase parent; + + private List generators = new ArrayList<>(); + + // These may be added to before OR after mapgen registration safely + private static List overworldGenerators = new ArrayList<>(); + private static List netherGenerators = new ArrayList<>(); + + // Hack to provide the current generating chunk's block metas to the generation function + private static byte[] blockMetas; + + // Executes our chainloaded parent, and all our child generators + @Override + public void func_151539_a(IChunkProvider chunk, World world, int chunkX, int chunkZ, Block[] blocks) { + parent.func_151539_a(chunk, world, chunkX, chunkZ, blocks); + + // Some mods may use vanilla gen events for added dimensions, so we guard against that here + if(world.provider.dimensionId != 0 && world.provider.dimensionId != -1) return; + + for(MapGenBase generator : generators) { + if(generator instanceof MapGenBaseMeta) ((MapGenBaseMeta)generator).setMetas(blockMetas); + generator.func_151539_a(chunk, world, chunkX, chunkZ, blocks); + } + } + + public static void register() { + MapGenEventHandler handler = new MapGenEventHandler(); + MinecraftForge.TERRAIN_GEN_BUS.register(handler); + MinecraftForge.EVENT_BUS.register(handler); + } + + public static void addOverworldGenerator(MapGenBase generator) { + if(overworldGenerators.contains(generator)) return; + overworldGenerators.add(generator); + } + + public static void addNetherGenerator(MapGenBase generator) { + if(netherGenerators.contains(generator)) return; + netherGenerators.add(generator); + } + + public static class MapGenEventHandler { + + // Register as late as possible to pick up any modded cave generators + @SubscribeEvent(priority = EventPriority.LOWEST) + public void addMapGenChainloader(InitMapGenEvent event) { + if(!(event.newGen instanceof MapGenChainloader)) { + if(event.type == EventType.CAVE) { + MapGenChainloader loader = new MapGenChainloader(); + loader.parent = event.newGen; + loader.generators = overworldGenerators; + event.newGen = loader; + } else if(event.type == EventType.NETHER_CAVE) { + MapGenChainloader loader = new MapGenChainloader(); + loader.parent = event.newGen; + loader.generators = netherGenerators; + event.newGen = loader; + } + } + } + + @SubscribeEvent + public void storeLatestBlockMeta(ReplaceBiomeBlocks event) { + blockMetas = event.metaArray; + } + + } + +} diff --git a/src/main/java/com/hbm/world/gen/terrain/MapGenBedrockOil.java b/src/main/java/com/hbm/world/gen/terrain/MapGenBedrockOil.java new file mode 100644 index 000000000..a01098e2c --- /dev/null +++ b/src/main/java/com/hbm/world/gen/terrain/MapGenBedrockOil.java @@ -0,0 +1,110 @@ +package com.hbm.world.gen.terrain; + +import com.hbm.blocks.ModBlocks; +import com.hbm.blocks.generic.BlockDeadPlant.EnumDeadPlantType; +import com.hbm.blocks.generic.BlockNTMFlower.EnumFlowerType; +import com.hbm.world.gen.MapGenBaseMeta; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.world.World; + +public class MapGenBedrockOil extends MapGenBaseMeta { + + /** + * Similar to oil bubbles, but with a few more behaviours, like adding oily dirt + * no porous stone don't @ me + */ + + private final int frequency; + + public Block block = ModBlocks.ore_bedrock_oil; + public Block replace = Blocks.stone; + + public int spotWidth = 5; + public int spotCount = 50; + public boolean addWillows = true; + + public MapGenBedrockOil(int frequency) { + this.frequency = frequency; + this.range = 4; + } + + @Override + protected void func_151538_a(World world, int offsetX, int offsetZ, int chunkX, int chunkZ, Block[] blocks) { + if(rand.nextInt(frequency) == frequency - 2) { + int xCoord = (chunkX - offsetX) * 16 + rand.nextInt(16); + int zCoord = (chunkZ - offsetZ) * 16 + rand.nextInt(16); + + // Add the bedrock oil spot + for(int bx = 15; bx >= 0; bx--) + for(int bz = 15; bz >= 0; bz--) + for(int y = 0; y < 5; y++) { + int index = (bx * 16 + bz) * 256 + y; + + if(blocks[index] == replace || blocks[index] == Blocks.bedrock) { + // x, z are the coordinates relative to the target virtual chunk origin + int x = xCoord + bx; + int z = zCoord + bz; + + if(Math.abs(x) < 5 && Math.abs(z) < 5 && Math.abs(x) + Math.abs(y) + Math.abs(z) <= 6) { + blocks[index] = block; + } + } + } + + int deadMetaCount = EnumDeadPlantType.values().length; + + // Add oil spot damage + for(int i = 0; i < spotCount; i++) { + int rx = (int)(rand.nextGaussian() * spotWidth) - xCoord; + int rz = (int)(rand.nextGaussian() * spotWidth) - zCoord; + + if(rx >= 0 && rx < 16 && rz >= 0 && rz < 16) { + // find ground level + for(int y = 127; y >= 0; y--) { + int index = (rx * 16 + rz) * 256 + y; + + if(blocks[index] != null && blocks[index].isOpaqueCube()) { + for(int oy = 1; oy > -3; oy--) { + int subIndex = index + oy; + + if(blocks[subIndex] == Blocks.grass || blocks[subIndex] == Blocks.dirt) { + blocks[subIndex] = rand.nextInt(10) == 0 ? ModBlocks.dirt_oily : ModBlocks.dirt_dead; + + if(addWillows && oy == 0 && rand.nextInt(50) == 0) { + blocks[subIndex + 1] = ModBlocks.plant_flower; + metas[subIndex + 1] = (byte)EnumFlowerType.CD0.ordinal(); + } + + // this generation occurs BEFORE decoration, so we have no plants to modify + // so we'll instead just add some new ones right now + if(oy == 0 && rand.nextInt(20) == 0) { + blocks[subIndex + 1] = ModBlocks.plant_dead; + metas[subIndex + 1] = (byte)rand.nextInt(deadMetaCount); + } + + break; + } else if(blocks[subIndex] == Blocks.sand || blocks[subIndex] == ModBlocks.ore_oil_sand) { + if(metas[subIndex] == 1) { + blocks[subIndex] = ModBlocks.sand_dirty_red; + } else { + blocks[subIndex] = ModBlocks.sand_dirty; + } + break; + } else if(blocks[subIndex] == Blocks.stone) { + blocks[subIndex] = ModBlocks.stone_cracked; + break; + } + } + + break; + } + } + } + } + } + } + + +} diff --git a/src/main/java/com/hbm/world/gen/terrain/MapGenBubble.java b/src/main/java/com/hbm/world/gen/terrain/MapGenBubble.java new file mode 100644 index 000000000..5562090cd --- /dev/null +++ b/src/main/java/com/hbm/world/gen/terrain/MapGenBubble.java @@ -0,0 +1,79 @@ +package com.hbm.world.gen.terrain; + +import java.util.function.Predicate; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.gen.MapGenBase; + +public class MapGenBubble extends MapGenBase { + + /** + * Generates oil bubbles, which are generally wider than a chunk, in a safe + cascadeless manner + * Pretty much just an oblate sphere generator (dimensions: 3 x 1 x 3) + */ + + private final int frequency; + private int minSize = 8; + private int maxSize = 64; + + public int minY = 0; + public int rangeY = 25; + + public boolean fuzzy; + + public Block block; + public Block replace = Blocks.stone; + + public Predicate canSpawn; + + public MapGenBubble(int frequency) { + this.frequency = frequency; + } + + public void setSize(int minSize, int maxSize) { + this.minSize = minSize; + this.maxSize = maxSize; + + this.range = (maxSize / 8) + 1; + } + + @Override + protected void func_151538_a(World world, int offsetX, int offsetZ, int chunkX, int chunkZ, Block[] blocks) { + if(rand.nextInt(frequency) == frequency - 1 && (canSpawn == null || canSpawn.test(world.getBiomeGenForCoords(offsetX * 16, offsetZ * 16)))) { + int xCoord = (chunkX - offsetX) * 16 + rand.nextInt(16); + int zCoord = (chunkZ - offsetZ) * 16 + rand.nextInt(16); + + int yCoord = rand.nextInt(rangeY) + minY; + + double radius = rand.nextInt(maxSize - minSize) + minSize; + double radiusSqr = (radius * radius) / 2; // original OilBubble implementation divided the square by 2 for some reason + + int yMin = Math.max(1, MathHelper.floor_double(yCoord - radius)); + int yMax = MathHelper.ceiling_double_int(yCoord + radius); + + for(int bx = 15; bx >= 0; bx--) // bx, bz is the coordinate of the block we're modifying, relative to the generating chunk origin + for(int bz = 15; bz >= 0; bz--) + for(int by = yMin; by < yMax; by++) { + int index = (bx * 16 + bz) * 256 + by; + + if(blocks[index] == replace) { + // x, z are the coordinates relative to the target virtual chunk origin + int x = xCoord + bx; + int z = zCoord + bz; + int y = yCoord - by; + + double rSqr = x * x + z * z + y * y * 3; + if(fuzzy) rSqr -= rand.nextDouble() * radiusSqr / 3; + if(rSqr < radiusSqr) { + blocks[index] = block; + } + } + } + } + } + +} diff --git a/src/main/java/com/hbm/world/gen/terrain/MapGenCrater.java b/src/main/java/com/hbm/world/gen/terrain/MapGenCrater.java new file mode 100644 index 000000000..9a1efd7e9 --- /dev/null +++ b/src/main/java/com/hbm/world/gen/terrain/MapGenCrater.java @@ -0,0 +1,90 @@ +package com.hbm.world.gen.terrain; + +import net.minecraft.block.Block; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.gen.MapGenBase; + +public class MapGenCrater extends MapGenBase { + + private int frequency = 100; + private int minSize = 8; + private int maxSize = 64; + + public Block regolith; + public Block rock; + + public BiomeGenBase targetBiome; + + public MapGenCrater(int frequency) { + this.frequency = frequency; + } + + public void setSize(int minSize, int maxSize) { + this.minSize = minSize; + this.maxSize = maxSize; + + this.range = (maxSize / 8) + 1; + } + + private double depthFunc(double x, double rad, double depth) { + return -Math.pow(x, 2) / Math.pow(rad, 2) * depth + depth; + } + + // This function is looped over from -this.range to +this.range on both XZ axes. + @Override + protected void func_151538_a(World world, int offsetX, int offsetZ, int chunkX, int chunkZ, Block[] blocks) { + if(rand.nextInt(frequency) == 0 && (targetBiome == null || targetBiome == world.getBiomeGenForCoords(offsetX * 16, offsetZ * 16))) { + int xCoord = -offsetX + chunkX; + int zCoord = -offsetZ + chunkZ; + + double radius = rand.nextInt(maxSize - minSize) + minSize; + double depth = radius * 0.35D; + + for(int bx = 15; bx >= 0; bx--) { // bx, bz is the coordinate of the block we're modifying, relative to the generating chunk origin + for(int bz = 15; bz >= 0; bz--) { + for(int y = 127; y >= 0; y--) { + int index = (bx * 16 + bz) * 256 + y; + + if(blocks[index] != null && (blocks[index].isOpaqueCube() || blocks[index].getMaterial().isLiquid())) { + // x, z are the coordinates relative to the target virtual chunk origin + int x = xCoord * 16 + bx; + int z = zCoord * 16 + bz; + + // y is at the current height now + double r = Math.sqrt(x * x + z * z); + + if(r - rand.nextInt(3) <= radius) { + // Carve out to intended depth + int dep = (int)MathHelper.clamp_double(depthFunc(r, radius, depth), 0, y - 1); + for(int i = 0; i < dep; i++) { + blocks[index - i] = null; + } + + index -= dep; + y -= dep; + + dep = Math.min(3, y - 1); + + // Fill back in + if(r + rand.nextInt(3) <= radius / 3D) { + for(int i = 0; i < dep; i++) { + blocks[index - i] = regolith; + } + } else { + for(int i = 0; i < dep; i++) { + blocks[index - i] = rock; + } + } + } + + break; + } + } + } + } + } + } + +}