public float GetLerpedCenterPixel(float x, float y, float z) { int posXLeft = (int)Math.Floor(x - 0.5f); int posXRight = posXLeft + 1; int posYBot = (int)Math.Floor(y - 0.5f); int posYTop = posYBot + 1; int posZLeft = (int)Math.Floor(z - 0.5f); int posZRight = posZLeft + 1; float fx = x - (posXLeft + 0.5f); float fy = y - (posYBot + 0.5f); float fz = z - (posZLeft + 0.5f); float up = GameMath.BiLerp( Data[(posYBot * Length + posZLeft) * Width + posXLeft], Data[(posYBot * Length + posZLeft) * Width + posXRight], Data[(posYBot * Length + posZRight) * Width + posXLeft], Data[(posYBot * Length + posZRight) * Width + posXRight], fx, fz ); float down = GameMath.BiLerp( Data[(posYTop * Length + posZLeft) * Width + posXLeft], Data[(posYTop * Length + posZLeft) * Width + posXRight], Data[(posYTop * Length + posZRight) * Width + posXLeft], Data[(posYTop * Length + posZRight) * Width + posXRight], fx, fz ); return(GameMath.Lerp(down, up, fy)); }
double[] GetTerrainNoise3D(double[] octX0, double[] octX1, double[] octX2, double[] octX3, double[] octThX0, double[] octThX1, double[] octThX2, double[] octThX3, int xPos, int yPos, int zPos) { for (int x = 0; x < paddedNoiseWidth; x++) { for (int z = 0; z < paddedNoiseWidth; z++) { for (int i = 0; i < TerraGenConfig.terrainGenOctaves; i++) { lerpedAmps[i] = GameMath.BiLerp(octX0[i], octX1[i], octX2[i], octX3[i], (double)x / paddedNoiseWidth, (double)z / paddedNoiseWidth); lerpedTh[i] = GameMath.BiLerp(octThX0[i], octThX1[i], octThX2[i], octThX3[i], (double)x / paddedNoiseWidth, (double)z / paddedNoiseWidth); } for (int y = 0; y < paddedNoiseHeight; y++) { noiseTemp[NoiseIndex3d(x, y, z)] = TerrainNoise.Noise( (xPos + x), (yPos + y) / TerraGenConfig.terrainNoiseVerticalScale, (zPos + z), lerpedAmps, lerpedTh ); } } } return(noiseTemp); }
double[] GetTerrainNoise3D(double[] octX0, double[] octX1, double[] octX2, double[] octX3, double[] octThX0, double[] octThX1, double[] octThX2, double[] octThX3, int xPos, int yPos, int zPos) { for (int x = 0; x < paddedNoiseWidth; x++) { for (int z = 0; z < paddedNoiseWidth; z++) { for (int i = 0; i < TerraGenConfig.terrainGenOctaves; i++) { lerpedAmps[i] = GameMath.BiLerp(octX0[i], octX1[i], octX2[i], octX3[i], (double)x / paddedNoiseWidth, (double)z / paddedNoiseWidth); lerpedTh[i] = GameMath.BiLerp(octThX0[i], octThX1[i], octThX2[i], octThX3[i], (double)x / paddedNoiseWidth, (double)z / paddedNoiseWidth); } float distx = (float)distort2dx.Noise(xPos + x, zPos + z); float distz = (float)distort2dz.Noise(xPos + x, zPos + z); for (int y = 0; y < paddedNoiseHeight; y++) { noiseTemp[NoiseIndex3d(x, y, z)] = TerrainNoise.Noise( (xPos + x) + (distx > 0 ? Math.Max(0, distx - 10) : Math.Min(0, distx + 10)), (yPos + y) / TerraGenConfig.terrainNoiseVerticalScale, (zPos + z) + (distz > 0 ? Math.Max(0, distz - 10) : Math.Min(0, distz + 10)), lerpedAmps, lerpedTh ); } } } return(noiseTemp); }
public float GetLerped(float x, float y, float z) { int posXLeft = (int)x; int posXRight = posXLeft + 1; int posYBot = (int)y; int posYTop = posYBot + 1; int posZLeft = (int)z; int posZRight = posZLeft + 1; float fx = x - (int)x; float fy = y - (int)y; float fz = z - (int)z; float down = GameMath.BiLerp( Data[(posYBot * Length + posZLeft) * Width + posXLeft], Data[(posYBot * Length + posZLeft) * Width + posXRight], Data[(posYBot * Length + posZRight) * Width + posXLeft], Data[(posYBot * Length + posZRight) * Width + posXRight], fx, fz ); float up = GameMath.BiLerp( Data[(posYTop * Length + posZLeft) * Width + posXLeft], Data[(posYTop * Length + posZLeft) * Width + posXRight], Data[(posYTop * Length + posZRight) * Width + posXLeft], Data[(posYTop * Length + posZRight) * Width + posXRight], fx, fz ); return(GameMath.Lerp(down, up, fy)); }
public PrecipitationState GetPrecipitationState(Vec3d pos) { LoadAdjacentSimsAndLerpValues(pos); double level = GameMath.BiLerp( adjacentSims[0].weatherData.PrecIntensity, adjacentSims[1].weatherData.PrecIntensity, adjacentSims[2].weatherData.PrecIntensity, adjacentSims[3].weatherData.PrecIntensity, lerpLeftRight, lerpTopBot ); double size = GameMath.BiLerp( adjacentSims[0].weatherData.PrecParticleSize, adjacentSims[1].weatherData.PrecParticleSize, adjacentSims[2].weatherData.PrecParticleSize, adjacentSims[3].weatherData.PrecParticleSize, lerpLeftRight, lerpTopBot ); EnumPrecipitationType top = lerpLeftRight < 0.5 ? adjacentSims[0].weatherData.nowPrecType : adjacentSims[1].weatherData.nowPrecType; EnumPrecipitationType bot = lerpLeftRight < 0.5 ? adjacentSims[2].weatherData.nowPrecType : adjacentSims[3].weatherData.nowPrecType; EnumPrecipitationType type = lerpTopBot < 0.5 ? top : bot; return(new PrecipitationState() { Level = level, ParticleSize = size, Type = type }); }
void genShrubs(int chunkX, int chunkZ) { int triesShrubs = (int)treeSupplier.treeGenProps.shrubsPerChunk.nextFloat(); int dx, dz, x, z; Block block; while (triesShrubs > 0) { triesShrubs--; dx = rnd.Next(chunksize); dz = rnd.Next(chunksize); x = dx + chunkX * chunksize; z = dz + chunkZ * chunksize; int y = heightmap[dz * chunksize + dx]; if (y <= 0 || y >= worldheight - 15) { continue; } tmpPos.Set(x, y, z); block = blockAccessor.GetBlock(tmpPos); if (block.Fertility == 0) { continue; } // Place according to forest value float treeDensity = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, (float)dx / chunksize, (float)dz / chunksize); int climate = GameMath.BiLerpRgbColor((float)dx / chunksize, (float)dz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); float shrubChance = GameMath.BiLerp(shrubUpLeft, shrubUpRight, shrubBotLeft, shrubBotRight, (float)dx / chunksize, (float)dz / chunksize); if (rnd.NextDouble() > (shrubChance / 255f) * (shrubChance / 255f)) { continue; } TreeGenForClimate treegenParams = treeSupplier.GetRandomShrubGenForClimate(climate, (int)shrubChance, y); if (treegenParams != null) { if (blockAccessor.GetBlock(tmpPos.X, tmpPos.Y, tmpPos.Z).Replaceable >= 6000) { tmpPos.Y--; } treegenParams.treeGen.GrowTree( blockAccessor, tmpPos, treegenParams.size, treegenParams.vinesGrowthChance ); } } }
public double GetBlendedUndulatingCloudModeness() { return(GameMath.BiLerp( adjacentSims[0].GetBlendedUndulatingCloudModeness(), adjacentSims[1].GetBlendedUndulatingCloudModeness(), adjacentSims[2].GetBlendedUndulatingCloudModeness(), adjacentSims[3].GetBlendedUndulatingCloudModeness(), lerpLeftRight, lerpTopBot )); }
protected double pgetBlendedUndulatingCloudModeness() { return(GameMath.BiLerp( AdjacentSims[0].GetBlendedUndulatingCloudModeness(), AdjacentSims[1].GetBlendedUndulatingCloudModeness(), AdjacentSims[2].GetBlendedUndulatingCloudModeness(), AdjacentSims[3].GetBlendedUndulatingCloudModeness(), LerpLeftRight, LerpTopBot )); }
public double GetBlendedCloudBrightness(float b) { return(GameMath.BiLerp( adjacentSims[0].GetBlendedCloudBrightness(b), adjacentSims[1].GetBlendedCloudBrightness(b), adjacentSims[2].GetBlendedCloudBrightness(b), adjacentSims[3].GetBlendedCloudBrightness(b), lerpLeftRight, lerpTopBot )); }
public double GetBlendedCloudThicknessAt(int cloudTileX, int cloudTileZ) { return(GameMath.BiLerp( adjacentSims[0].GetBlendedCloudThicknessAt(cloudTileX, cloudTileZ), adjacentSims[1].GetBlendedCloudThicknessAt(cloudTileX, cloudTileZ), adjacentSims[2].GetBlendedCloudThicknessAt(cloudTileX, cloudTileZ), adjacentSims[3].GetBlendedCloudThicknessAt(cloudTileX, cloudTileZ), lerpLeftRight, lerpTopBot )); }
protected double pgetWindSpeed(double posY) { return(GameMath.BiLerp( AdjacentSims[0].GetWindSpeed(posY), AdjacentSims[1].GetWindSpeed(posY), AdjacentSims[2].GetWindSpeed(posY), AdjacentSims[3].GetWindSpeed(posY), LerpLeftRight, LerpTopBot )); }
private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams) { IntMap beachMap = chunks[0].MapChunk.MapRegion.BeachMap; Vec3i climate = chunks[0].MapChunk.MapRegion.ClimateMap.ToClimateVec(chunkX, chunkZ, api.WorldManager.RegionSize, chunksize); BlockPos pos = new BlockPos(); ushort[] heightMap = chunks[0].MapChunk.RainHeightMap; int regionChunkSize = api.WorldManager.RegionSize / chunksize; int rdx = chunkX % regionChunkSize; int rdz = chunkZ % regionChunkSize; float beachStep = (float)beachMap.InnerSize / regionChunkSize; int beachUpLeft = beachMap.GetUnpaddedInt((int)(rdx * beachStep), (int)(rdz * beachStep)); int beachUpRight = beachMap.GetUnpaddedInt((int)(rdx * beachStep + beachStep), (int)(rdz * beachStep)); int beachBotLeft = beachMap.GetUnpaddedInt((int)(rdx * beachStep), (int)(rdz * beachStep + beachStep)); int beachBotRight = beachMap.GetUnpaddedInt((int)(rdx * beachStep + beachStep), (int)(rdz * beachStep + beachStep)); for (int x = 0; x < chunksize; x++) { for (int z = 0; z < chunksize; z++) { int y = heightMap[z * chunksize + x]; float beachRel = GameMath.BiLerp(beachUpLeft, beachUpRight, beachBotLeft, beachBotRight, (float)x / chunksize, (float)z / chunksize) / 255f; float tempRel = climate.Z / 255f; if (beachRel > 0.5 && tempRel > 0.5) { pos.X = chunkX * chunksize + x; pos.Y = y + 1; pos.Z = chunkZ * chunksize + z; var a = api.ModLoader.GetModSystem <GenBlockLayers>(); int rockID = chunks[0].MapChunk.TopRockIdMap[z * chunksize + x]; if (a.blockLayerConfig.BeachLayer.BlockIdMapping.TryGetValue(rockID, out int sand)) { int lY = y % chunksize; int i3d = (chunksize * lY + z) * chunksize + x; int chunkY = y / chunksize; double noise = sNoise.Noise(rdx + x, rdx + z); if (chunks[chunkY].Blocks[i3d] == sand && noise > 0.84) { GenPalmTree(blockAccessor, pos, sizeNoise.Noise(pos.X, pos.Y, pos.Z), fruitNoise.Noise(pos.X, pos.Y, pos.Z), frondNoise.Noise(pos.X, pos.Y, pos.Z)); } } } } } }
public double GetRainFall(Vec3d pos) { LoadAdjacentSimsAndLerpValues(pos); return(GameMath.BiLerp( adjacentSims[0].weatherData.PrecIntensity, adjacentSims[1].weatherData.PrecIntensity, adjacentSims[2].weatherData.PrecIntensity, adjacentSims[3].weatherData.PrecIntensity, lerpLeftRight, lerpTopBot )); }
public float GetUnpaddedIntLerped(float x, float z) { int ix = (int)x; int iz = (int)z; return(GameMath.BiLerp( Data[(iz + TopLeftPadding) * Size + ix + TopLeftPadding], Data[(iz + TopLeftPadding) * Size + ix + 1 + TopLeftPadding], Data[(iz + 1 + TopLeftPadding) * Size + ix + TopLeftPadding], Data[(iz + 1 + TopLeftPadding) * Size + ix + 1 + TopLeftPadding], x - ix, z - iz )); }
public double GetWindSpeed(Vec3d pos) { LoadAdjacentSimsAndLerpValues(pos); return(GameMath.BiLerp( adjacentSims[0].GetWindSpeed(pos.Y), adjacentSims[1].GetWindSpeed(pos.Y), adjacentSims[2].GetWindSpeed(pos.Y), adjacentSims[3].GetWindSpeed(pos.Y), lerpLeftRight, lerpTopBot )); }
protected double pgetBlendedCloudBrightness(float b) { double bright = GameMath.BiLerp( AdjacentSims[0].GetBlendedCloudBrightness(b), AdjacentSims[1].GetBlendedCloudBrightness(b), AdjacentSims[2].GetBlendedCloudBrightness(b), AdjacentSims[3].GetBlendedCloudBrightness(b), LerpLeftRight, LerpTopBot ); double rainbright = rainOverlayData.State.nowCloudBrightness; return(GameMath.Lerp(bright, rainbright, lerpRainCloudOverlay)); }
protected double pgetBlendedCloudThicknessAt(int cloudTileX, int cloudTileZ) { double thick = GameMath.BiLerp( AdjacentSims[0].GetBlendedCloudThicknessAt(cloudTileX, cloudTileZ), AdjacentSims[1].GetBlendedCloudThicknessAt(cloudTileX, cloudTileZ), AdjacentSims[2].GetBlendedCloudThicknessAt(cloudTileX, cloudTileZ), AdjacentSims[3].GetBlendedCloudThicknessAt(cloudTileX, cloudTileZ), LerpLeftRight, LerpTopBot ); double rainThick = rainOverlayData.State.nowbaseThickness; return(GameMath.Lerp(thick, rainThick, lerpRainCloudOverlay)); }
protected double pgetBlendedCloudOpaqueness() { double opaque = GameMath.BiLerp( AdjacentSims[0].GetBlendedCloudOpaqueness(), AdjacentSims[1].GetBlendedCloudOpaqueness(), AdjacentSims[2].GetBlendedCloudOpaqueness(), AdjacentSims[3].GetBlendedCloudOpaqueness(), LerpLeftRight, LerpTopBot ); double rainopaque = rainOverlayData.State.nowbaseOpaqueness; return(GameMath.Lerp(opaque, rainopaque, lerpRainCloudOverlay)); }
public bool TryGetCachedWeather(double x, double z, ref float[] weather) { int cX = (int)Math.Round(x / chunksize); int cZ = (int)Math.Round(z / chunksize); int startX = (cX - 1) * chunksize + chunksize / 2; int startZ = (cZ - 1) * chunksize + chunksize / 2; float dx = (float)((x - startX) / chunksize); float dz = (float)((z - startZ) / chunksize); double hoursTotal = world.Calendar.TotalHours; double timespan = snap2.hoursTotal - snap1.hoursTotal; long topleft = ((cX - 1) << 32) | (cZ - 1); long topright = (cX << 32) | (cZ - 1); long bottomright = (cX << 32) | cZ; long bottomleft = ((cX - 1) << 32) | cZ; bool success = true; float[] wtl1 = null, wtr1 = null, wbr1 = null, wbl1 = null, wtl2 = null, wtr2 = null, wbr2 = null, wbl2 = null; success = success && snap1.WeatherNoiseByChunk.TryGetValue(topleft, out wtl1); success = success && snap1.WeatherNoiseByChunk.TryGetValue(topright, out wtr1); success = success && snap1.WeatherNoiseByChunk.TryGetValue(bottomright, out wbr1); success = success && snap1.WeatherNoiseByChunk.TryGetValue(bottomleft, out wbl1); success = success && snap2.WeatherNoiseByChunk.TryGetValue(topleft, out wtl2); success = success && snap2.WeatherNoiseByChunk.TryGetValue(topright, out wtr2); success = success && snap2.WeatherNoiseByChunk.TryGetValue(bottomright, out wbr2); success = success && snap2.WeatherNoiseByChunk.TryGetValue(bottomleft, out wbl2); if (!success) { return(false); } for (int i = 0; i < weather.Length; i++) { float weatherSnap1 = GameMath.BiLerp(wtl1[i], wtr1[i], wbr1[i], wbl1[i], dx, dz); float weatherSnap2 = GameMath.BiLerp(wtl2[i], wtr2[i], wbr2[i], wbl2[i], dx, dz); weather[i] = GameMath.Lerp(weatherSnap1, weatherSnap2, (float)((hoursTotal - snap1.hoursTotal) / timespan)); } return(true); }
public float GetIntLerpedCorrectly(float x, float z) { int posXLeft = (int)Math.Floor(x - 0.5f); int posXRight = posXLeft + 1; int posZLeft = (int)Math.Floor(z - 0.5f); int posZRight = posZLeft + 1; float fx = x - (posXLeft + 0.5f); float fz = z - (posZLeft + 0.5f); return(GameMath.BiLerp( Data[(posZLeft + TopLeftPadding) * Size + posXLeft + TopLeftPadding], Data[(posZLeft + TopLeftPadding) * Size + posXRight + TopLeftPadding], Data[(posZRight + TopLeftPadding) * Size + posXLeft + TopLeftPadding], Data[(posZRight + TopLeftPadding) * Size + posXRight + TopLeftPadding], fx, fz )); }
void genPatches(int chunkX, int chunkZ, bool postPass) { int dx, dz, x, z; Block block; for (int i = 0; i < bpc.Patches.Length; i++) { BlockPatch blockPatch = bpc.Patches[i]; if (blockPatch.PostPass != postPass) { continue; } float chance = blockPatch.Chance * bpc.ChanceMultiplier.nextFloat(); while (chance-- > rnd.NextDouble()) { dx = rnd.Next(chunksize); dz = rnd.Next(chunksize); x = dx + chunkX * chunksize; z = dz + chunkZ * chunksize; int y = heightmap[dz * chunksize + dx]; if (y <= 0 || y >= worldheight - 15) { continue; } tmpPos.Set(x, y, z); block = blockAccessor.GetBlock(tmpPos); // Place according to forest value float forestRel = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, (float)dx / chunksize, (float)dz / chunksize) / 255f; int climate = GameMath.BiLerpRgbColor((float)dx / chunksize, (float)dz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); //float shrubChance = GameMath.BiLerp(shrubUpLeft, shrubUpRight, shrubBotLeft, shrubBotRight, (float)dx / chunksize, (float)dz / chunksize); if (bpc.IsPatchSuitableAt(blockPatch, block, api.WorldManager, climate, y, forestRel)) { int firstBlockId = 0; bool found = true; if (blockPatch.BlocksByRockType != null) { found = false; int dy = 1; while (dy < 5 && y - dy > 0) { string lastCodePart = blockAccessor.GetBlock(x, y - dy, z).LastCodePart(); if (RockBlockIdsByType.TryGetValue(lastCodePart, out firstBlockId)) { found = true; break; } dy++; } } if (found) { blockPatch.Generate(blockAccessor, rnd, x, y, z, firstBlockId); } } } } }
private void OnChunkColumnGeneration(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null) { rnd.InitPositionSeed(chunkX, chunkZ); IntDataMap2D forestMap = chunks[0].MapChunk.MapRegion.ForestMap; IntDataMap2D climateMap = chunks[0].MapChunk.MapRegion.ClimateMap; IntDataMap2D beachMap = chunks[0].MapChunk.MapRegion.BeachMap; ushort[] heightMap = chunks[0].MapChunk.RainHeightMap; int regionChunkSize = api.WorldManager.RegionSize / chunksize; int rdx = chunkX % regionChunkSize; int rdz = chunkZ % regionChunkSize; // Amount of data points per chunk float climateStep = (float)climateMap.InnerSize / regionChunkSize; float forestStep = (float)forestMap.InnerSize / regionChunkSize; float beachStep = (float)beachMap.InnerSize / regionChunkSize; // Retrieves the map data on the chunk edges int forestUpLeft = forestMap.GetUnpaddedInt((int)(rdx * forestStep), (int)(rdz * forestStep)); int forestUpRight = forestMap.GetUnpaddedInt((int)(rdx * forestStep + forestStep), (int)(rdz * forestStep)); int forestBotLeft = forestMap.GetUnpaddedInt((int)(rdx * forestStep), (int)(rdz * forestStep + forestStep)); int forestBotRight = forestMap.GetUnpaddedInt((int)(rdx * forestStep + forestStep), (int)(rdz * forestStep + forestStep)); int beachUpLeft = beachMap.GetUnpaddedInt((int)(rdx * beachStep), (int)(rdz * beachStep)); int beachUpRight = beachMap.GetUnpaddedInt((int)(rdx * beachStep + beachStep), (int)(rdz * beachStep)); int beachBotLeft = beachMap.GetUnpaddedInt((int)(rdx * beachStep), (int)(rdz * beachStep + beachStep)); int beachBotRight = beachMap.GetUnpaddedInt((int)(rdx * beachStep + beachStep), (int)(rdz * beachStep + beachStep)); // increasing x -> left to right // increasing z -> top to bottom float transitionSize = blockLayerConfig.blockLayerTransitionSize; for (int x = 0; x < chunksize; x++) { for (int z = 0; z < chunksize; z++) { // Some weird randomnes stuff to hide fundamental bugs in the climate transition system :D T_T (maybe not bugs but just fundamental shortcomings of using lerp on a very low resolution map) float distx = (float)distort2dx.Noise(chunkX * chunksize + x, chunkZ * chunksize + z); float distz = (float)distort2dz.Noise(chunkX * chunksize + x, chunkZ * chunksize + z); double posRand = (double)GameMath.MurmurHash3(x + chunkX * chunksize, 1, z + chunkZ * chunksize) / int.MaxValue; double transitionRand = (posRand + 1) * transitionSize; int posY = heightMap[z * chunksize + x]; int climate = climateMap.GetUnpaddedColorLerped( rdx * climateStep + climateStep * (float)(x + distx) / chunksize, rdz * climateStep + climateStep * (float)(z + distz) / chunksize ); int tempUnscaled = (climate >> 16) & 0xff; int rnd = (int)(distx / 5); float temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat(tempUnscaled, posY - TerraGenConfig.seaLevel + rnd); float tempRel = TerraGenConfig.GetAdjustedTemperature(tempUnscaled, posY - TerraGenConfig.seaLevel + rnd) / 255f; float rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, posY + rnd) / 255f; float forestRel = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, (float)x / chunksize, (float)z / chunksize) / 255f; float beachRel = GameMath.BiLerp(beachUpLeft, beachUpRight, beachBotLeft, beachBotRight, (float)x / chunksize, (float)z / chunksize) / 255f; int prevY = posY; posY = PutLayers(transitionRand, x, posY, z, chunks, rainRel, temp, tempUnscaled, heightMap); int blockID = chunks[0].MapChunk.TopRockIdMap[z * chunksize + x]; GenBeach(x, prevY, z, chunks, rainRel, temp, beachRel, blockID); PlaceTallGrass(x, prevY, z, chunks, rainRel, tempRel, temp, forestRel); // Try again to put layers if above sealevel and we found over 10 air blocks int foundAir = 0; while (posY >= TerraGenConfig.seaLevel - 1) { int chunkY = posY / chunksize; int lY = posY % chunksize; int index3d = (chunksize * lY + z) * chunksize + x; int blockId = chunks[chunkY].Blocks[index3d]; if (blockId == 0) { foundAir++; } else { if (foundAir >= 8) { //temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat(tempUnscaled, posY - TerraGenConfig.seaLevel); //rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, posY) / 255f; //PutLayers(transitionRand, x, posY, z, chunks, rainRel, temp, tempUnscaled, null); break; } else { foundAir = 0; } } posY--; } } } }
void genShrubs(int chunkX, int chunkZ) { int triesShrubs = (int)treeSupplier.treeGenProps.shrubsPerChunk.nextFloat(); int dx, dz, x, z; Block block; while (triesShrubs > 0) { triesShrubs--; dx = rnd.NextInt(chunksize); dz = rnd.NextInt(chunksize); x = dx + chunkX * chunksize; z = dz + chunkZ * chunksize; int y = heightmap[dz * chunksize + dx]; if (y <= 0 || y >= worldheight - 15) { continue; } tmpPos.Set(x, y, z); block = blockAccessor.GetBlock(tmpPos); if (block.Fertility == 0) { continue; } // Place according to forest value int climate = GameMath.BiLerpRgbColor((float)dx / chunksize, (float)dz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); float shrubChance = GameMath.BiLerp(shrubUpLeft, shrubUpRight, shrubBotLeft, shrubBotRight, (float)dx / chunksize, (float)dz / chunksize); shrubChance = GameMath.Clamp(shrubChance + 255 * forestMod, 0, 255); if (rnd.NextDouble() > (shrubChance / 255f) * (shrubChance / 255f)) { continue; } TreeGenForClimate treegenParams = treeSupplier.GetRandomShrubGenForClimate(climate, (int)shrubChance, y); if (treegenParams != null) { bool canGen = true; for (int i = 0; i < structuresIntersectingChunk.Count; i++) { if (structuresIntersectingChunk[i].Location.Contains(tmpPos)) { canGen = false; break; } } if (!canGen) { continue; } if (blockAccessor.GetBlock(tmpPos.X, tmpPos.Y, tmpPos.Z).Replaceable >= 6000) { tmpPos.Y--; } treegenParams.treeGen.GrowTree( blockAccessor, tmpPos, treegenParams.size, treegenParams.vinesGrowthChance ); } } }
void genTrees(int chunkX, int chunkZ) { int climate = GameMath.BiLerpRgbColor((float)0.5f, (float)0.5f, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); float wetrel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, heightmap[(chunksize / 2) * chunksize + chunksize / 2]) / 255f; float dryrel = 1 - wetrel; float drypenalty = 1 - GameMath.Clamp(2f * (dryrel - 0.5f), 0, 0.8f); // Reduce tree generation by up to 70% in low rain places float wetboost = 1 + 3 * Math.Max(0, wetrel - 0.75f); int triesTrees = (int)(treeSupplier.treeGenProps.treesPerChunk.nextFloat() * drypenalty * wetboost); int dx, dz, x, z; Block block; while (triesTrees > 0) { triesTrees--; dx = rnd.NextInt(chunksize); dz = rnd.NextInt(chunksize); x = dx + chunkX * chunksize; z = dz + chunkZ * chunksize; int y = heightmap[dz * chunksize + dx]; if (y <= 0 || y >= worldheight - 15) { continue; } tmpPos.Set(x, y, z); block = blockAccessor.GetBlock(tmpPos); if (block.Fertility == 0) { continue; } // Place according to forest value float treeDensity = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, (float)dx / chunksize, (float)dz / chunksize); climate = GameMath.BiLerpRgbColor((float)dx / chunksize, (float)dz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); //float shrubChance = GameMath.BiLerp(shrubUpLeft, shrubUpRight, shrubBotLeft, shrubBotRight, (float)dx / chunksize, (float)dz / chunksize); treeDensity = GameMath.Clamp(treeDensity + forestMod * 255, 0, 255); float treeDensityNormalized = treeDensity / 255f; // 1 in 400 chance to always spawn a tree // otherwise go by tree density using a quadratic drop off to create clearer forest edges if (rnd.NextDouble() > Math.Max(0.0025, treeDensityNormalized * treeDensityNormalized) || forestMod <= -1) { continue; } TreeGenForClimate treegenParams = treeSupplier.GetRandomTreeGenForClimate(climate, (int)treeDensity, y); if (treegenParams != null) { bool canGen = true; for (int i = 0; i < structuresIntersectingChunk.Count; i++) { if (structuresIntersectingChunk[i].Location.Contains(tmpPos)) { canGen = false; break; } } if (!canGen) { continue; } if (blockAccessor.GetBlock(tmpPos.X, tmpPos.Y, tmpPos.Z).Replaceable >= 6000) { tmpPos.Y--; } treegenParams.treeGen.GrowTree( blockAccessor, tmpPos, treegenParams.size, treegenParams.vinesGrowthChance ); } } }
private string getWeatherInfo <T>(IPlayer player) where T : WeatherSystemBase { T wsys = api.ModLoader.GetModSystem <T>(); Vec3d plrPos = player.Entity.SidedPos.XYZ; BlockPos pos = plrPos.AsBlockPos; var wreader = wsys.getWeatherDataReaderPreLoad(); wreader.LoadAdjacentSimsAndLerpValues(plrPos, 1); int regionX = (int)pos.X / api.World.BlockAccessor.RegionSize; int regionZ = (int)pos.Z / api.World.BlockAccessor.RegionSize; WeatherSimulationRegion weatherSim; long index2d = wsys.MapRegionIndex2D(regionX, regionZ); wsys.weatherSimByMapRegion.TryGetValue(index2d, out weatherSim); if (weatherSim == null) { return("weatherSim is null. No idea what to do here"); } StringBuilder sb = new StringBuilder(); sb.AppendLine(string.Format("Weather by region:")); // (lerp-lr: {0}, lerp-bt: {1}), wsys.lerpLeftRight.ToString("0.##"), wsys.lerpTopBot.ToString("0.##"))); string[] cornerNames = new string[] { "tl", "tr", "bl", "br" }; //topBlendedWeatherData.SetLerped(adjacentSims[0].weatherData, adjacentSims[1].weatherData, (float)lerpLeftRight); //botBlendedWeatherData.SetLerped(adjacentSims[2].weatherData, adjacentSims[3].weatherData, (float)lerpLeftRight); //blendedWeatherData.SetLerped(topBlendedWeatherData, botBlendedWeatherData, (float)lerpTopBot); double tlLerp = GameMath.BiLerp(1, 0, 0, 0, wreader.LerpLeftRight, wreader.LerpTopBot); double trLerp = GameMath.BiLerp(0, 1, 0, 0, wreader.LerpLeftRight, wreader.LerpTopBot); double blLerp = GameMath.BiLerp(0, 0, 1, 0, wreader.LerpLeftRight, wreader.LerpTopBot); double brLerp = GameMath.BiLerp(0, 0, 0, 1, wreader.LerpLeftRight, wreader.LerpTopBot); int[] lerps = new int[] { (int)(100 * tlLerp), (int)(100 * trLerp), (int)(100 * blLerp), (int)(100 * brLerp) }; for (int i = 0; i < 4; i++) { WeatherSimulationRegion sim = wreader.AdjacentSims[i]; if (sim == wsys.dummySim) { sb.AppendLine(string.Format("{0}: missing", cornerNames[i])); } else { /*sb.AppendLine(string.Format("{10}% of {0}@{8}/{9}: {1}% {2}, {3}% {4}. Prec: {5}, Wind: {6} (v={7})", * cornerNames[i], (int)(100 * sim.Weight), sim.NewWePattern.GetWeatherName(), (int)(100 - 100 * sim.Weight), * sim.OldWePattern.GetWeatherName(), sim.weatherData.PrecIntensity.ToString("0.###"), * sim.CurWindPattern.GetWindName(), sim.GetWindSpeed(pos.Y).ToString("0.###"), * sim.regionX, sim.regionZ, * lerps[i] * )) ;*/ sb.AppendLine(string.Format("{9}% of {0}@{7}/{8}: {1}% {2}, {3}% {4}. Wind: {5}, Event: {10} (v={6})", cornerNames[i], (int)(100 * sim.Weight), sim.NewWePattern.GetWeatherName(), (int)(100 - 100 * sim.Weight), sim.OldWePattern.GetWeatherName(), sim.CurWindPattern.GetWindName(), sim.GetWindSpeed(pos.Y).ToString("0.###"), sim.regionX, sim.regionZ, lerps[i], sim.CurWeatherEvent.config.Code )); } } //wsys.updateAdjacentAndBlendWeatherData(); //WeatherDataSnapshot wData = wsys.blendedWeatherData; //sb.AppendLine(string.Format(string.Format("Blended:\nPrecipitation: {0}, Particle size: {1}, Type: {2}, Wind speed: {3}", wData.PrecIntensity, wData.PrecParticleSize, wData.BlendedPrecType, wsys.GetWindSpeed(plrPos)))); ClimateCondition climate = api.World.BlockAccessor.GetClimateAt(player.Entity.Pos.AsBlockPos, EnumGetClimateMode.NowValues); sb.AppendLine(string.Format("Current precipitation: {0}%", (int)(climate.Rainfall * 100f))); sb.AppendLine(string.Format("Current wind: {0}", API.Config.GlobalConstants.CurrentWindSpeedClient)); return(sb.ToString()); }
private void TrySpawnGroupAt(BlockPos origin, Vec3d posAsVec, EntityProperties entityType, EntityProperties[] grouptypes) { BlockPos pos = origin.Copy(); float xRel = (float)(posAsVec.X % chunksize) / chunksize; float zRel = (float)(posAsVec.Z % chunksize) / chunksize; int climate = GameMath.BiLerpRgbColor(xRel, zRel, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); float temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat((climate >> 16) & 0xff, (int)posAsVec.Y - TerraGenConfig.seaLevel); float rain = ((climate >> 8) & 0xff) / 255f; float forestDensity = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, xRel, zRel); float shrubDensity = GameMath.BiLerp(shrubsUpLeft, shrubsUpRight, shrubsBotLeft, shrubsBotRight, xRel, zRel); int spawned = 0; WorldGenSpawnConditions sc = entityType.Server.SpawnConditions.Worldgen; bool hasCompanions = sc.Companions != null && sc.Companions.Length > 0; spawnPositions.Clear(); int nextGroupSize = 0; int tries = 10; while (nextGroupSize <= 0 && tries-- > 0) { float val = sc.GroupSize.nextFloat(); nextGroupSize = (int)val + ((val - (int)val) > rnd.NextDouble() ? 1 : 0); } for (int i = 0; i < nextGroupSize * 4 + 5; i++) { if (spawned >= nextGroupSize) { break; } EntityProperties typeToSpawn = entityType; // First entity 80% chance to spawn the dominant creature, every subsequent only 20% chance for males (or even lower if more than 5 companion types) double dominantChance = i == 0 ? 0.8 : Math.Min(0.2, 1f / grouptypes.Length); if (grouptypes.Length > 1 && rnd.NextDouble() > dominantChance) { typeToSpawn = grouptypes[1 + rnd.Next(grouptypes.Length - 1)]; } posAsVec.Set(pos.X + 0.5, pos.Y + 0.005, pos.Z + 0.5); IBlockAccessor blockAccesssor = wgenBlockAccessor.GetChunkAtBlockPos(pos.X, pos.Y, pos.Z) == null ? api.World.BlockAccessor : wgenBlockAccessor; IMapChunk mapchunk = blockAccesssor.GetMapChunkAtBlockPos(pos); if (mapchunk != null) { ushort[] heightMap = mapchunk.WorldGenTerrainHeightMap; pos.Y = sc.TryOnlySurface ? heightMap[((int)pos.Z % chunksize) * chunksize + ((int)pos.X % chunksize)] + 1 : pos.Y ; xRel = (float)(posAsVec.X % chunksize) / chunksize; zRel = (float)(posAsVec.Z % chunksize) / chunksize; climate = GameMath.BiLerpRgbColor(xRel, zRel, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat((climate >> 16) & 0xff, (int)posAsVec.Y - TerraGenConfig.seaLevel); rain = ((climate >> 8) & 0xff) / 255f; forestDensity = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, xRel, zRel) / 255f; shrubDensity = GameMath.BiLerp(shrubsUpLeft, shrubsUpRight, shrubsBotLeft, shrubsBotRight, xRel, zRel) / 255f; if (CanSpawnAt(blockAccesssor, typeToSpawn, pos, posAsVec, sc, rain, temp, forestDensity, shrubDensity)) { spawnPositions.Add(new SpawnOppurtunity() { ForType = typeToSpawn, Pos = posAsVec.Clone() }); spawned++; } } pos.X = origin.X + ((rnd.Next(11) - 5) + (rnd.Next(11) - 5)) / 2; pos.Z = origin.Z + ((rnd.Next(11) - 5) + (rnd.Next(11) - 5)) / 2; } // Only spawn if the group reached the minimum group size if (spawnPositions.Count >= nextGroupSize) { long herdId = api.WorldManager.GetNextHerdId(); foreach (SpawnOppurtunity so in spawnPositions) { Entity ent = CreateEntity(so.ForType, so.Pos); if (ent is EntityAgent) { (ent as EntityAgent).HerdId = herdId; } if (wgenBlockAccessor.GetChunkAtBlockPos(pos.X, pos.Y, pos.Z) == null) { api.World.SpawnEntity(ent); } else { wgenBlockAccessor.AddEntity(ent); } } //Console.WriteLine("Spawn a group of {0}x{1} at {2}", spawnPositions.Count, entityType.Code, origin); } }
private void OnChunkColumnGeneration(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null) { int seaLevel = api.World.SeaLevel; int mapSizeY = api.WorldManager.MapSizeY; var veinMaps = chunks[0].MapChunk.MapRegion.GetModdata <Dictionary <string, IntDataMap2D> >("veinmaps"); var oreMaps = chunks[0].MapChunk.MapRegion.OreMaps; ushort[] heightMap = chunks[0].MapChunk.RainHeightMap; int chunksize = api.World.BlockAccessor.ChunkSize; int regionChunkSize = api.WorldManager.RegionSize / chunksize; int rdx = chunkX % regionChunkSize; int rdz = chunkZ % regionChunkSize; foreach (var vein in veinMaps) { if (!DepositByCode.ContainsKey(vein.Key)) { continue; } var deposit = DepositByCode[vein.Key]; Dictionary <int, ResolvedDepositBlock> placeBlockByInBlockId = deposit.GeneratorInst.GetField <Dictionary <int, ResolvedDepositBlock> >("placeBlockByInBlockId"); Dictionary <int, ResolvedDepositBlock> surfaceBlockByInBlockId = deposit.GeneratorInst.GetField <Dictionary <int, ResolvedDepositBlock> >("surfaceBlockByInBlockId"); var oreMap = oreMaps[vein.Key]; var veinMap = vein.Value; float veinStep = (float)veinMap.InnerSize / regionChunkSize; float oreStep = (float)oreMap.InnerSize / regionChunkSize; for (int x = 0; x < chunksize; x++) { for (int z = 0; z < chunksize; z++) { rand.InitPositionSeed(chunkX + x, chunkZ + z); int dCx = rand.NextInt(9) - 4; int dCz = rand.NextInt(9) - 4; int height = heightMap[z * chunksize + x]; veinAtPos.Value = veinMap.GetInt((int)(rdx * veinStep + x), (int)(rdz * veinStep + z)); surfaceAtPos.Value = veinMap.GetInt((int)GameMath.Clamp(rdx * veinStep + (x + dCx), 0, veinMap.Size - 1), (int)GameMath.Clamp(rdz * veinStep + (z + dCz), 0, veinMap.Size - 1)); if (veinAtPos.Value == 0 && surfaceAtPos.Value == 0) { continue; } int oreUpLeft = oreMap.GetUnpaddedInt((int)(rdx * oreStep), (int)(rdz * oreStep)); int oreUpRight = oreMap.GetUnpaddedInt((int)(rdx * oreStep + oreStep), (int)(rdz * oreStep)); int oreBotLeft = oreMap.GetUnpaddedInt((int)(rdx * oreStep), (int)(rdz * oreStep + oreStep)); int oreBotRight = oreMap.GetUnpaddedInt((int)(rdx * oreStep + oreStep), (int)(rdz * oreStep + oreStep)); uint oreMapInt = (uint)GameMath.BiLerp(oreUpLeft, oreUpRight, oreBotLeft, oreBotRight, (float)x / chunksize, (float)z / chunksize); float oreMapRel = ((oreMapInt & ~0xFF00FF) >> 8) / 15f; if (veinAtPos.Rrel > 0.0) { int y = (int)((veinAtPos.Grel * mapSizeY) % height); int depth = (int)(veinAtPos.Rrel * 10) + 1; for (int dy = -depth; dy < depth; dy++) { if (y + dy > 0 && y + dy < mapSizeY) { int chunkY = (y + dy) / chunksize; int lY = (y + dy) % chunksize; int index3d = (chunksize * lY + z) * chunksize + x; int blockId = chunks[chunkY].Blocks[index3d]; if (placeBlockByInBlockId?.ContainsKey(blockId) ?? false) { var blocks = placeBlockByInBlockId[blockId].Blocks; chunks[chunkY].Blocks[index3d] = blocks[(int)(oreMapRel * (blocks.Length - 1))].Id; if (deposit.ChildDeposits != null) { foreach (var child in deposit.ChildDeposits) { if (veinAtPos.Brel > 0.5) { Dictionary <int, ResolvedDepositBlock> childPlaceBlockByInBlockId = child.GeneratorInst.GetField <Dictionary <int, ResolvedDepositBlock> >("placeBlockByInBlockId"); Dictionary <int, ResolvedDepositBlock> childSurfaceBlockByInBlockId = child.GeneratorInst.GetField <Dictionary <int, ResolvedDepositBlock> >("surfaceBlockByInBlockId"); if (childPlaceBlockByInBlockId.ContainsKey(blockId)) { blocks = childPlaceBlockByInBlockId[blockId].Blocks; chunks[chunkY].Blocks[index3d] = blocks[(int)(oreMapRel * (blocks.Length - 1))].Id; } } } } } } } } if (surfaceAtPos.Rrel > 0.0) { //gen surface deposits int y = (int)((surfaceAtPos.Grel * mapSizeY) % height); int chunkY = y / chunksize; int lY = y % chunksize; int index3d = (chunksize * lY + z) * chunksize + x; int blockId = chunks[chunkY].Blocks[index3d]; if (surfaceBlockByInBlockId?.ContainsKey(blockId) ?? false) { if (height < mapSizeY && surfaceAtPos.Brel > 0.5f) { Block belowBlock = api.World.Blocks[chunks[height / chunksize].Blocks[(height % chunksize * chunksize + z) * chunksize + x]]; index3d = ((height + 1) % chunksize * chunksize + z) * chunksize + x; if (belowBlock.SideSolid[BlockFacing.UP.Index] && chunks[(height + 1) / chunksize].Blocks[index3d] == 0) { chunks[(height + 1) / chunksize].Blocks[index3d] = surfaceBlockByInBlockId[blockId].Blocks[0].BlockId; #if DEBUG //so I can see it better when debugging index3d = (height % chunksize * chunksize + z) * chunksize + x; chunks[height / chunksize].Blocks[index3d] = 1; #endif } } } } } } } }
/// <summary> /// forceInitialPosY is for subdeposits /// </summary> /// <param name="chunks"></param> /// <param name="chunkX"></param> /// <param name="chunkZ"></param> /// <param name="offsetX"></param> /// <param name="offsetZ"></param> /// <param name="variant"></param> /// <param name="forceInitialPosY"></param> /// <returns></returns> Dictionary <Vec3i, DepositVariant> GenDeposit(IServerChunk[] chunks, int chunkX, int chunkZ, int offsetX, int offsetZ, DepositVariant variant, int?forceInitialPosY = null) { Dictionary <Vec3i, DepositVariant> SubDepositsToPlace = new Dictionary <Vec3i, DepositVariant>(); IMapChunk mapchunk = chunks[0].MapChunk; int radius = Math.Min(64, (int)variant.Radius.nextFloat(1, depositRand)); if (radius <= 0) { return(SubDepositsToPlace); } // Let's deform that perfect circle a bit (+/- 25%) float deform = GameMath.Clamp(depositRand.NextFloat() - 0.5f, -0.25f, 0.25f); int radiusX = radius - (int)(radius * deform); int radiusZ = radius + (int)(radius * deform); int posY; // No need to caluclate further if this deposit won't be part of this chunk if (radiusX + offsetX < 0 || radiusZ + offsetZ < 0 || offsetX - radiusX >= chunksize || offsetZ - radiusZ >= chunksize) { return(SubDepositsToPlace); } IMapChunk originMapchunk = null; int origPosY = 0; int lx = GameMath.Mod(offsetX, chunksize); int lz = GameMath.Mod(offsetZ, chunksize); if (variant.MaxY < 1 || variant.CheckClimate) { originMapchunk = api.WorldManager.GetMapChunk((chunkX * chunksize + offsetX) / chunksize, (chunkZ * chunksize + offsetZ) / chunksize); if (originMapchunk == null) { return(SubDepositsToPlace); // argh >.< } origPosY = originMapchunk.RainHeightMap[lz * chunksize + lx]; if ((float)origPosY / api.World.BlockAccessor.MapSizeY > variant.MaxY) { return(SubDepositsToPlace); } } // Check if suited for this area, climate wise if (variant.CheckClimate) { IntMap climateMap = api.World.BlockAccessor.GetMapRegion((chunkX * chunksize + offsetX) / regionSize, (chunkZ * chunksize + offsetZ) / regionSize).ClimateMap; float posXInRegionClimate = ((float)lx / regionSize - lx / regionSize) * noiseSizeClimate; float posZInRegionClimate = ((float)lz / regionSize - lz / regionSize) * noiseSizeClimate; int climate = climateMap.GetUnpaddedColorLerped(posXInRegionClimate, posZInRegionClimate); float temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat((climate >> 16) & 0xff, origPosY - TerraGenConfig.seaLevel); float rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, origPosY) / 255f; if (rainRel < variant.MinRain || rainRel > variant.MaxRain || temp < variant.MinTemp || temp > variant.MaxTemp) { return(SubDepositsToPlace); } } // Ok generate float th = variant.Thickness.nextFloat(1, depositRand); int thickness = (int)th + (depositRand.NextFloat() < th - (int)th ? 1 : 0); float xRadSqInv = 1f / (radiusX * radiusX); float zRadSqInv = 1f / (radiusZ * radiusZ); int blockIndex = 0; bool parentBlockOk = false; float depthf; bool shouldGenSurfaceDeposit = depositRand.NextFloat() > 0.35f && variant.SurfaceBlockCode != null; if (forceInitialPosY != null) { depthf = (float)forceInitialPosY / mapchunk.WorldGenTerrainHeightMap[offsetX * chunksize + offsetZ]; } else { depthf = variant.Depth.nextFloat(1, depositRand); } int depthi = (int)depthf; int topLeft = 2 * depositRand.NextInt(radiusX + 1) - radiusX; int topRight = 2 * depositRand.NextInt(radiusZ + 1) - radiusZ; int botLeft = 2 * depositRand.NextInt(radiusX + 1) - radiusX; int botRight = 2 * depositRand.NextInt(radiusZ + 1) - radiusZ; int yOff = 0; // Only generate inside this current chunk column int minx = GameMath.Clamp(offsetX - radiusX, 0, chunksize); int maxx = GameMath.Clamp(offsetX + radiusX, 0, chunksize); int minz = GameMath.Clamp(offsetZ - radiusZ, 0, chunksize); int maxz = GameMath.Clamp(offsetZ + radiusZ, 0, chunksize); float invChunkAreaSize = 1f / (chunksize * chunksize); for (int x = minx; x < maxx; x++) { float xSq = (x - offsetX) * (x - offsetX) * xRadSqInv; for (int z = minz; z < maxz; z++) { if (xSq + (z - offsetZ) * (z - offsetZ) * zRadSqInv > 1) { continue; } if (variant.Placement == EnumDepositPlacement.FollowSurfaceBelow) { posY = mapchunk.WorldGenTerrainHeightMap[z * chunksize + x] - depthi; } else if (variant.Placement == EnumDepositPlacement.FollowSurface) { yOff = (int)GameMath.BiLerp(topLeft, topRight, botLeft, botRight, (x - offsetX + radiusX) / (2f * radiusX), (z - offsetZ + radiusZ) / (2f * radiusZ)); posY = (int)(depthf * mapchunk.WorldGenTerrainHeightMap[z * chunksize + x]) + yOff / 2; } else if (variant.Placement == EnumDepositPlacement.Straight) { posY = (int)(depthf * mapchunk.WorldGenTerrainHeightMap[z * chunksize + x]); } else { yOff = (int)GameMath.BiLerp(topLeft, topRight, botLeft, botRight, (x - offsetX + radiusX) / (2f * radiusX), (z - offsetZ + radiusZ) / (2f * radiusZ)); posY = depthi + yOff; } // Some deposits may not appear all over cliffs if (variant.CheckClimate && Math.Abs(origPosY - posY) > variant.MaxYRoughness) { continue; } for (int y = 0; y < thickness; y++) { if (posY <= 1 || posY >= worldheight) { continue; } long index3d = ((posY % chunksize) * chunksize + z) * chunksize + x; ushort blockId = chunks[posY / chunksize].Blocks[index3d]; // Check if we are in mother material, but only if it has changed since last iteration (should reduce amount of these checks by 50-100%) parentBlockOk = false; for (int i = 0; i < variant.ParentBlockIds.Length; i++) { if (variant.ParentBlockIds[i] == blockId) { parentBlockOk = true; blockIndex = i; break; } } if (parentBlockOk) { if (variant.WithBlockCallback) { tmpPos.Set(chunkX * chunksize + x, posY, chunkZ * chunksize + z); blockTypes[variant.BlockIds[blockIndex]].TryPlaceBlockForWorldGen(blockAccessor, tmpPos, BlockFacing.UP); } else { chunks[posY / chunksize].Blocks[index3d] = variant.BlockIds[blockIndex]; } for (int i = 0; i < variant.ChildDeposits.Length; i++) { float rndVal = depositRand.NextFloat(); float quantity = variant.ChildDeposits[i].Quantity * invChunkAreaSize; if (quantity > rndVal) { Vec3i pos = new Vec3i(x, posY, z); if (ShouldPlaceAdjustedForOreMap(variant.ChildDeposits[i], chunkX * chunksize + x, chunkZ * chunksize + z, quantity, rndVal)) { SubDepositsToPlace[pos] = variant.ChildDeposits[i]; } } } if (shouldGenSurfaceDeposit) { int surfaceY = mapchunk.RainHeightMap[z * chunksize + x]; int depth = surfaceY - posY; float chance = variant.SurfaceBlockChance * Math.Max(0, 1 - depth / 8f); if (depositRand.NextFloat() < chance) { index3d = (((surfaceY + 1) % chunksize) * chunksize + z) * chunksize + x; Block belowBlock = api.World.Blocks[chunks[surfaceY / chunksize].Blocks[((surfaceY % chunksize) * chunksize + z) * chunksize + x]]; if (belowBlock.SideSolid[BlockFacing.UP.Index] && chunks[(surfaceY + 1) / chunksize].Blocks[index3d] == 0) { chunks[(surfaceY + 1) / chunksize].Blocks[index3d] = variant.SurfaceBlockIds[blockIndex]; } } } } posY--; } } } return(SubDepositsToPlace); }
private void OnChunkColumnGeneration(IServerChunk[] chunks, int chunkX, int chunkZ) { IntMap forestMap = chunks[0].MapChunk.MapRegion.ForestMap; IntMap climateMap = chunks[0].MapChunk.MapRegion.ClimateMap; ushort[] heightMap = chunks[0].MapChunk.RainHeightMap; int regionChunkSize = api.WorldManager.RegionSize / chunksize; int rlX = chunkX % regionChunkSize; int rlZ = chunkZ % regionChunkSize; // "Pixels per chunk" float facF = (float)forestMap.InnerSize / regionChunkSize; // Retrieves the map data on the chunk edges int forestUpLeft = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF)); int forestUpRight = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF)); int forestBotLeft = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF + facF)); int forestBotRight = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF + facF)); float facC = (float)climateMap.InnerSize / regionChunkSize; int climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC)); int climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC)); int climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC + facC)); int climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC + facC)); for (int x = 0; x < chunksize; x++) { for (int z = 0; z < chunksize; z++) { int posY = heightMap[z * chunksize + x]; int climate = GameMath.BiLerpRgbColor((float)x / chunksize, (float)z / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); int tempUnscaled = (climate >> 16) & 0xff; float temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat(tempUnscaled, posY - TerraGenConfig.seaLevel); float rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, posY) / 255f; float forestRel = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, (float)x / chunksize, (float)z / chunksize) / 255f; int prevY = posY; posY = PutLayers(x, posY, z, chunks, rainRel, temp, tempUnscaled, heightMap); PlaceTallGrass(x, prevY, z, chunks, rainRel, temp, forestRel); // Try again to put layers if above sealevel and we found over 10 air blocks int foundAir = 0; while (posY >= TerraGenConfig.seaLevel - 1) { int chunkY = posY / chunksize; int lY = posY % chunksize; int index3d = (chunksize * lY + z) * chunksize + x; ushort blockId = chunks[chunkY].Blocks[index3d]; if (blockId == 0) { foundAir++; } else { if (foundAir >= 8) { temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat(tempUnscaled, posY - TerraGenConfig.seaLevel); rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, posY) / 255f; PutLayers(x, posY, z, chunks, rainRel, temp, tempUnscaled, null); break; } else { foundAir = 0; } } posY--; } } } }
void genTrees(int chunkX, int chunkZ) { int triesTrees = (int)treeSupplier.treeGenProps.treesPerChunk.nextFloat(); int dx, dz, x, z; Block block; while (triesTrees > 0) { triesTrees--; dx = rnd.Next(chunksize); dz = rnd.Next(chunksize); x = dx + chunkX * chunksize; z = dz + chunkZ * chunksize; int y = heightmap[dz * chunksize + dx]; if (y <= 0 || y >= worldheight - 15) { continue; } tmpPos.Set(x, y, z); block = blockAccessor.GetBlock(tmpPos); if (block.Fertility == 0) { continue; } // Place according to forest value float treeDensity = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, (float)dx / chunksize, (float)dz / chunksize); int climate = GameMath.BiLerpRgbColor((float)dx / chunksize, (float)dz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); float shrubChance = GameMath.BiLerp(shrubUpLeft, shrubUpRight, shrubBotLeft, shrubBotRight, (float)dx / chunksize, (float)dz / chunksize); float treeDensityNormalized = treeDensity / 255f; // 1 in 400 chance to always spawn a tree // otherwise go by tree density using a quadratic drop off to create clearer forest edges if (rnd.NextDouble() > Math.Max(0.0025, treeDensityNormalized * treeDensityNormalized)) { continue; } TreeGenForClimate treegenParams = treeSupplier.GetRandomTreeGenForClimate(climate, (int)treeDensity, y); if (treegenParams != null) { bool canGen = true; for (int i = 0; i < structuresIntersectingChunk.Count; i++) { if (structuresIntersectingChunk[i].Location.Contains(tmpPos)) { canGen = false; break; } } if (!canGen) { continue; } if (blockAccessor.GetBlock(tmpPos.X, tmpPos.Y, tmpPos.Z).Replaceable >= 6000) { tmpPos.Y--; } treegenParams.treeGen.GrowTree( blockAccessor, tmpPos, treegenParams.size, treegenParams.vinesGrowthChance, treeDensityNormalized ); } } }