private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null) { 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; 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); float temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat((climate >> 16) & 0xff, posY - TerraGenConfig.seaLevel); int prevY = posY; if (PlaceSnowLayer(x, prevY, z, chunks, temp)) { heightMap[z * chunksize + x]++; } } } }
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 int GetUnpaddedColorLerped(float x, float z) { int ix = (int)x; int iz = (int)z; return(GameMath.BiLerpRgbColor(x - ix, z - iz, 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] )); }
private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ) { ushort[] heightmap = chunks[0].MapChunk.RainHeightMap; IntMap climateMap = chunks[0].MapChunk.MapRegion.ClimateMap; int regionChunkSize = api.WorldManager.RegionSize / chunksize; float fac = (float)climateMap.InnerSize / regionChunkSize; int rlX = chunkX % regionChunkSize; int rlZ = chunkZ % regionChunkSize; climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac)); climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac)); climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac + fac)); climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac + fac)); int climateMid = GameMath.BiLerpRgbColor(0.5f, 0.5f, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); // 16-23 bits = Red = temperature // 8-15 bits = Green = rain // 0-7 bits = Blue = humidity int rain = (climateMid >> 8) & 0xff; int humidity = climateMid & 0xff; // Lake density at chunk center float lakeDensity = 4 * (rain + humidity) / 255f; float maxTries = lakeDensity * 10; int dx, dz; while (maxTries-- > 0) { if (maxTries < 1 && rand.NextDouble() > maxTries) { break; } dx = rand.Next(chunksize); dz = rand.Next(chunksize); TryPlaceLakeAt(dx, dz, chunkX, chunkZ, heightmap); //ushort blockId = blockAccessor.GetBlock(new AssetLocation("creativeblock-37")).BlockId; //blockAccessor.SetBlock(blockId, new BlockPos(chunkX * chunksize + dx, heightmap[dz * chunksize + dx] + 1, chunkZ * chunksize + dz)); } }
public int GetColorLerpedCorrectly(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.BiLerpRgbColor( fx, fz, Data[(posZLeft + TopLeftPadding) * Size + posXLeft + TopLeftPadding], Data[(posZLeft + TopLeftPadding) * Size + posXRight + TopLeftPadding], Data[(posZRight + TopLeftPadding) * Size + posXLeft + TopLeftPadding], Data[(posZRight + TopLeftPadding) * Size + posXRight + TopLeftPadding] )); }
public static Vec3i ToClimateVec(this IntDataMap2D climateMap, int chunkX, int chunkZ, int regionsize, int chunksize, float lx = 0.5f, float ly = 0.5f) { int regionChunkSize = regionsize / chunksize; float fac = (float)climateMap.InnerSize / regionChunkSize; int rlX = chunkX % regionChunkSize; int rlZ = chunkZ % regionChunkSize; int climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac)); int climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac)); int climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac + fac)); int climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac + fac)); int climateMid = GameMath.BiLerpRgbColor(lx, ly, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); int rain = (climateMid >> 8) & 0xff; int humidity = climateMid & 0xff; int temp = (climateMid >> 16) & 0xff; return(new Vec3i(rain, humidity, temp)); }
private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null) { IntMap climateMap = chunks[0].MapChunk.MapRegion.ClimateMap; int regionChunkSize = api.WorldManager.RegionSize / chunksize; float fac = (float)climateMap.InnerSize / regionChunkSize; int rlX = chunkX % regionChunkSize; int rlZ = chunkZ % regionChunkSize; int climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac)); int climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac)); int climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac + fac)); int climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac + fac)); int climateMid = GameMath.BiLerpRgbColor(0.5f, 0.5f, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); // 16-23 bits = Red = temperature // 8-15 bits = Green = rain // 0-7 bits = Blue = humidity int rain = (climateMid >> 8) & 0xff; int humidity = climateMid & 0xff; int temp = (climateMid >> 16) & 0xff; int quantityRivulets = (int)(80 * (rain + humidity) / 255f) * (api.WorldManager.MapSizeY / chunksize) - Math.Max(0, 100 - temp); int fx, fy, fz; while (quantityRivulets-- > 0) { int dx = 1 + rnd.Next(chunksize - 2); int y = 1 + rnd.Next(api.WorldManager.MapSizeY - 2); int dz = 1 + rnd.Next(chunksize - 2); int quantitySolid = 0; int quantityAir = 0; for (int i = 0; i < BlockFacing.ALLFACES.Length; i++) { BlockFacing facing = BlockFacing.ALLFACES[i]; fx = dx + facing.Normali.X; fy = y + facing.Normali.Y; fz = dz + facing.Normali.Z; Block block = api.World.Blocks[ chunks[fy / chunksize].Blocks[(chunksize * (fy % chunksize) + fz) * chunksize + fx] ]; bool solid = block.BlockMaterial == EnumBlockMaterial.Stone; quantitySolid += solid ? 1 : 0; quantityAir += (block.BlockMaterial == EnumBlockMaterial.Air) ? 1 : 0; if (!solid && facing == BlockFacing.UP) { quantitySolid = 0; } } if (quantitySolid != 5 || quantityAir != 1) { continue; } chunks[y / chunksize].Blocks[(chunksize * (y % chunksize) + dz) * chunksize + dx] = y < 24 ? GlobalConfig.lavaBlockId : GlobalConfig.waterBlockId; BlockPos pos = new BlockPos(chunkX * chunksize + dx, y, chunkZ * chunksize + dz); blockAccessor.ScheduleBlockUpdate(pos); } }
internal bool TryGenerateAtSurface(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos) { int chunksize = blockAccessor.ChunkSize; int climate = GameMath.BiLerpRgbColor((float)(pos.X % chunksize) / chunksize, (float)(pos.Z % chunksize) / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); int num = rand.NextInt(schematicDatas.Length); int orient = rand.NextInt(4); BlockSchematicStructure schematic = schematicDatas[num][orient]; int widthHalf = (int)Math.Ceiling(schematic.SizeX / 2f); int lengthHalf = (int)Math.Ceiling(schematic.SizeZ / 2f); // Probe all 4 corners + center if they are on the same height int centerY = blockAccessor.GetTerrainMapheightAt(pos); tmpPos.Set(pos.X - widthHalf, 0, pos.Z - lengthHalf); int topLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X + widthHalf, 0, pos.Z - lengthHalf); int topRightY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X - widthHalf, 0, pos.Z + lengthHalf); int botLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X + widthHalf, 0, pos.Z + lengthHalf); int botRightY = blockAccessor.GetTerrainMapheightAt(tmpPos); int diff = GameMath.Max(centerY, topLeftY, topRightY, botLeftY, botRightY) - GameMath.Min(centerY, topLeftY, topRightY, botLeftY, botRightY); if (diff != 0) { return(false); } pos.Y += centerY - pos.Y + 1 + OffsetY; // Ensure not floating on water tmpPos.Set(pos.X - widthHalf, pos.Y - 1, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X + widthHalf, pos.Y - 1, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X - widthHalf, pos.Y - 1, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X + widthHalf, pos.Y - 1, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } // Ensure not submerged in water tmpPos.Set(pos.X - widthHalf, pos.Y, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X + widthHalf, pos.Y, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X - widthHalf, pos.Y, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X + widthHalf, pos.Y, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X - widthHalf, pos.Y + 1, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X + widthHalf, pos.Y + 1, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X - widthHalf, pos.Y + 1, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X + widthHalf, pos.Y + 1, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } if (!satisfiesMinDistance(pos, worldForCollectibleResolve)) { return(false); } if (isStructureAt(pos, worldForCollectibleResolve)) { return(false); } LastPlacedSchematicLocation.Set(pos.X, pos.Y, pos.Z, pos.X + schematic.SizeX, pos.Y + schematic.SizeY, pos.Z + schematic.SizeZ); LastPlacedSchematic = schematic; schematic.PlaceRespectingBlockLayers(blockAccessor, worldForCollectibleResolve, pos, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight, replaceblockids); return(true); }
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 ); } } }
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 genPatches(int chunkX, int chunkZ) { int dx, dz, x, z; Block block; for (int i = 0; i < bpc.Patches.Length; i++) { BlockPatch blockPatch = bpc.Patches[i]; if (!blockPatch.PrePass) { 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 int climate = GameMath.BiLerpRgbColor((float)dx / chunksize, (float)dz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); if (bpc.IsPatchSuitableAt(blockPatch, block, api.WorldManager, climate, y, 0)) { 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 OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null) { rand.InitPositionSeed(chunkX, chunkZ); ushort[] heightmap = chunks[0].MapChunk.RainHeightMap; IntDataMap2D climateMap = chunks[0].MapChunk.MapRegion.ClimateMap; int regionChunkSize = api.WorldManager.RegionSize / chunksize; float fac = (float)climateMap.InnerSize / regionChunkSize; int rlX = chunkX % regionChunkSize; int rlZ = chunkZ % regionChunkSize; climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac)); climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac)); climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac + fac)); climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac + fac)); int climateMid = GameMath.BiLerpRgbColor(0.5f, 0.5f, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); // 16-23 bits = Red = temperature // 8-15 bits = Green = rain // 0-7 bits = Blue = humidity int rain = (climateMid >> 8) & 0xff; int humidity = climateMid & 0xff; int temp = (climateMid >> 16) & 0xff; // Lake density at chunk center float pondDensity = 4 * (rain + humidity) / 255f; float sealeveltemp = TerraGenConfig.GetScaledAdjustedTemperatureFloat(temp, 0); // Less lakes where its below -5 degrees pondDensity -= Math.Max(0, 5 - sealeveltemp); float maxTries = pondDensity * 10; int dx, dz; int baseX = chunkX * chunksize; int baseZ = chunkZ * chunksize; while (maxTries-- > 0) { if (maxTries < 1 && rand.NextDouble() > maxTries) { break; } dx = rand.NextInt(chunksize); dz = rand.NextInt(chunksize); pondYPos = heightmap[dz * chunksize + dx] + 1; if (pondYPos <= 0 || pondYPos >= mapheight - 1) { return; } TryPlacePondAt(dx, pondYPos, dz, chunkX, chunkZ); } maxTries = 600; while (maxTries-- > 0) { if (maxTries < 1 && rand.NextDouble() > maxTries) { break; } dx = rand.NextInt(chunksize); dz = rand.NextInt(chunksize); pondYPos = (int)(rand.NextDouble() * heightmap[dz * chunksize + dx]); if (pondYPos <= 0 || pondYPos >= mapheight - 1) { return; } int chunkY = pondYPos / chunksize; int dy = pondYPos % chunksize; int blockID = chunks[chunkY].Blocks[(dy * chunksize + dz) * chunksize + dx]; while (blockID == 0 && pondYPos > 20) { pondYPos--; chunkY = pondYPos / chunksize; dy = pondYPos % chunksize; blockID = chunks[chunkY].Blocks[(dy * chunksize + dz) * chunksize + dx]; if (blockID != 0) { //blockAccessor.SetBlock(63, new BlockPos(dx + baseX, pondYPos, dz + baseZ)); TryPlacePondAt(dx, pondYPos, dz, chunkX, chunkZ); } } } }
/// <summary> /// For placement of ruins during worldgen, replaces the topsoil with the area specific soil (e.g. sand) /// </summary> /// <param name="blockAccessor"></param> /// <param name="blocks"></param> /// <param name="startPos"></param> /// <param name="climateUpLeft"></param> /// <param name="climateUpRight"></param> /// <param name="climateBotLeft"></param> /// <param name="climateBotRight"></param> /// <param name="replaceblockids"></param> /// <returns></returns> public int PlaceRespectingBlockLayers(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos startPos, int climateUpLeft, int climateUpRight, int climateBotLeft, int climateBotRight, int[] replaceblockids, bool replaceMetaBlocks = true) { BlockPos curPos = new BlockPos(); int placed = 0; int chunksize = blockAccessor.ChunkSize; for (int x = 0; x < SizeX; x++) { for (int z = 0; z < SizeZ; z++) { curPos.Set(x + startPos.X, startPos.Y, z + startPos.Z); IMapChunk mapchunk = blockAccessor.GetMapChunkAtBlockPos(curPos); int rockblockid = mapchunk.TopRockIdMap[(curPos.Z % chunksize) * chunksize + curPos.X % chunksize]; int depth = 0; int maxY = -1; for (int y = SizeY - 1; y >= 0; y--) { curPos.Set(x + startPos.X, y + startPos.Y, z + startPos.Z); Block newBlock = blocksByPos[x, y, z]; if (newBlock == null) { continue; } if (replaceMetaBlocks && newBlock == undergroundBlock) { continue; } if (newBlock.Replaceable < 1000) { if (replaceblockids.Length > depth && newBlock.BlockId == replaceblockids[depth]) { int climate = GameMath.BiLerpRgbColor((float)x / chunksize, (float)z / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); newBlock = GetBlockLayerBlock((climate >> 8) & 0xff, (climate >> 16) & 0xff, startPos.Y, rockblockid, depth, newBlock, worldForCollectibleResolve.Blocks); } depth++; } Block oldBlock = blockAccessor.GetBlock(curPos); int p = handler(blockAccessor, curPos, oldBlock, newBlock); placed += p; if (p > 0 && !newBlock.RainPermeable) { if (newBlock == fillerBlock || newBlock == pathwayBlock) { int lx = curPos.X % chunksize; int lz = curPos.Z % chunksize; if (mapchunk.RainHeightMap[lz * chunksize + lx] == curPos.Y) { mapchunk.RainHeightMap[lz * chunksize + lx]--; } } else { maxY = Math.Max(curPos.Y, maxY); } } byte[] lightHsv = newBlock.GetLightHsv(blockAccessor, curPos); if (lightHsv[2] > 0 && blockAccessor is IWorldGenBlockAccessor) { ((IWorldGenBlockAccessor)blockAccessor).ScheduleBlockLightUpdate(curPos.Copy(), oldBlock.BlockId, newBlock.BlockId); } } // In the post pass the rain map does not update, so let's set it ourselves if (maxY >= 0) { int lx = curPos.X % chunksize; int lz = curPos.Z % chunksize; int y = mapchunk.RainHeightMap[lz * chunksize + lx]; mapchunk.RainHeightMap[lz * chunksize + lx] = (ushort)Math.Max(y, maxY); } } } PlaceEntitiesAndBlockEntities(blockAccessor, worldForCollectibleResolve, startPos); return(placed); }
public void TryPlacePondAt(int dx, int pondYPos, int dz, int chunkX, int chunkZ, int depth = 0) { searchPositionsDeltas.Clear(); pondPositions.Clear(); // Clear Array for (int i = 0; i < didCheckPosition.Length; i++) { didCheckPosition[i] = false; } int basePosX = chunkX * chunksize; int basePosZ = chunkZ * chunksize; Vec2i tmp = new Vec2i(); searchPositionsDeltas.Enqueue(new Vec2i(dx, dz)); pondPositions.Enqueue(new Vec2i(basePosX + dx, basePosZ + dz)); didCheckPosition[(dz + mapOffset) * searchSize + dx + mapOffset] = true; while (searchPositionsDeltas.Count > 0) { Vec2i p = searchPositionsDeltas.Dequeue(); foreach (BlockFacing facing in BlockFacing.HORIZONTALS) { ndx = p.X + facing.Normali.X; ndz = p.Y + facing.Normali.Z; tmp.Set(chunkX * chunksize + ndx, chunkZ * chunksize + ndz); Block belowBlock = blockAccessor.GetBlock(tmp.X, pondYPos - 1, tmp.Y); bool inBoundary = ndx > minBoundary && ndz > minBoundary && ndx < maxBoundary && ndz < maxBoundary; // Only continue when within our 3x3 chunk search area and having a more or less solid block below (or water) if (inBoundary && (belowBlock.Replaceable < 6000 || belowBlock.BlockId == GlobalConfig.waterBlockId)) { int arrayIndex = (ndz + mapOffset) * searchSize + ndx + mapOffset; // Already checked or did we reach a pond border? if (!didCheckPosition[arrayIndex] && blockAccessor.GetBlock(tmp.X, pondYPos, tmp.Y).Replaceable >= 6000) { searchPositionsDeltas.Enqueue(new Vec2i(ndx, ndz)); pondPositions.Enqueue(tmp.Copy()); didCheckPosition[arrayIndex] = true; } } else { pondPositions.Clear(); searchPositionsDeltas.Clear(); return; } } } if (pondPositions.Count == 0) { return; } int curChunkX, curChunkZ; int prevChunkX = -1, prevChunkZ = -1; int regionChunkSize = api.WorldManager.RegionSize / chunksize; IMapChunk mapchunk = null; IServerChunk chunk = null; IServerChunk chunkOneBlockBelow = null; int ly = GameMath.Mod(pondYPos, chunksize); bool extraPondDepth = rand.NextDouble() > 0.5; bool withSeabed = extraPondDepth || pondPositions.Count > 16; foreach (Vec2i p in pondPositions) { curChunkX = p.X / chunksize; curChunkZ = p.Y / chunksize; int lx = GameMath.Mod(p.X, chunksize); int lz = GameMath.Mod(p.Y, chunksize); // Get correct chunk and correct climate data if we don't have it already if (curChunkX != prevChunkX || curChunkZ != prevChunkZ) { chunk = (IServerChunk)blockAccessor.GetChunk(curChunkX, pondYPos / chunksize, curChunkZ); if (chunk == null) { chunk = api.WorldManager.GetChunk(curChunkX, pondYPos / chunksize, curChunkZ); } chunk.Unpack(); if (ly == 0) { chunkOneBlockBelow = ((IServerChunk)blockAccessor.GetChunk(curChunkX, (pondYPos - 1) / chunksize, curChunkZ)); if (chunkOneBlockBelow == null) { return; } chunkOneBlockBelow.Unpack(); } else { chunkOneBlockBelow = chunk; } mapchunk = chunk.MapChunk; IntDataMap2D climateMap = mapchunk.MapRegion.ClimateMap; float fac = (float)climateMap.InnerSize / regionChunkSize; int rlX = curChunkX % regionChunkSize; int rlZ = curChunkZ % regionChunkSize; climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac)); climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac)); climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac + fac)); climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac + fac)); prevChunkX = curChunkX; prevChunkZ = curChunkZ; chunkOneBlockBelow.MarkModified(); chunk.MarkModified(); } // Raise heightmap by 1 mapchunk.RainHeightMap[lz * chunksize + lx] = Math.Max(mapchunk.RainHeightMap[lz * chunksize + lx], (ushort)pondYPos); // Identify correct climate at this position int climate = GameMath.BiLerpRgbColor((float)lx / chunksize, (float)lz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); float temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat((climate >> 16) & 0xff, pondYPos - TerraGenConfig.seaLevel); // 1. Place water or ice block chunk.Blocks[(ly * chunksize + lz) * chunksize + lx] = temp < -5 ? GlobalConfig.lakeIceBlockId : GlobalConfig.waterBlockId; // 2. Let's make a nice muddy gravely sea bed if (!withSeabed) { continue; } // Need to check the block below first int index = ly == 0 ? ((31 * chunksize + lz) * chunksize + lx) : (((ly - 1) * chunksize + lz) * chunksize + lx) ; Block belowBlock = api.World.Blocks[chunkOneBlockBelow.Blocks[index]]; // Water below? Seabed already placed if (belowBlock.IsLiquid()) { continue; } float rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, pondYPos) / 255f; int rockBlockId = mapchunk.TopRockIdMap[lz * chunksize + lx]; if (rockBlockId == 0) { continue; } for (int i = 0; i < lakebedLayerConfig.BlockCodeByMin.Length; i++) { if (lakebedLayerConfig.BlockCodeByMin[i].Suitable(temp, rainRel, (float)pondYPos / mapheight, rand)) { chunkOneBlockBelow.Blocks[index] = lakebedLayerConfig.BlockCodeByMin[i].GetBlockForMotherRock(rockBlockId); break; } } } if (pondPositions.Count > 0 && extraPondDepth) { TryPlacePondAt(dx, pondYPos + 1, dz, chunkX, chunkZ, depth + 1); } }
protected BlockSchematicStructure GetGeneratableStructure(VillageSchematic schem, IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos) { int chunksize = blockAccessor.ChunkSize; int climate = GameMath.BiLerpRgbColor((float)(pos.X % chunksize) / chunksize, (float)(pos.Z % chunksize) / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); int num = rand.NextInt(schem.Structures.Length); BlockSchematicStructure schematic = schem.Structures[num]; int widthHalf = (int)Math.Ceiling(schematic.SizeX / 2f); int lengthHalf = (int)Math.Ceiling(schematic.SizeZ / 2f); pos.Y += schem.OffsetY; // Probe all 4 corners + center if they are on the same height int centerY = blockAccessor.GetTerrainMapheightAt(pos); tmpPos.Set(pos.X - widthHalf, 0, pos.Z - lengthHalf); int topLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X + widthHalf, 0, pos.Z - lengthHalf); int topRightY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X - widthHalf, 0, pos.Z + lengthHalf); int botLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X + widthHalf, 0, pos.Z + lengthHalf); int botRightY = blockAccessor.GetTerrainMapheightAt(tmpPos); int diff = GameMath.Max(centerY, topLeftY, topRightY, botLeftY, botRightY) - GameMath.Min(centerY, topLeftY, topRightY, botLeftY, botRightY); if (diff > 2) { return(null); } pos.Y += centerY - pos.Y + 1 + schem.OffsetY; if (pos.Y <= 0) { return(null); } // Ensure not floating on water tmpPos.Set(pos.X - widthHalf, pos.Y - 1, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X + widthHalf, pos.Y - 1, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X - widthHalf, pos.Y - 1, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X + widthHalf, pos.Y - 1, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } // Ensure not submerged in water tmpPos.Set(pos.X - widthHalf, pos.Y, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X + widthHalf, pos.Y, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X - widthHalf, pos.Y, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X + widthHalf, pos.Y, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X - widthHalf, pos.Y + 1, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X + widthHalf, pos.Y + 1, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X - widthHalf, pos.Y + 1, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } tmpPos.Set(pos.X + widthHalf, pos.Y + 1, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(null); } if (!TestUndergroundCheckPositions(blockAccessor, pos, schematic.UndergroundCheckPositions)) { return(null); } if (isStructureAt(pos, worldForCollectibleResolve)) { return(null); } return(schematic); }
/// <summary> /// For placement of ruins during worldgen, replaces the topsoil with the area specific soil (e.g. sand) /// </summary> /// <param name="blockAccessor"></param> /// <param name="blocks"></param> /// <param name="startPos"></param> /// <param name="climateUpLeft"></param> /// <param name="climateUpRight"></param> /// <param name="climateBotLeft"></param> /// <param name="climateBotRight"></param> /// <param name="replaceblockids"></param> /// <returns></returns> public int PlaceRespectingBlockLayers(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos startPos, int climateUpLeft, int climateUpRight, int climateBotLeft, int climateBotRight, ushort[] replaceblockids) { BlockPos curPos = new BlockPos(); int placed = 0; int chunksize = blockAccessor.ChunkSize; for (int x = 0; x < SizeX; x++) { for (int z = 0; z < SizeZ; z++) { curPos.Set(x + startPos.X, startPos.Y, z + startPos.Z); ushort rockblockid = blockAccessor.GetMapChunkAtBlockPos(curPos).TopRockIdMap[(curPos.Z % chunksize) * chunksize + curPos.X % chunksize]; int depth = 0; for (int y = SizeY - 1; y >= 0; y--) { curPos.Set(x + startPos.X, y + startPos.Y, z + startPos.Z); Block newBlock = blocksByPos[x, y, z]; if (newBlock == null) { continue; } if (newBlock.Replaceable < 1000) { if (replaceblockids.Length > depth && newBlock.BlockId == replaceblockids[depth]) { int climate = GameMath.BiLerpRgbColor((float)x / chunksize, (float)z / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); newBlock = GetBlockLayerBlock((climate >> 8) & 0xff, (climate >> 16) & 0xff, startPos.Y, rockblockid, depth, newBlock, worldForCollectibleResolve.Blocks); } depth++; } Block oldBlock = blockAccessor.GetBlock(curPos); placed += handler(blockAccessor, curPos, oldBlock, newBlock); byte[] lightHsv = newBlock.GetLightHsv(blockAccessor, curPos); if (lightHsv[2] > 0 && blockAccessor is IWorldGenBlockAccessor) { int chunkSize = blockAccessor.ChunkSize; ((IWorldGenBlockAccessor)blockAccessor).ScheduleBlockLightUpdate(curPos.Copy(), oldBlock.BlockId, newBlock.BlockId); } } } } foreach (var val in BlockEntities) { uint index = val.Key; int dx = (int)(index & 0x1ff); int dy = (int)((index >> 20) & 0x1ff); int dz = (int)((index >> 10) & 0x1ff); curPos.Set(startPos.X + dx, startPos.Y + dy, startPos.Z + dz); BlockEntity be = blockAccessor.GetBlockEntity(curPos); if (be != null) { be.FromTreeAtributes(DecodeBlockEntityData(val.Value), worldForCollectibleResolve); be.OnLoadCollectibleMappings(worldForCollectibleResolve, BlockCodes, ItemCodes); be.pos = curPos.Copy(); } } return(placed); }
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); } }
void genPatches(int chunkX, int chunkZ, bool postPass) { int dx, dz, x, z; Block block; int mapsizeY = blockAccessor.MapSizeY; var mapregion = sapi?.WorldManager.GetMapRegion((chunkX * chunksize) / regionSize, (chunkZ * chunksize) / regionSize); for (int i = 0; i < bpc.PatchesNonTree.Length; i++) { BlockPatch blockPatch = bpc.PatchesNonTree[i]; if (blockPatch.PostPass != postPass) { continue; } float chance = blockPatch.Chance * bpc.ChanceMultiplier.nextFloat(); while (chance-- > rnd.NextDouble()) { 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); // Place according to forest value float forestRel = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, (float)dx / chunksize, (float)dz / chunksize) / 255f; forestRel = GameMath.Clamp(forestRel + forestMod, 0, 1); float shrubRel = GameMath.BiLerp(shrubUpLeft, shrubUpRight, shrubBotLeft, shrubBotRight, (float)dx / chunksize, (float)dz / chunksize) / 255f; shrubRel = GameMath.Clamp(shrubRel + shrubMod, 0, 1); int climate = GameMath.BiLerpRgbColor((float)dx / chunksize, (float)dz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); if (bpc.IsPatchSuitableAt(blockPatch, block, mapsizeY, climate, y, forestRel, shrubRel)) { if (blockPatch.MapCode != null && rnd.NextInt(255) > GetPatchDensity(blockPatch.MapCode, x, z, mapregion)) { continue; } 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 OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null) { landforms = NoiseLandforms.landforms; IMapChunk mapchunk = chunks[0].MapChunk; int climateUpLeft; int climateUpRight; int climateBotLeft; int climateBotRight; IntMap climateMap = chunks[0].MapChunk.MapRegion.ClimateMap; int regionChunkSize = api.WorldManager.RegionSize / chunksize; float fac = (float)climateMap.InnerSize / regionChunkSize; int rlX = chunkX % regionChunkSize; int rlZ = chunkZ % regionChunkSize; climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac)); climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac)); climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac + fac)); climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac + fac)); int freezingTemp = TerraGenConfig.DescaleTemperature(-17); IntMap landformMap = mapchunk.MapRegion.LandformMap; // Amount of pixels for each chunk (probably 1, 2, or 4) in the land form map float chunkPixelSize = landformMap.InnerSize / regionChunkSize; // Adjusted lerp for the noiseWidth float chunkPixelStep = chunkPixelSize / noiseWidth; // Start coordinates for the chunk in the region map float baseX = (chunkX % regionChunkSize) * chunkPixelSize; float baseZ = (chunkZ % regionChunkSize) * chunkPixelSize; LerpedWeightedIndex2DMap landLerpMap = GetOrLoadLerpedLandformMap(chunks[0].MapChunk, chunkX / regionChunkSize, chunkZ / regionChunkSize); // Terrain octaves double[] octNoiseX0, octNoiseX1, octNoiseX2, octNoiseX3; double[] octThX0, octThX1, octThX2, octThX3; // So it seems we have some kind of off-by-one error here? // When the slope of a mountain goes up (in positive z or x direction), particularly at large word heights (512+) // then the last blocks (again in postive x/z dir) are below of where they should be? // I have no idea why, but this offset seems to greatly mitigate the issue float weirdOffset = 0.25f; chunkPixelSize += weirdOffset; GetInterpolatedOctaves(landLerpMap[baseX, baseZ], out octNoiseX0, out octThX0); GetInterpolatedOctaves(landLerpMap[baseX + chunkPixelSize, baseZ], out octNoiseX1, out octThX1); GetInterpolatedOctaves(landLerpMap[baseX, baseZ + chunkPixelSize], out octNoiseX2, out octThX2); GetInterpolatedOctaves(landLerpMap[baseX + chunkPixelSize, baseZ + chunkPixelSize], out octNoiseX3, out octThX3); double[] terrainNoise3d = GetTerrainNoise3D(octNoiseX0, octNoiseX1, octNoiseX2, octNoiseX3, octThX0, octThX1, octThX2, octThX3, chunkX * noiseWidth, 0, chunkZ * noiseWidth); // Store heightmap in the map chunk ushort[] rainheightmap = chunks[0].MapChunk.RainHeightMap; ushort[] terrainheightmap = chunks[0].MapChunk.WorldGenTerrainHeightMap; // Terrain thresholds double tnoiseY0; double tnoiseY1; double tnoiseY2; double tnoiseY3; double tnoiseGainY0; double tnoiseGainY1; double tnoiseGainY2; double tnoiseGainY3; double thNoiseX0; double thNoiseX1; double thNoiseGainX0; double thNoiseGainX1; double thNoiseGainZ0; double thNoiseZ0; float[] terrainThresholdsX0 = new float[api.WorldManager.MapSizeY]; float[] terrainThresholdsX1 = new float[api.WorldManager.MapSizeY]; float[] terrainThresholdsX2 = new float[api.WorldManager.MapSizeY]; float[] terrainThresholdsX3 = new float[api.WorldManager.MapSizeY]; for (int xN = 0; xN < noiseWidth; xN++) { for (int zN = 0; zN < noiseWidth; zN++) { // Landform thresholds LoadInterpolatedThresholds(landLerpMap[baseX + xN * chunkPixelStep, baseZ + zN * chunkPixelStep], terrainThresholdsX0); LoadInterpolatedThresholds(landLerpMap[baseX + (xN + 1) * chunkPixelStep, baseZ + zN * chunkPixelStep], terrainThresholdsX1); LoadInterpolatedThresholds(landLerpMap[baseX + xN * chunkPixelStep, baseZ + (zN + 1) * chunkPixelStep], terrainThresholdsX2); LoadInterpolatedThresholds(landLerpMap[baseX + (xN + 1) * chunkPixelStep, baseZ + (zN + 1) * chunkPixelStep], terrainThresholdsX3); for (int yN = 0; yN < noiseHeight; yN++) { // Terrain noise tnoiseY0 = terrainNoise3d[NoiseIndex3d(xN, yN, zN)]; tnoiseY1 = terrainNoise3d[NoiseIndex3d(xN, yN, zN + 1)]; tnoiseY2 = terrainNoise3d[NoiseIndex3d(xN + 1, yN, zN)]; tnoiseY3 = terrainNoise3d[NoiseIndex3d(xN + 1, yN, zN + 1)]; tnoiseGainY0 = (terrainNoise3d[NoiseIndex3d(xN, yN + 1, zN)] - tnoiseY0) * lerpDeltaVert; tnoiseGainY1 = (terrainNoise3d[NoiseIndex3d(xN, yN + 1, zN + 1)] - tnoiseY1) * lerpDeltaVert; tnoiseGainY2 = (terrainNoise3d[NoiseIndex3d(xN + 1, yN + 1, zN)] - tnoiseY2) * lerpDeltaVert; tnoiseGainY3 = (terrainNoise3d[NoiseIndex3d(xN + 1, yN + 1, zN + 1)] - tnoiseY3) * lerpDeltaVert; for (int y = 0; y < lerpVer; y++) { int posY = yN * lerpVer + y; int chunkY = posY / chunksize; int localY = posY % chunksize; // For Terrain noise double tnoiseX0 = tnoiseY0; double tnoiseX1 = tnoiseY1; double tnoiseGainX0 = (tnoiseY2 - tnoiseY0) * lerpDeltaHor; double tnoiseGainX1 = (tnoiseY3 - tnoiseY1) * lerpDeltaHor; // Landform thresholds lerp thNoiseX0 = terrainThresholdsX0[posY]; thNoiseX1 = terrainThresholdsX2[posY]; thNoiseGainX0 = (terrainThresholdsX1[posY] - thNoiseX0) * lerpDeltaHor; thNoiseGainX1 = (terrainThresholdsX3[posY] - thNoiseX1) * lerpDeltaHor; for (int x = 0; x < lerpHor; x++) { // For terrain noise double tnoiseZ0 = tnoiseX0; double tnoiseGainZ0 = (tnoiseX1 - tnoiseX0) * lerpDeltaHor; // Landform thNoiseZ0 = thNoiseX0; thNoiseGainZ0 = (thNoiseX1 - thNoiseX0) * lerpDeltaHor; for (int z = 0; z < lerpHor; z++) { int lX = xN * lerpHor + x; int lZ = zN * lerpHor + z; int mapIndex = ChunkIndex2d(lX, lZ); int chunkIndex = ChunkIndex3d(lX, localY, lZ); chunks[chunkY].Blocks[chunkIndex] = 0; if (posY == 0) { chunks[chunkY].Blocks[chunkIndex] = GlobalConfig.mantleBlockId; continue; } if (tnoiseZ0 > thNoiseZ0) { terrainheightmap[mapIndex] = rainheightmap[mapIndex] = (ushort)Math.Max(rainheightmap[mapIndex], posY); chunks[chunkY].Blocks[chunkIndex] = GlobalConfig.defaultRockId; } else { if (posY < TerraGenConfig.seaLevel) { terrainheightmap[mapIndex] = rainheightmap[mapIndex] = (ushort)Math.Max(rainheightmap[mapIndex], posY); if (posY == TerraGenConfig.seaLevel - 1) { int temp = (GameMath.BiLerpRgbColor(((float)lX) / chunksize, ((float)lZ) / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight) >> 16) & 0xff; float distort = (float)distort2dx.Noise(chunkX * chunksize + lX, chunkZ * chunksize + lZ) / 20f; float tempf = TerraGenConfig.GetScaledAdjustedTemperatureFloat(temp, 0) + distort; // dominionsmod chunks[chunkY].Blocks[chunkIndex] = (tempf < -17) ? GlobalConfig.lakeIceBlockId : saltWater; } else { // dominionsmod chunks[chunkY].Blocks[chunkIndex] = saltWater; } } else { chunks[chunkY].Blocks[chunkIndex] = 0; } } tnoiseZ0 += tnoiseGainZ0; thNoiseZ0 += thNoiseGainZ0; } tnoiseX0 += tnoiseGainX0; tnoiseX1 += tnoiseGainX1; thNoiseX0 += thNoiseGainX0; thNoiseX1 += thNoiseGainX1; } tnoiseY0 += tnoiseGainY0; tnoiseY1 += tnoiseGainY1; tnoiseY2 += tnoiseGainY2; tnoiseY3 += tnoiseGainY3; } } } } int ymax = 0; for (int i = 0; i < rainheightmap.Length; i++) { ymax = Math.Max(ymax, rainheightmap[i]); } chunks[0].MapChunk.YMax = (ushort)ymax; }
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 ); } } }
internal bool TryGenerateAtSurface(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos) { int chunksize = blockAccessor.ChunkSize; int climate = GameMath.BiLerpRgbColor((float)(pos.X % chunksize) / chunksize, (float)(pos.Z % chunksize) / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); int num = rand.Next(schematicDatas.Length); int orient = rand.Next(4); BlockSchematicStructure schematic = schematicDatas[num][orient]; int widthHalf = (int)Math.Ceiling(schematic.SizeX / 2f); int lengthHalf = (int)Math.Ceiling(schematic.SizeZ / 2f); // Ensure not submerged in water tmpPos.Set(pos.X - widthHalf, pos.Y + OffsetY, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X + widthHalf, pos.Y + OffsetY, pos.Z - lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X - widthHalf, pos.Y + OffsetY, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X + widthHalf, pos.Y + OffsetY, pos.Z + lengthHalf); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } // Probe all 4 corners + center if they either touch the surface or are sightly below ground int centerDiff = blockAccessor.GetTerrainMapheightAt(pos) - pos.Y; tmpPos.Set(pos.X - widthHalf, 0, pos.Z - lengthHalf); int topLeftDiff = blockAccessor.GetTerrainMapheightAt(tmpPos) - pos.Y; tmpPos.Set(pos.X + widthHalf, 0, pos.Z - lengthHalf); int topRightDiff = blockAccessor.GetTerrainMapheightAt(tmpPos) - pos.Y; tmpPos.Set(pos.X - widthHalf, 0, pos.Z + lengthHalf); int botLeftDiff = blockAccessor.GetTerrainMapheightAt(tmpPos) - pos.Y; tmpPos.Set(pos.X + widthHalf, 0, pos.Z + lengthHalf); int botRightDiff = blockAccessor.GetTerrainMapheightAt(tmpPos) - pos.Y; bool ok = centerDiff >= -3 && centerDiff <= 1 && topLeftDiff >= -3 && topLeftDiff <= 1 && topRightDiff >= -3 && topRightDiff <= 1 && botLeftDiff >= -3 && botLeftDiff <= 1 && botRightDiff >= -3 && botRightDiff <= 1 ; if (ok) { schematic.PlaceRespectingBlockLayers(blockAccessor, worldForCollectibleResolve, pos, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight, replaceblockids); } return(ok); }