private static readonly IntVec2 TexturesInAtlas = new IntVec2(2, 2); // two by two, meaning four variants for each worldmaterial. public override IEnumerable Regenerate() { foreach (object obj in base.Regenerate()) // I'll be honest, I don't know what this does. { yield return(obj); } Rand.PushState(); Rand.Seed = Find.World.info.Seed; WorldGrid worldGrid = Find.WorldGrid; List <BiomeDef> allDefsListForReading = DefDatabase <BiomeDef> .AllDefsListForReading; foreach (BiomeDef biomeDef in allDefsListForReading.Where(x => x.HasModExtension <BiomesKitControls>())) { for (int tileID = 0; tileID < Find.WorldGrid.TilesCount; tileID++) { Tile tile = Find.WorldGrid[tileID]; BiomesKitControls biomesKit = biomeDef.GetModExtension <BiomesKitControls>(); if (tile.biome != biomeDef) { continue; } if (biomesKit.materialPath == "World/MapGraphics/Default") { continue; } Material material = MaterialPool.MatFrom(biomesKit.materialPath, ShaderDatabase.WorldOverlayTransparentLit, biomesKit.materialLayer); LayerSubMesh subMesh = GetSubMesh(material); Vector3 vector = worldGrid.GetTileCenter(tileID); WorldRendererUtility.PrintQuadTangentialToPlanet(vector, vector, worldGrid.averageTileSize, 0.01f, subMesh, false, true, false); WorldRendererUtility.PrintTextureAtlasUVs(Rand.Range(0, TexturesInAtlas.x), Rand.Range(0, TexturesInAtlas.z), TexturesInAtlas.x, TexturesInAtlas.z, subMesh); } } Rand.PopState(); base.FinalizeMesh(MeshParts.All); yield break; }
static ErrorLogs() { List <BiomeDef> allDefsListForReading = DefDatabase <BiomeDef> .AllDefsListForReading; foreach (BiomeDef biomeDef2 in allDefsListForReading.Where(x => x.HasModExtension <BiomesKitControls>())) { BiomesKitControls biomesKit = biomeDef2.GetModExtension <BiomesKitControls>(); HashSet <BiomeDef> defs = new HashSet <BiomeDef>(); foreach (BiomeDef targetBiome in biomesKit.spawnOnBiomes) { if (!defs.Add(targetBiome)) { Log.Warning("[BiomesKit] XML Config Error: " + biomeDef2 + ": spawnOnBiomes includes " + targetBiome + " twice."); } } Material testMaterial = MaterialPool.MatFrom(biomesKit.materialPath, ShaderDatabase.WorldOverlayTransparentLit, biomesKit.materialLayer); if (biomesKit.materialLayer >= 3560) { Log.Warning("[BiomesKit] XML Config Error: " + biomeDef2 + ": The materialLayer is set to 3560 or higher, making the material display on top of the selection indicator."); } if (!biomesKit.allowOnLand && !biomesKit.allowOnWater) { Log.Warning("[BiomesKit] XML Config Error: " + biomeDef2 + ": Biome is disallowed on both land and water and will never spawn."); } if (biomesKit.minTemperature > biomesKit.maxTemperature) { Log.Warning("[BiomesKit] XML Config Error: " + biomeDef2 + ": minTemperature set above maxTemperature."); } if (biomesKit.minNorthLatitude > biomesKit.maxNorthLatitude) { Log.Warning("[BiomesKit] XML Config Error: " + biomeDef2 + ": minNorthLatitude set above maxNorthLatitude."); } if (biomesKit.minSouthLatitude > biomesKit.maxSouthLatitude) { Log.Warning("[BiomesKit] XML Config Error: " + biomeDef2 + ": minSouthLatitude set above maxSouthLatitude."); } if (biomesKit.minHilliness > biomesKit.maxHilliness) { Log.Warning("[BiomesKit] XML Config Error: " + biomeDef2 + ": minHilliness set above maxHilliness."); } if (biomesKit.minElevation > biomesKit.maxElevation) { Log.Warning("[BiomesKit] XML Config Error: " + biomeDef2 + ": minElevation set above maxElevation."); } if (biomesKit.minRainfall > biomesKit.maxRainfall) { Log.Warning("[BiomesKit] XML Config Error: " + biomeDef2 + ": minRainfall set above maxRainfall."); } if (biomesKit.frequency > 100) { Log.Warning("[BiomesKit] XML Config Error: " + biomeDef2 + ": frequency set above 100. Frequency accepts values 1-100. Setting Frequency higher than that is not supported."); } if (biomesKit.usePerlin == false && biomesKit.useAlternativePerlinSeedPreset == true) { Log.Warning("[BiomesKit] XML Config Error: " + biomeDef2 + ": usePerlin is false but useAlternativePerlinSeedPreset is true. useAlternativePerlinSeedPreset should be false if usePerlin is set to false."); } if (biomesKit.usePerlin == false && biomesKit.perlinCustomSeed != null) { Log.Warning("[BiomesKit] XML Config Error: " + biomeDef2 + ": usePerlin is false but perlinCustomSeed is assigned. perlinCustomSeed will not be read if usePerlin is set to false."); } } }
private void BiomesKit() { // Rimworld is kind enough to have a centralized list of all BiomeDefs. Here, we iterate through thouse with the BiomesKit ModExtension. foreach (BiomeDef biomeDef2 in DefDatabase <BiomeDef> .AllDefsListForReading.Where(x => x.HasModExtension <BiomesKitControls>())) { // We then get the modextension from the specific BiomeDef we are iterating through right now. BiomesKitControls biomesKit = biomeDef2.GetModExtension <BiomesKitControls>(); // South Latitudes need to be negative values. Here we convert them for the user's convenience. float minSouthLatitude = biomesKit.minSouthLatitude * -1; float maxSouthLatitude = biomesKit.maxSouthLatitude * -1; // Now we start iterating through tiles on the world map. This is inside the loop iterating through BiomeDefs. // so this is done for each BiomeDef with the ModExtension. for (int tileID = 0; tileID < Find.WorldGrid.TilesCount; tileID++) { WorldGrid worldGrid = Find.WorldGrid; Tile tile = worldGrid[tileID]; // Next we find out what latitude the tile is on. float latitude = worldGrid.LongLatOf(tileID).y; // We set up some perlin values. int perlinSeed = Find.World.info.Seed; var coords = worldGrid.GetTileCenter(tileID); // We give ourselves a way to reference the tile that's being checked. // Now we start actually doing something. First up, we respond to the spawnOnBiomes tag. bool validTarget = true; // The tile is a valid target by default. // We iterate through another list. This time of biomes specified by the tag. foreach (BiomeDef targetBiome in biomesKit.spawnOnBiomes) { // If the BiomeDef matches the tile, we declare the tile a valid target and stop iterating. if (tile.biome == targetBiome) { validTarget = true; break; } // If the BiomeDef doesn't match the tile, we declare the tile an invalid target and move on to the next BiomeDef on the list. else { validTarget = false; } } // After that, if the tile is no longer a valid target, we skip to the next tile. if (validTarget == false) { continue; } // Next up is the latitude tags. bool validSouthLatitude = true; // Southern latitude is valid by default. // If the tile's southern latitude is lesser than the minimum and greater than the maximum, declare the tile's south latitude valid. // Since southern altitude uses negative numbers, we want it lower than the minimum and higher than the maximum. if (latitude < minSouthLatitude && latitude > maxSouthLatitude) { validSouthLatitude = true; } // If the tile's southern latitude is greater than the ninimum and lesser than the maximum, we declare the tile's south latitude invalid. else { validSouthLatitude = false; } // Now for the northern latitude. bool validNorthLatitude = true; // Northern latitude is also valid by default. // If the tile's northern latitude is greater than the minimum and lesser than the maximum, declare the north latitude valid. if (latitude > biomesKit.minNorthLatitude && latitude < biomesKit.maxNorthLatitude) { validNorthLatitude = true; } // If the tile's northern latitude is lesser than the minimum and greater than the maximum, declare the northern latitude invalid. else { validNorthLatitude = false; } // We check if both the north and the south latitudes are invalid. if (validNorthLatitude == false && validSouthLatitude == false) { // If they are both invalid, we check if every latitude tag has been set by the user. if (biomesKit.minSouthLatitude != -9999 && biomesKit.minNorthLatitude != -9999 && biomesKit.maxSouthLatitude != -9999 && biomesKit.maxNorthLatitude != 9999) { continue; // If not a single latitude tag has been set, we skip to the next tile. } } // If the tile is a water tile and the biome is not allowed on water, we skip to the next tile. if (tile.WaterCovered && biomesKit.allowOnWater == false) { continue; } // If the tile is a land tile and the biome is not allowed on land, we skip to the next tile. if (!tile.WaterCovered && biomesKit.allowOnLand == false) { continue; } // Does the biome need a river? if (biomesKit.needRiver == true) { // If it does, and the tile doesn't have a river, we skip to the next tile. if (tile.Rivers == null || tile.Rivers.Count == 0) { continue; } } // Now we define the Perlin Noise seed. // If the user has assigned a custom seed, we use that. if (biomesKit.perlinCustomSeed != null) { perlinSeed = biomesKit.perlinCustomSeed.Value; } // If not, we check if they've asked to use the alternative preset seed. else if (biomesKit.useAlternativePerlinSeedPreset) // If they have, we use that. { perlinSeed = tileID; } // Are we using perlin for this biome? if (biomesKit.usePerlin == true) { // If we are, it's time to generate our perlin noise. PerlinNoise = new Perlin(0.1, 10, 0.6, 12, perlinSeed, QualityMode.Low); float perlinNoiseValue = PerlinNoise.GetValue(coords); // And after that we cull the lower perlin values. if (perlinNoiseValue <= (biomesKit.perlinCulling)) { continue; } } // Compare a random number between 0 and 1 to the userdefined frequency to the power of two divided by ten thousand. I promise it makes sense to do it this way. if (Rand.Value > (Math.Pow(biomesKit.frequency, 2) / 10000f)) { continue; } // If the tile's elevation is higher is lower than the minimum or higher than the maximum, we skip to the next tile. if (tile.elevation < biomesKit.minElevation || tile.elevation > biomesKit.maxElevation) { continue; } // If the tile's temperature is higher is lower than the minimum or higher than the maximum, we skip to the next tile. if (tile.temperature < biomesKit.minTemperature || tile.temperature > biomesKit.maxTemperature) { continue; } // If the tile's rainfall is higher is lower than the minimum or higher than the maximum, we skip to the next tile. if (tile.rainfall < biomesKit.minRainfall || tile.rainfall > biomesKit.maxRainfall) { continue; } // If the tile's hilliness is higher is lower than the minimum or higher than the maximum, we skip to the next tile. if (tile.hilliness < biomesKit.minHilliness || tile.hilliness > biomesKit.maxHilliness) { continue; } // If we get this far, we can spawn the biome! tile.biome = biomeDef2; // If the user wants to give random hilliness to the biome, we do that here. if (biomesKit.randomizeHilliness == true) { // random number from 0 to 3. switch (Rand.Range(0, 3)) { case 0: // 0 means flat. tile.hilliness = Hilliness.Flat; break; case 1: // 1 means small hills. tile.hilliness = Hilliness.SmallHills; break; case 2: // 2 means large hills. tile.hilliness = Hilliness.LargeHills; break; case 3: // 3 means mountainous. tile.hilliness = Hilliness.Mountainous; break; } } // If the user wants to give the biome a specific hilliness we can do that too. if (biomesKit.spawnHills != null) { tile.hilliness = biomesKit.spawnHills.Value; } } } }
private static readonly IntVec2 TexturesInAtlas = new IntVec2(2, 2); // two by two, meaning four variants for each worldmaterial. public override IEnumerable Regenerate() { foreach (object obj in base.Regenerate()) { yield return(obj); } Rand.PushState(); Rand.Seed = Find.World.info.Seed; WorldGrid worldGrid = Find.WorldGrid; for (int tileID = 0; tileID < Find.WorldGrid.TilesCount; tileID++) { Tile tile = Find.WorldGrid[tileID]; if (tile.biome.HasModExtension <BiomesKitControls>()) { Dictionary <Tile, Hilliness> backupHilliness = LateBiomeWorker.backupHilliness; BiomesKitControls biomesKit = tile.biome.GetModExtension <BiomesKitControls>(); Vector3 vector = worldGrid.GetTileCenter(tileID); if (biomesKit.hillMaterialPath != "World/MapGraphics/Default") { tile.hilliness = backupHilliness[tile]; Material hill; if (tile.hilliness == Hilliness.SmallHills) { hill = MaterialPool.MatFrom(biomesKit.hillMaterialPath + "/Hills/SmallHills", ShaderDatabase.WorldOverlayTransparentLit, biomesKit.materialLayer); LayerSubMesh subMeshHill = GetSubMesh(hill); WorldRendererUtility.PrintQuadTangentialToPlanet(vector, vector, (worldGrid.averageTileSize * 1.5f), 0.01f, subMeshHill, false, biomesKit.materialRandomRotation, false); WorldRendererUtility.PrintTextureAtlasUVs(Rand.Range(0, TexturesInAtlas.x), Rand.Range(0, TexturesInAtlas.z), TexturesInAtlas.x, TexturesInAtlas.z, subMeshHill); } if (tile.hilliness == Hilliness.LargeHills) { hill = MaterialPool.MatFrom(biomesKit.hillMaterialPath + "/Hills/LargeHills", ShaderDatabase.WorldOverlayTransparentLit, biomesKit.materialLayer); LayerSubMesh subMeshHill = GetSubMesh(hill); WorldRendererUtility.PrintQuadTangentialToPlanet(vector, vector, (worldGrid.averageTileSize * 1.5f), 0.01f, subMeshHill, false, biomesKit.materialRandomRotation, false); WorldRendererUtility.PrintTextureAtlasUVs(Rand.Range(0, TexturesInAtlas.x), Rand.Range(0, TexturesInAtlas.z), TexturesInAtlas.x, TexturesInAtlas.z, subMeshHill); } if (tile.hilliness == Hilliness.Mountainous) { hill = MaterialPool.MatFrom(biomesKit.hillMaterialPath + "/Hills/Mountains", ShaderDatabase.WorldOverlayTransparentLit, biomesKit.materialLayer); LayerSubMesh subMeshHill = GetSubMesh(hill); WorldRendererUtility.PrintQuadTangentialToPlanet(vector, vector, (worldGrid.averageTileSize * 1.5f), 0.01f, subMeshHill, false, biomesKit.materialRandomRotation, false); WorldRendererUtility.PrintTextureAtlasUVs(Rand.Range(0, TexturesInAtlas.x), Rand.Range(0, TexturesInAtlas.z), TexturesInAtlas.x, TexturesInAtlas.z, subMeshHill); } if (tile.hilliness == Hilliness.Impassable) { hill = MaterialPool.MatFrom(biomesKit.hillMaterialPath + "/Hills/Impassable", ShaderDatabase.WorldOverlayTransparentLit, biomesKit.materialLayer); LayerSubMesh subMeshHill = GetSubMesh(hill); WorldRendererUtility.PrintQuadTangentialToPlanet(vector, vector, (worldGrid.averageTileSize * 1.5f), 0.01f, subMeshHill, false, biomesKit.materialRandomRotation, false); WorldRendererUtility.PrintTextureAtlasUVs(Rand.Range(0, TexturesInAtlas.x), Rand.Range(0, TexturesInAtlas.z), TexturesInAtlas.x, TexturesInAtlas.z, subMeshHill); } } if (biomesKit.materialMaxHilliness != Hilliness.Undefined) { if (tile.hilliness > biomesKit.materialMaxHilliness || tile.hilliness < biomesKit.materialMinHilliness) { continue; } } bool roadPresent = true; if (tile.Roads == null || tile.Roads.Count == 0) { roadPresent = false; } bool riverPresent = true; if (tile.Rivers == null || tile.Rivers.Count == 0) { riverPresent = false; } if (biomesKit.forestMaterialPath != "World/MapGraphics/Default") { if (!riverPresent && !roadPresent) { Material forestMaterial; if (tile.temperature < biomesKit.forestSnowyBelow) { forestMaterial = MaterialPool.MatFrom(biomesKit.forestMaterialPath + "/Forest_Snowy", ShaderDatabase.WorldOverlayTransparentLit, biomesKit.materialLayer); } else if (tile.rainfall < biomesKit.forestSparseBelow) { forestMaterial = MaterialPool.MatFrom(biomesKit.forestMaterialPath + "/Forest_Sparse", ShaderDatabase.WorldOverlayTransparentLit, biomesKit.materialLayer); } else if (tile.rainfall > biomesKit.forestDenseAbove) { forestMaterial = MaterialPool.MatFrom(biomesKit.forestMaterialPath + "/Forest_Dense", ShaderDatabase.WorldOverlayTransparentLit, biomesKit.materialLayer); } else { forestMaterial = MaterialPool.MatFrom(biomesKit.forestMaterialPath + "/Forest", ShaderDatabase.WorldOverlayTransparentLit, biomesKit.materialLayer); } LayerSubMesh subMeshForest = GetSubMesh(forestMaterial); WorldRendererUtility.PrintQuadTangentialToPlanet(vector, vector, (worldGrid.averageTileSize * biomesKit.materialSizeMultiplier), 0.01f, subMeshForest, false, biomesKit.materialRandomRotation, false); WorldRendererUtility.PrintTextureAtlasUVs(Rand.Range(0, TexturesInAtlas.x), Rand.Range(0, TexturesInAtlas.z), TexturesInAtlas.x, TexturesInAtlas.z, subMeshForest); } } if (biomesKit.materialPath != "World/MapGraphics/Default") { Material material = MaterialPool.MatFrom(biomesKit.materialPath, ShaderDatabase.WorldOverlayTransparentLit, biomesKit.materialLayer); LayerSubMesh subMesh = GetSubMesh(material); WorldRendererUtility.PrintQuadTangentialToPlanet(vector, vector, (worldGrid.averageTileSize * biomesKit.materialSizeMultiplier), 0.01f, subMesh, false, biomesKit.materialRandomRotation, false); WorldRendererUtility.PrintTextureAtlasUVs(Rand.Range(0, TexturesInAtlas.x), Rand.Range(0, TexturesInAtlas.z), TexturesInAtlas.x, TexturesInAtlas.z, subMesh); } } } Rand.PopState(); base.FinalizeMesh(MeshParts.All); yield break; }