package gregtech.common; import cpw.mods.fml.common.IWorldGenerator; import cpw.mods.fml.common.registry.GameRegistry; import gregtech.api.GregTech_API; import gregtech.api.enums.Materials; import gregtech.api.objects.XSTR; import gregtech.api.util.GT_Log; import gregtech.api.world.GT_Worldgen; import gregtech.common.blocks.GT_TileEntity_Ores; import net.minecraft.init.Blocks; import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.IChunkProvider; import java.util.ArrayList; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Random; import static gregtech.api.enums.GT_Values.debugOrevein; import static gregtech.api.enums.GT_Values.debugWorldGen; import static gregtech.api.enums.GT_Values.oreveinAttempts; import static gregtech.api.enums.GT_Values.oreveinMaxPlacementAttempts; import static gregtech.api.enums.GT_Values.oreveinPercentage; public class GT_Worldgenerator implements IWorldGenerator { private static int mEndAsteroidProbability = 300; private static int mSize = 100; private static int endMinSize = 50; private static int endMaxSize = 200; private static boolean endAsteroids = true; public static List mList = new ArrayList(); public static HashSet ProcChunks = new HashSet(); // This is probably not going to work. Trying to create a fake orevein to put into hashtable when there will be no ores in a vein. public static GT_Worldgen_GT_Ore_Layer noOresInVein = new GT_Worldgen_GT_Ore_Layer( "NoOresInVein", false, 0, 255, 0, 255, 16, false, false, false, Materials.Aluminium, Materials.Aluminium, Materials.Aluminium, Materials.Aluminium); public static Hashtable validOreveins = new Hashtable(1024); public boolean mIsGenerating = false; public static final Object listLock = new Object(); public GT_Worldgenerator() { endAsteroids = GregTech_API.sWorldgenFile.get("endasteroids", "GenerateAsteroids", true); endMinSize = GregTech_API.sWorldgenFile.get("endasteroids", "AsteroidMinSize", 50); endMaxSize = GregTech_API.sWorldgenFile.get("endasteroids", "AsteroidMaxSize", 200); mEndAsteroidProbability = GregTech_API.sWorldgenFile.get("endasteroids", "AsteroidProbability", 300); GameRegistry.registerWorldGenerator(this, 1073741823); if (debugWorldGen) { GT_Log.out.println( "GT_Worldgenerator created" ); } } @Override public void generate(Random aRandom, int aX, int aZ, World aWorld, IChunkProvider aChunkGenerator, IChunkProvider aChunkProvider) { synchronized (listLock) { mList.add(new WorldGenContainer(new XSTR(Math.abs(aRandom.nextInt()) +1), aX, aZ, aWorld.provider.dimensionId, aWorld, aChunkGenerator, aChunkProvider, aWorld.getBiomeGenForCoords(aX * 16 + 8, aZ * 16 + 8).biomeName)); if (debugWorldGen) GT_Log.out.println( "ADD WorldSeed:"+aWorld.getSeed() + " DimId" + aWorld.provider.dimensionId + " chunk x:" + aX + " z:" + aZ + " SIZE: " + mList.size() ); } if (!this.mIsGenerating) { this.mIsGenerating = true; int mList_sS= mList.size(); mList_sS = Math.min(mList_sS, 5); // Run a maximum of 5 chunks at a time through worldgen. Extra chunks get done later. for (int i = 0; i < mList_sS; i++) { WorldGenContainer toRun = (WorldGenContainer) mList.get(0); if (debugWorldGen) GT_Log.out.println( "RUN WorldSeed:"+aWorld.getSeed()+ " DimId" + aWorld.provider.dimensionId + " chunk x:" + toRun.mX + " z:" + toRun.mZ + " SIZE: " + mList.size() + " i: " + i ); synchronized (listLock) { mList.remove(0); } toRun.run(); } this.mIsGenerating = false; } } public static class WorldGenContainer implements Runnable { public final Random mRandom; public final int mX; public final int mZ; public final int mDimensionType; public final World mWorld; public final IChunkProvider mChunkGenerator; public final IChunkProvider mChunkProvider; public final String mBiome; // Used for outputting orevein weights and bins // static int test=0; // Local class to track which orevein seeds must be checked when doing chunkified worldgen class NearbySeeds { public int mX; public int mZ; NearbySeeds( int x, int z) { this.mX = x; this.mZ = z; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof GT_Worldgenerator.WorldGenContainer.NearbySeeds)) return false; GT_Worldgenerator.WorldGenContainer.NearbySeeds that = (GT_Worldgenerator.WorldGenContainer.NearbySeeds) o; if (this.mX != that.mX) return false; return this.mZ == that.mZ; } @Override public int hashCode() { int result = this.mX; result = 31 * result + this.mZ; return result; } }; public static ArrayList seedList = new ArrayList(); // aX and aZ are now the by-chunk X and Z for the chunk of interest public WorldGenContainer(Random aRandom, int aX, int aZ, int aDimensionType, World aWorld, IChunkProvider aChunkGenerator, IChunkProvider aChunkProvider, String aBiome) { this.mRandom = aRandom; this.mX = aX; this.mZ = aZ; this.mDimensionType = aDimensionType; this.mWorld = aWorld; this.mChunkGenerator = aChunkGenerator; this.mChunkProvider = aChunkProvider; this.mBiome = aBiome; } // How to evaluate oregen distribution // - Enable debugOreveins // - Fly around for a while, or teleport jumping ~320 blocks at a time, with // a 15-30s pause for worldgen to catch up // - Do this across a large area, at least 2000x2000 blocks for good numbers // - Open logs\gregtech.log // - Using notepad++, do a Search | Find - enter "Added" for the search term // - Select Find All In Current Document // - In the Search window, right-click and Select All // - Copy and paste to a new file // - Delete extraneous stuff at top, and blank line at bottom. Line count is // # of total oreveins // - For simple spot checks, use Find All in Current Document for specific // oremixes, ie ore.mix.diamond, to check how many appear in the list. // - For more complex work, import file into Excel, and sort based on oremix // column. Drag select the oremix names, in the bottom right will be how many // entries to add in a seperate tab to calculate %ages. // // When using the ore weights, discount or remove the high altitude veins since // their high weight are offset by their rareness. I usually just use zero for them. // Actual spawn rates will vary based upon the average height of the stone layers // in the dimension. For example veins that range above and below the average height // will be less, and veins that are completely above the average height will be much less. public void worldGenFindVein( int oreseedX, int oreseedZ) { // Explanation of oreveinseed implementation. // (long)this.mWorld.getSeed()<<16) Deep Dark does two oregen passes, one with getSeed set to +1 the original world seed. This pushes that +1 off the low bits of oreseedZ, so that the hashes are far apart for the two passes. // ((this.mWorld.provider.dimensionId & 0xffL)<<56) Puts the dimension in the top bits of the hash, to make sure to get unique hashes per dimension // ((long)oreseedX & 0x000000000fffffffL) << 28) Puts the chunk X in the bits 29-55. Cuts off the top few bits of the chunk so we have bits for dimension. // ( (long)oreseedZ & 0x000000000fffffffL )) Puts the chunk Z in the bits 0-27. Cuts off the top few bits of the chunk so we have bits for dimension. long oreveinSeed = ((long)this.mWorld.getSeed()<<16) ^ ((long)((this.mWorld.provider.dimensionId & 0xffL)<<56) |( ((long)oreseedX & 0x000000000fffffffL) << 28) | ( (long)oreseedZ & 0x000000000fffffffL )); // Use an RNG that is identical every time it is called for this oreseed. XSTR oreveinRNG = new XSTR( oreveinSeed ); int oreveinPercentageRoll = oreveinRNG.nextInt(100); // Roll the dice, see if we get an orevein here at all int noOrePlacedCount=0; String tDimensionName = ""; if (debugOrevein) { tDimensionName = this.mWorld.provider.getDimensionName(); } if (debugOrevein) GT_Log.out.println( " Finding oreveins for oreveinSeed="+ oreveinSeed + " mX="+ this.mX + " mZ="+ this.mZ + " oreseedX="+ oreseedX + " oreseedZ="+ oreseedZ + " worldSeed="+this.mWorld.getSeed() ); // Search for a valid orevein for this dimension if( !validOreveins.containsKey(oreveinSeed) ) { if ( (oreveinPercentageRoll 0) && (GT_Worldgen_GT_Ore_Layer.sList.size() > 0)) { int placementAttempts = 0; boolean oreveinFound = false; int i; // Used for outputting orevein weights and bins /* if( test==0 ) { test = 1; GT_Log.out.println( "sWeight = " + GT_Worldgen_GT_Ore_Layer.sWeight ); for (GT_Worldgen_GT_Ore_Layer tWorldGen : GT_Worldgen_GT_Ore_Layer.sList) { GT_Log.out.println( ( tWorldGen).mWorldGenName + " mWeight = " + ( tWorldGen).mWeight + " mSize = " + (tWorldGen).mSize ); } } */ for( i = 0; (i < oreveinAttempts) && (!oreveinFound) && (placementAttempts 0) && (GT_Worldgen_GT_Ore_Layer.sList.size() > 0)) { boolean temp = true; int tRandomWeight; for (int i = 0; (i < oreveinAttempts) && (temp); i++) { tRandomWeight = aRandom.nextInt(GT_Worldgen_GT_Ore_Layer.sWeight); for (GT_Worldgen_GT_Ore_Layer tWorldGen : GT_Worldgen_GT_Ore_Layer.sList) { tRandomWeight -= ((GT_Worldgen_GT_Ore_Layer) tWorldGen).mWeight; if (tRandomWeight <= 0) { try { //if ((tWorldGen.mEndAsteroid && tDimensionType == 1) || (tWorldGen.mAsteroid && tDimensionType == -30)) { if (tWorldGen.mEndAsteroid && tDimensionType == 1) { primaryMeta = tWorldGen.mPrimaryMeta; secondaryMeta = tWorldGen.mSecondaryMeta; betweenMeta = tWorldGen.mBetweenMeta; sporadicMeta = tWorldGen.mSporadicMeta; temp = false; break; } } catch (Throwable e) { e.printStackTrace(GT_Log.err); } } } } } //if(GT_Values.D1)GT_FML_LOGGER.info("do asteroid gen: "+this.mX+" "+this.mZ); int tX = mX * 16 + aRandom.nextInt(16); int tY = 50 + aRandom.nextInt(200 - 50); int tZ = mZ * 16 + aRandom.nextInt(16); if (tDimensionType == 1) { mSize = aRandom.nextInt((int) (endMaxSize - endMinSize)); //} else if (tDimensionName.equals("Asteroids")) { // mSize = aRandom.nextInt((int) (gcMaxSize - gcMinSize)); } if ((mWorld.getBlock(tX, tY, tZ).isAir(mWorld, tX, tY, tZ))) { float var6 = aRandom.nextFloat() * 3.141593F; double var7 = tX + 8 + MathHelper.sin(var6) * mSize / 8.0F; double var9 = tX + 8 - MathHelper.sin(var6) * mSize / 8.0F; double var11 = tZ + 8 + MathHelper.cos(var6) * mSize / 8.0F; double var13 = tZ + 8 - MathHelper.cos(var6) * mSize / 8.0F; double var15 = tY + aRandom.nextInt(3) - 2; double var17 = tY + aRandom.nextInt(3) - 2; for (int var19 = 0; var19 <= mSize; var19++) { double var20 = var7 + (var9 - var7) * var19 / mSize; double var22 = var15 + (var17 - var15) * var19 / mSize; double var24 = var11 + (var13 - var11) * var19 / mSize; double var26 = aRandom.nextDouble() * mSize / 16.0D; double var28 = (MathHelper.sin(var19 * 3.141593F / mSize) + 1.0F) * var26 + 1.0D; double var30 = (MathHelper.sin(var19 * 3.141593F / mSize) + 1.0F) * var26 + 1.0D; int tMinX = MathHelper.floor_double(var20 - var28 / 2.0D); int tMinY = MathHelper.floor_double(var22 - var30 / 2.0D); int tMinZ = MathHelper.floor_double(var24 - var28 / 2.0D); int tMaxX = MathHelper.floor_double(var20 + var28 / 2.0D); int tMaxY = MathHelper.floor_double(var22 + var30 / 2.0D); int tMaxZ = MathHelper.floor_double(var24 + var28 / 2.0D); for (int eX = tMinX; eX <= tMaxX; eX++) { double var39 = (eX + 0.5D - var20) / (var28 / 2.0D); if (var39 * var39 < 1.0D) { for (int eY = tMinY; eY <= tMaxY; eY++) { double var42 = (eY + 0.5D - var22) / (var30 / 2.0D); if (var39 * var39 + var42 * var42 < 1.0D) { for (int eZ = tMinZ; eZ <= tMaxZ; eZ++) { double var45 = (eZ + 0.5D - var24) / (var28 / 2.0D); if ((var39 * var39 + var42 * var42 + var45 * var45 < 1.0D) && (mWorld.getBlock(tX, tY, tZ).isAir(mWorld, tX, tY, tZ))) { int ranOre = aRandom.nextInt(50); if (ranOre < 3) { GT_TileEntity_Ores.setOreBlock(mWorld, eX, eY, eZ, primaryMeta, false); } else if (ranOre < 6) { GT_TileEntity_Ores.setOreBlock(mWorld, eX, eY, eZ, secondaryMeta, false); } else if (ranOre < 8) { GT_TileEntity_Ores.setOreBlock(mWorld, eX, eY, eZ, betweenMeta, false); } else if (ranOre < 10) { GT_TileEntity_Ores.setOreBlock(mWorld, eX, eY, eZ, sporadicMeta, false); } else { mWorld.setBlock(eX, eY, eZ, Blocks.end_stone, 0, 0); } } } } } } } } } } Chunk tChunk = this.mWorld.getChunkFromBlockCoords(this.mX, this.mZ); if (tChunk != null) { tChunk.isModified = true; } long endTime = System.nanoTime(); long duration = (endTime - startTime); if (debugWorldGen) { GT_Log.out.println( " Oregen took " + (oregenTime-leftOverTime)+ " Leftover gen took " + (leftOverTime - startTime) + " Worldgen took " + duration + " nanoseconds" ); } } } }