package com.thexfactor117.losteclipse.generation; import java.util.Map.Entry; import java.util.Random; import com.thexfactor117.losteclipse.LostEclipse; import com.thexfactor117.losteclipse.config.Config; import com.thexfactor117.losteclipse.generation.procedural.ProceduralDungeon; import com.thexfactor117.losteclipse.init.ModBlocks; import com.thexfactor117.losteclipse.init.ModLootTables; import com.thexfactor117.losteclipse.util.Reference; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Biomes; import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.IChunkGenerator; import net.minecraft.world.chunk.IChunkProvider; import net.minecraft.world.gen.feature.WorldGenMinable; import net.minecraft.world.gen.structure.template.PlacementSettings; import net.minecraft.world.gen.structure.template.Template; import net.minecraft.world.gen.structure.template.TemplateManager; import net.minecraftforge.fml.common.IWorldGenerator; /** * * @author TheXFactor117 * */ public class LEWorldGenerator implements IWorldGenerator { @Override public void generate(Random rand, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider) { int blockX = chunkX * 16; int blockZ = chunkZ * 16; switch (world.provider.getDimension()) { case -1: generateNether(world, rand, blockX, blockZ); break; case 0: generateOverworld(world, rand, blockX, blockZ); break; case 1: generateEnd(world, rand, blockX, blockZ); break; } } private void generateOverworld(World world, Random rand, int blockX, int blockZ) { generateOverworldOres(world, rand, blockX, blockZ); generateOverworldStructures(world, rand, blockX, blockZ); } private void generateNether(World world, Random rand, int chunkX, int chunkZ) {} private void generateEnd(World world, Random rand, int chunkX, int chunkZ) {} /** * Generates ores in the overworld. Helper method to make things cleaner. * @param world * @param rand * @param blockX * @param blockZ */ private void generateOverworldOres(World world, Random rand, int blockX, int blockZ) { IBlockState verantiumOre = ModBlocks.verantiumOre.getDefaultState(); IBlockState vexalOre = ModBlocks.vexalOre.getDefaultState(); IBlockState astrillOre = ModBlocks.astrillOre.getDefaultState(); addOreSpawn(verantiumOre, world, rand, blockX, blockZ, 16, 16, 4 + rand.nextInt(4), 14, 1, 64); addOreSpawn(vexalOre, world, rand, blockX, blockZ, 16, 16, 2 + rand.nextInt(2), 6, 24, 48); addOreSpawn(astrillOre, world, rand, blockX, blockZ, 16, 16, 1, 3, 1, 15); } /** * Generates structures in the overworld. Helper method to make things cleaner. * @param world * @param rand * @param blockX * @param blockZ */ private void generateOverworldStructures(World world, Random rand, int blockX, int blockZ) { if (Config.spawnStructures) { WorldServer server = (WorldServer) world; TemplateManager manager = server.getStructureTemplateManager(); // templates Template smallHouse = manager.getTemplate(world.getMinecraftServer(), new ResourceLocation(Reference.MODID, "smallhouse")); Template castle = manager.getTemplate(world.getMinecraftServer(), new ResourceLocation(Reference.MODID, "castle1")); // structures if ((int) (Math.random() * Config.smallHouseChance) == 0) { int randX = blockX + (int) Math.random() * 16; int randZ = blockZ + (int) Math.random() * 16; int groundY = getGroundFromAbove(world, randX, randZ); BlockPos pos = new BlockPos(randX, groundY, randZ); if (canSpawnHere(smallHouse, world, pos)) { LostEclipse.LOGGER.info("Generating Small House at " + pos); smallHouse.addBlocksToWorld(world, pos, new PlacementSettings()); handleDataBlocks(smallHouse, world, pos, new PlacementSettings()); } } if ((int) (Math.random() * Config.castleChance) == 0) { int randX = blockX + (int) Math.random() * 16; int randZ = blockZ + (int) Math.random() * 16; int groundY = getGroundFromAbove(world, randX, randZ); BlockPos pos = new BlockPos(randX, groundY, randZ); if (canSpawnHere(castle, world, pos) && world.getBiome(pos) == Biomes.PLAINS) { LostEclipse.LOGGER.info("Generating Castle at " + pos); castle.addBlocksToWorld(world, pos, new PlacementSettings()); handleDataBlocks(castle, world, pos, new PlacementSettings()); } } } if (Config.spawnDungeons) { // dungeons if ((int) (Math.random() * 500) == 0) { int randX = blockX + (int) Math.random() * 16; int randZ = blockZ + (int) Math.random() * 16; int y = (int) (Math.random() * 45 + 5); BlockPos pos = new BlockPos(randX, y, randZ); int maxRooms = 4 + (int) (Math.random() * 2); LostEclipse.LOGGER.info("Generating Dungeon (" + maxRooms + ") at " + pos); ProceduralDungeon dungeon = new ProceduralDungeon(maxRooms); dungeon.generate(world, rand, pos); } } } /** * Gets the Y-value of the ground at a specifix x/y coordinate. * @param world * @param x * @param z * @return */ private int getGroundFromAbove(World world, int x, int z) { int y = 255; boolean foundGround = false; while(!foundGround && y-- >= 63) { Block blockAt = world.getBlockState(new BlockPos(x,y,z)).getBlock(); foundGround = blockAt == Blocks.DIRT || blockAt == Blocks.GRASS || blockAt == Blocks.SAND || blockAt == Blocks.SNOW || blockAt == Blocks.SNOW_LAYER; } return y; } private boolean canSpawnHere(Template template, World world, BlockPos posAboveGround) { int zwidth = template.getSize().getZ(); int xwidth = template.getSize().getX(); // check all the corners to see which ones are replaceable boolean corner1 = isCornerValid(world, posAboveGround); boolean corner2 = isCornerValid(world, posAboveGround.add(xwidth, 0, zwidth)); // if Y > 20 and all corners pass the test, it's okay to spawn the structure return posAboveGround.getY() > 63 && corner1 && corner2; } private boolean isCornerValid(World world, BlockPos pos) { int variation = 3; int highestBlock = getGroundFromAbove(world, pos.getX(), pos.getZ()); if (highestBlock > pos.getY() - variation && highestBlock < pos.getY() + variation) return true; LostEclipse.LOGGER.info("Canceling gen for this structure."); return false; } /** * Adds the specified block to be generated in throughout the world. * Key parameters: maxVeinSize, chanceToSpawn, minY, maxY. * @param block * @param world * @param random * @param blockXPos * @param blockZPos * @param maxX * @param maxZ * @param maxVeinSize * @param chanceToSpawn * @param minY * @param maxY */ private void addOreSpawn(IBlockState block, World world, Random random, int blockXPos, int blockZPos, int maxX, int maxZ, int maxVeinSize, int chanceToSpawn, int minY, int maxY) { for (int i = 0; i < chanceToSpawn; i++) { int posX = blockXPos + random.nextInt(maxX); int posY = minY + random.nextInt(maxY - minY); int posZ = blockZPos + random.nextInt(maxZ); new WorldGenMinable(block, maxVeinSize).generate(world, random, new BlockPos(posX, posY, posZ)); } } /** * Iterates through every Data Structure Block in the given template. Used to add loot to chests. * @param template * @param world * @param pos * @param settings */ private void handleDataBlocks(Template template, World world, BlockPos pos, PlacementSettings settings) { // loop through all data blocks within the structure for (Entry<BlockPos, String> e : template.getDataBlocks(pos, settings).entrySet()) { if ("common_chest".equals(e.getValue())) // check data block tag { BlockPos dataPos = e.getKey(); world.setBlockState(dataPos, Blocks.AIR.getDefaultState(), 3); // remove data block TileEntity chestEntity = world.getTileEntity(dataPos.down()); // chest is located under data block if (chestEntity instanceof TileEntityChest) { int rand = (int) (Math.random() * 100 + 1); if (rand <= 85) ((TileEntityChest) chestEntity).setLootTable(ModLootTables.STRUCTURE_COMMON, world.rand.nextLong()); else if (rand > 95) ((TileEntityChest) chestEntity).setLootTable(ModLootTables.STRUCTURE_LEGENDARY, world.rand.nextLong()); else ((TileEntityChest) chestEntity).setLootTable(ModLootTables.STRUCTURE_RARE, world.rand.nextLong()); } } else if ("rare_chest".equals(e.getValue())) // check data block tag { BlockPos dataPos = e.getKey(); world.setBlockState(dataPos, Blocks.AIR.getDefaultState(), 3); // remove data block TileEntity chestEntity = world.getTileEntity(dataPos.down()); // chest is located under data block if (chestEntity instanceof TileEntityChest) { int rand = (int) (Math.random() * 100 + 1); if (rand <= 40) ((TileEntityChest) chestEntity).setLootTable(ModLootTables.STRUCTURE_COMMON, world.rand.nextLong()); else if (rand > 90) ((TileEntityChest) chestEntity).setLootTable(ModLootTables.STRUCTURE_LEGENDARY, world.rand.nextLong()); else ((TileEntityChest) chestEntity).setLootTable(ModLootTables.STRUCTURE_RARE, world.rand.nextLong()); } } else if ("legendary_chest".equals(e.getValue())) // check data block tag { BlockPos dataPos = e.getKey(); world.setBlockState(dataPos, Blocks.AIR.getDefaultState(), 3); // remove data block TileEntity chestEntity = world.getTileEntity(dataPos.down()); // chest is located under data block if (chestEntity instanceof TileEntityChest) { int rand = (int) (Math.random() * 100 + 1); if (rand <= 10) ((TileEntityChest) chestEntity).setLootTable(ModLootTables.STRUCTURE_COMMON, world.rand.nextLong()); else if (rand > 50) ((TileEntityChest) chestEntity).setLootTable(ModLootTables.STRUCTURE_LEGENDARY, world.rand.nextLong()); else ((TileEntityChest) chestEntity).setLootTable(ModLootTables.STRUCTURE_RARE, world.rand.nextLong()); } } } } }