1
0

Implemented OverworldClumpFlowers

This commit is contained in:
NiLSPACE 2016-03-05 23:56:08 +01:00
parent 503a79f19a
commit ab6e8b790c
3 changed files with 283 additions and 0 deletions

View File

@ -438,6 +438,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
m_FinishGens.push_back(gen);
}
}
else if (NoCaseCompare(finisher, "OverworldClumpFlowers") == 0)
{
auto flowers = cFinishGenClumpTopBlock::ParseIniFile(a_IniFile, "OverworldClumpFlowers");
m_FinishGens.push_back(cFinishGenPtr(new cFinishGenClumpTopBlock(Seed, flowers)));
}
else if (NoCaseCompare(finisher, "PieceStructures") == 0)
{
if (split.size() < 2)

View File

@ -179,6 +179,210 @@ void cFinishGenNetherClumpFoliage::TryPlaceClump(cChunkDesc & a_ChunkDesc, int a
////////////////////////////////////////////////////////////////////////////////
// cFinishGenClumpTopBlock
void cFinishGenClumpTopBlock::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
int NoiseVal = m_Noise.IntNoise2DInt(ChunkX, ChunkZ);
EMCSBiome Biome = a_ChunkDesc.GetBiome(cChunkDef::Width / 2, cChunkDef::Width / 2);
BiomeInfo info = m_FlowersPerBiome[static_cast<size_t>(Biome)];
const auto & PossibleBlocks = info.m_Blocks;
if (PossibleBlocks.empty())
{
// No need to go any further. This biome can't generate any blocks.
return;
}
int NumClumps = info.m_MaxNumClumpsPerChunk - info.m_MinNumClumpsPerChunk;
if (NumClumps == 0)
{
NumClumps = 1;
}
NumClumps = NoiseVal % NumClumps + info.m_MinNumClumpsPerChunk;
for (int i = 0; i < NumClumps; i++)
{
int Val1 = m_Noise.IntNoise2DInt(ChunkX * ChunkZ * i, ChunkZ + ChunkX + i);
int Val2 = m_Noise.IntNoise2DInt(ChunkZ * ChunkX + i, ChunkZ - ChunkX * i);
int BlockVal = m_Noise.IntNoise2DInt(Val1, Val2);
int PosX = Val1 % (cChunkDef::Width - RANGE_FROM_CENTER * 2) + RANGE_FROM_CENTER;
int PosZ = Val2 % (cChunkDef::Width - RANGE_FROM_CENTER * 2) + RANGE_FROM_CENTER;
int TotalWeight = 0;
for (const auto & Block : PossibleBlocks)
{
TotalWeight += Block.m_Weight;
}
// Prevent division by 0
TotalWeight = (TotalWeight != 0) ? TotalWeight : 1;
int Weight = BlockVal % TotalWeight;
for (const auto & Block : PossibleBlocks)
{
Weight -= Block.m_Weight;
if (Weight < 0)
{
TryPlaceFoliageClump(a_ChunkDesc, PosX, PosZ, Block.m_BlockType, Block.m_BlockMeta, Block.m_BlockType == E_BLOCK_BIG_FLOWER);
break;
}
}
}
}
void cFinishGenClumpTopBlock::TryPlaceFoliageClump(cChunkDesc & a_ChunkDesc, int a_CenterX, int a_CenterZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_IsDoubleTall)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
int NumBlocks = m_Noise.IntNoise2DInt(a_CenterX + ChunkX * 16, a_CenterZ + ChunkZ * 16) % (MAX_NUM_FOLIAGE - MIN_NUM_FOLIAGE) + MIN_NUM_FOLIAGE + 1;
for (int i = 1; i < NumBlocks; i++)
{
int rnd = m_Noise.IntNoise2DInt(ChunkX + ChunkZ + i, ChunkX - ChunkZ - i) / 59;
int x = a_CenterX + (((rnd % 256) % RANGE_FROM_CENTER * 2) - RANGE_FROM_CENTER);
int z = a_CenterZ + (((rnd / 256) % RANGE_FROM_CENTER * 2) - RANGE_FROM_CENTER);
int Top = a_ChunkDesc.GetHeight(x, z);
if (a_ChunkDesc.GetBlockType(x, Top, z) != E_BLOCK_GRASS)
{
continue;
}
a_ChunkDesc.SetBlockTypeMeta(x, Top + 1, z, a_BlockType, a_BlockMeta);
if (a_IsDoubleTall)
{
a_ChunkDesc.SetBlockTypeMeta(x, Top + 2, z, E_BLOCK_BIG_FLOWER, 8);
}
}
}
void cFinishGenClumpTopBlock::ParseConfigurationString(AString a_RawClumpInfo, std::vector<BiomeInfo> & a_Output)
{
// Initialize the vector for all biomes.
for (int i = static_cast<int>(a_Output.size()); i < static_cast<int>(biMaxVariantBiome); i++)
{
a_Output.push_back(BiomeInfo());
}
AStringVector ClumpInfo = StringSplitAndTrim(a_RawClumpInfo, "=");
// Information about a clump is divided in 2 parts. The biomes they can be in and the blocks that can be placed.
if (ClumpInfo.size() != 2)
{
LOGWARNING("OverworldClumpFoliage: Data missing for \"%s\". Please divide biome and blocks with a semi colon", a_RawClumpInfo.c_str());
return;
}
AStringVector Biomes = StringSplitAndTrim(ClumpInfo[0], ";");
AStringVector Blocks = StringSplitAndTrim(ClumpInfo[1], ";");
for (const auto & RawBiomeInfo : Biomes)
{
AStringVector BiomeInfo = StringSplitAndTrim(RawBiomeInfo, ",");
AString BiomeName = BiomeInfo[0];
EMCSBiome Biome = StringToBiome(BiomeName);
if (Biome == biInvalidBiome)
{
LOGWARNING("Biome \"%s\" is invalid.", BiomeName.c_str());
continue;
}
if (BiomeInfo.size() == 2)
{
// Only the minimum amount of clumps per chunk is changed.
int MinNumClump = 1;
if (!StringToInteger(BiomeInfo[1], MinNumClump))
{
LOGWARNING("OverworldClumpFoliage: Invalid data in \"%s\". Second parameter is either not existing or a number", RawBiomeInfo.c_str());
continue;
}
a_Output[static_cast<size_t>(Biome)].m_MinNumClumpsPerChunk = MinNumClump;
// In case the minimum number is higher than the current maximum value we change the max to the minimum value.
a_Output[static_cast<size_t>(Biome)].m_MaxNumClumpsPerChunk = std::max(MinNumClump, a_Output[static_cast<size_t>(Biome)].m_MaxNumClumpsPerChunk);
}
else if (BiomeInfo.size() == 3)
{
// Both the minimum and maximum amount of clumps per chunk is changed.
int MinNumClumps = 0, MaxNumClumps = 1;
if (!StringToInteger(BiomeInfo[1], MinNumClumps) || !StringToInteger(BiomeInfo[2], MaxNumClumps))
{
LOGWARNING("Invalid data in \"%s\". Second parameter is either not existing or a number", RawBiomeInfo.c_str());
continue;
}
a_Output[static_cast<size_t>(Biome)].m_MaxNumClumpsPerChunk = MaxNumClumps + 1;
a_Output[static_cast<size_t>(Biome)].m_MinNumClumpsPerChunk = MinNumClumps;
}
// TODO: Make the weight configurable.
for (const auto & BlockName : Blocks)
{
cItem Block = cItem();
if (!StringToItem(BlockName, Block) && IsValidBlock(Block.m_ItemType))
{
LOGWARNING("Block \"%s\" is invalid", BlockName.c_str());
continue;
}
FoliageInfo info = FoliageInfo(static_cast<BLOCKTYPE>(Block.m_ItemType), static_cast<NIBBLETYPE>(Block.m_ItemDamage), 100);
a_Output[static_cast<size_t>(Biome)].m_Blocks.push_back(info);
}
}
}
std::vector<cFinishGenClumpTopBlock::BiomeInfo> cFinishGenClumpTopBlock::ParseIniFile(cIniFile & a_IniFile, AString a_ClumpPrefix)
{
// Also check dashes in case we will get more configuration options with the same prefix.
a_ClumpPrefix += "-";
std::vector<cFinishGenClumpTopBlock::BiomeInfo> foliage;
int NumGeneratorValues = a_IniFile.GetNumValues("Generator");
int GeneratorKeyId = a_IniFile.FindKey("Generator");
for (int i = 0; i < NumGeneratorValues; i++)
{
AString ValueName = a_IniFile.GetValueName("Generator", i);
if (ValueName.substr(0, a_ClumpPrefix.size()) == a_ClumpPrefix)
{
AString RawClump = a_IniFile.GetValue(GeneratorKeyId, i);
cFinishGenClumpTopBlock::ParseConfigurationString(RawClump, foliage);
}
}
if (foliage.size() == 0)
{
cFinishGenClumpTopBlock::ParseConfigurationString(a_IniFile.GetValueSet("Generator", a_ClumpPrefix + "-1", "Forest, -2, 2; ForestHills, -3, 2; FlowerForest = yellowflower, redflower, lilac, rosebush"), foliage);
cFinishGenClumpTopBlock::ParseConfigurationString(a_IniFile.GetValueSet("Generator", a_ClumpPrefix + "-2", "Plains, -2, 1; SunflowerPlains = yellowflower, redflower, azurebluet, oxeyedaisy"), foliage);
cFinishGenClumpTopBlock::ParseConfigurationString(a_IniFile.GetValueSet("Generator", a_ClumpPrefix + "-3", "SunflowerPlains, 1, 2 = sunflower"), foliage);
cFinishGenClumpTopBlock::ParseConfigurationString(a_IniFile.GetValueSet("Generator", a_ClumpPrefix + "-4", "FlowerForest, 2, 5 = allium, redtulip, orangetulip, whitetulip, pinktulip, oxeyedaisy"), foliage);
cFinishGenClumpTopBlock::ParseConfigurationString(a_IniFile.GetValueSet("Generator", a_ClumpPrefix + "-5", "Swampland, SwamplandM = brownmushroom, redmushroom, blueorchid"), foliage);
}
return foliage;
}
////////////////////////////////////////////////////////////////////////////////
// cFinishGenGlowStone:

