summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJulian Laubstein <julianlaubstein@yahoo.de>2015-11-25 16:52:32 +0100
committerJulian Laubstein <julianlaubstein@yahoo.de>2015-11-25 16:52:32 +0100
commitd6ad5245b3590cc71686a763d71db82542b2f279 (patch)
treee03a27694e4b589f5bf04d2a595393661fa36654 /src
parentMerge pull request #2687 from Gargaj/signfix (diff)
parentOrePockets finisher is now configurable. (diff)
downloadcuberite-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.cpp128
-rw-r--r--src/Generating/FinishGen.cpp453
-rw-r--r--src/Generating/FinishGen.h176
-rw-r--r--src/Generating/StructGen.cpp110
-rw-r--r--src/Generating/StructGen.h48
-rw-r--r--src/Noise/Noise.h1
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);