public override void GenDeposit(IBlockAccessor blockAccessor, IServerChunk[] chunks, int originChunkX, int originChunkZ, BlockPos pos, ref Dictionary <BlockPos, DepositVariant> subDepositsToPlace) { IMapChunk heremapchunk = chunks[0].MapChunk; int depositGradeIndex = PlaceBlock.AllowedVariants != null?DepositRand.NextInt(PlaceBlock.AllowedVariants.Length) : 0; int radius = Math.Min(64, (int)Radius.nextFloat(1, DepositRand)); if (radius <= 0) { return; } radius++; bool shouldGenSurfaceDeposit = DepositRand.NextFloat() > 0.35f && SurfaceBlock != null; float tries = RandomTries.nextFloat(1, DepositRand); for (int i = 0; i < tries; i++) { targetPos.Set( pos.X + DepositRand.NextInt(2 * radius + 1) - radius, pos.Y + DepositRand.NextInt(2 * radius + 1) - radius, pos.Z + DepositRand.NextInt(2 * radius + 1) - radius ); int lx = targetPos.X % chunksize; int lz = targetPos.Z % chunksize; if (targetPos.Y <= 1 || targetPos.Y >= worldheight || lx < 0 || lz < 0 || lx >= chunksize || lz >= chunksize) { continue; } int index3d = ((targetPos.Y % chunksize) * chunksize + lz) * chunksize + lx; int blockId = chunks[targetPos.Y / chunksize].Blocks[index3d]; ResolvedDepositBlock resolvedPlaceBlock; if (placeBlockByInBlockId.TryGetValue(blockId, out resolvedPlaceBlock)) { Block placeblock = resolvedPlaceBlock.Blocks[depositGradeIndex]; if (variant.WithBlockCallback) { placeblock.TryPlaceBlockForWorldGen(blockAccessor, targetPos, BlockFacing.UP, DepositRand); } else { chunks[targetPos.Y / chunksize].Blocks[index3d] = placeblock.BlockId; } if (shouldGenSurfaceDeposit) { int surfaceY = heremapchunk.RainHeightMap[lz * chunksize + lx]; int depth = surfaceY - targetPos.Y; float chance = SurfaceBlockChance * Math.Max(0, 1 - depth / 8f); if (surfaceY < worldheight && DepositRand.NextFloat() < chance) { index3d = (((surfaceY + 1) % chunksize) * chunksize + lz) * chunksize + lx; Block belowBlock = Api.World.Blocks[chunks[surfaceY / chunksize].Blocks[((surfaceY % chunksize) * chunksize + lz) * chunksize + lx]]; if (belowBlock.SideSolid[BlockFacing.UP.Index] && chunks[(surfaceY + 1) / chunksize].Blocks[index3d] == 0) { chunks[(surfaceY + 1) / chunksize].Blocks[index3d] = surfaceBlockByInBlockId[blockId].Blocks[0].BlockId; } } } } } }
public override void GenDeposit(IBlockAccessor blockAccessor, IServerChunk[] chunks, int chunkX, int chunkZ, BlockPos depoCenterPos, ref Dictionary <BlockPos, DepositVariant> subDepositsToPlace) { int depositGradeIndex = PlaceBlock.MaxGrade == 0 ? 0 : DepositRand.NextInt(PlaceBlock.MaxGrade); int radius = Math.Min(64, (int)Radius.nextFloat(1, DepositRand)); if (radius <= 0) { return; } // Let's deform that perfect circle a bit (+/- 25%) float deform = GameMath.Clamp(DepositRand.NextFloat() - 0.5f, -0.25f, 0.25f); radiusX = radius - (int)(radius * deform); radiusZ = radius + (int)(radius * deform); int baseX = chunkX * chunksize; int baseZ = chunkZ * chunksize; // No need to caluclate further if this deposit won't be part of this chunk if (depoCenterPos.X + radiusX < baseX - 6 || depoCenterPos.Z + radiusZ < baseZ - 6 || depoCenterPos.X - radiusX >= baseX + chunksize + 6 || depoCenterPos.Z - radiusZ >= baseZ + chunksize + 6) { return; } IMapChunk heremapchunk = chunks[0].MapChunk; beforeGenDeposit(heremapchunk, depoCenterPos); // Ok generate float th = Thickness.nextFloat(1, DepositRand); depoitThickness = (int)th + (DepositRand.NextFloat() < th - (int)th ? 1 : 0); float xRadSqInv = 1f / (radiusX * radiusX); float zRadSqInv = 1f / (radiusZ * radiusZ); bool parentBlockOk = false; ResolvedDepositBlock resolvedPlaceBlock = null; bool shouldGenSurfaceDeposit = DepositRand.NextFloat() <= GenSurfaceBlockChance && SurfaceBlock != null; int lx = GameMath.Mod(depoCenterPos.X, chunksize); int lz = GameMath.Mod(depoCenterPos.Z, chunksize); int distx, distz; // No need to go search far beyond chunk boundaries int minx = baseX - 6; int maxx = baseX + chunksize + 6; int minz = baseZ - 6; int maxz = baseZ + chunksize + 6; minx = GameMath.Clamp(depoCenterPos.X - radiusX, minx, maxx); maxx = GameMath.Clamp(depoCenterPos.X + radiusX, minx, maxx); minz = GameMath.Clamp(depoCenterPos.Z - radiusZ, minz, maxz); maxz = GameMath.Clamp(depoCenterPos.Z + radiusZ, minz, maxz); //int placed = 0; float invChunkAreaSize = 1f / (chunksize * chunksize); double val = 1; for (int posx = minx; posx < maxx; posx++) { targetPos.X = posx; lx = targetPos.X - baseX; distx = posx - depoCenterPos.X; float xSq = distx * distx * xRadSqInv; for (int posz = minz; posz < maxz; posz++) { targetPos.Y = depoCenterPos.Y; targetPos.Z = posz; lz = targetPos.Z - baseZ; distz = posz - depoCenterPos.Z; // Kinda weird mathematically speaking, but seems to work as a means to distort the perfect circleness of deposits ¯\_(ツ)_/¯ // Also not very efficient to use direct perlin noise in here :/ // But after ~10 hours of failing (=weird lines of missing deposit material) with a pre-generated 2d distortion map i give up >.> val = 1 - (radius > 3 ? DistortNoiseGen.Noise(targetPos.X / 3.0, targetPos.Z / 3.0) * 0.2 : 0); double distanceToEdge = val - (xSq + distz * distz * zRadSqInv); if (distanceToEdge < 0 || lx < 0 || lz < 0 || lx >= chunksize || lz >= chunksize) { continue; } loadYPosAndThickness(heremapchunk, lx, lz, targetPos, distanceToEdge); // Some deposits may not appear all over cliffs if (Math.Abs(depoCenterPos.Y - targetPos.Y) > MaxYRoughness) { continue; } for (int y = 0; y < hereThickness; y++) { if (targetPos.Y <= 1 || targetPos.Y >= worldheight) { continue; } int index3d = ((targetPos.Y % chunksize) * chunksize + lz) * chunksize + lx; int blockId = chunks[targetPos.Y / chunksize].Blocks[index3d]; if (!IgnoreParentTestPerBlock || !parentBlockOk) { parentBlockOk = placeBlockByInBlockId.TryGetValue(blockId, out resolvedPlaceBlock); } if (parentBlockOk && resolvedPlaceBlock.Blocks.Length > 0) { int gradeIndex = Math.Min(resolvedPlaceBlock.Blocks.Length - 1, depositGradeIndex); Block placeblock = resolvedPlaceBlock.Blocks[gradeIndex]; if (variant.WithBlockCallback || (WithLastLayerBlockCallback && y == hereThickness - 1)) { placeblock.TryPlaceBlockForWorldGen(blockAccessor, targetPos.Copy(), BlockFacing.UP, rand); } else { chunks[targetPos.Y / chunksize].Blocks[index3d] = placeblock.BlockId; //placed++; } if (variant.ChildDeposits != null) { for (int i = 0; i < variant.ChildDeposits.Length; i++) { float rndVal = DepositRand.NextFloat(); float quantity = variant.ChildDeposits[i].TriesPerChunk * invChunkAreaSize; if (quantity > rndVal) { if (ShouldPlaceAdjustedForOreMap(variant.ChildDeposits[i], targetPos.X, targetPos.Z, quantity, rndVal)) { subDepositsToPlace[targetPos.Copy()] = variant.ChildDeposits[i]; } } } } if (shouldGenSurfaceDeposit) { int surfaceY = heremapchunk.RainHeightMap[lz * chunksize + lx]; int depth = surfaceY - targetPos.Y; float chance = SurfaceBlockChance * Math.Max(0, 1.11f - depth / 9f); if (surfaceY < worldheight && DepositRand.NextFloat() < chance) { Block belowBlock = Api.World.Blocks[chunks[surfaceY / chunksize].Blocks[((surfaceY % chunksize) * chunksize + lz) * chunksize + lx]]; index3d = (((surfaceY + 1) % chunksize) * chunksize + lz) * chunksize + lx; if (belowBlock.SideSolid[BlockFacing.UP.Index] && chunks[(surfaceY + 1) / chunksize].Blocks[index3d] == 0) { chunks[(surfaceY + 1) / chunksize].Blocks[index3d] = surfaceBlockByInBlockId[blockId].Blocks[0].BlockId; } } } } targetPos.Y--; } } } //Console.WriteLine("placed {0} blocks", placed); }