View File

@ -70,6 +70,80 @@ protected:
class cFinishGenClumpTopBlock :
public cFinishGen
{
public:
// Contains the meta, type and weight for a clump block
struct FoliageInfo
{
BLOCKTYPE m_BlockType;
NIBBLETYPE m_BlockMeta;
int m_Weight;
FoliageInfo(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_Weight) :
m_BlockType(a_BlockType),
m_BlockMeta(a_BlockMeta),
m_Weight(a_Weight)
{}
};
// Contains the minimum and maximum amount of clumps for a biome and it's blocks.
struct BiomeInfo
{
int m_MinNumClumpsPerChunk;
int m_MaxNumClumpsPerChunk;
std::vector<FoliageInfo> m_Blocks;
BiomeInfo() :
m_MinNumClumpsPerChunk(0),
m_MaxNumClumpsPerChunk(2),
m_Blocks()
{}
BiomeInfo(int a_MinNumClumpsPerChunk, int a_MaxNumClumpsPerChunk, std::vector<FoliageInfo> a_Blocks) :
m_MinNumClumpsPerChunk(a_MinNumClumpsPerChunk),
m_MaxNumClumpsPerChunk(a_MaxNumClumpsPerChunk),
m_Blocks(a_Blocks)
{}
};
cFinishGenClumpTopBlock(int a_Seed, std::vector<BiomeInfo> a_BlockList) :
m_Noise(a_Seed),
m_FlowersPerBiome()
{
std::swap(a_BlockList, m_FlowersPerBiome);
}
/** Parses a string and puts a vector with a length of biMaxVariantBiome in a_Output.
The format of the string is "<Biomes separated with a comma>;<Blocks separated with a comma>". This can also be repeated with a | */
static void ParseConfigurationString(AString a_String, std::vector<BiomeInfo> & a_Output);
/** Parses an inifile in search for all clumps */
static std::vector<BiomeInfo> ParseIniFile(cIniFile & a_IniFile, AString a_ClumpPrefix);
protected:
cNoise m_Noise;
std::vector<BiomeInfo> m_FlowersPerBiome;
/** The maximum number of foliage per clump */
const int MAX_NUM_FOLIAGE = 8;
/** The mininum number of foliage per clump */
const int MIN_NUM_FOLIAGE = 4;
/** The maximum range a foliage can be placed from the center of the clump */
const int RANGE_FROM_CENTER = 5;
void TryPlaceFoliageClump(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_IsDoubleTall);
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
};
class cFinishGenGlowStone :
public cFinishGen
{