package com.dreammaster.modfixes.oilgen; import com.dreammaster.main.MainRegistry; import com.dreammaster.modfixes.ModFixBase; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.registry.GameRegistry; import eu.usrv.yamcore.YAMCore; import eu.usrv.yamcore.auxiliary.IntHelper; import eu.usrv.yamcore.auxiliary.LogHelper; import net.minecraft.block.Block; import net.minecraft.block.BlockFlower; import net.minecraft.block.BlockGravel; import net.minecraft.block.BlockLiquid; import net.minecraft.block.BlockSand; import net.minecraft.block.BlockStaticLiquid; import net.minecraft.block.material.Material; import net.minecraft.util.Vec3; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.chunk.Chunk; import net.minecraftforge.common.config.Configuration; import net.minecraftforge.event.terraingen.PopulateChunkEvent; import net.minecraftforge.event.terraingen.TerrainGen; import net.minecraftforge.fluids.BlockFluidBase; import net.minecraftforge.fluids.IFluidBlock; import java.util.ArrayList; import java.util.List; import java.util.Random; public class OilGeneratorFix extends ModFixBase { private enum EDEPOSIT_SIZE { SMALL, MEDIUM, LARGE } public static class OilConfig { public boolean OilFixEnabled = false; public int OilDepostMinDistance = 2; public double OilSphereChance = 30.0D; public int OilSphereMinRadius = 8; public int OilSphereMaxSize = 15; public int OilDepositThresholdLarge = 14; public int OilDepositThresholdMedium = 11; public int OilFountainSizeSmall = 5; public int OilFountainSizeLarge = 16; public double OilBiomeBoostFactor = 2.5D; public List<Integer> OilDimensionWhitelist = new ArrayList<>(); public List<Integer> OilBiomeIDBlackList = new ArrayList<>(); public List<Integer> OilBoostBiomes = new ArrayList<>(); public OilConfig( Configuration pConfigObject ) { pConfigObject.addCustomCategoryComment( "ModFixes.OilGen", "The OilgenChance is based on height of the biome. On high-y biomes, the basic chance is divided by 2, on low-y biomes like oceans, it is multiplied by 1.8.\nThe multiplier set here for -OilBoostBiomes- Biomes is applied after those multipliers are set." ); OilFixEnabled = pConfigObject.getBoolean( "GenerateOil", "ModFixes", OilFixEnabled, "Set to true to enable OilSpawn from this Mod. Make sure to disable Oil-Spawn in BuildCraft if you do" ); OilDepostMinDistance = pConfigObject.getInt( "OilDepostMinDistance", "ModFixes.OilGen", OilDepostMinDistance, 0, 1024, "The minimum distance of 2 Oil-Deposits in chunks. Modulo-Based; A 2 here means an deposit can only spawn in chunks that have a number that is a multiple of 2 (Chunknumber * 16 = X/Z coord)" ); OilSphereChance = pConfigObject.getFloat( "OilSphereChance", "ModFixes.OilGen", (float) OilSphereChance, 0.0F, 2000F, "General OilGen factor" ); OilSphereMinRadius = pConfigObject.getInt( "OilSphereMinRadius", "ModFixes.OilGen", OilSphereMinRadius, 0, 20, "The minimum radius of an underground OilSphere" ); OilSphereMaxSize = pConfigObject.getInt( "OilSphereMaxSize", "ModFixes.OilGen", OilSphereMaxSize, 3, 50, "The maximum radius of an underground OilSphere. The final size is calculated by OilSphereMinRadius + Random(OilSphereMaxSize-OilSphereMinRadius)" ); OilDepositThresholdMedium = pConfigObject.getInt( "OilDepositThresholdMedium", "ModFixes.OilGen", OilDepositThresholdMedium, 0, 100, "Threshold at which an oil-deposit will be considered as 'medium' and the fountain will be higher and thicker." ); OilDepositThresholdLarge = pConfigObject.getInt( "OilDepositThresholdLarge", "ModFixes.OilGen", OilDepositThresholdLarge, 0, 100, "Threshold at which an oil-deposit will be considered as 'large' and the fountain will be higher and thicker." ); OilFountainSizeSmall = pConfigObject.getInt( "OilFountainSizeSmall", "ModFixes.OilGen", OilFountainSizeSmall, 0, 100, "Visible height of the fountain above the oil-deposit for MEDIUM deposits" ); OilFountainSizeLarge = pConfigObject.getInt( "OilFountainSizeLarge", "ModFixes.OilGen", OilFountainSizeLarge, 0, 100, "Visible height of the fountain above the oil-deposit for LARGE deposits" ); OilBiomeBoostFactor = pConfigObject.getFloat( "OilBiomeBoostFactor", "ModFixes.OilGen", (float) OilBiomeBoostFactor, 0.0F, 50.0F, "Boost factor of oil spheres in certain Biomes that are listed in -OilBoostBiomes-" ); OilDimensionWhitelist = parseStringListToIntList( pConfigObject.getStringList( "OilDimensionWhitelist", "ModFixes.OilGen", new String[] { "0" }, "List DimensionIDs (Numbers only; One per line!) here where the OilGenerator should do its work" ) ); OilBiomeIDBlackList = parseStringListToIntList( pConfigObject.getStringList( "OilBiomeIDBlackList", "ModFixes.OilGen", new String[] {}, "List BiomeIDs (Numbers only; One per line!) where no oil should be generated" ) ); OilBoostBiomes = parseStringListToIntList( pConfigObject.getStringList( "OilBoostBiomes", "ModFixes.OilGen", new String[] {}, "List BiomeIDs (Numbers only; One per line!) where the boost multiplicator is applied. Leave empty to disable Biome-Boost" ) ); } private List<Integer> parseStringListToIntList( String[] pSource ) { List<Integer> tLst = new ArrayList<>(); for( String tEntry : pSource ) { if( IntHelper.tryParse( tEntry ) ) { tLst.add(Integer.parseInt(tEntry)); } } return tLst; } } private Block _mBuildCraftOilBlock; public static String ModFixName = "OilGeneratorFix"; private LogHelper _mLog; public OilGeneratorFix() { super( ModFixName ); _mBuildCraftOilBlock = GameRegistry.findBlock( "BuildCraft|Energy", "blockOil" ); _mLog = MainRegistry.Logger; } @Override public boolean getIsActive() { return _mBuildCraftOilBlock != null; } @Override public boolean init() { if( _mBuildCraftOilBlock == null ) { _mLog.error( "Unable to find BuildCraft Oil Block. ModFix will not spawn anything" ); return false; } else { _mLog.info( "Found BC Oil block. Ready for worldgen" ); return true; } } @Override public boolean needsForgeEventBus() { return true; } @Override public boolean needsFMLEventBus() { return false; } @SubscribeEvent public void populate( PopulateChunkEvent.Post event ) { try { if( _mBuildCraftOilBlock == null ) { return; } int tMinDist = MainRegistry.CoreConfig.OilFixConfig.OilDepostMinDistance; if (tMinDist > 1) { if (event.chunkX % tMinDist != 0 || event.chunkZ % tMinDist != 0) { return; } } boolean doGen = TerrainGen.populate( event.chunkProvider, event.world, event.rand, event.chunkX, event.chunkZ, event.hasVillageGenerated, PopulateChunkEvent.Populate.EventType.CUSTOM ); if( !doGen ) { return; } int worldX = event.chunkX << 4; int worldZ = event.chunkZ << 4; generateOil( event.world, event.rand, worldX + event.rand.nextInt( 16 ), worldZ + event.rand.nextInt( 16 ), false ); } catch( Exception e ) { e.printStackTrace(); } } private void generateOil( World world, Random rand, int xx, int zz, boolean testFirst ) { Vec3 pos = Vec3.createVectorHelper( 0, 0, 0 ); if( shouldSpawnOil( world, rand, xx, zz, pos ) ) { int x = (int) pos.xCoord; int cy = (int) pos.yCoord; int z = (int) pos.zCoord; int tMinRadius = MainRegistry.CoreConfig.OilFixConfig.OilSphereMinRadius; int tMaxRadius = MainRegistry.CoreConfig.OilFixConfig.OilSphereMaxSize; int r = rand.nextInt(tMaxRadius + 1 - tMinRadius) + tMinRadius; if( testFirst && checkOilPresent( world, x, cy, z, r )) { return; } if( YAMCore.isDebug() ) { _mLog.info(String.format("About to generate OilSphere, centered at %d/%d/%d, radius %d", x, cy, z, r)); } // Taken from BuildCraft; Dont' generate if topblock is at y = 5 // Should already be covered in shouldSpawnOil, but you never know.. int groundLevel = getTopBlock( world, x, z ); if( groundLevel < 5 ) { if( YAMCore.isDebug() ) { _mLog.warn("OilGenerator stopped; World-height is below 5"); } return; } buildOilStructure( world, rand, x, cy, z, r, groundLevel, _mBuildCraftOilBlock, true ); } } public void buildOilStructure( World pWorld, Random pRand, int pSphereX, int pSphereY, int pSphereZ, int pRadius, int pGroundLevel, Block pTargetBlock, boolean pCheckValidLocation ) { // Make sure to not exceed the max-build height of minecraft EDEPOSIT_SIZE eSize; int tSpringHeight = 0; if( pRadius >= MainRegistry.CoreConfig.OilFixConfig.OilDepositThresholdLarge ) { tSpringHeight = MainRegistry.CoreConfig.OilFixConfig.OilFountainSizeLarge; eSize = EDEPOSIT_SIZE.LARGE; } else if( pRadius >= MainRegistry.CoreConfig.OilFixConfig.OilDepositThresholdMedium ) { tSpringHeight = MainRegistry.CoreConfig.OilFixConfig.OilFountainSizeSmall; eSize = EDEPOSIT_SIZE.MEDIUM; } else { eSize = EDEPOSIT_SIZE.SMALL; } int pMaxHeight = pGroundLevel + tSpringHeight; if( pMaxHeight >= pWorld.getActualHeight() - 1 ) { if( YAMCore.isDebug() ) { _mLog.warn("The total height of the calculated OilDeposit would exceed the maximum world-size."); } return; } int r2 = pRadius * pRadius; for( int bx = -pRadius; bx <= pRadius; bx++ ) { for( int by = -pRadius + 2; by <= pRadius - 2; by++ ) { for( int bz = -pRadius; bz <= pRadius; bz++ ) { int d2 = bx * bx + by * by * 3 + bz * bz; if( d2 <= r2 ) { if( !checkBlock( pWorld, bx + pSphereX - 1, by + pSphereY, bz + pSphereZ ) || !pCheckValidLocation ) { if( !checkBlock( pWorld, bx + pSphereX + 1, by + pSphereY, bz + pSphereZ ) || !pCheckValidLocation ) { if( !checkBlock( pWorld, bx + pSphereX, by + pSphereY - 1, bz + pSphereZ ) || !pCheckValidLocation ) { if( !checkBlock( pWorld, bx + pSphereX, by + pSphereY, bz + pSphereZ - 1 ) || !pCheckValidLocation ) { if( !checkBlock( pWorld, bx + pSphereX, by + pSphereY, bz + pSphereZ + 1 ) || !pCheckValidLocation ) { if( !checkBlockAbove( pWorld, bx + pSphereX, by + pSphereY + 1, bz + pSphereZ ) || !pCheckValidLocation ) { pWorld.setBlock( bx + pSphereX, by + pSphereY, bz + pSphereZ, pTargetBlock, 0, 2 ); } } } } } } } } } } if( eSize.ordinal() >= EDEPOSIT_SIZE.MEDIUM.ordinal() ) { for( int y = pSphereY + 1; y <= pMaxHeight; y++ ) { pWorld.setBlock( pSphereX, y, pSphereZ, pTargetBlock, 0, 3 ); } } if( eSize == EDEPOSIT_SIZE.LARGE ) { for( int y = pSphereY; y <= pMaxHeight - tSpringHeight / 2; y++ ) { pWorld.setBlock( pSphereX + 1, y, pSphereZ, pTargetBlock, 0, 3 ); pWorld.setBlock( pSphereX - 1, y, pSphereZ, pTargetBlock, 0, 3 ); pWorld.setBlock( pSphereX, y, pSphereZ + 1, pTargetBlock, 0, 3 ); pWorld.setBlock( pSphereX, y, pSphereZ - 1, pTargetBlock, 0, 3 ); } } } private int getTopBlock( World pWorld, int pLocX, int pLocZ ) { Chunk tChunk = pWorld.getChunkFromBlockCoords( pLocX, pLocZ ); int y = tChunk.getTopFilledSegment() + 15; int trimmedX = pLocX & 0xF; int trimmedZ = pLocZ & 0xF; for( ; y > 0; y-- ) { Block tBlock = tChunk.getBlock( trimmedX, y, trimmedZ ); if( !tBlock.isAir( pWorld, pLocX, y, pLocZ ) ) { if(tBlock instanceof BlockStaticLiquid) { return y; } if(tBlock instanceof BlockFluidBase) { return y; } if(tBlock instanceof IFluidBlock) { return y; } if( tBlock.getMaterial().blocksMovement() ) { if( !( tBlock instanceof BlockFlower ) ) { return y - 1; } } } } return -1; } private boolean checkOilPresent( World pWorld, int pLocX, int pLocY, int pLocZ, int pRadius ) { int r2 = pRadius * pRadius; for( int bx = -pRadius; bx <= pRadius; bx++ ) { for( int by = -pRadius + 2; by <= pRadius - 2; by++ ) { for( int bz = -pRadius; bz <= pRadius; bz++ ) { int d2 = bx * bx + by * by * 3 + bz * bz; if( d2 <= r2 ) { if( !checkBlock( pWorld, bx + pLocX - 1, by + pLocY, bz + pLocZ ) ) { if( !checkBlock( pWorld, bx + pLocX + 1, by + pLocY, bz + pLocZ ) ) { if( !checkBlock( pWorld, bx + pLocX, by + pLocY - 1, bz + pLocZ ) ) { if( !checkBlock( pWorld, bx + pLocX, by + pLocY, bz + pLocZ - 1 ) ) { if( !checkBlock( pWorld, bx + pLocX, by + pLocY, bz + pLocZ + 1 ) ) { if( !checkBlockAbove( pWorld, bx + pLocX, by + pLocY + 1, bz + pLocZ ) ) { if( pWorld.getBlock( bx + pLocX, by + pLocY, bz + pLocZ ) == _mBuildCraftOilBlock ) { return true; } } } } } } } } } } } return false; } // This is supposed to check if the block in question to be replaced is NOT air, and if it's a liquid // that it is NOT our BC oil. (The logic in checkOilPresent is inverted) private boolean checkBlock( World pWorld, int pLocX, int pLocY, int pLocZ ) { Block tBlock = pWorld.getBlock(pLocX, pLocY, pLocZ); return tBlock.getMaterial() == Material.air || tBlock instanceof BlockLiquid && tBlock != _mBuildCraftOilBlock; } // This is supposed to make sure no falling blocks are above the block to be placed, // would otherwise cause issues I assume private static boolean checkBlockAbove( World pWorld, int pLocX, int pLocY, int pLocZ ) { Block tBlock = pWorld.getBlock( pLocX, pLocY, pLocZ ); if(tBlock instanceof BlockSand) { return true; } if(tBlock instanceof BlockGravel) { return true; } return false; } // Check if given location is valid for spawning oil, and return the actual position in pPos private boolean shouldSpawnOil( World pWorld, Random pRand, int pX, int pZ, Vec3 pPos ) { // Limited to Whitelisted Dimensions if( !MainRegistry.CoreConfig.OilFixConfig.OilDimensionWhitelist.contains( pWorld.provider.dimensionId ) ) { if( YAMCore.isDebug() ) { _mLog.info(String.format("Not generating OilDeposit; Dimension is not Whitelisted %d", pWorld.provider.dimensionId)); } return false; } BiomeGenBase biomegenbase = pWorld.getBiomeGenForCoords( pX + 8, pZ + 8 ); // Skip blacklisted DimensionIDs if( MainRegistry.CoreConfig.OilFixConfig.OilBiomeIDBlackList.contains( biomegenbase.biomeID ) ) { if( YAMCore.isDebug() ) { _mLog.info(String.format("Not generating OilDeposit; BiomeID %d is Blacklisted", biomegenbase.biomeID)); } return false; } pRand.setSeed( pWorld.getSeed() ); long i1 = pRand.nextInt() / 2L * 2L + 1L; long j1 = pRand.nextInt() / 2L * 2L + 1L; pRand.setSeed( pX * i1 + pZ * j1 ^ pWorld.getSeed() ); double randMod = Math.min( 0.2D, 0.0001D * MainRegistry.CoreConfig.OilFixConfig.OilSphereChance ); if( biomegenbase.rootHeight >= 0.45F ) { randMod /= 2.0D; } if( biomegenbase.rootHeight < -0.5F ) { randMod *= 1.8D; } if( MainRegistry.CoreConfig.OilFixConfig.OilBoostBiomes.contains( biomegenbase.biomeID ) ) { randMod *= MainRegistry.CoreConfig.OilFixConfig.OilBiomeBoostFactor; } boolean flag1 = pRand.nextDouble() <= randMod; boolean flag2 = pRand.nextDouble() <= randMod; if( flag1 || flag2) { pPos.yCoord = 17 + pRand.nextInt( 10 ) + pRand.nextInt( 5 ); pPos.xCoord = pX + pRand.nextInt( 16 ); pPos.zCoord = pZ + pRand.nextInt( 16 ); return true; } return false; } }