public override bool TryPlaceBlockForWorldGen(IBlockAccessor blockAccessor, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldgenRandom) { var dBlock = blockAccessor.GetBlock(pos.X, pos.Y - 1, pos.Z); if (dBlock.Fertility <= 20) { return(false); } var climate = blockAccessor.GetClimateAt(pos, EnumGetClimateMode.WorldGenValues); int rnd = worldgenRandom.NextInt(WorldGenConds.Length); int len = WorldGenConds.Length; for (int i = 0; i < len; i++) { var conds = WorldGenConds[(i + rnd) % len]; if (conds.MinTemp <= climate.Temperature && conds.MaxTemp >= climate.Temperature && conds.MinRain <= climate.Rainfall && conds.MaxRain >= climate.Rainfall && worldgenRandom.NextFloat() <= conds.Chance) { blockAccessor.SetBlock(BlockId, pos); blockAccessor.SpawnBlockEntity(EntityClass, pos); var be = blockAccessor.GetBlockEntity(pos) as BlockEntityFruitTreeBranch; be.TreeType = conds.Type; be.InitAfterWorldGen = true; return(true); } } return(false); }
internal void CreateForestFloor(IBlockAccessor blockAccessor, TreeGenConfig config, BlockPos pos, LCGRandom rnd, int treesInChunkGenerated) { int grassLevelOffset = 0; // More grass coverage for jungles ClimateCondition climate = blockAccessor.GetClimateAt(pos, EnumGetClimateMode.WorldGenValues); if (climate.Temperature > 24 && climate.Rainfall > 160) { grassLevelOffset = 2; } short[] outline = outlineThreadSafe.Value; this.api = blockAccessor; float forestness = climate.ForestDensity * climate.ForestDensity * 4 * (climate.Fertility + 0.25f); // Only replace soil with forestFloor in certain climate conditions if (climate.Fertility <= 0.25 || forestness <= 0.4) { return; } // Otherwise adjust the strength of the effect according to forest density and fertility (fertility is higher for tropical forests) for (int i = 0; i < outline.Length; i++) { outline[i] = (short)(outline[i] * forestness + 0.3f); } // Blend the canopy outline outwards from the center in a way that ensures smoothness for (int pass = 0; pass < 7; pass++) { bool noChange = true; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { if (x == 0 && z == 0) { continue; } int o = Math.Min((int)outline[(16 + z) * 33 + (16 + x)], 18 * 9); if (o == 0) { continue; } int n1 = (17 + z) * 33 + (16 + x); int n2 = (16 + z) * 33 + (17 + x); if (outline[n1] < o - 18) { outline[n1] = (short)(o - 18); noChange = false; } if (outline[n2] < o - 18) { outline[n2] = (short)(o - 18); noChange = false; } o = Math.Min((int)outline[(16 - z) * 33 + (16 + x)], 18 * 9); n1 = (15 - z) * 33 + (16 + x); n2 = (16 - z) * 33 + (17 + x); if (outline[n1] < o - 18) { outline[n1] = (short)(o - 18); noChange = false; } if (outline[n2] < o - 18) { outline[n2] = (short)(o - 18); noChange = false; } } for (int z = 0; z < 16; z++) { if (x == 0 && z == 0) { continue; } int o = Math.Min((int)outline[(16 + z) * 33 + (16 - x)], 18 * 9); int n1 = (17 + z) * 33 + (16 - x); int n2 = (16 + z) * 33 + (15 - x); if (outline[n1] < o - 18) { outline[n1] = (short)(o - 18); noChange = false; } if (outline[n2] < o - 18) { outline[n2] = (short)(o - 18); noChange = false; } o = Math.Min((int)outline[(16 - z) * 33 + (16 - x)], 18 * 9); n1 = (15 - z) * 33 + (16 - x); n2 = (16 - z) * 33 + (15 - x); if (outline[n1] < o - 18) { outline[n1] = (short)(o - 18); noChange = false; } if (outline[n2] < o - 18) { outline[n2] = (short)(o - 18); noChange = false; } } } if (noChange) { break; } } BlockPos currentPos = new BlockPos(); for (int canopyIndex = 0; canopyIndex < outline.Length; canopyIndex++) { int intensity = outline[canopyIndex]; if (intensity == 0) { continue; } int dz = canopyIndex / 33 - 16; int dx = canopyIndex % 33 - 16; currentPos.Set(pos.X + dx, pos.Y, pos.Z + dz); currentPos.Y = blockAccessor.GetTerrainMapheightAt(currentPos); if (currentPos.Y - pos.Y < 4) //Don't place forest floor above approximate height of the canopy of this tree { CheckAndReplaceForestFloor(currentPos, intensity, grassLevelOffset); } } GenPatches(blockAccessor, pos, forestness, config.Treetype, rnd); }
private void GenPatches(IBlockAccessor blockAccessor, BlockPos pos, float forestNess, EnumTreeType treetype, LCGRandom rnd) { var bpc = genPatchesSystem.bpc; int radius = 5; int worldheight = blockAccessor.MapSizeY; int cnt = underTreePatches?.Count ?? 0; for (int i = 0; i < cnt; i++) { BlockPatch bPatch = underTreePatches[i]; if (bPatch.TreeType != EnumTreeType.Any && bPatch.TreeType != treetype) { continue; } float chance = 0.003f * forestNess * bPatch.Chance * bpc.ChanceMultiplier.nextFloat(); //if (bPatch.blockCodes[0].Path.Contains("mushroom")) chance *= 20; - for debugging while (chance-- > rnd.NextDouble()) { int dx = rnd.NextInt(2 * radius) - radius; int dz = rnd.NextInt(2 * radius) - radius; tmpPos.Set(pos.X + dx, 0, pos.Z + dz); int y = blockAccessor.GetTerrainMapheightAt(tmpPos); if (y <= 0 || y >= worldheight - 8) { continue; } tmpPos.Y = y; var climate = blockAccessor.GetClimateAt(tmpPos, EnumGetClimateMode.WorldGenValues); if (climate == null) { continue; } if (bpc.IsPatchSuitableUnderTree(bPatch, worldheight, climate, y)) { int regionX = pos.X / blockAccessor.RegionSize; int regionZ = pos.Z / blockAccessor.RegionSize; if (bPatch.MapCode != null && rnd.NextInt(255) > genPatchesSystem.GetPatchDensity(bPatch.MapCode, tmpPos.X, tmpPos.Z, blockAccessor.GetMapRegion(regionX, regionZ))) { continue; } int firstBlockId = 0; bool found = true; if (bPatch.BlocksByRockType != null) { found = false; int dy = 1; while (dy < 5 && y - dy > 0) { string lastCodePart = blockAccessor.GetBlock(tmpPos.X, y - dy, tmpPos.Z).LastCodePart(); if (genPatchesSystem.RockBlockIdsByType.TryGetValue(lastCodePart, out firstBlockId)) { found = true; break; } dy++; } } if (found) { bPatch.Generate(blockAccessor, rnd, tmpPos.X, tmpPos.Y, tmpPos.Z, firstBlockId); } } } } cnt = onTreePatches?.Count ?? 0; for (int i = 0; i < cnt; i++) { BlockPatch blockPatch = onTreePatches[i]; float chance = 3 * forestNess * blockPatch.Chance * bpc.ChanceMultiplier.nextFloat(); while (chance-- > rnd.NextDouble()) { int dx = 1 - rnd.NextInt(2) * 2; int dy = rnd.NextInt(5); int dz = 1 - rnd.NextInt(2) * 2; tmpPos.Set(pos.X + dx, pos.Y + dy, pos.Z + dz); var block = api.GetBlock(tmpPos); if (block.Id != 0) { continue; } BlockFacing facing = null; for (int j = 0; j < 4; j++) { var f = BlockFacing.HORIZONTALS[j]; var nblock = api.GetBlock(tmpPos.X + f.Normali.X, tmpPos.Y, tmpPos.Z + f.Normali.Z); if (nblock is BlockLog && nblock.Variant["type"] != "resin") { facing = f; break; } } if (facing == null) { break; } var climate = blockAccessor.GetClimateAt(tmpPos, EnumGetClimateMode.WorldGenValues); if (climate == null) { continue; } if (bpc.IsPatchSuitableUnderTree(blockPatch, worldheight, climate, tmpPos.Y)) { int regionX = pos.X / blockAccessor.RegionSize; int regionZ = pos.Z / blockAccessor.RegionSize; if (blockPatch.MapCode != null && rnd.NextInt(255) > genPatchesSystem.GetPatchDensity(blockPatch.MapCode, tmpPos.X, tmpPos.Z, blockAccessor.GetMapRegion(regionX, regionZ))) { continue; } int index = rnd.NextInt(blockPatch.Blocks.Length); blockPatch.Blocks[index].TryPlaceBlockForWorldGen(blockAccessor, tmpPos, facing, rnd); } } } }