package rtg.world.gen; import java.util.*; import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; import net.minecraft.block.Block; import net.minecraft.block.BlockFalling; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EnumCreatureType; import net.minecraft.init.Blocks; import net.minecraft.util.ClassInheritanceMultiMap; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.World; import net.minecraft.world.WorldEntitySpawner; import net.minecraft.world.biome.Biome; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkPrimer; import net.minecraft.world.chunk.IChunkGenerator; import net.minecraft.world.chunk.IChunkProvider; import net.minecraft.world.chunk.storage.AnvilChunkLoader; import net.minecraft.world.gen.ChunkProviderServer; import net.minecraft.world.gen.MapGenBase; import net.minecraft.world.gen.MapGenCaves; import net.minecraft.world.gen.MapGenRavine; import net.minecraft.world.gen.structure.*; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.event.terraingen.ChunkGeneratorEvent; import net.minecraftforge.event.terraingen.DecorateBiomeEvent; import net.minecraftforge.event.terraingen.InitMapGenEvent.EventType; import net.minecraftforge.event.terraingen.PopulateChunkEvent; import net.minecraftforge.event.terraingen.TerrainGen; import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.fml.common.eventhandler.Event; import mcp.MethodsReturnNonnullByDefault; import rtg.api.RTGAPI; import rtg.api.config.RTGConfig; import rtg.api.util.*; import rtg.api.world.RTGWorld; import rtg.util.CanyonColour; import rtg.util.Logger; import rtg.util.TimeTracker; import rtg.world.WorldTypeRTG; import rtg.world.biome.BiomeAnalyzer; import rtg.world.biome.BiomeProviderRTG; import rtg.world.biome.IBiomeProviderRTG; import rtg.world.biome.realistic.RealisticBiomeBase; import rtg.world.biome.realistic.RealisticBiomePatcher; import rtg.world.gen.structure.MapGenScatteredFeatureRTG; import rtg.world.gen.structure.MapGenStrongholdRTG; import rtg.world.gen.structure.MapGenVillageRTG; import rtg.world.gen.structure.StructureOceanMonumentRTG; //@SuppressWarnings({"UnusedParameters", "deprecation"}) @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault public class ChunkProviderRTG implements IChunkGenerator { private static ChunkProviderRTG populatingProvider; private RTGConfig rtgConfig = RTGAPI.config(); private final MapGenBase caveGenerator; private final MapGenBase ravineGenerator; private final MapGenStronghold strongholdGenerator; private final MapGenMineshaft mineshaftGenerator; private final MapGenVillage villageGenerator; private final MapGenScatteredFeature scatteredFeatureGenerator; private final StructureOceanMonument oceanMonumentGenerator; private final int sampleSize = 8; private final int sampleArraySize; private BiomeAnalyzer analyzer = new BiomeAnalyzer(); private int [] xyinverted = analyzer.xyinverted(); private final LandscapeGenerator landscapeGenerator; private final LimitedMap<ChunkPos, Chunk> availableChunks; private final HashSet<ChunkPos> toDecorate = new HashSet<>(); private boolean mapFeaturesEnabled; private Block bedrockBlock = Block.getBlockFromName(rtgConfig.BEDROCK_BLOCK_ID.get()); private byte bedrockByte = (byte) rtgConfig.BEDROCK_BLOCK_BYTE.get(); private Random rand; private Random mapRand; private final World worldObj; public final RTGWorld rtgWorld; private WorldUtil worldUtil; private IBiomeProviderRTG cmr; private Biome[] baseBiomesList; private float[] borderNoise; private long worldSeed; private RealisticBiomePatcher biomePatcher; private HashMap<ChunkPos, Chunk> inGeneration = new HashMap<>(); private HashSet<ChunkPos> toCheck = new HashSet<>(); private Compass compass = new Compass(); private ArrayList<Direction> directions = compass.directions(); //private HashSet<PlaneLocation> everGenerated = new HashSet<PlaneLocation>(); private TimedHashSet<ChunkPos> chunkMade = new TimedHashSet<>(5 * 1000); private boolean populating = false; private boolean fakeGenerator = false; private LimitedSet<ChunkPos> alreadyDecorated = new LimitedSet<>(1000); private ChunkOreGenTracker chunkOreGenTracker = new ChunkOreGenTracker(); private AnvilChunkLoader chunkLoader; private VolcanoGenerator volcanoGenerator; // we have to store this callback because it's a WeakReference in the event manager public final Acceptor<ChunkEvent.Load> delayedDecorator = new Acceptor<ChunkEvent.Load>() { @Override public void accept(ChunkEvent.Load event) { if (event.isCanceled()) return; ChunkPos pos = event.getChunk().getPos(); if (!toCheck.contains(pos)) return; toCheck.remove(pos); for (Direction forPopulation : directions) { decorateIfOtherwiseSurrounded(event.getWorld().getChunkProvider(), pos, forPopulation); } //clearDecorations(0); } }; public ChunkProviderRTG(World world, long seed) { worldObj = world; worldUtil = new WorldUtil(world); rtgWorld = new RTGWorld(worldObj); cmr = (BiomeProviderRTG) worldObj.getBiomeProvider(); rand = new Random(seed); landscapeGenerator = new LandscapeGenerator(rtgWorld); mapRand = new Random(seed); worldSeed = seed; volcanoGenerator = new VolcanoGenerator(seed); Map<String, String> m = new HashMap<>(); m.put("size", "0"); m.put("distance", "24"); mapFeaturesEnabled = world.getWorldInfo().isMapFeaturesEnabled(); boolean isRTGWorld = world.getWorldType() instanceof WorldTypeRTG; if (isRTGWorld && rtgConfig.ENABLE_CAVE_MODIFICATIONS.get()) { caveGenerator = (MapGenCaves) TerrainGen.getModdedMapGen(new MapGenCavesRTG(), EventType.CAVE); } else { caveGenerator = (MapGenCaves) TerrainGen.getModdedMapGen(new MapGenCaves(), EventType.CAVE); } if (isRTGWorld && rtgConfig.ENABLE_RAVINE_MODIFICATIONS.get()) { ravineGenerator = (MapGenRavine) TerrainGen.getModdedMapGen(new MapGenRavineRTG(), EventType.RAVINE); } else { ravineGenerator = (MapGenRavine) TerrainGen.getModdedMapGen(new MapGenRavine(), EventType.RAVINE); } if (isRTGWorld && rtgConfig.ENABLE_VILLAGE_MODIFICATIONS.get()) { villageGenerator = (MapGenVillage) TerrainGen.getModdedMapGen(new MapGenVillageRTG(), EventType.VILLAGE); } else { villageGenerator = (MapGenVillage) TerrainGen.getModdedMapGen(new MapGenVillage(m), EventType.VILLAGE); } if (isRTGWorld && rtgConfig.ENABLE_STRONGHOLD_MODIFICATIONS.get()) { strongholdGenerator = (MapGenStronghold) TerrainGen.getModdedMapGen(new MapGenStrongholdRTG(), EventType.STRONGHOLD); } else { strongholdGenerator = (MapGenStronghold) TerrainGen.getModdedMapGen(new MapGenStronghold(), EventType.STRONGHOLD); } mineshaftGenerator = (MapGenMineshaft) TerrainGen.getModdedMapGen(new MapGenMineshaft(), EventType.MINESHAFT); if (isRTGWorld && rtgConfig.ENABLE_SCATTERED_FEATURE_MODIFICATIONS.get()) { scatteredFeatureGenerator = (MapGenScatteredFeature) TerrainGen.getModdedMapGen(new MapGenScatteredFeatureRTG(), EventType.SCATTERED_FEATURE); } else { scatteredFeatureGenerator = (MapGenScatteredFeature) TerrainGen.getModdedMapGen(new MapGenScatteredFeature(), EventType.SCATTERED_FEATURE); } if (isRTGWorld && rtgConfig.ENABLE_OCEAN_MONUMENT_MODIFICATIONS.get()) { oceanMonumentGenerator = (StructureOceanMonument) TerrainGen.getModdedMapGen(new StructureOceanMonumentRTG(), EventType.OCEAN_MONUMENT); } else { oceanMonumentGenerator = (StructureOceanMonument) TerrainGen.getModdedMapGen(new StructureOceanMonument(), EventType.OCEAN_MONUMENT); } CanyonColour.init(seed); sampleArraySize = sampleSize * 2 + 5; baseBiomesList = new Biome[256]; biomePatcher = new RealisticBiomePatcher(); // set up the cache of available chunks availableChunks = new LimitedMap<>(1000); setWeightings(); // check for bogus world if (worldObj == null) throw new RuntimeException("Attempt to create chunk provider without a world"); } private void setWeightings() { float[][] weightings = new float[sampleArraySize * sampleArraySize][256]; for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { float limit = (float) Math.pow((56f * 56f), .7); // float limit = 56f; for (int mapX = 0; mapX < sampleArraySize; mapX++) { for (int mapZ = 0; mapZ < sampleArraySize; mapZ++) { float xDist = (i - chunkCoordinate(mapX)); float yDist = (j - chunkCoordinate(mapZ)); float distanceSquared = xDist * xDist + yDist * yDist; //float distance = (float)Math.sqrt(distanceSquared); float distance = (float) Math.pow(distanceSquared, .7); float weight = 1f - distance / limit; if (weight < 0) weight = 0; weightings[mapX * sampleArraySize + mapZ][i * 16 + j] = weight; } } } } } private int chunkCoordinate(int biomeMapCoordinate) { return (biomeMapCoordinate - sampleSize) * 8; } public void isFakeGenerator() { this.fakeGenerator = true; this.mapFeaturesEnabled = false; } public Chunk provideChunk(final int cx, final int cz) { final ChunkPos pos = new ChunkPos(cx, cz); if (inGeneration.containsKey(pos)) return inGeneration.get(pos); //if (availableChunks.size() > 1000) throw new RuntimeException(); if (chunkMade.contains(pos)) { Chunk available; available = availableChunks.get(pos); // this should never be happening but it came up when Forge/MC re-requested an already // made chunk for a lighting check (???) // we are having a problem with Forge complaining about double entity registration // so we'll unload any loaded entities if (available != null) { ClassInheritanceMultiMap<Entity>[] entityLists = available.getEntityLists(); for (ClassInheritanceMultiMap<Entity> entityList : entityLists) { /* Iterator iterator = entityLists[i].iterator(); while (iterator.hasNext()) { iterator.next(); iterator.remove(); } */ worldObj.unloadEntities(entityList); } toCheck.add(pos); return available; } } //if (everGenerated.contains(pos)) throw new RuntimeException(); String rtgTerrain = "RTG Terrain"; TimeTracker.manager.start(rtgTerrain); rand.setSeed((long) cx * 0x4f9939f508L + (long) cz * 0x1ef1565bd5L); ChunkPrimer primer = new ChunkPrimer(); int k; String landscaping = "RTG Landscape"; TimeTracker.manager.start(landscaping); ChunkLandscape landscape = landscapeGenerator.landscape(cmr, cx * 16, cz * 16); TimeTracker.manager.stop(landscaping); String fill = "RTG Fill"; TimeTracker.manager.start(fill); generateTerrain(cmr, cx, cz, primer, landscape.biome, landscape.noise); TimeTracker.manager.stop(fill); // that routine can change the blocks. //get standard biome Data String volcanos = "Volcanos"; TimeTracker.manager.start(volcanos); for (k = 0; k < 256; k++) { try { baseBiomesList[k] = landscape.biome[k].baseBiome; } catch (Exception e) { baseBiomesList[k] = biomePatcher.getPatchedBaseBiome("" + Biome.getIdForBiome(landscape.biome[k].baseBiome)); } } volcanoGenerator.generateMapGen(primer, worldSeed, worldObj, cmr, mapRand, cx, cz, rtgWorld.simplex, rtgWorld.cell, landscape.noise); TimeTracker.manager.stop(volcanos); String replace = "RTG Replace"; TimeTracker.manager.start(replace); borderNoise = landscapeGenerator.noiseFor(cmr, cx * 16, cz * 16); replaceBlocksForBiome(cx, cz, primer, landscape.biome, baseBiomesList, landscape.noise); TimeTracker.manager.stop(replace); caveGenerator.generate(worldObj, cx, cz, primer); ravineGenerator.generate(worldObj, cx, cz, primer); if (mapFeaturesEnabled) { if (rtgConfig.GENERATE_MINESHAFTS.get()) { try { mineshaftGenerator.generate(this.worldObj, cx, cz, primer); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in mineshaftGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in mineshaftGenerator"); e.printStackTrace(); } } } if (rtgConfig.GENERATE_STRONGHOLDS.get()) { try { strongholdGenerator.generate(this.worldObj, cx, cz, primer); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in strongholdGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in strongholdGenerator"); e.printStackTrace(); } } } if (rtgConfig.GENERATE_VILLAGES.get()) { try { villageGenerator.generate(this.worldObj, cx, cz, primer); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in villageGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in villageGenerator"); e.printStackTrace(); } } } if (rtgConfig.GENERATE_SCATTERED_FEATURES.get()) { try { scatteredFeatureGenerator.generate(this.worldObj, cx, cz, primer); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in scatteredFeatureGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in scatteredFeatureGenerator"); e.printStackTrace(); } } } if (rtgConfig.GENERATE_OCEAN_MONUMENTS.get()) { try { oceanMonumentGenerator.generate(this.worldObj, cx, cz, primer); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in oceanMonumentGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in oceanMonumentGenerator"); e.printStackTrace(); } } } } // store in the in process pile Chunk chunk = new Chunk(this.worldObj, primer, cx, cz); inGeneration.put(pos, chunk); // doJitter no longer needed as the biome array gets fixed byte[] abyte1 = chunk.getBiomeArray(); for (k = 0; k < abyte1.length; ++k) { // Biomes are y-first and terrain x-first byte b = (byte) Biome.getIdForBiome(this.baseBiomesList[xyinverted[k]]); abyte1[k] = b; } chunk.setBiomeArray(abyte1); chunk.generateSkylightMap(); toCheck.add(pos); // remove from in process pile inGeneration.remove(pos); this.chunkMade.add(pos); //this.everGenerated.add(pos); /*if (!chunkMade.contains(pos)||!everGenerated.contains(pos)) { throw new RuntimeException(pos.toString() + chunkMade.size()); }*/ availableChunks.put(pos, chunk); TimeTracker.manager.stop(rtgTerrain); return chunk; } private void generateTerrain(IBiomeProviderRTG cmr, int cx, int cz, ChunkPrimer primer, RealisticBiomeBase biomes[], float[] noise) { int h; for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { h = (int) noise[i * 16 + j]; for (int k = 0; k < 256; k++) { if (k > h) { if (k < 63) { primer.setBlockState(i, k, j, Blocks.WATER.getDefaultState()); } else { primer.setBlockState(i, k, j, Blocks.AIR.getDefaultState()); } } else { primer.setBlockState(i, k, j, Blocks.STONE.getDefaultState()); } } } } } private void replaceBlocksForBiome(int cx, int cz, ChunkPrimer primer, RealisticBiomeBase[] biomes, Biome[] base, float[] n) { ChunkGeneratorEvent.ReplaceBiomeBlocks event = new ChunkGeneratorEvent.ReplaceBiomeBlocks( this, cx, cz, primer, this.worldObj); MinecraftForge.EVENT_BUS.post(event); if (event.getResult() == Event.Result.DENY) return; int i, j, depth; float river; RealisticBiomeBase biome; for (i = 0; i < 16; i++) { for (j = 0; j < 16; j++) { /* * Some of the 'i' and 'j' parameters have been flipped when passing them. * Prior to flipping, the surface was being XZ-chunk-flipped. - WhichOnesPink */ biome = biomes[i * 16 + j]; river = -cmr.getRiverStrength(cx * 16 + i, cz * 16 + j); depth = -1; biome.rReplace(primer, cx * 16 + i, cz * 16 + j, i, j, depth, rtgWorld, n, river, base); int rough; int flatBedrockLayers = rtgConfig.FLAT_BEDROCK_LAYERS.get(); flatBedrockLayers = flatBedrockLayers < 0 ? 0 : (flatBedrockLayers > 5 ? 5 : flatBedrockLayers); if (flatBedrockLayers > 0) { for (int bl = 0; bl < flatBedrockLayers; bl++) { primer.setBlockState(i, bl, j, bedrockBlock.getStateFromMeta(bedrockByte)); } } else { primer.setBlockState(i, 0, j, bedrockBlock.getStateFromMeta(bedrockByte)); rough = rand.nextInt(2); primer.setBlockState(i, rough, j, bedrockBlock.getStateFromMeta(bedrockByte)); rough = rand.nextInt(3); primer.setBlockState(i, rough, j, bedrockBlock.getStateFromMeta(bedrockByte)); rough = rand.nextInt(4); primer.setBlockState(i, rough, j, bedrockBlock.getStateFromMeta(bedrockByte)); rough = rand.nextInt(5); primer.setBlockState(i, rough, j, bedrockBlock.getStateFromMeta(bedrockByte)); } } } } @Override public void populate(int x, int z) { // check if this is the master provider if (this.fakeGenerator) return; //if (this.alreadyDecorated.contains(new PlaneLocation.Invariant(chunkX, chunkZ))) return; if (this.neighborsDone(x, z)) { this.doPopulate(x, z); } clearDecorations(0); } private boolean neighborsDone(int cx, int cz) { return chunkExists(true, cx - 1, cz - 1) && chunkExists(true, cx - 1, cz) && chunkExists(true, cx - 1, cz + 1) && chunkExists(true, cx, cz - 1) && chunkExists(true, cx, cz + 1) && chunkExists(true, cx + 1, cz - 1) && chunkExists(true, cx + 1, cz) && chunkExists(true, cx + 1, cz + 1); } private void doPopulate(int chunkX, int chunkZ) { // don't populate if already done ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); //Logger.debug("trying to decorate: " + chunkPos.toString()); if (alreadyDecorated.contains(chunkPos)) return; if (populating) { // this has been created by another decoration; put in to-do pile addToDecorationList(chunkPos); return; } if (populatingProvider != null) throw new RuntimeException(toString() + " " + populatingProvider.toString()); if (inGeneration.containsKey(chunkPos)) { addToDecorationList(chunkPos); return; } //Logger.debug("decorating"); alreadyDecorated.add(chunkPos); populating = true; populatingProvider = this; TimeTracker.manager.start("RTG populate"); TimeTracker.manager.start("Features"); BlockFalling.fallInstantly = true; int worldX = chunkX * 16; int worldZ = chunkZ * 16; TimeTracker.manager.start("Biome Layout"); //Flippy McFlipperson. RealisticBiomeBase biome = cmr.getBiomeDataAt(worldX + 16, worldZ + 16); //Logger.debug("CPRTG#doPopulate: %s at %d %d", biome.baseBiome.getBiomeName(), worldX + 16, worldZ + 16); TimeTracker.manager.stop("Biome Layout"); this.rand.setSeed(this.worldObj.getSeed()); long i1 = this.rand.nextLong() / 2L * 2L + 1L; long j1 = this.rand.nextLong() / 2L * 2L + 1L; this.rand.setSeed((long) chunkX * i1 + (long) chunkZ * j1 ^ this.worldObj.getSeed()); boolean hasPlacedVillageBlocks = false; ForgeEventFactory.onChunkPopulate(true, this, this.worldObj, this.rand, chunkX, chunkZ, false); if (mapFeaturesEnabled) { TimeTracker.manager.start("Mineshafts"); if (rtgConfig.GENERATE_MINESHAFTS.get()) { try { mineshaftGenerator.generateStructure(worldObj, rand, chunkPos); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in mineshaftGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in mineshaftGenerator"); e.printStackTrace(); } } } TimeTracker.manager.stop("Mineshafts"); TimeTracker.manager.start("Strongholds"); if (rtgConfig.GENERATE_STRONGHOLDS.get()) { try { strongholdGenerator.generateStructure(worldObj, rand, chunkPos); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in strongholdGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in strongholdGenerator"); e.printStackTrace(); } } } TimeTracker.manager.stop("Strongholds"); TimeTracker.manager.start("Villages"); if (rtgConfig.GENERATE_VILLAGES.get()) { try { hasPlacedVillageBlocks = villageGenerator.generateStructure(worldObj, rand, chunkPos); } catch (Exception e) { hasPlacedVillageBlocks = false; if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in villageGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in villageGenerator"); e.printStackTrace(); } } } TimeTracker.manager.stop("Villages"); TimeTracker.manager.start("Scattered"); if (rtgConfig.GENERATE_SCATTERED_FEATURES.get()) { try { scatteredFeatureGenerator.generateStructure(worldObj, rand, chunkPos); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in scatteredFeatureGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in scatteredFeatureGenerator"); e.printStackTrace(); } } } TimeTracker.manager.stop("Scattered"); TimeTracker.manager.start("Monuments"); if (rtgConfig.GENERATE_OCEAN_MONUMENTS.get()) { try { oceanMonumentGenerator.generateStructure(this.worldObj, rand, chunkPos); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in oceanMonumentGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in oceanMonumentGenerator"); e.printStackTrace(); } } } TimeTracker.manager.stop("Monuments"); } TimeTracker.manager.start("Pools"); biome.rDecorator.rPopulatePreDecorate(this, worldObj, rand, chunkX, chunkZ, hasPlacedVillageBlocks); TimeTracker.manager.stop("Pools"); /* * What is this doing? And why does it need to be done here? - Pink * Answer: building a frequency table of nearby biomes - Zeno. */ borderNoise = landscapeGenerator.noiseFor(cmr, worldX, worldZ); /* * ######################################################################## * # START DECORATE BIOME * ######################################################################## */ TimeTracker.manager.start("Decorations"); MinecraftForge.EVENT_BUS.post(new DecorateBiomeEvent.Pre(worldObj, rand, new BlockPos(worldX, 0, worldZ))); // Ore gen. this.generateOres(biome, new BlockPos(worldX, 0, worldZ)); //Initialise variables. float river = -cmr.getRiverStrength(worldX + 16, worldZ + 16); //Border noise. (Does this have to be done here? - Pink) RealisticBiomeBase realisticBiome; for (int bn = 0; bn < 256; bn++) { if (borderNoise[bn] > 0f) { if (borderNoise[bn] >= 1f) borderNoise[bn] = 1f; realisticBiome = RealisticBiomeBase.getBiome(bn); // Do we need to patch the biome? if (realisticBiome == null) { realisticBiome = biomePatcher.getPatchedRealisticBiome( "NULL biome (" + bn + ") found when generating border noise."); } /* * When decorating the biome, we need to look at the biome configs to see if RTG is allowed to decorate it. * If the biome configs don't allow it, then we try to let the base biome decorate itself. * However, there are some mod biomes that crash when they try to decorate themselves, * so that's what the try/catch is for. If it fails, then it falls back to RTG decoration. */ if (rtgConfig.ENABLE_RTG_BIOME_DECORATIONS.get() && realisticBiome.getConfig().USE_RTG_DECORATIONS.get()) { realisticBiome.rDecorate(this.rtgWorld, this.rand, worldX, worldZ, borderNoise[bn], river, hasPlacedVillageBlocks); } else { try { realisticBiome.baseBiome.decorate(this.worldObj, rand, new BlockPos(worldX, 0, worldZ)); } catch (Exception e) { realisticBiome.rDecorate(this.rtgWorld, this.rand, worldX, worldZ, borderNoise[bn], river, hasPlacedVillageBlocks); } } /* if(realisticBiome.baseBiome.getTemperature() < 0.15f) {} else {} */ borderNoise[bn] = 0f; } } MinecraftForge.EVENT_BUS.post(new DecorateBiomeEvent.Post(worldObj, rand, new BlockPos(worldX, 0, worldZ))); TimeTracker.manager.stop("Decorations"); /* * ######################################################################## * # END DECORATE BIOME * ######################################################################## */ TimeTracker.manager.start("Post-decorations"); biome.rDecorator.rPopulatePostDecorate(worldObj, rand, chunkX, chunkZ, hasPlacedVillageBlocks); TimeTracker.manager.stop("Post-decorations"); TimeTracker.manager.start("Entities"); if (TerrainGen.populate(this, this.worldObj, this.rand, chunkX, chunkZ, hasPlacedVillageBlocks, PopulateChunkEvent.Populate.EventType.ANIMALS)) { WorldEntitySpawner.performWorldGenSpawning(this.worldObj, biome.baseBiome, worldX + 8, worldZ + 8, 16, 16, this.rand); } TimeTracker.manager.stop("Entities"); TimeTracker.manager.start("Ice"); if (TerrainGen.populate(this, this.worldObj, this.rand, chunkX, chunkZ, hasPlacedVillageBlocks, PopulateChunkEvent.Populate.EventType.ICE)) { int i4, j4; IBlockState snowLayerBlock = Blocks.SNOW_LAYER.getDefaultState(); IBlockState iceBlock = Blocks.ICE.getDefaultState(); for (i4 = 0; i4 < 16; ++i4) { for (j4 = 0; j4 < 16; ++j4) { BlockPos snowPos = this.worldObj.getPrecipitationHeight(new BlockPos(worldX + i4, 0, worldZ + j4)); BlockPos icePos = snowPos.down(); // Ice. if(this.worldObj.canBlockFreezeWater(icePos)) { this.worldObj.setBlockState(icePos, iceBlock, 2); } // Snow. if (rtgConfig.ENABLE_SNOW_LAYERS.get() && this.worldUtil.canSnowAt(snowPos, true)) { this.worldObj.setBlockState(snowPos, snowLayerBlock, 2); } } } } TimeTracker.manager.stop("Ice"); ForgeEventFactory.onChunkPopulate(false, this, this.worldObj, this.rand, chunkX, chunkZ, hasPlacedVillageBlocks); BlockFalling.fallInstantly = false; TimeTracker.manager.stop("RTG populate"); populating = false; populatingProvider = null; } private void clearDecorations(int limit) { if (WorldTypeRTG.chunkProvider != this) return; Set<ChunkPos> toProcess = doableLocations(limit); toProcess.forEach(this::removeFromDecorationList); for (ChunkPos location : toProcess) { doPopulate(location.chunkXPos, location.chunkZPos); } } private Set<ChunkPos> doableLocations(int limit) { HashSet<ChunkPos> toProcess = new HashSet<>(); int found = 0; synchronized (toDecorate) { for (ChunkPos pos : toDecorate) { /* Chunk existing; existing = availableChunks.get(pos); if (existing != null) { if (!existing.isTerrainPopulated()) { //continue; // not populated so let more "normal" systems handle it } } */ if (inGeneration.containsKey(pos)) continue; toProcess.add(pos); if (++found == limit) return toProcess; } } return toProcess; } @Override public boolean generateStructures(@Nonnull Chunk chunkIn, int x, int z) { boolean flag = false; if (rtgConfig.GENERATE_OCEAN_MONUMENTS.get() && this.mapFeaturesEnabled && chunkIn.getInhabitedTime() < 3600L) { flag = this.oceanMonumentGenerator.generateStructure(this.worldObj, this.rand, new ChunkPos(x, z)); } return flag; } @Override public List<Biome.SpawnListEntry> getPossibleCreatures(@Nonnull EnumCreatureType creatureType, @Nonnull BlockPos pos) { Biome biome = this.worldObj.getBiome(pos); if (this.mapFeaturesEnabled) { if (creatureType == EnumCreatureType.MONSTER && this.scatteredFeatureGenerator.isSwampHut(pos)) { return this.scatteredFeatureGenerator.getScatteredFeatureSpawnList(); } if (creatureType == EnumCreatureType.MONSTER && rtgConfig.GENERATE_OCEAN_MONUMENTS.get() && this.oceanMonumentGenerator.isPositionInStructure(this.worldObj, pos)) { return this.oceanMonumentGenerator.getScatteredFeatureSpawnList(); } } return biome.getSpawnableList(creatureType); } @Override public BlockPos getStrongholdGen(World worldIn, String structureName, BlockPos position, boolean findUnexplored) { if (!rtgConfig.GENERATE_STRONGHOLDS.get()) return null; return "Stronghold".equals(structureName) && this.strongholdGenerator != null ? this.strongholdGenerator.getClosestStrongholdPos(worldIn, position, findUnexplored) : null; } @Override public void recreateStructures(@Nonnull Chunk chunk, int par1, int par2) { if (mapFeaturesEnabled) { if (rtgConfig.GENERATE_MINESHAFTS.get()) { try { mineshaftGenerator.generate(worldObj, par1, par2, new ChunkPrimer()); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in mineshaftGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in mineshaftGenerator"); e.printStackTrace(); } } } if (rtgConfig.GENERATE_STRONGHOLDS.get()) { try { strongholdGenerator.generate(worldObj, par1, par2, new ChunkPrimer()); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in strongholdGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in strongholdGenerator"); e.printStackTrace(); } } } if (rtgConfig.GENERATE_VILLAGES.get()) { try { villageGenerator.generate(this.worldObj, par1, par2, new ChunkPrimer()); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in villageGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in villageGenerator"); e.printStackTrace(); } } } if (rtgConfig.GENERATE_SCATTERED_FEATURES.get()) { try { scatteredFeatureGenerator.generate(this.worldObj, par1, par2, new ChunkPrimer()); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in scatteredFeatureGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in scatteredFeatureGenerator"); e.printStackTrace(); } } } if (rtgConfig.GENERATE_OCEAN_MONUMENTS.get()) { try { oceanMonumentGenerator.generate(this.worldObj, par1, par2, new ChunkPrimer()); } catch (Exception e) { if (rtgConfig.CRASH_ON_STRUCTURE_EXCEPTIONS.get()) { Logger.fatal("Exception in oceanMonumentGenerator"); throw new RuntimeException(e.getMessage()); } else { Logger.error("Exception in oceanMonumentGenerator"); e.printStackTrace(); } } } } } private void decorateIfOtherwiseSurrounded(IChunkProvider world, ChunkPos pos, Direction fromNewChunk) { // check if this is the master provider if (WorldTypeRTG.chunkProvider != this) return; // see if otherwise surrounded besides the new chunk ChunkPos probe = new ChunkPos(pos.chunkXPos + fromNewChunk.xOffset, pos.chunkZPos + fromNewChunk.zOffset); // check to see if already decorated; shouldn't be but just in case if (this.alreadyDecorated.contains(probe)) return; // if an in-process chunk; we'll get a populate call later; // if (this.inGeneration.containsKey(probe)) return; for (Direction checked : directions) { if (checked == compass.opposite(fromNewChunk)) continue; // that's the new chunk if (!chunkExists(true, probe.chunkXPos + checked.xOffset, probe.chunkZPos + checked.zOffset)) return;// that one's missing } // passed all checks addToDecorationList(probe); //this.doPopulate(probe.chunkXPos, probe.chunkZPos); } private boolean chunkExists(boolean checkNeighbours, int cx, int cz) { //if (chunkExists(cx,cz)) return true; ChunkPos location = new ChunkPos(cx, cz); if (inGeneration.containsKey(location)) return true; if (toCheck.contains(location)) return true; if (this.chunkMade.contains(location)) return true; //if (world.chunkExists(cx, cz)) return true; if (chunkLoader().chunkExists(worldObj, cx, cz)) return true; //if (this.everGenerated.contains(location)) throw new RuntimeException("somehow lost "+location.toString()); return false; } public boolean chunkExists(int x, int z) { return this.chunkExists(true, x, z); } private void addToDecorationList(ChunkPos toAdd) { synchronized (toDecorate) { toDecorate.add(toAdd); } } private AnvilChunkLoader chunkLoader() { if (chunkLoader == null) { ChunkProviderServer server = (ChunkProviderServer) (worldObj.getChunkProvider()); chunkLoader = (AnvilChunkLoader) (server.chunkLoader); } return chunkLoader; } /** * @see IChunkProvider * Loads or generates the chunk at the chunk location specified. */ @SuppressWarnings("unused") public Chunk loadChunk(int par1, int par2) { throw new RuntimeException(); // return provideChunk(par1, par2); } public Runnable clearOnServerClose() { return this::clearToDecorateList; } private void clearToDecorateList() { if (WorldTypeRTG.chunkProvider != this) return; if (populating) return;// in process, do later; // we have to make a copy of the set to work on or we'll get errors Set<ChunkPos> toProcess = doableLocations(0); while (toProcess.size() > 0) { toProcess.forEach(this::removeFromDecorationList); for (ChunkPos location : toProcess) { doPopulate(location.chunkXPos, location.chunkZPos); } // and loop because the decorating might have created other chunks to decorate; toProcess = doableLocations(0); } } private void removeFromDecorationList(ChunkPos toAdd) { synchronized (toDecorate) { toDecorate.remove(toAdd); } } private void generateOres(RealisticBiomeBase rb, BlockPos pos) { int x = pos.getX(); int z = pos.getZ(); // Have we already generated ores for this chunk? if (chunkOreGenTracker.hasGeneratedOres(pos)) { Logger.debug("Already generated ores for %d %d", x, z); return; } rb.rDecorator.decorateOres(this.worldObj, this.rand, x, z); chunkOreGenTracker.addOreChunk(pos); } public ChunkOreGenTracker getChunkOreGenTracker() { return this.chunkOreGenTracker; } }