diff options
author | Julian Laubstein <julianlaubstein@yahoo.de> | 2015-11-25 16:52:32 +0100 |
---|---|---|
committer | Julian Laubstein <julianlaubstein@yahoo.de> | 2015-11-25 16:52:32 +0100 |
commit | d6ad5245b3590cc71686a763d71db82542b2f279 (patch) | |
tree | e03a27694e4b589f5bf04d2a595393661fa36654 /src | |
parent | Merge pull request #2687 from Gargaj/signfix (diff) | |
parent | OrePockets finisher is now configurable. (diff) | |
download | cuberite-d6ad5245b3590cc71686a763d71db82542b2f279.tar cuberite-d6ad5245b3590cc71686a763d71db82542b2f279.tar.gz cuberite-d6ad5245b3590cc71686a763d71db82542b2f279.tar.bz2 cuberite-d6ad5245b3590cc71686a763d71db82542b2f279.tar.lz cuberite-d6ad5245b3590cc71686a763d71db82542b2f279.tar.xz cuberite-d6ad5245b3590cc71686a763d71db82542b2f279.tar.zst cuberite-d6ad5245b3590cc71686a763d71db82542b2f279.zip |
Diffstat (limited to '')
-rw-r--r-- | src/Generating/ComposableGenerator.cpp | 128 | ||||
-rw-r--r-- | src/Generating/FinishGen.cpp | 453 | ||||
-rw-r--r-- | src/Generating/FinishGen.h | 176 | ||||
-rw-r--r-- | src/Generating/StructGen.cpp | 110 | ||||
-rw-r--r-- | src/Generating/StructGen.h | 48 | ||||
-rw-r--r-- | src/Noise/Noise.h | 1 |
6 files changed, 649 insertions, 267 deletions
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index eb1d0e1ee..fa8db8f93 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -330,6 +330,14 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) { m_FinishGens.push_back(cFinishGenPtr(new cStructGenDirectOverhangs(Seed))); } + else if (NoCaseCompare(*itr, "DirtPockets") == 0) + { + auto gen = std::make_shared<cFinishGenOrePockets>(Seed + 1, cFinishGenOrePockets::DefaultNaturalPatches()); + if (gen->Initialize(a_IniFile, "DirtPockets")) + { + m_FinishGens.push_back(gen); + } + } else if (NoCaseCompare(*itr, "DistortedMembraneOverhangs") == 0) { m_FinishGens.push_back(cFinishGenPtr(new cStructGenDistortedMembraneOverhangs(Seed))); @@ -397,52 +405,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) } else if (NoCaseCompare(*itr, "NaturalPatches") == 0) { - cStructGenOreNests::OreList Ores; - - // Dirt vein - cStructGenOreNests::OreInfo DirtVein; - DirtVein.BlockType = E_BLOCK_DIRT; - DirtVein.MaxHeight = 127; - DirtVein.NumNests = 20; - DirtVein.NestSize = 32; - Ores.push_back(DirtVein); - - // Gravel vein - cStructGenOreNests::OreInfo GravelVein; - GravelVein.BlockType = E_BLOCK_GRAVEL; - GravelVein.MaxHeight = 127; - GravelVein.NumNests = 20; - GravelVein.NestSize = 32; - Ores.push_back(GravelVein); - - // Granite vein - cStructGenOreNests::OreInfo GraniteVein; - GraniteVein.BlockType = E_BLOCK_STONE; - GraniteVein.BlockMeta = 1; - GraniteVein.MaxHeight = 127; - GraniteVein.NumNests = 20; - GraniteVein.NestSize = 32; - Ores.push_back(GraniteVein); - - // Diorite vein - cStructGenOreNests::OreInfo DioriteVein; - DioriteVein.BlockType = E_BLOCK_STONE; - DioriteVein.BlockMeta = 3; - DioriteVein.MaxHeight = 127; - DioriteVein.NumNests = 20; - DioriteVein.NestSize = 32; - Ores.push_back(DioriteVein); - - // Andesite vein - cStructGenOreNests::OreInfo AndesiteVein; - AndesiteVein.BlockType = E_BLOCK_STONE; - AndesiteVein.BlockMeta = 5; - AndesiteVein.MaxHeight = 127; - AndesiteVein.NumNests = 20; - AndesiteVein.NestSize = 32; - Ores.push_back(AndesiteVein); - - m_FinishGens.push_back(cFinishGenPtr(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE))); + m_FinishGens.push_back(std::make_shared<cFinishGenOreNests>(Seed + 1, cFinishGenOreNests::DefaultNaturalPatches())); } else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0) { @@ -457,72 +420,19 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) } else if (NoCaseCompare(*itr, "NetherOreNests") == 0) { - cStructGenOreNests::OreList Ores; - - // Quartz vein - cStructGenOreNests::OreInfo QuartzVein; - QuartzVein.BlockType = E_BLOCK_NETHER_QUARTZ_ORE; - QuartzVein.MaxHeight = 255; - QuartzVein.NumNests = 80; - QuartzVein.NestSize = 8; - Ores.push_back(QuartzVein); - - m_FinishGens.push_back(cFinishGenPtr(new cStructGenOreNests(Seed, Ores, E_BLOCK_NETHERRACK))); - + m_FinishGens.push_back(std::make_shared<cFinishGenOreNests>(Seed + 2, cFinishGenOreNests::DefaultNetherOres())); } else if (NoCaseCompare(*itr, "OreNests") == 0) { - cStructGenOreNests::OreList Ores; - - // Coal vein - cStructGenOreNests::OreInfo CoalVein; - CoalVein.BlockType = E_BLOCK_COAL_ORE; - CoalVein.MaxHeight = 127; - CoalVein.NumNests = 50; - CoalVein.NestSize = 10; - Ores.push_back(CoalVein); - - // Iron vein - cStructGenOreNests::OreInfo IronVein; - IronVein.BlockType = E_BLOCK_IRON_ORE; - IronVein.MaxHeight = 64; - IronVein.NumNests = 14; - IronVein.NestSize = 6; - Ores.push_back(IronVein); - - // Gold vein - cStructGenOreNests::OreInfo GoldVein; - GoldVein.BlockType = E_BLOCK_GOLD_ORE; - GoldVein.MaxHeight = 32; - GoldVein.NumNests = 2; - GoldVein.NestSize = 6; - Ores.push_back(GoldVein); - - // Redstone vein - cStructGenOreNests::OreInfo RedstoneVein; - RedstoneVein.BlockType = E_BLOCK_REDSTONE_ORE; - RedstoneVein.MaxHeight = 16; - RedstoneVein.NumNests = 4; - RedstoneVein.NestSize = 6; - Ores.push_back(RedstoneVein); - - // Lapis vein - cStructGenOreNests::OreInfo LapisVein; - LapisVein.BlockType = E_BLOCK_LAPIS_ORE; - LapisVein.MaxHeight = 30; - LapisVein.NumNests = 2; - LapisVein.NestSize = 5; - Ores.push_back(LapisVein); - - // Diamond vein - cStructGenOreNests::OreInfo DiamondVein; - DiamondVein.BlockType = E_BLOCK_DIAMOND_ORE; - DiamondVein.MaxHeight = 15; - DiamondVein.NumNests = 1; - DiamondVein.NestSize = 4; - Ores.push_back(DiamondVein); - - m_FinishGens.push_back(cFinishGenPtr(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE))); + m_FinishGens.push_back(std::make_shared<cFinishGenOreNests>(Seed + 3, cFinishGenOreNests::DefaultOverworldOres())); + } + else if (NoCaseCompare(*itr, "OrePockets") == 0) + { + auto gen = std::make_shared<cFinishGenOrePockets>(Seed + 2, cFinishGenOrePockets::DefaultOverworldOres()); + if (gen->Initialize(a_IniFile, "OrePockets")) + { + m_FinishGens.push_back(gen); + } } else if (NoCaseCompare(*itr, "POCPieces") == 0) { diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index 513c2bd49..6e833ad6d 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -1395,3 +1395,456 @@ eMonsterType cFinishGenPassiveMobs::GetRandomMob(cChunkDesc & a_ChunkDesc) + +//////////////////////////////////////////////////////////////////////////////// +// cFinishGenOres: + +void cFinishGenOres::GenFinish(cChunkDesc & a_ChunkDesc) +{ + int seq = 1; + + // Generate the ores from the ore list. + for (const auto & ore: m_OreInfos) + { + GenerateOre( + a_ChunkDesc, + ore.m_BlockType, ore.m_BlockMeta, + ore.m_MaxHeight, ore.m_NumNests, ore.m_NestSize, + seq + ); + seq++; + } +} + + + + + +const cFinishGenOres::OreInfos & cFinishGenOres::DefaultOverworldOres(void) +{ + static OreInfos res + { + // OreType, OreMeta, MaxHeight, NumNests, NestSize + {E_BLOCK_COAL_ORE, 0, 127, 20, 16}, + {E_BLOCK_IRON_ORE, 0, 64, 20, 8}, + {E_BLOCK_GOLD_ORE, 0, 32, 2, 8}, + {E_BLOCK_REDSTONE_ORE, 0, 16, 8, 7}, + {E_BLOCK_DIAMOND_ORE, 0, 15, 1, 7}, + {E_BLOCK_LAPIS_ORE, 0, 30, 1, 6}, + }; + return res; +} + + + + + +const cFinishGenOres::OreInfos & cFinishGenOres::DefaultNetherOres(void) +{ + static OreInfos res + { + // OreType, OreMeta, MaxHeight, NumNests, NestSize + {E_BLOCK_NETHER_QUARTZ_ORE, 0, 127, 20, 8}, + }; + return res; +} + + + + + +const cFinishGenOres::OreInfos & cFinishGenOres::DefaultNaturalPatches(void) +{ + static OreInfos res + { + // OreType, OreMeta, MaxHeight, NumNests, NestSize + {E_BLOCK_DIRT, 0, 127, 20, 32}, + {E_BLOCK_GRAVEL, 0, 127, 10, 32}, + {E_BLOCK_STONE, E_META_STONE_GRANITE, 127, 20, 32}, + {E_BLOCK_STONE, E_META_STONE_DIORITE, 127, 20, 32}, + {E_BLOCK_STONE, E_META_STONE_ANDESITE, 127, 20, 32}, + }; + return res; +} + + + + + +cFinishGenOres::OreInfos cFinishGenOres::OreInfosFromString(const AString & a_OreInfosString) +{ + // The string is expected to be formatted as "<OreInfo1> | <OreInfo2> | <OreInfo3> | ..." + // Each OreInfo is expected to be formatted as "<OreType> : <OreMeta> : <MaxHeight> : <NumNests> : <NestSize>" + + OreInfos res; + auto ores = StringSplitAndTrim(a_OreInfosString, "|"); + for (const auto & ore: ores) + { + auto parts = StringSplitAndTrim(ore, ":"); + if (parts.size() != 5) + { + LOGWARNING("Cannot parse ore information from string, not enough OreInfo members (exp 5, got %d). Offending item: \"%s\".", + static_cast<unsigned>(parts.size()), ore.c_str() + ); + continue; + } + auto oreType = BlockStringToType(parts[0]); + if (oreType < 0) + { + LOGWARNING("Cannot parse ore information from string, invalid OreType: \"%s\".", parts[0].c_str()); + continue; + } + NIBBLETYPE oreMeta; + int maxHeight, numNests, nestSize; + if ( + !StringToInteger(parts[1], oreMeta) || + !StringToInteger(parts[2], maxHeight) || + !StringToInteger(parts[3], numNests) || + !StringToInteger(parts[4], nestSize) + ) + { + LOGWARNING("Cannot parse ore information from string, invalid number in OreInfo \"%s\".", ore.c_str()); + continue; + } + res.emplace_back(oreType, oreMeta, maxHeight, numNests, nestSize); + } // for i - split[] + return res; +} + + + + + +AString cFinishGenOres::OreInfosToString(const cFinishGenOres::OreInfos & a_OreInfos) +{ + AString res; + for (const auto & ore: a_OreInfos) + { + if (!res.empty()) + { + res.append(" | "); + } + AppendPrintf(res, "%s:%d:%d:%d:%d", + ItemTypeToString(ore.m_BlockType).c_str(), ore.m_BlockMeta, + ore.m_MaxHeight, ore.m_NumNests, ore.m_NestSize + ); + } // for ore - a_OreInfos[] + return res; +} + + + + + +void cFinishGenOres::SetSeed(int a_Seed) +{ + m_Noise.SetSeed(a_Seed); +} + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cFinishGenOreNests: + +void cFinishGenOreNests::GenerateOre( + cChunkDesc & a_ChunkDesc, + BLOCKTYPE a_OreType, NIBBLETYPE a_OreMeta, + int a_MaxHeight, int a_NumNests, int a_NestSize, + int a_Seq +) +{ + // This function generates several "nests" of ore, each nest consisting of number of ore blocks relatively adjacent to each other. + // It does so by making a random XYZ walk and adding ore along the way in cuboids of different (random) sizes + // Only "terraformable" blocks get replaced with ore, all other blocks stay (so the nest can actually be smaller than specified). + + auto chunkX = a_ChunkDesc.GetChunkX(); + auto chunkZ = a_ChunkDesc.GetChunkZ(); + auto & blockTypes = a_ChunkDesc.GetBlockTypes(); + auto & blockMetas = a_ChunkDesc.GetBlockMetasUncompressed(); + for (int i = 0; i < a_NumNests; i++) + { + int nestRnd = m_Noise.IntNoise3DInt(chunkX + i, a_Seq, chunkZ + 64 * i) / 8; + int BaseX = nestRnd % cChunkDef::Width; + nestRnd /= cChunkDef::Width; + int BaseZ = nestRnd % cChunkDef::Width; + nestRnd /= cChunkDef::Width; + int BaseY = nestRnd % a_MaxHeight; + nestRnd /= a_MaxHeight; + int NestSize = a_NestSize + (nestRnd % (a_NestSize / 4)); // The actual nest size may be up to 1 / 4 larger + int Num = 0; + while (Num < NestSize) + { + // Put a cuboid around [BaseX, BaseY, BaseZ] + int rnd = m_Noise.IntNoise3DInt(chunkX + 64 * i, 2 * a_Seq + Num, chunkZ + 32 * i) / 8; + int xsize = rnd % 2; + int ysize = (rnd / 4) % 2; + int zsize = (rnd / 16) % 2; + rnd >>= 8; + for (int x = xsize; x >= 0; --x) + { + int BlockX = BaseX + x; + if (cChunkDef::IsValidWidth(BlockX)) + { + Num++; // So that the cycle finishes even if the base coords wander away from the chunk + continue; + } + for (int y = ysize; y >= 0; --y) + { + int BlockY = BaseY + y; + if (!cChunkDef::IsValidHeight(BlockY)) + { + Num++; // So that the cycle finishes even if the base coords wander away from the chunk + continue; + } + for (int z = zsize; z >= 0; --z) + { + int BlockZ = BaseZ + z; + if (cChunkDef::IsValidWidth(BlockZ)) + { + Num++; // So that the cycle finishes even if the base coords wander away from the chunk + continue; + } + + int Index = cChunkDef::MakeIndexNoCheck(BlockX, BlockY, BlockZ); + auto blockType = blockTypes[Index]; + if ((blockType == E_BLOCK_STONE) || (blockType == E_BLOCK_NETHERRACK)) + { + blockTypes[Index] = a_OreType; + blockMetas[Index] = a_OreMeta; + } + Num++; + } // for z + } // for y + } // for x + + // Move the base to a neighbor voxel + switch (rnd % 4) + { + case 0: BaseX--; break; + case 1: BaseX++; break; + } + switch ((rnd >> 3) % 4) + { + case 0: BaseY--; break; + case 1: BaseY++; break; + } + switch ((rnd >> 6) % 4) + { + case 0: BaseZ--; break; + case 1: BaseZ++; break; + } + } // while (Num < NumBlocks) + } // for i - NumNests +} + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cFinishGenOrePockets: + +bool cFinishGenOrePockets::Initialize(cIniFile & a_IniFile, const AString & a_GenName) +{ + // Read the OreInfos configuration: + auto valueName = a_GenName + "_blocks"; + auto pocketCfg = a_IniFile.GetValue("Generator", valueName, ""); + if (pocketCfg.empty()) + { + // There's no config currently stored in the INI file. Store the defaults as the config: + a_IniFile.SetValue("Generator", valueName, OreInfosToString(m_OreInfos)); + } + else + { + m_OreInfos = OreInfosFromString(pocketCfg); + } + + // Read the optional seed configuration (but do not store the default): + valueName = a_GenName + "_seed"; + SetSeed(a_IniFile.GetValueI("Generator", valueName, m_Noise.GetSeed())); + + return true; +} + + + + + +void cFinishGenOrePockets::GenerateOre( + cChunkDesc & a_ChunkDesc, + BLOCKTYPE a_OreType, NIBBLETYPE a_OreMeta, + int a_MaxHeight, int a_NumNests, int a_NestSize, + int a_Seq +) +{ + // This function generates several "pockets" of the specified ore + // Each chunk can contain only pockets that are generated for that chunk, or for its XM / ZM neighbors. + + // Generate for the 3 neighbors in the XP / ZP direction as well, so that pockets crossing the boundaries are accounted for as well: + int chunkZ = a_ChunkDesc.GetChunkZ(); + int chunkX = a_ChunkDesc.GetChunkX(); + imprintChunkOrePockets(chunkX - 1, chunkZ - 1, a_ChunkDesc, a_OreType, a_OreMeta, a_MaxHeight, a_NumNests, a_NestSize, a_Seq); + imprintChunkOrePockets(chunkX - 1, chunkZ, a_ChunkDesc, a_OreType, a_OreMeta, a_MaxHeight, a_NumNests, a_NestSize, a_Seq); + imprintChunkOrePockets(chunkX, chunkZ - 1, a_ChunkDesc, a_OreType, a_OreMeta, a_MaxHeight, a_NumNests, a_NestSize, a_Seq); + imprintChunkOrePockets(chunkX, chunkZ, a_ChunkDesc, a_OreType, a_OreMeta, a_MaxHeight, a_NumNests, a_NestSize, a_Seq); +} + + + + + +void cFinishGenOrePockets::imprintChunkOrePockets( + int a_ChunkX, int a_ChunkZ, + cChunkDesc & a_ChunkDesc, + BLOCKTYPE a_OreType, NIBBLETYPE a_OreMeta, + int a_MaxHeight, int a_NumNests, int a_NestSize, + int a_Seq +) +{ + // Pick a starting coord for each nest: + int baseBlockX = a_ChunkX * cChunkDef::Width; + int baseBlockZ = a_ChunkZ * cChunkDef::Width; + for (int i = 0; i < a_NumNests; i++) + { + int nestRnd = m_Noise.IntNoise3DInt(a_ChunkX + i, a_Seq, a_ChunkZ + 64 * i) / 7; + int baseX = (nestRnd % cChunkDef::Width) + baseBlockX; + nestRnd /= cChunkDef::Width; + int baseZ = (nestRnd % cChunkDef::Width) + baseBlockZ; + nestRnd /= cChunkDef::Width; + int baseY = nestRnd % a_MaxHeight; + nestRnd /= a_MaxHeight; + imprintPocket( + a_ChunkDesc, + baseX, baseY, baseZ, + a_NestSize, i + 200 * a_Seq, + a_OreType, a_OreMeta + ); + } // for i - NumNests +} + + + + + +void cFinishGenOrePockets::imprintPocket( + cChunkDesc & a_ChunkDesc, + int a_MinPocketX, int a_PocketY, int a_MinPocketZ, + int a_NestSize, int a_Seq, + BLOCKTYPE a_OreType, NIBBLETYPE a_OreMeta +) +{ + // A line segment in a random direction is chosen. Then, several spheres are formed along this line segment, + // with their diameters diminishing towards the line ends (one half of a sinusoid) + + double x1 = static_cast<double>(a_MinPocketX) + 0.5; + double y1 = static_cast<double>(a_PocketY) + 0.5; + double z1 = static_cast<double>(a_MinPocketZ) + 0.5; + int rnd = m_Noise.IntNoise2DInt(a_MinPocketX + 7 * a_Seq, a_MinPocketZ + a_PocketY * 11) / 7; + double angle = static_cast<double>(rnd % 256) / (256.0 * M_PI / 2.0); // range [0 .. pi / 2] + rnd /= 256; + double length = static_cast<double>(a_NestSize) / 4.0; + double x2 = x1 + sin(angle) * length; // Always larger than x1 + double z2 = z1 + cos(angle) * length; // Always larger than z1 + double y2 = y1 + static_cast<double>((rnd % 3) - 1); // Up to 1 block away from y1 + + // Iterate over the line segment in a total of a_NestSize steps: + double stepX = (x2 - x1) / static_cast<double>(a_NestSize); + double stepY = (y2 - y1) / static_cast<double>(a_NestSize); + double stepZ = (z2 - z1) / static_cast<double>(a_NestSize); + double stepR = M_PI / static_cast<double>(a_NestSize); + double size = static_cast<double>(a_NestSize) / 16.0; + for (int i = 0; i < a_NestSize; ++i) + { + double iDbl = static_cast<double>(i); + double sphereX = x1 + stepX * iDbl; + double sphereY = y1 + stepY * iDbl; + double sphereZ = z1 + stepZ * iDbl; + double radius = (sin(stepR * iDbl) + 1.0) * size + 1.0; + imprintSphere(a_ChunkDesc, sphereX, sphereY, sphereZ, radius, a_OreType, a_OreMeta); + } // for i +} + + + + + +void cFinishGenOrePockets::imprintSphere( + cChunkDesc & a_ChunkDesc, + double a_SphereX, double a_SphereY, double a_SphereZ, double a_Radius, + BLOCKTYPE a_OreType, NIBBLETYPE a_OreMeta +) +{ + // Get the sphere's bounding box, unioned with the chunk's bounding box (possibly empty): + int baseX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int baseZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; + int minX = std::max(FloorC(a_SphereX - a_Radius), baseX); + int minY = std::max(FloorC(a_SphereY - a_Radius), 0); + int minZ = std::max(FloorC(a_SphereZ - a_Radius), baseZ); + int maxX = std::min(CeilC(a_SphereX + a_Radius), baseX + cChunkDef::Width - 1); + int maxY = std::min(CeilC(a_SphereY + a_Radius), cChunkDef::Height - 1); + int maxZ = std::min(CeilC(a_SphereZ + a_Radius), baseZ + cChunkDef::Width - 1); + + /* + // DEBUG: + int blockX = FloorC(a_SphereX); + int blockY = FloorC(a_SphereY); + int blockZ = FloorC(a_SphereZ); + if ( + (blockX >= baseX) && (blockX < baseX + cChunkDef::Width) && + (blockY >= 0) && (blockY < cChunkDef::Height) && + (blockZ >= baseZ) && (blockZ < baseZ + cChunkDef::Width) + ) + { + // LOGD("Imprinting a sphere center at {%d, %d, %d}", blockX, blockY, blockZ); + a_ChunkDesc.SetBlockTypeMeta(blockX - baseX, blockY, blockZ - baseZ, a_OreType, a_OreMeta); + } + return; + //*/ + + // Imprint the parts of the sphere intersecting the chunk: + double radiusSq = a_Radius * a_Radius / 4.0; + for (int y = minY; y <= maxY; y++) + { + double relY = static_cast<double>(y) + 0.5 - a_SphereY; + double relYSq = relY * relY; + if (relYSq > radiusSq) + { + // outside the sphere, bail out + continue; + } + for (int z = minZ; z <= maxZ; z++) + { + double relZ = static_cast<double>(z) + 0.5 - a_SphereZ; + double relZSq = relZ * relZ; + if (relZSq + relYSq > radiusSq) + { + // outside the sphere, bail out + continue; + } + for (int x = minX; x <= maxX; x++) + { + double relX = static_cast<double>(x) + 0.5 - a_SphereX; + double relXSq = relX * relX; + if (relZSq + relYSq + relXSq > radiusSq) + { + // outside the sphere, bail out + continue; + } + int bX = x - baseX; + int bZ = z - baseZ; + auto blockType = a_ChunkDesc.GetBlockType(bX, y, bZ); + if ((blockType == E_BLOCK_STONE) || (blockType == E_BLOCK_NETHERRACK)) + { + a_ChunkDesc.SetBlockTypeMeta(bX, y, bZ, a_OreType, a_OreMeta); + } + } // for x + } // for z + } // for y +} + + + + + diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h index aa2d0a12d..464ed209f 100644 --- a/src/Generating/FinishGen.h +++ b/src/Generating/FinishGen.h @@ -398,3 +398,179 @@ protected: + +/** Base class for generators that have an ore list attached to them. +Provides the storage and parsing for the ore list, as well as the generic plumbing for generating individual ores. +Descendants should override GenerateOre() to provide the specific ore generation technique. +Note that this class uses the "Nest" terminology for individual packs of ore, it doesn't imply any shape or algorithm. */ +class cFinishGenOres: + public cFinishGen +{ + typedef cFinishGen Super; + +public: + struct OreInfo + { + BLOCKTYPE m_BlockType; // The type of the nest. + NIBBLETYPE m_BlockMeta; // The block meta + int m_MaxHeight; // The highest possible a nest can occur + int m_NumNests; // How many nests per chunk + int m_NestSize; // The amount of blocks a nest can have. + + OreInfo() : + m_BlockType(0), + m_BlockMeta(0), + m_MaxHeight(0), + m_NumNests(0), + m_NestSize(0) + { + } + + OreInfo(BLOCKTYPE a_OreType, NIBBLETYPE a_OreMeta, int a_MaxHeight, int a_NumNests, int a_NestSize) : + m_BlockType(a_OreType), + m_BlockMeta(a_OreMeta), + m_MaxHeight(a_MaxHeight), + m_NumNests(a_NumNests), + m_NestSize(a_NestSize) + { + } + }; + + typedef std::vector<OreInfo> OreInfos; + + cFinishGenOres(int a_Seed, const OreInfos & a_OreInfos): + m_Noise(a_Seed), + m_OreInfos(a_OreInfos) + { + } + + // cFinishGen overrides: + virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; + + /** Returns a vector of OreInfo structures describing the default Overworld ores, usable in the constructor. */ + static const OreInfos & DefaultOverworldOres(void); + + /** Returns a vector of OreInfo structures describing the default Nether ores, usable in the constructor. */ + static const OreInfos & DefaultNetherOres(void); + + /** Returns a vector of OreInfo structures describing the default Overworld non-ore pockets (dirt, diorite etc), usable in the constructor. */ + static const OreInfos & DefaultNaturalPatches(void); + + /** Parses the parameter string into OreInfos array. + See OreInfosToString() for the complementary function. + Used for loading configuration from INI files. */ + static OreInfos OreInfosFromString(const AString & a_OreInfosString); + + /** Returns a string that represents the OreInfos given as the parameter. + See OreInfosFromString() for the complementary function. + Used for storing defaults in the INI file. */ + static AString OreInfosToString(const OreInfos & a_OreInfos); + + /** (Re-)sets the seed used by the internal generating mechanisms. */ + void SetSeed(int a_Seed); + +protected: + /** The noise used for generating. */ + cNoise m_Noise; + + /** All the ores enabled in this generator. */ + OreInfos m_OreInfos; + + + /** Generates a single ore in the specified chunk image. + a_Seq is the sequencing number (used as a complement to seed to make each ore in the same chunk have different nests) */ + virtual void GenerateOre( + cChunkDesc & a_ChunkDesc, + BLOCKTYPE a_OreType, NIBBLETYPE a_OreMeta, + int a_MaxHeight, int a_NumNests, int a_NestSize, + int a_Seq + ) = 0; + + // TODO: Helper function to parse a config string into m_OreInfos +}; + + + + + +class cFinishGenOreNests : + public cFinishGenOres +{ + typedef cFinishGenOres Super; + +public: + cFinishGenOreNests(int a_Seed, const OreInfos & a_OreInfos): + Super(a_Seed, a_OreInfos) + {} + +protected: + + // cFinishGenOreClumps overrides: + virtual void GenerateOre( + cChunkDesc & a_ChunkDesc, + BLOCKTYPE a_OreType, NIBBLETYPE a_OreMeta, + int a_MaxHeight, int a_NumNests, int a_NestSize, + int a_Seq + ) override; +} ; + + + + + +class cFinishGenOrePockets: + public cFinishGenOres +{ + typedef cFinishGenOres Super; + +public: + cFinishGenOrePockets(int a_Seed, const OreInfos & a_OreInfos): + Super(a_Seed, a_OreInfos) + {} + + /** Reads the configuration from the specified INI file. + a_GenName is the name of the generator (this class may be used for OrePockets and DirtPockets, each has a different default). + Returns true on success, false and logs errors to console on failure. */ + bool Initialize(cIniFile & a_IniFile, const AString & a_GenName); + +protected: + + // cFinishGenOreClumps overrides: + virtual void GenerateOre( + cChunkDesc & a_ChunkDesc, + BLOCKTYPE a_OreType, NIBBLETYPE a_OreMeta, + int a_MaxNestHeight, int a_NumNests, int a_NestSize, + int a_Seq + ) override; + + /** Calculates the pockets for the specified chunk and imprints them into the specified ChunkDesc (not necessarily the same chunk). + a_Seq is the sequence number of the ore, to provide another source of randomness. */ + void imprintChunkOrePockets( + int a_ChunkX, int a_ChunkZ, + cChunkDesc & a_ChunkDesc, + BLOCKTYPE a_OreType, NIBBLETYPE a_OreMeta, + int a_MaxHeight, int a_NumNests, int a_NestSize, + int a_Seq + ); + + /** Imprints a single pocket of the specified ore at the specified coords into the chunk. + The pocket shape has its minimum X and Z coords specified, Y can be anywhere around the specified Y coord. + a_Seq is the sequence number of the ore, to provide another source of randomness. */ + void imprintPocket( + cChunkDesc & a_ChunkDesc, + int a_MinPocketX, int a_PocketY, int a_MinPocketZ, + int a_NestSize, int a_Seq, + BLOCKTYPE a_OreType, NIBBLETYPE a_OreMeta + ); + + /** Imprints a single sphere of the specified ore at the specified coords. */ + void imprintSphere( + cChunkDesc & a_ChunkDesc, + double a_SphereX, double a_SphereY, double a_SphereZ, double a_Radius, + BLOCKTYPE a_OreType, NIBBLETYPE a_OreMeta + ); +}; + + + + diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp index 3b04f66b7..29cab86f1 100644 --- a/src/Generating/StructGen.cpp +++ b/src/Generating/StructGen.cpp @@ -273,116 +273,6 @@ int cStructGenTrees::GetNumTrees( //////////////////////////////////////////////////////////////////////////////// -// cStructGenOreNests: - -void cStructGenOreNests::GenFinish(cChunkDesc & a_ChunkDesc) -{ - int ChunkX = a_ChunkDesc.GetChunkX(); - int ChunkZ = a_ChunkDesc.GetChunkZ(); - cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes(); - cChunkDesc::BlockNibbleBytes & BlockMetas = a_ChunkDesc.GetBlockMetasUncompressed(); - - int seq = 1; - - // Generate the ores from the ore list. - for (OreList::const_iterator itr = m_OreList.begin(); itr != m_OreList.end(); ++itr) - { - GenerateOre(ChunkX, ChunkZ, itr->BlockType, itr->BlockMeta, itr->MaxHeight, itr->NumNests, itr->NestSize, BlockTypes, BlockMetas, seq); - seq++; - } -} - - - - - -void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, NIBBLETYPE a_BlockMeta, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, cChunkDesc::BlockNibbleBytes & a_BlockMetas, int a_Seq) -{ - // This function generates several "nests" of ore, each nest consisting of number of ore blocks relatively adjacent to each other. - // It does so by making a random XYZ walk and adding ore along the way in cuboids of different (random) sizes - // Only stone gets replaced with ore, all other blocks stay (so the nest can actually be smaller than specified). - - for (int i = 0; i < a_NumNests; i++) - { - int Nestrnd = m_Noise.IntNoise3DInt(a_ChunkX + i, a_Seq, a_ChunkZ + 64 * i) / 8; - int BaseX = Nestrnd % cChunkDef::Width; - Nestrnd /= cChunkDef::Width; - int BaseZ = Nestrnd % cChunkDef::Width; - Nestrnd /= cChunkDef::Width; - int BaseY = Nestrnd % a_MaxHeight; - Nestrnd /= a_MaxHeight; - int NestSize = a_NestSize + (Nestrnd % (a_NestSize / 4)); // The actual nest size may be up to 1 / 4 larger - int Num = 0; - while (Num < NestSize) - { - // Put a cuboid around [BaseX, BaseY, BaseZ] - int rnd = m_Noise.IntNoise3DInt(a_ChunkX + 64 * i, 2 * a_Seq + Num, a_ChunkZ + 32 * i) / 8; - int xsize = rnd % 2; - int ysize = (rnd / 4) % 2; - int zsize = (rnd / 16) % 2; - rnd >>= 8; - for (int x = xsize; x >= 0; --x) - { - int BlockX = BaseX + x; - if ((BlockX < 0) || (BlockX >= cChunkDef::Width)) - { - Num++; // So that the cycle finishes even if the base coords wander away from the chunk - continue; - } - for (int y = ysize; y >= 0; --y) - { - int BlockY = BaseY + y; - if ((BlockY < 0) || (BlockY >= cChunkDef::Height)) - { - Num++; // So that the cycle finishes even if the base coords wander away from the chunk - continue; - } - for (int z = zsize; z >= 0; --z) - { - int BlockZ = BaseZ + z; - if ((BlockZ < 0) || (BlockZ >= cChunkDef::Width)) - { - Num++; // So that the cycle finishes even if the base coords wander away from the chunk - continue; - } - - int Index = cChunkDef::MakeIndexNoCheck(BlockX, BlockY, BlockZ); - if (a_BlockTypes[Index] == m_ToReplace) - { - a_BlockTypes[Index] = a_OreType; - a_BlockMetas[Index] = a_BlockMeta; - } - Num++; - } // for z - } // for y - } // for x - - // Move the base to a neighbor voxel - switch (rnd % 4) - { - case 0: BaseX--; break; - case 1: BaseX++; break; - } - switch ((rnd >> 3) % 4) - { - case 0: BaseY--; break; - case 1: BaseY++; break; - } - switch ((rnd >> 6) % 4) - { - case 0: BaseZ--; break; - case 1: BaseZ++; break; - } - } // while (Num < NumBlocks) - } // for i - NumNests -} - - - - - - -//////////////////////////////////////////////////////////////////////////////// // cStructGenLakes: void cStructGenLakes::GenFinish(cChunkDesc & a_ChunkDesc) diff --git a/src/Generating/StructGen.h b/src/Generating/StructGen.h index 796abf0f5..b5cfcb07c 100644 --- a/src/Generating/StructGen.h +++ b/src/Generating/StructGen.h @@ -72,54 +72,6 @@ protected: -class cStructGenOreNests : - public cFinishGen -{ -public: - struct OreInfo - { - BLOCKTYPE BlockType; // The type of the nest. - NIBBLETYPE BlockMeta; // The block meta - int MaxHeight; // The highest possible a nest can occur - int NumNests; // How many nests per chunk - int NestSize; // The amount of blocks a nest can have. - - OreInfo() : - BlockType(0), - BlockMeta(0), - MaxHeight(0), - NumNests(0), - NestSize(0) - { - } - }; - - typedef std::vector<OreInfo> OreList; - - cStructGenOreNests(int a_Seed, OreList a_OreList, BLOCKTYPE a_ToReplace) : - m_Noise(a_Seed), - m_Seed(a_Seed), - m_OreList(a_OreList), - m_ToReplace(a_ToReplace) - {} - -protected: - cNoise m_Noise; - int m_Seed; - - OreList m_OreList; // A list of possible ores. - BLOCKTYPE m_ToReplace; - - // cFinishGen override: - virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; - - void GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, NIBBLETYPE a_BlockMeta, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, cChunkDesc::BlockNibbleBytes & a_BlockMetas, int a_Seq); -} ; - - - - - class cStructGenLakes : public cFinishGen { diff --git a/src/Noise/Noise.h b/src/Noise/Noise.h index b08b96e24..4c99cee5b 100644 --- a/src/Noise/Noise.h +++ b/src/Noise/Noise.h @@ -49,6 +49,7 @@ public: NOISE_DATATYPE CubicNoise3D (NOISE_DATATYPE a_X, NOISE_DATATYPE a_Y, NOISE_DATATYPE a_Z) const; void SetSeed(int a_Seed) { m_Seed = a_Seed; } + int GetSeed(void) const { return m_Seed; } inline static NOISE_DATATYPE CubicInterpolate (NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_C, NOISE_DATATYPE a_D, NOISE_DATATYPE a_Pct); inline static NOISE_DATATYPE CosineInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct); |