1
0

Merge pull request #2670 from cuberite/OrePockets

Added OrePockets and DirtPockets finish gens.
This commit is contained in:
Julian Laubstein 2015-11-25 16:52:32 +01:00
commit d6ad5245b3
6 changed files with 649 additions and 267 deletions

View File

@ -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)
{

View File

@ -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
}

View File

@ -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
);
};

View File

@ -272,116 +272,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:

View File

@ -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
{

View File

@ -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);