public override bool TryPlaceBlockForWorldGen(IBlockAccessor blockAccessor, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldGenRand) { bool didplace = false; if (blockAccessor.GetBlock(pos).Replaceable < 6000) { return(false); } BlockPos npos = pos.Copy(); for (int i = 0; i < 150 + worldGenRand.NextInt(30); i++) { npos.X = pos.X + worldGenRand.NextInt(11) - 5; npos.Y = pos.Y + worldGenRand.NextInt(11) - 5; npos.Z = pos.Z + worldGenRand.NextInt(11) - 5; if (npos.Y > api.World.SeaLevel - 10 || npos.Y < 25) { continue; // To hot for glowworms } if (blockAccessor.GetBlock(npos).Replaceable < 6000) { continue; } didplace |= TryGenGlowWorm(blockAccessor, npos, worldGenRand); } return(didplace); }
private void GenHere(IBlockAccessor blockAccessor, BlockPos pos, LCGRandom worldGenRand) { int rnd = worldGenRand.NextInt(bases.Length); Block placeblock = api.World.GetBlock(CodeWithVariant("type", bases[rnd])); blockAccessor.SetBlock(placeblock.Id, pos); if (segments[rnd] != null) { placeblock = api.World.GetBlock(CodeWithVariant("type", segments[rnd])); int len = worldGenRand.NextInt(3); while (len-- > 0) { pos.Down(); if (blockAccessor.GetBlock(pos).Replaceable > 6000) { blockAccessor.SetBlock(placeblock.Id, pos); } } pos.Down(); placeblock = api.World.GetBlock(CodeWithVariant("type", ends[rnd])); if (blockAccessor.GetBlock(pos).Replaceable > 6000) { blockAccessor.SetBlock(placeblock.Id, pos); } } }
public override bool TryPlaceBlockForWorldGen(IBlockAccessor blockAccessor, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldGenRand) { if (!HasBeachyGround(blockAccessor, pos)) { return(false); } tmpDict["type"] = types[worldGenRand.NextInt(types.Length)]; if (worldGenRand.NextInt(100) < 8) { tmpDict["color"] = rarecolors[worldGenRand.NextInt(rarecolors.Length)]; } else { tmpDict["color"] = colors[worldGenRand.NextInt(colors.Length)]; } Block block = blockAccessor.GetBlock(CodeWithVariants(tmpDict)); if (block == null) { return(false); } if (blockAccessor.GetBlock(pos).IsReplacableBy(this)) { blockAccessor.SetBlock(block.BlockId, pos); return(true); } return(false); }
internal void LoadRandomPattern() { NewWePattern = RandomWeatherPattern(); OldWePattern = RandomWeatherPattern(); NewWePattern.OnBeginUse(); OldWePattern.OnBeginUse(); CurWindPattern = WindPatterns[Rand.NextInt(WindPatterns.Length)]; CurWindPattern.OnBeginUse(); CurWeatherEvent = RandomWeatherEvent(); CurWeatherEvent.OnBeginUse(); Weight = 1; wsServer?.SendWeatherStateUpdate(new WeatherState() { RegionX = regionX, RegionZ = regionZ, NewPattern = NewWePattern.State, OldPattern = OldWePattern.State, WindPattern = CurWindPattern.State, WeatherEvent = CurWeatherEvent?.State, TransitionDelay = 0, Transitioning = false, Weight = Weight, updateInstant = false, LcgCurrentSeed = Rand.currentSeed, LcgMapGenSeed = Rand.mapGenSeed, LcgWorldSeed = Rand.worldSeed }); }
public override bool TryPlaceBlockForWorldGen(IBlockAccessor blockAccessor, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldGenRand) { if (blockAccessor.GetBlockId(pos) != 0) { return(false); } int surfaceY = blockAccessor.GetTerrainMapheightAt(pos); if (surfaceY - pos.Y < 30 || pos.Y < 25) { return(false); } BlockPos cavepos = getSemiLargeCavePos(blockAccessor, pos); if (cavepos == null) { return(false); } int dy = 0; while (dy < 15 && !blockAccessor.GetBlock(cavepos.X, cavepos.Y + dy, cavepos.Z).SideSolid[BlockFacing.UP.Index]) { dy++; } if (dy >= 15) { return(false); } blockAccessor.SetBlock(this.BlockId, cavepos.AddCopy(0, dy, 0)); if (EntityClass != null) { blockAccessor.SpawnBlockEntity(EntityClass, cavepos.AddCopy(0, dy, 0)); } BlockPos tmppos = new BlockPos(); int tries = 55 + worldGenRand.NextInt(55); while (tries-- > 0) { int offX = worldGenRand.NextInt(15) - 7; int offY = worldGenRand.NextInt(15) - 7; int offZ = worldGenRand.NextInt(15) - 7; if (worldGenRand.NextDouble() < 0.4) { tryPlaceDecoUp(tmppos.Set(cavepos.X + offX, cavepos.Y + offY, cavepos.Z + offZ), blockAccessor, worldGenRand); } else { tryPlaceDecoDown(tmppos.Set(cavepos.X + offX, cavepos.Y + offY, cavepos.Z + offZ), blockAccessor, worldGenRand); } } return(true); }
private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null) { Dictionary <Vec3i, int> ores = new Dictionary <Vec3i, int>(); for (int cY = 0; cY < chunks.Length; cY++) { IServerChunk chunk = chunks[cY]; if (chunk.Blocks == null) { continue; } for (int x = 0; x < chunksize; x++) { for (int y = 0; y < chunksize; y++) { for (int z = 0; z < chunksize; z++) { int block = chunk.Blocks[(y * chunksize + z) * chunksize + x]; if (surfaceBlocks.ContainsKey(block) && !ores.ContainsKey(new Vec3i(x, y, z))) { ores.Add(new Vec3i(x, y, z), block); } } } } foreach (var val in ores) { Vec3i vec = val.Key; int ore = val.Value; if (surfaceBlocks.TryGetValue(ore, out int surface)) { for (int y = vec.Y; y < chunksize; y++) { rnd.InitPositionSeed(chunkX * vec.X, chunkZ * vec.Z); if (y < 1 || rnd.NextDouble() > 0.1) { continue; } int dX = rnd.NextInt(chunksize), dZ = rnd.NextInt(chunksize); int block = chunk.Blocks[(y * chunksize + dZ) * chunksize + dX]; int dBlock = chunk.Blocks[((y - 1) * chunksize + dZ) * chunksize + dX]; if (bA.GetBlock(dBlock).Fertility > 4 && bA.GetBlock(block).IsReplacableBy(bA.GetBlock(ore)) && !bA.GetBlock(block).IsLiquid()) { chunk.Blocks[(y * chunksize + dZ) * chunksize + dX] = surface; bA.ScheduleBlockUpdate(new BlockPos(dX, y, dZ)); } } } } } }
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); }
void PlaceTallGrass(int x, int posY, int z, IServerChunk[] chunks, float rainRel, float tempRel, float temp, float forestRel) { double rndVal = blockLayerConfig.Tallgrass.RndWeight * rnd.NextDouble() + blockLayerConfig.Tallgrass.PerlinWeight * grassDensity.Noise(x, z, -0.5f); double extraGrass = Math.Max(0, rainRel * tempRel - 0.25); if (rndVal <= GameMath.Clamp(forestRel - extraGrass, 0.05, 0.99) || posY >= mapheight - 1 || posY < 1) { return; } int blockId = chunks[posY / chunksize].Blocks[(chunksize * (posY % chunksize) + z) * chunksize + x]; if (api.World.Blocks[blockId].Fertility <= rnd.NextInt(100)) { return; } double gheight = Math.Max(0, grassHeight.Noise(x, z) * blockLayerConfig.Tallgrass.BlockCodeByMin.Length - 1); int start = (int)gheight + (rnd.NextDouble() < gheight ? 1 : 0); for (int i = start; i < blockLayerConfig.Tallgrass.BlockCodeByMin.Length; i++) { TallGrassBlockCodeByMin bcbymin = blockLayerConfig.Tallgrass.BlockCodeByMin[i]; if (forestRel <= bcbymin.MaxForest && rainRel >= bcbymin.MinRain && temp >= bcbymin.MinTemp) { chunks[(posY + 1) / chunksize].Blocks[(chunksize * ((posY + 1) % chunksize) + z) * chunksize + x] = bcbymin.BlockId; return; } } }
private void tryPlaceDecoUp(BlockPos blockPos, IBlockAccessor blockAccessor, LCGRandom worldgenRand) { if (blockAccessor.GetBlockId(blockPos) != 0) { return; } int tries = 7; while (tries-- > 0) { blockPos.Y++; Block block = blockAccessor.GetBlock(blockPos); if (block.IsLiquid()) { return; } if (block.SideSolid[BlockFacing.DOWN.Index]) { blockPos.Y--; Block placeblock = DecoBlocksCeiling[worldgenRand.NextInt(DecoBlocksCeiling.Length)]; blockAccessor.SetBlock(placeblock.BlockId, blockPos); return; } } }
public void Generate(IBlockAccessor blockAccessor, LCGRandom rnd, int posX, int posY, int posZ, int firstBlockId) { float quantity = Quantity.nextFloat() + 1; int chunkSize = blockAccessor.ChunkSize; Block[] blocks = getBlocks(firstBlockId); if (blocks.Length == 0) { return; } while (quantity-- > 0) { if (quantity < 1 && rnd.NextDouble() > quantity) { break; } pos.X = posX + (int)OffsetX.nextFloat(); pos.Z = posZ + (int)OffsetZ.nextFloat(); int index = GameMath.Mod((int)BlockCodeIndex.nextFloat(), blocks.Length); IServerChunk chunk = (IServerChunk)blockAccessor.GetChunk(pos.X / chunkSize, 0, pos.Z / chunkSize); if (chunk == null) { break; } int lx = GameMath.Mod(pos.X, chunkSize); int lz = GameMath.Mod(pos.Z, chunkSize); if (Placement == EnumBlockPatchPlacement.Underground) { pos.Y = rnd.NextInt(Math.Max(1, chunk.MapChunk.WorldGenTerrainHeightMap[lz * blockAccessor.ChunkSize + lx] - 1)); } else { pos.Y = chunk.MapChunk.RainHeightMap[lz * blockAccessor.ChunkSize + lx] + 1; if (Math.Abs(pos.Y - posY) > 8 || pos.Y >= blockAccessor.MapSizeY - 1) { continue; } if (Placement == EnumBlockPatchPlacement.UnderWater) { tempPos.Set(pos.X, pos.Y - GameMath.Max(1, MinWaterDepth), pos.Z); Block downBlock = blockAccessor.GetBlock(tempPos); if (downBlock == null || downBlock.LiquidCode != "water") { continue; } } } blocks[index].TryPlaceBlockForWorldGen(blockAccessor, pos, BlockFacing.UP, rnd); } }
public void Init(ICoreServerAPI api, RockStrataConfig rockstrata, LCGRandom rnd, int i) { List <Block> blocks = new List <Block>(); for (int j = 0; j < blockCodes.Length; j++) { AssetLocation code = blockCodes[j]; if (code.Path.Contains("{rocktype}")) { if (BlocksByRockType == null) { BlocksByRockType = new Dictionary <int, Block[]>(); } for (int k = 0; k < rockstrata.Variants.Length; k++) { string rocktype = rockstrata.Variants[k].BlockCode.Path.Split('-')[1]; AssetLocation rocktypedCode = code.CopyWithPath(code.Path.Replace("{rocktype}", rocktype)); Block rockBlock = api.World.GetBlock(rockstrata.Variants[k].BlockCode); if (rockBlock != null) { BlocksByRockType[rockBlock.BlockId] = new Block[] { api.World.GetBlock(rocktypedCode) }; } } } else { Block block = api.World.GetBlock(code); if (block != null) { blocks.Add(block); } else { api.World.Logger.Warning("Block patch Nr. {0}: Unable to resolve block with code {1}. Will ignore.", i, code); } } } Blocks = blocks.ToArray(); if (BlockCodeIndex == null) { BlockCodeIndex = NatFloat.createUniform(0, Blocks.Length); } if (RandomMapCodePool != null) { int index = rnd.NextInt(RandomMapCodePool.Length); MapCode = RandomMapCodePool[index]; } }
private void GenRareColorPatch(IBlockAccessor blockAccessor, BlockPos pos, Block block, LCGRandom worldGenRand) { int cnt = 2 + worldGenRand.NextInt(6); int tries = 30; BlockPos npos = pos.Copy(); while (cnt > 0 && tries-- > 0) { npos.Set(pos).Add(worldGenRand.NextInt(5) - 2, 0, worldGenRand.NextInt(5) - 2); npos.Y = blockAccessor.GetTerrainMapheightAt(npos) + 1; Block nblock = blockAccessor.GetBlock(npos); if ((nblock.IsReplacableBy(block) || nblock is BlockLupine) && CanPlantStay(blockAccessor, npos)) { blockAccessor.SetBlock(block.BlockId, npos); cnt--; } } }
public override bool TryPlaceBlockForWorldGen(IBlockAccessor blockAccessor, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldGenRand) { bool placed = base.TryPlaceBlockForWorldGen(blockAccessor, pos, onBlockFace, worldGenRand); if (!placed) { return(false); } double rnd = worldGenRand.NextDouble(); if (rnd < 1 / 300.0) { GenRareColorPatch(blockAccessor, pos, rareVariants[worldGenRand.NextInt(rareVariants.Length)], worldGenRand); } else if (rnd < 1 / 120.0) { GenRareColorPatch(blockAccessor, pos, uncommonVariants[worldGenRand.NextInt(uncommonVariants.Length)], worldGenRand); } return(true); }
public override bool TryPlaceBlockForWorldGen(IBlockAccessor blockAccessor, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldGenRand) { bool didplace = false; if (blockAccessor.GetBlock(pos).Replaceable < 6000) { return(false); } pos = pos.Copy(); for (int i = 0; i < 5 + worldGenRand.NextInt(25); i++) { if (pos.Y < 15) { continue; // To hot for stalactites } didplace |= TryGenStalag(blockAccessor, pos, worldGenRand.NextInt(4), worldGenRand); pos.X += worldGenRand.NextInt(9) - 4; pos.Y += worldGenRand.NextInt(3) - 1; pos.Z += worldGenRand.NextInt(9) - 4; } return(didplace); }
/// <summary> /// Performs a Fisher-Yates shuffle in linear time or O(n) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="rand"></param> /// <param name="array"></param> public static T[] Shuffle <T>(this T[] array, LCGRandom rand) { int n = array.Length; // The number of items left to shuffle (loop invariant). while (n > 1) { int k = rand.NextInt(n); // 0 <= k < n. n--; // n is now the last pertinent index; T temp = array[n]; // swap array[n] with array[k] (does nothing if k == n). array[n] = array[k]; array[k] = temp; } return(array); }
private void GrowDownFrom(IBlockAccessor blockAccessor, BlockPos pos, string rocktype, int thickOff, LCGRandom worldGenRand) { for (int i = thicknessIndex[Thickness] + thickOff + worldGenRand.NextInt(2); i < Thicknesses.Length; i++) { Block stalagBlock = GetBlock(api.World, rocktype, Thicknesses[i]); if (stalagBlock == null) { continue; } Block block = blockAccessor.GetBlock(pos); if (!block.IsLiquid() && block.Replaceable >= 6000) { blockAccessor.SetBlock(stalagBlock.BlockId, pos); } else { break; } pos.Y--; } }
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); } } } }
public void InitWorldGen() { LoadGlobalConfig(api); IAsset asset = api.Assets.Get("worldgen/rockstrata.json"); RockStrataConfig rockstrata = asset.ToObject <RockStrataConfig>(); asset = api.Assets.Get("worldgen/blocklayers.json"); blockLayerConfig = asset.ToObject <BlockLayerConfig>(); blockLayerConfig.ResolveBlockIds(api, rockstrata); rnd = new LCGRandom(api.WorldManager.Seed); grassDensity = new ClampedSimplexNoise(new double[] { 4 }, new double[] { 0.5 }, rnd.NextInt()); grassHeight = new ClampedSimplexNoise(new double[] { 1.5 }, new double[] { 0.5 }, rnd.NextInt()); mapheight = api.WorldManager.MapSizeY; }
public bool TryGenerate(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos, int climateUpLeft, int climateUpRight, int climateBotLeft, int climateBotRight, DidGenerate didGenerateStructure) { this.climateUpLeft = climateUpLeft; this.climateUpRight = climateUpRight; this.climateBotLeft = climateBotLeft; this.climateBotRight = climateBotRight; float cnt = QuantityStructures.nextFloat(); int minQuantity = (int)cnt; BlockPos schemPos = pos.Copy(); Cuboidi location = new Cuboidi(); rand.InitPositionSeed(pos.X, pos.Z); List <GeneratableStructure> generatables = new List <GeneratableStructure>(); while (cnt-- > 0) { if (cnt < 1 && rand.NextDouble() > cnt) { break; } int tries = 30; while (tries-- > 0) { schemPos.Set(pos); schemPos.Add(rand.NextInt(50) - 25, 0, rand.NextInt(50) - 25); schemPos.Y = blockAccessor.GetTerrainMapheightAt(schemPos); double rndVal = rand.NextDouble() * totalWeight; int i = 0; VillageSchematic schem = null; while (rndVal > 0) { schem = Schematics[i++]; rndVal -= schem.Weight; } BlockSchematicStructure struc = GetGeneratableStructure(schem, blockAccessor, worldForCollectibleResolve, schemPos); if (struc != null) { location.Set(schemPos.X, schemPos.Y, schemPos.Z, schemPos.X + struc.SizeX, schemPos.Y + struc.SizeY, schemPos.Z + struc.SizeZ); bool intersect = false; for (int k = 0; k < generatables.Count; k++) { if (location.IntersectsOrTouches(generatables[k].location)) { intersect = true; break; } } if (!intersect) { generatables.Add(new GeneratableStructure() { struc = struc, pos = schemPos.Copy(), location = location.Clone() }); } break; } } } if (generatables.Count >= minQuantity) { foreach (var val in generatables) { val.struc.PlaceRespectingBlockLayers(blockAccessor, worldForCollectibleResolve, val.pos, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight, replaceblockids); didGenerateStructure(val.location, val.struc); } } return(true); }
internal bool TryGenerateRuinAtSurface(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos) { int num = rand.NextInt(schematicDatas.Length); int orient = rand.NextInt(4); BlockSchematicStructure schematic = schematicDatas[num][orient]; int wdthalf = (int)Math.Ceiling(schematic.SizeX / 2f); int lenhalf = (int)Math.Ceiling(schematic.SizeZ / 2f); int wdt = schematic.SizeX; int len = schematic.SizeZ; tmpPos.Set(pos.X + wdthalf, 0, pos.Z + lenhalf); int centerY = blockAccessor.GetTerrainMapheightAt(pos); // Probe all 4 corners + center if they either touch the surface or are sightly below ground tmpPos.Set(pos.X, 0, pos.Z); int topLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X + wdt, 0, pos.Z); int topRightY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X, 0, pos.Z + len); int botLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos); tmpPos.Set(pos.X + wdt, 0, pos.Z + len); int botRightY = blockAccessor.GetTerrainMapheightAt(tmpPos); int maxY = GameMath.Max(centerY, topLeftY, topRightY, botLeftY, botRightY); int minY = GameMath.Min(centerY, topLeftY, topRightY, botLeftY, botRightY); int diff = Math.Abs(maxY - minY); if (diff > 3) { return(false); } pos.Y = minY; // Ensure not deeply submerged in water tmpPos.Set(pos.X, pos.Y + 1 + OffsetY, pos.Z); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X + wdt, pos.Y + 1 + OffsetY, pos.Z); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X, pos.Y + 1 + OffsetY, pos.Z + len); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } tmpPos.Set(pos.X + wdt, pos.Y + 1 + OffsetY, pos.Z + len); if (blockAccessor.GetBlock(tmpPos).IsLiquid()) { return(false); } pos.Y--; 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); }
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); } } } }
public override bool TryPlaceBlockForWorldGen(IBlockAccessor blAcc, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldgenRand) { int cnt = 2 + worldgenRand.NextInt(25); float depth = GameMath.Sqrt(GameMath.Sqrt(cnt)); float craterRadius = GameMath.Sqrt(cnt) * 1.25f; // Look for even or downwards curved ground if (pos.Y > 250 || !IsSolid(blAcc, pos.X, pos.Y - 3, pos.Z) || !IsSolid(blAcc, pos.X, pos.Y - (int)depth, pos.Z) || !IsSolid(blAcc, pos.X + (int)craterRadius, pos.Y - 1, pos.Z) || !IsSolid(blAcc, pos.X - (int)craterRadius, pos.Y - 1, pos.Z) || !IsSolid(blAcc, pos.X, pos.Y - 1, pos.Z - (int)craterRadius) || !IsSolid(blAcc, pos.X, pos.Y - 1, pos.Z + (int)craterRadius) ) { return(false); } int y1 = blAcc.GetTerrainMapheightAt(tmpPos.Set(pos.X - 5, pos.Y, pos.Z)); int y2 = blAcc.GetTerrainMapheightAt(tmpPos.Set(pos.X + 5, pos.Y, pos.Z)); int y3 = blAcc.GetTerrainMapheightAt(tmpPos.Set(pos.X - 0, pos.Y, pos.Z + 5)); int y4 = blAcc.GetTerrainMapheightAt(tmpPos.Set(pos.X - 0, pos.Y, pos.Z - 5)); if ((GameMath.Max(y1, y2, y3, y4) - GameMath.Min(y1, y2, y3, y4)) > 4) { return(false); } tmpPos = tmpPos.Set(pos.X, pos.Y - (int)depth - 2, pos.Z); while (cnt-- > 0) { tmpPos.X += worldgenRand.NextInt(3) == 0 ? (worldgenRand.NextInt(3) - 1) : 0; tmpPos.Y += worldgenRand.NextInt(8) == 0 ? (worldgenRand.NextInt(3) - 1) : 0; tmpPos.Z += worldgenRand.NextInt(3) == 0 ? (worldgenRand.NextInt(3) - 1) : 0; blAcc.SetBlock(this.BlockId, tmpPos); } int sueviteBlockId = api.World.GetBlock(new AssetLocation("rock-suevite")).BlockId; int fragmentBlockId = api.World.GetBlock(new AssetLocation("loosestones-meteorite-iron-free")).BlockId; int looseSueviteBlockId = api.World.GetBlock(new AssetLocation("loosestones-suevite-free")).BlockId; float impactRockRadius = craterRadius * 1.2f; int range = (int)Math.Ceiling(impactRockRadius); int chunksize = api.World.BlockAccessor.ChunkSize; Vec2i vecTmp = new Vec2i(); // 1. Generate a basin of suevite and lower terrain for (int dx = -range; dx <= range; dx++) { for (int dz = -range; dz <= range; dz++) { float distImpactRockEdge = (dx * dx + dz * dz) / (impactRockRadius * impactRockRadius); if (distImpactRockEdge > 1) { continue; } tmpPos.X = pos.X + dx; tmpPos.Z = pos.Z + dz; int surfaceY = blAcc.GetTerrainMapheightAt(tmpPos); tmpPos.Y = surfaceY - (int)depth; vecTmp.X = tmpPos.X / chunksize; vecTmp.Y = tmpPos.Z / chunksize; IMapChunk mapchunk = blAcc.GetMapChunk(vecTmp); float q = 3 * Math.Max(0, 2 * (1 - distImpactRockEdge) - 0.2f); tmpPos.Y -= (int)q + 1; while (q > 0) { if (q < 1 && worldgenRand.NextDouble() > q) { break; } Block block = blAcc.GetBlock(tmpPos); if (block != this && block.BlockMaterial == EnumBlockMaterial.Stone) { blAcc.SetBlock(sueviteBlockId, tmpPos); } q--; tmpPos.Y++; } float distToCraterEdge = (dx * dx + dz * dz) / (craterRadius * craterRadius) + (float)worldgenRand.NextDouble() * 0.1f; if (distToCraterEdge > 1) { continue; } q = depth * (1 - distToCraterEdge); tmpPos.Y = surfaceY; Block surfaceblock = blAcc.GetBlock(tmpPos); Block abovesurfaceblock = blAcc.GetBlock(tmpPos.X, tmpPos.Y + 1, tmpPos.Z); for (int i = -1; i <= (int)q; i++) { tmpPos.Y = surfaceY - i; int id = i == (int)q ? surfaceblock.BlockId : 0; Block bblock = blAcc.GetBlock(tmpPos); if (!bblock.IsLiquid()) { blAcc.SetBlock(id, tmpPos); } } mapchunk.WorldGenTerrainHeightMap[(tmpPos.Z % chunksize) * chunksize + (tmpPos.X % chunksize)] -= (ushort)q; tmpPos.Y = blAcc.GetTerrainMapheightAt(tmpPos) + 1; blAcc.SetBlock(abovesurfaceblock.BlockId, tmpPos); } } int quantityFragments = 0; if (worldgenRand.NextInt(10) == 0) { quantityFragments = worldgenRand.NextInt(10); } else if (worldgenRand.NextInt(5) == 0) { quantityFragments = worldgenRand.NextInt(5); } while (quantityFragments-- > 0) { tmpPos.Set( pos.X + (worldgenRand.NextInt(11) + worldgenRand.NextInt(11)) / 2 - 5, 0, pos.Z + (worldgenRand.NextInt(11) + worldgenRand.NextInt(11)) / 2 - 5 ); tmpPos.Y = blAcc.GetTerrainMapheightAt(tmpPos) + 1; if (!blAcc.GetBlock(tmpPos.X, tmpPos.Y - 1, tmpPos.Z).SideSolid[BlockFacing.UP.Index]) { continue; } if (worldgenRand.NextDouble() < 0.3) { blAcc.SetBlock(fragmentBlockId, tmpPos); } else { blAcc.SetBlock(looseSueviteBlockId, tmpPos); } } //blAcc.SetBlock(61, pos.AddCopy(0, 20, 0)); return(true); }
private void DoGenStructures(IMapRegion region, int chunkX, int chunkZ, bool postPass, ITreeAttribute chunkGenParams = null) { BlockPos pos = new BlockPos(); ITreeAttribute chanceModTree = null; ITreeAttribute maxQuantityModTree = null; if (chunkGenParams?["structureChanceModifier"] != null) { chanceModTree = chunkGenParams["structureChanceModifier"] as TreeAttribute; } if (chunkGenParams?["structureMaxCount"] != null) { maxQuantityModTree = chunkGenParams["structureMaxCount"] as TreeAttribute; } strucRand.InitPositionSeed(chunkX, chunkZ); scfg.Structures.Shuffle(strucRand); for (int i = 0; i < scfg.Structures.Length; i++) { WorldGenStructure struc = scfg.Structures[i]; if (struc.PostPass != postPass) { continue; } float chance = struc.Chance * scfg.ChanceMultiplier; int toGenerate = 9999; if (chanceModTree != null) { chance *= chanceModTree.GetFloat(struc.Code, 0); } if (maxQuantityModTree != null) { toGenerate = maxQuantityModTree.GetInt(struc.Code, 9999); } while (chance-- > strucRand.NextDouble() && toGenerate > 0) { int dx = strucRand.NextInt(chunksize); int dz = strucRand.NextInt(chunksize); int ySurface = heightmap[dz * chunksize + dx]; if (ySurface <= 0 || ySurface >= worldheight - 15) { continue; } if (struc.Placement == EnumStructurePlacement.Underground) { if (struc.Depth != null) { pos.Set(chunkX * chunksize + dx, ySurface - (int)struc.Depth.nextFloat(1, strucRand), chunkZ * chunksize + dz); } else { pos.Set(chunkX * chunksize + dx, 8 + strucRand.NextInt(ySurface - 8 - 5), chunkZ * chunksize + dz); } } else { pos.Set(chunkX * chunksize + dx, ySurface, chunkZ * chunksize + dz); } if (struc.TryGenerate(worldgenBlockAccessor, api.World, pos, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight)) { Cuboidi loc = struc.LastPlacedSchematicLocation; string code = struc.Code + (struc.LastPlacedSchematic == null ? "" : "/" + struc.LastPlacedSchematic.FromFileName); region.GeneratedStructures.Add(new GeneratedStructure() { Code = code, Group = struc.Group, Location = loc.Clone() }); region.DirtyForSaving = true; if (struc.BuildProtected) { api.World.Claims.Add(new LandClaim() { Areas = new List <Cuboidi>() { loc.Clone() }, Description = struc.BuildProtectionDesc, ProtectionLevel = 10, LastKnownOwnerName = struc.BuildProtectionName, AllowUse = true }); } toGenerate--; } } } }
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.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); int climate = GameMath.BiLerpRgbColor((float)dx / chunksize, (float)dz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); 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 CarveTunnel(IServerChunk[] chunks, int chunkX, int chunkZ, double posX, double posY, double posZ, float horAngle, float vertAngle, float horizontalSize, float verticalSize, int currentIteration, int maxIterations, int branchLevel, bool extraBranchy = false, float curviness = 0.1f, bool largeNearLavaLayer = false) { blockId = airBlockId; ushort[] terrainheightmap = chunks[0].MapChunk.WorldGenTerrainHeightMap; ushort[] rainheightmap = chunks[0].MapChunk.RainHeightMap; float horAngleChange = 0; float vertAngleChange = 0; float horRadiusGain = 0; float horRadiusLoss = 0; float horRadiusGainAccum = 0; float horRadiusLossAccum = 0; float verHeightGain = 0; float verHeightLoss = 0; float verHeightGainAccum = 0; float verHeightLossAccum = 0; float sizeChangeSpeedAccum = 0.15f; float sizeChangeSpeedGain = 0f; float relPos; int branchRand = (branchLevel + 1) * (extraBranchy ? 12 : 25); while (currentIteration++ < maxIterations) { relPos = (float)currentIteration / maxIterations; float horRadius = 1.5f + GameMath.FastSin(relPos * GameMath.PI) * horizontalSize + horRadiusGainAccum; horRadius = Math.Min(horRadius, Math.Max(1, horRadius - horRadiusLossAccum)); float vertRadius = 1.5f + GameMath.FastSin(relPos * GameMath.PI) * (verticalSize + horRadiusLossAccum / 4) + verHeightGainAccum; // - horRadiusGainAccum / 2 vertRadius = Math.Min(vertRadius, Math.Max(0.6f, vertRadius - verHeightLossAccum)); float advanceHor = GameMath.FastCos(vertAngle); float advanceVer = GameMath.FastSin(vertAngle); // Caves get bigger near y=12 if (largeNearLavaLayer) { horRadius *= 1 + Math.Max(0, (10 - (float)Math.Abs(posY - 12)) / 10f); vertRadius *= 1 + Math.Max(0, (10 - (float)Math.Abs(posY - 12)) / 10f); } if (vertRadius < 1) { vertAngle *= 0.1f; } posX += GameMath.FastCos(horAngle) * advanceHor; posY += GameMath.Clamp(advanceVer, -vertRadius, vertRadius); posZ += GameMath.FastSin(horAngle) * advanceHor; vertAngle *= 0.8f; if (caveRand.NextInt(80) == 0) { sizeChangeSpeedGain = (caveRand.NextFloat() * caveRand.NextFloat()) / 2; } int rnd = caveRand.NextInt(10000); // Calls to caveRand are not too cheap, so lets just use one for all those random variation changes // 1/330 * 10k = 30 // 1/130 * 10k = 76 // 1/100 * 10k = 100 // 1/120 * 10k = 83 // 1/800 * 10k = 12 // Rarely change direction if ((rnd -= 30) <= 0) { horAngle = caveRand.NextFloat() * GameMath.TWOPI; } else // Rarely change direction somewhat if ((rnd -= 76) <= 0) { horAngle += caveRand.NextFloat() * GameMath.PI - GameMath.PIHALF; } else // Rarely go pretty wide if ((rnd -= 60) <= 0) { horRadiusGain = caveRand.NextFloat() * caveRand.NextFloat() * 3.5f; } else // Rarely go thin if ((rnd -= 60) <= 0) { horRadiusLoss = caveRand.NextFloat() * caveRand.NextFloat() * 10; } else // Rarely go flat if ((rnd -= 50) <= 0) { if (posY < TerraGenConfig.seaLevel - 10) { verHeightLoss = caveRand.NextFloat() * caveRand.NextFloat() * 12; horRadiusGain = Math.Max(horRadiusGain, caveRand.NextFloat() * caveRand.NextFloat() * 3); } } else // Very rarely go really wide if ((rnd -= 9) <= 0) { if (posY < TerraGenConfig.seaLevel - 20) { horRadiusGain = 1 + caveRand.NextFloat() * caveRand.NextFloat() * 5f; } } else // Very rarely go really tall if ((rnd -= 9) <= 0) { verHeightGain = 2 + caveRand.NextFloat() * caveRand.NextFloat() * 7; } else // Rarely large lava caverns if ((rnd -= 100) <= 0) { if (posY < 19) { verHeightGain = 2 + caveRand.NextFloat() * caveRand.NextFloat() * 5; horRadiusGain = 4 + caveRand.NextFloat() * caveRand.NextFloat() * 9; } } sizeChangeSpeedAccum = Math.Max(0.1f, sizeChangeSpeedAccum + sizeChangeSpeedGain * 0.05f); sizeChangeSpeedGain -= 0.02f; horRadiusGainAccum = Math.Max(0, horRadiusGainAccum + horRadiusGain * sizeChangeSpeedAccum); horRadiusGain -= 0.45f; horRadiusLossAccum = Math.Max(0, horRadiusLossAccum + horRadiusLoss * sizeChangeSpeedAccum); horRadiusLoss -= 0.4f; verHeightGainAccum = Math.Max(0, verHeightGainAccum + verHeightGain * sizeChangeSpeedAccum); verHeightGain -= 0.45f; verHeightLossAccum = Math.Max(0, verHeightLossAccum + verHeightLoss * sizeChangeSpeedAccum); verHeightLoss -= 0.4f; horAngle += curviness * horAngleChange; vertAngle += curviness * vertAngleChange; vertAngleChange = 0.9f * vertAngleChange + (caveRand.NextFloat() - caveRand.NextFloat()) * caveRand.NextFloat() * 3; horAngleChange = 0.9f * horAngleChange + (caveRand.NextFloat() - caveRand.NextFloat()) * caveRand.NextFloat() * 1; if (caveRand.NextInt(140) == 0) { horAngleChange *= caveRand.NextFloat() * 6; } // Horizontal branch int brand = branchRand + 2 * Math.Max(0, (int)posY - (TerraGenConfig.seaLevel - 20)); // Lower chance of branches above sealevel because Saraty does not like strongly cut out mountains if ((vertRadius > 1 || horRadius > 1) && branchLevel < 3 && caveRand.NextInt(brand) == 0) { CarveTunnel( chunks, chunkX, chunkZ, posX, posY + verHeightGainAccum / 2, posZ, horAngle + (caveRand.NextFloat() + caveRand.NextFloat() - 1) + GameMath.PI, vertAngle + (caveRand.NextFloat() - 0.5f) * (caveRand.NextFloat() - 0.5f), horizontalSize, verticalSize + verHeightGainAccum, currentIteration, maxIterations - (int)(caveRand.NextFloat() * 0.5 * maxIterations), branchLevel + 1 ); } // Vertical branch if (horRadius > 3 && posY > 60 && branchLevel < 1 && caveRand.NextInt(60) == 0) { CarveShaft( chunks, chunkX, chunkZ, posX, posY + verHeightGainAccum / 2, posZ, horAngle + (caveRand.NextFloat() + caveRand.NextFloat() - 1) + GameMath.PI, -GameMath.PI / 2 - 0.1f + 0.2f * caveRand.NextFloat(), Math.Min(3.5f, horRadius - 1), verticalSize + verHeightGainAccum, currentIteration, maxIterations - (int)(caveRand.NextFloat() * 0.5 * maxIterations) + (int)((posY / 5) * (0.5f + 0.5f * caveRand.NextFloat())), branchLevel ); branchLevel++; } if (horRadius >= 2 && caveRand.NextInt(5) == 0) { continue; } // Check just to prevent unnecessary calculations // As long as we are outside the currently generating chunk, we don't need to generate anything if (posX <= -horRadius * 2 || posX >= chunksize + horRadius * 2 || posZ <= -horRadius * 2 || posZ >= chunksize + horRadius * 2) { continue; } SetBlocks(chunks, horRadius, vertRadius + verHeightGainAccum, posX, posY + verHeightGainAccum / 2, posZ, terrainheightmap, rainheightmap, chunkX, chunkZ); } }
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 } } } } } } } }