Merge remote-tracking branch 'origin-master' into c++11
This commit is contained in:
parent
2ae4d2a96a
commit
187bdab4fa
@ -10,6 +10,7 @@ SET (SRCS
|
||||
ChunkDesc.cpp
|
||||
ChunkGenerator.cpp
|
||||
CompoGen.cpp
|
||||
CompoGenBiomal.cpp
|
||||
ComposableGenerator.cpp
|
||||
DistortedHeightmap.cpp
|
||||
DungeonRoomsFinisher.cpp
|
||||
@ -30,8 +31,10 @@ SET (SRCS
|
||||
StructGen.cpp
|
||||
TestRailsGen.cpp
|
||||
Trees.cpp
|
||||
TwoHeights.cpp
|
||||
UnderwaterBaseGen.cpp
|
||||
VillageGen.cpp)
|
||||
VillageGen.cpp
|
||||
)
|
||||
|
||||
SET (HDRS
|
||||
BioGen.h
|
||||
@ -39,7 +42,9 @@ SET (HDRS
|
||||
ChunkDesc.h
|
||||
ChunkGenerator.h
|
||||
CompoGen.h
|
||||
CompoGenBiomal.h
|
||||
ComposableGenerator.h
|
||||
CompositedHeiGen.h
|
||||
DistortedHeightmap.h
|
||||
DungeonRoomsFinisher.h
|
||||
EndGen.h
|
||||
@ -58,11 +63,14 @@ SET (HDRS
|
||||
RainbowRoadsGen.h
|
||||
Ravines.h
|
||||
RoughRavines.h
|
||||
ShapeGen.cpp
|
||||
StructGen.h
|
||||
TestRailsGen.h
|
||||
Trees.h
|
||||
TwoHeights.h
|
||||
UnderwaterBaseGen.h
|
||||
VillageGen.h)
|
||||
VillageGen.h
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
add_library(Generating ${SRCS} ${HDRS})
|
||||
|
@ -152,6 +152,52 @@ int cChunkDesc::GetHeight(int a_RelX, int a_RelZ)
|
||||
|
||||
|
||||
|
||||
void cChunkDesc::SetHeightFromShape(const Shape & a_Shape)
|
||||
{
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
for (int y = cChunkDef::Height - 1; y > 0; y--)
|
||||
{
|
||||
if (a_Shape[y + x * 256 + z * 16 * 256] != 0)
|
||||
{
|
||||
cChunkDef::SetHeight(m_HeightMap, x, z, y);
|
||||
break;
|
||||
}
|
||||
} // for y
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkDesc::GetShapeFromHeight(Shape & a_Shape) const
|
||||
{
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
int height = cChunkDef::GetHeight(m_HeightMap, x, z);
|
||||
for (int y = 0; y <= height; y++)
|
||||
{
|
||||
a_Shape[y + x * 256 + z * 16 * 256] = 1;
|
||||
}
|
||||
|
||||
for (int y = height + 1; y < cChunkDef::Height; y++)
|
||||
{
|
||||
a_Shape[y + x * 256 + z * 16 * 256] = 0;
|
||||
} // for y
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkDesc::SetUseDefaultBiomes(bool a_bUseDefaultBiomes)
|
||||
{
|
||||
m_bUseDefaultBiomes = a_bUseDefaultBiomes;
|
||||
@ -366,6 +412,23 @@ HEIGHTTYPE cChunkDesc::GetMaxHeight(void) const
|
||||
|
||||
|
||||
|
||||
HEIGHTTYPE cChunkDesc::GetMinHeight(void) const
|
||||
{
|
||||
HEIGHTTYPE MinHeight = m_HeightMap[0];
|
||||
for (size_t i = 1; i < ARRAYCOUNT(m_HeightMap); i++)
|
||||
{
|
||||
if (m_HeightMap[i] < MinHeight)
|
||||
{
|
||||
MinHeight = m_HeightMap[i];
|
||||
}
|
||||
}
|
||||
return MinHeight;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkDesc::FillRelCuboid(
|
||||
int a_MinX, int a_MaxX,
|
||||
int a_MinY, int a_MaxY,
|
||||
|
@ -29,10 +29,17 @@ class cChunkDesc
|
||||
{
|
||||
public:
|
||||
// tolua_end
|
||||
|
||||
/** The datatype used to represent the entire chunk worth of shape.
|
||||
0 = air
|
||||
1 = solid
|
||||
Indexed as [y + 256 * x + 256 * 16 * z]. */
|
||||
typedef Byte Shape[256 * 16 * 16];
|
||||
|
||||
/** Uncompressed block metas, 1 meta per byte */
|
||||
typedef NIBBLETYPE BlockNibbleBytes[cChunkDef::NumBlocks];
|
||||
|
||||
|
||||
cChunkDesc(int a_ChunkX, int a_ChunkZ);
|
||||
~cChunkDesc();
|
||||
|
||||
@ -57,10 +64,21 @@ public:
|
||||
EMCSBiome GetBiome(int a_RelX, int a_RelZ);
|
||||
|
||||
// These operate on the heightmap, so they could get out of sync with the data
|
||||
// Use UpdateHeightmap() to re-sync
|
||||
// Use UpdateHeightmap() to re-calculate heightmap from the block data
|
||||
void SetHeight(int a_RelX, int a_RelZ, int a_Height);
|
||||
int GetHeight(int a_RelX, int a_RelZ);
|
||||
|
||||
// tolua_end
|
||||
|
||||
/** Sets the heightmap to match the given shape data.
|
||||
Note that this ignores overhangs; the method is mostly used by old composition generators. */
|
||||
void SetHeightFromShape(const Shape & a_Shape);
|
||||
|
||||
/** Sets the shape in a_Shape to match the heightmap stored currently in m_HeightMap. */
|
||||
void GetShapeFromHeight(Shape & a_Shape) const;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
// Default generation:
|
||||
void SetUseDefaultBiomes(bool a_bUseDefaultBiomes);
|
||||
bool IsUsingDefaultBiomes(void) const;
|
||||
@ -77,8 +95,11 @@ public:
|
||||
/** Reads an area from the chunk into a cBlockArea, blocktypes and blockmetas */
|
||||
void ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX, int a_MinRelY, int a_MaxRelY, int a_MinRelZ, int a_MaxRelZ);
|
||||
|
||||
/** Returns the maximum height value in the heightmap */
|
||||
/** Returns the maximum height value in the heightmap. */
|
||||
HEIGHTTYPE GetMaxHeight(void) const;
|
||||
|
||||
/** Returns the minimum height value in the heightmap. */
|
||||
HEIGHTTYPE GetMinHeight(void) const;
|
||||
|
||||
/** Fills the relative cuboid with specified block; allows cuboid out of range of this chunk */
|
||||
void FillRelCuboid(
|
||||
|
@ -21,8 +21,9 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cCompoGenSameBlock:
|
||||
|
||||
void cCompoGenSameBlock::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
void cCompoGenSameBlock::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
a_ChunkDesc.SetHeightFromShape(a_Shape);
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
@ -63,7 +64,7 @@ void cCompoGenSameBlock::InitializeCompoGen(cIniFile & a_IniFile)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cCompoGenDebugBiomes:
|
||||
|
||||
void cCompoGenDebugBiomes::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
void cCompoGenDebugBiomes::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
static BLOCKTYPE Blocks[] =
|
||||
{
|
||||
@ -92,6 +93,7 @@ void cCompoGenDebugBiomes::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
E_BLOCK_BEDROCK,
|
||||
} ;
|
||||
|
||||
a_ChunkDesc.SetHeightFromShape(a_Shape);
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
@ -131,7 +133,7 @@ cCompoGenClassic::cCompoGenClassic(void) :
|
||||
|
||||
|
||||
|
||||
void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
/* The classic composition means:
|
||||
- 1 layer of grass, 3 of dirt and the rest stone, if the height > sealevel + beachheight
|
||||
@ -142,6 +144,7 @@ void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
*/
|
||||
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
a_ChunkDesc.SetHeightFromShape(a_Shape);
|
||||
|
||||
// The patterns to use for different situations, must be same length!
|
||||
const BLOCKTYPE PatternGround[] = {m_BlockTop, m_BlockMiddle, m_BlockMiddle, m_BlockMiddle} ;
|
||||
@ -194,7 +197,7 @@ void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
|
||||
void cCompoGenClassic::InitializeCompoGen(cIniFile & a_IniFile)
|
||||
{
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "ClassicSeaLevel", m_SeaLevel);
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", m_SeaLevel);
|
||||
m_BeachHeight = a_IniFile.GetValueSetI("Generator", "ClassicBeachHeight", m_BeachHeight);
|
||||
m_BeachDepth = a_IniFile.GetValueSetI("Generator", "ClassicBeachDepth", m_BeachDepth);
|
||||
m_BlockTop = (BLOCKTYPE)(GetIniItemSet(a_IniFile, "Generator", "ClassicBlockTop", "grass").m_ItemType);
|
||||
@ -209,323 +212,6 @@ void cCompoGenClassic::InitializeCompoGen(cIniFile & a_IniFile)
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cCompoGenBiomal:
|
||||
|
||||
void cCompoGenBiomal::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
|
||||
int ChunkX = a_ChunkDesc.GetChunkX();
|
||||
int ChunkZ = a_ChunkDesc.GetChunkZ();
|
||||
|
||||
/*
|
||||
_X 2013_04_22:
|
||||
There's no point in generating the whole cubic noise at once, because the noise values are used in
|
||||
only about 20 % of the cases, so the speed gained by precalculating is lost by precalculating too much data
|
||||
*/
|
||||
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
int Height = a_ChunkDesc.GetHeight(x, z);
|
||||
if (Height > m_SeaLevel)
|
||||
{
|
||||
switch (a_ChunkDesc.GetBiome(x, z))
|
||||
{
|
||||
case biOcean:
|
||||
case biPlains:
|
||||
case biExtremeHills:
|
||||
case biForest:
|
||||
case biTaiga:
|
||||
case biSwampland:
|
||||
case biRiver:
|
||||
case biFrozenOcean:
|
||||
case biFrozenRiver:
|
||||
case biIcePlains:
|
||||
case biIceMountains:
|
||||
case biForestHills:
|
||||
case biTaigaHills:
|
||||
case biExtremeHillsEdge:
|
||||
case biJungle:
|
||||
case biJungleHills:
|
||||
case biJungleEdge:
|
||||
case biDeepOcean:
|
||||
case biStoneBeach:
|
||||
case biColdBeach:
|
||||
case biBirchForest:
|
||||
case biBirchForestHills:
|
||||
case biRoofedForest:
|
||||
case biColdTaiga:
|
||||
case biColdTaigaHills:
|
||||
case biExtremeHillsPlus:
|
||||
case biSavanna:
|
||||
case biSavannaPlateau:
|
||||
case biSunflowerPlains:
|
||||
case biExtremeHillsM:
|
||||
case biFlowerForest:
|
||||
case biTaigaM:
|
||||
case biSwamplandM:
|
||||
case biIcePlainsSpikes:
|
||||
case biJungleM:
|
||||
case biJungleEdgeM:
|
||||
case biBirchForestM:
|
||||
case biBirchForestHillsM:
|
||||
case biRoofedForestM:
|
||||
case biColdTaigaM:
|
||||
case biExtremeHillsPlusM:
|
||||
case biSavannaM:
|
||||
case biSavannaPlateauM:
|
||||
{
|
||||
FillColumnGrass(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
break;
|
||||
}
|
||||
|
||||
case biMesa:
|
||||
case biMesaPlateauF:
|
||||
case biMesaPlateau:
|
||||
case biMesaBryce:
|
||||
case biMesaPlateauFM:
|
||||
case biMesaPlateauM:
|
||||
{
|
||||
FillColumnClay(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
break;
|
||||
}
|
||||
|
||||
case biMegaTaiga:
|
||||
case biMegaTaigaHills:
|
||||
case biMegaSpruceTaiga:
|
||||
case biMegaSpruceTaigaHills:
|
||||
{
|
||||
FillColumnDirt(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
break;
|
||||
}
|
||||
|
||||
case biDesertHills:
|
||||
case biDesert:
|
||||
case biDesertM:
|
||||
case biBeach:
|
||||
{
|
||||
FillColumnSand(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
break;
|
||||
}
|
||||
case biMushroomIsland:
|
||||
case biMushroomShore:
|
||||
{
|
||||
FillColumnMycelium(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// TODO
|
||||
ASSERT(!"CompoGenBiomal: Biome not implemented yet!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (a_ChunkDesc.GetBiome(x, z))
|
||||
{
|
||||
case biDesert:
|
||||
case biBeach:
|
||||
{
|
||||
// Fill with water, sand, sandstone and stone
|
||||
FillColumnWaterSand(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Fill with water, sand/dirt/clay mix and stone
|
||||
if (m_Noise.CubicNoise2D(0.3f * (cChunkDef::Width * ChunkX + x), 0.3f * (cChunkDef::Width * ChunkZ + z)) < 0)
|
||||
{
|
||||
FillColumnWaterSand(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
}
|
||||
else
|
||||
{
|
||||
FillColumnWaterDirt(x, z, Height, a_ChunkDesc.GetBlockTypes());
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // switch (biome)
|
||||
a_ChunkDesc.SetHeight(x, z, m_SeaLevel + 1);
|
||||
} // else (under water)
|
||||
a_ChunkDesc.SetBlockType(x, 0, z, E_BLOCK_BEDROCK);
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::InitializeCompoGen(cIniFile & a_IniFile)
|
||||
{
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "BiomalSeaLevel", m_SeaLevel) - 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnGrass(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
BLOCKTYPE Pattern[] =
|
||||
{
|
||||
E_BLOCK_GRASS,
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
||||
|
||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnClay(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
BLOCKTYPE Pattern[] =
|
||||
{
|
||||
E_BLOCK_HARDENED_CLAY,
|
||||
E_BLOCK_HARDENED_CLAY,
|
||||
E_BLOCK_HARDENED_CLAY,
|
||||
E_BLOCK_HARDENED_CLAY,
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
||||
|
||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnDirt(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
if (a_Height - y < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, a_Height - y, a_RelZ, E_BLOCK_DIRT);
|
||||
}
|
||||
for (int y = a_Height - 4; y > 0; y--)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnSand(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
BLOCKTYPE Pattern[] =
|
||||
{
|
||||
E_BLOCK_SAND,
|
||||
E_BLOCK_SAND,
|
||||
E_BLOCK_SAND,
|
||||
E_BLOCK_SANDSTONE,
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
||||
|
||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnMycelium (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
BLOCKTYPE Pattern[] =
|
||||
{
|
||||
E_BLOCK_MYCELIUM,
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
||||
|
||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnWaterSand(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
FillColumnSand(a_RelX, a_RelZ, a_Height, a_BlockTypes);
|
||||
for (int y = a_Height + 1; y <= m_SeaLevel + 1; y++)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnWaterDirt(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes)
|
||||
{
|
||||
// Dirt
|
||||
BLOCKTYPE Pattern[] =
|
||||
{
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
E_BLOCK_DIRT,
|
||||
} ;
|
||||
FillColumnPattern(a_RelX, a_RelZ, a_Height, a_BlockTypes, Pattern, ARRAYCOUNT(Pattern));
|
||||
|
||||
for (int y = a_Height - ARRAYCOUNT(Pattern); y > 0; y--)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
for (int y = a_Height + 1; y <= m_SeaLevel + 1; y++)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCompoGenBiomal::FillColumnPattern(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes, const BLOCKTYPE * a_Pattern, int a_PatternSize)
|
||||
{
|
||||
for (int y = a_Height, idx = 0; (y >= 0) && (idx < a_PatternSize); y--, idx++)
|
||||
{
|
||||
cChunkDef::SetBlock(a_BlockTypes, a_RelX, y, a_RelZ, a_Pattern[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cCompoGenNether:
|
||||
|
||||
@ -540,7 +226,7 @@ cCompoGenNether::cCompoGenNether(int a_Seed) :
|
||||
|
||||
|
||||
|
||||
void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
HEIGHTTYPE MaxHeight = a_ChunkDesc.GetMaxHeight();
|
||||
|
||||
@ -696,7 +382,7 @@ cCompoGenCache::~cCompoGenCache()
|
||||
|
||||
|
||||
|
||||
void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (((m_NumHits + m_NumMisses) % 1024) == 10)
|
||||
@ -731,6 +417,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
// Use the cached data:
|
||||
memcpy(a_ChunkDesc.GetBlockTypes(), m_CacheData[Idx].m_BlockTypes, sizeof(a_ChunkDesc.GetBlockTypes()));
|
||||
memcpy(a_ChunkDesc.GetBlockMetasUncompressed(), m_CacheData[Idx].m_BlockMetas, sizeof(a_ChunkDesc.GetBlockMetasUncompressed()));
|
||||
memcpy(a_ChunkDesc.GetHeightMap(), m_CacheData[Idx].m_HeightMap, sizeof(a_ChunkDesc.GetHeightMap()));
|
||||
|
||||
m_NumHits++;
|
||||
m_TotalChain += i;
|
||||
@ -739,7 +426,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
|
||||
// Not in the cache:
|
||||
m_NumMisses++;
|
||||
m_Underlying->ComposeTerrain(a_ChunkDesc);
|
||||
m_Underlying->ComposeTerrain(a_ChunkDesc, a_Shape);
|
||||
|
||||
// Insert it as the first item in the MRU order:
|
||||
int Idx = m_CacheOrder[m_CacheSize - 1];
|
||||
@ -750,6 +437,7 @@ void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
m_CacheOrder[0] = Idx;
|
||||
memcpy(m_CacheData[Idx].m_BlockTypes, a_ChunkDesc.GetBlockTypes(), sizeof(a_ChunkDesc.GetBlockTypes()));
|
||||
memcpy(m_CacheData[Idx].m_BlockMetas, a_ChunkDesc.GetBlockMetasUncompressed(), sizeof(a_ChunkDesc.GetBlockMetasUncompressed()));
|
||||
memcpy(m_CacheData[Idx].m_HeightMap, a_ChunkDesc.GetHeightMap(), sizeof(a_ChunkDesc.GetHeightMap()));
|
||||
m_CacheData[Idx].m_ChunkX = ChunkX;
|
||||
m_CacheData[Idx].m_ChunkZ = ChunkZ;
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ protected:
|
||||
bool m_IsBedrocked;
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
} ;
|
||||
|
||||
@ -55,7 +55,7 @@ public:
|
||||
protected:
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||
} ;
|
||||
|
||||
|
||||
@ -81,7 +81,7 @@ protected:
|
||||
BLOCKTYPE m_BlockSea;
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
} ;
|
||||
|
||||
@ -89,40 +89,6 @@ protected:
|
||||
|
||||
|
||||
|
||||
class cCompoGenBiomal :
|
||||
public cTerrainCompositionGen
|
||||
{
|
||||
public:
|
||||
cCompoGenBiomal(int a_Seed) :
|
||||
m_Noise(a_Seed + 1000),
|
||||
m_SeaLevel(62)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
cNoise m_Noise;
|
||||
int m_SeaLevel;
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
|
||||
void FillColumnGrass (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
void FillColumnClay (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
void FillColumnDirt (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
void FillColumnSand (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
void FillColumnMycelium (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
void FillColumnWaterSand(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
void FillColumnWaterDirt(int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes);
|
||||
|
||||
void FillColumnPattern (int a_RelX, int a_RelZ, int a_Height, cChunkDef::BlockTypes & a_BlockTypes, const BLOCKTYPE * a_Pattern, int a_PatternSize);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cCompoGenNether :
|
||||
public cTerrainCompositionGen
|
||||
{
|
||||
@ -136,7 +102,7 @@ protected:
|
||||
int m_Threshold;
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
} ;
|
||||
|
||||
@ -153,7 +119,7 @@ public:
|
||||
~cCompoGenCache();
|
||||
|
||||
// cTerrainCompositionGen override:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
|
||||
protected:
|
||||
@ -166,6 +132,7 @@ protected:
|
||||
int m_ChunkZ;
|
||||
cChunkDef::BlockTypes m_BlockTypes;
|
||||
cChunkDesc::BlockNibbleBytes m_BlockMetas; // The metas are uncompressed, 1 meta per byte
|
||||
cChunkDef::HeightMap m_HeightMap;
|
||||
} ;
|
||||
|
||||
// To avoid moving large amounts of data for the MRU behavior, we MRU-ize indices to an array of the actual data
|
||||
|
586
src/Generating/CompoGenBiomal.cpp
Normal file
586
src/Generating/CompoGenBiomal.cpp
Normal file
@ -0,0 +1,586 @@
|
||||
|
||||
// CompoGenBiomal.cpp
|
||||
|
||||
// Implements the cCompoGenBiomal class representing the biome-aware composition generator
|
||||
|
||||
#include "Globals.h"
|
||||
#include "ComposableGenerator.h"
|
||||
#include "../IniFile.h"
|
||||
#include "../Noise/Noise.h"
|
||||
#include "../LinearUpscale.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cPattern:
|
||||
|
||||
/** This class is used to store a column pattern initialized at runtime,
|
||||
so that the program doesn't need to explicitly set 256 values for each pattern
|
||||
Each pattern has 256 blocks so that there's no need to check pattern bounds when assigning the
|
||||
pattern - there will always be enough pattern left, even for the whole-chunk-height columns. */
|
||||
class cPattern
|
||||
{
|
||||
public:
|
||||
struct BlockInfo
|
||||
{
|
||||
BLOCKTYPE m_BlockType;
|
||||
NIBBLETYPE m_BlockMeta;
|
||||
};
|
||||
|
||||
cPattern(BlockInfo * a_TopBlocks, size_t a_Count)
|
||||
{
|
||||
// Copy the pattern into the top:
|
||||
for (size_t i = 0; i < a_Count; i++)
|
||||
{
|
||||
m_Pattern[i] = a_TopBlocks[i];
|
||||
}
|
||||
|
||||
// Fill the rest with stone:
|
||||
static BlockInfo Stone = {E_BLOCK_STONE, 0};
|
||||
for (size_t i = a_Count; i < cChunkDef::Height; i++)
|
||||
{
|
||||
m_Pattern[i] = Stone;
|
||||
}
|
||||
}
|
||||
|
||||
const BlockInfo * Get(void) const { return m_Pattern; }
|
||||
|
||||
protected:
|
||||
BlockInfo m_Pattern[cChunkDef::Height];
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// The arrays to use for the top block pattern definitions:
|
||||
|
||||
static cPattern::BlockInfo tbGrass[] =
|
||||
{
|
||||
{E_BLOCK_GRASS, 0},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbSand[] =
|
||||
{
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SANDSTONE, 0},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbDirt[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbPodzol[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_PODZOL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbGrassLess[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_GRASSLESS},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbMycelium[] =
|
||||
{
|
||||
{E_BLOCK_MYCELIUM, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbGravel[] =
|
||||
{
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbStone[] =
|
||||
{
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Ocean floor pattern top-block definitions:
|
||||
|
||||
static cPattern::BlockInfo tbOFSand[] =
|
||||
{
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SANDSTONE, 0}
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbOFClay[] =
|
||||
{
|
||||
{ E_BLOCK_CLAY, 0},
|
||||
{ E_BLOCK_CLAY, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
} ;
|
||||
|
||||
static cPattern::BlockInfo tbOFOrangeClay[] =
|
||||
{
|
||||
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_GLASS_ORANGE},
|
||||
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_GLASS_ORANGE},
|
||||
{ E_BLOCK_STAINED_CLAY, E_META_STAINED_GLASS_ORANGE},
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Individual patterns to use:
|
||||
|
||||
static cPattern patGrass (tbGrass, ARRAYCOUNT(tbGrass));
|
||||
static cPattern patSand (tbSand, ARRAYCOUNT(tbSand));
|
||||
static cPattern patDirt (tbDirt, ARRAYCOUNT(tbDirt));
|
||||
static cPattern patPodzol (tbPodzol, ARRAYCOUNT(tbPodzol));
|
||||
static cPattern patGrassLess(tbGrassLess, ARRAYCOUNT(tbGrassLess));
|
||||
static cPattern patMycelium (tbMycelium, ARRAYCOUNT(tbMycelium));
|
||||
static cPattern patGravel (tbGravel, ARRAYCOUNT(tbGravel));
|
||||
static cPattern patStone (tbStone, ARRAYCOUNT(tbStone));
|
||||
|
||||
static cPattern patOFSand (tbOFSand, ARRAYCOUNT(tbOFSand));
|
||||
static cPattern patOFClay (tbOFClay, ARRAYCOUNT(tbOFClay));
|
||||
static cPattern patOFOrangeClay(tbOFOrangeClay, ARRAYCOUNT(tbOFOrangeClay));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cCompoGenBiomal:
|
||||
|
||||
class cCompoGenBiomal :
|
||||
public cTerrainCompositionGen
|
||||
{
|
||||
public:
|
||||
cCompoGenBiomal(int a_Seed) :
|
||||
m_SeaLevel(62),
|
||||
m_OceanFloorSelect(a_Seed + 1),
|
||||
m_MesaFloor(a_Seed + 2)
|
||||
{
|
||||
initMesaPattern(a_Seed);
|
||||
}
|
||||
|
||||
protected:
|
||||
/** The block height at which water is generated instead of air. */
|
||||
int m_SeaLevel;
|
||||
|
||||
/** The pattern used for mesa biomes. Initialized by seed on generator creation. */
|
||||
cPattern::BlockInfo m_MesaPattern[2 * cChunkDef::Height];
|
||||
|
||||
/** Noise used for selecting between dirt and sand on the ocean floor. */
|
||||
cNoise m_OceanFloorSelect;
|
||||
|
||||
/** Noise used for the floor of the clay blocks in mesa biomes. */
|
||||
cNoise m_MesaFloor;
|
||||
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override
|
||||
{
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
ComposeColumn(a_ChunkDesc, x, z, &(a_Shape[x * 256 + z * 16 * 256]));
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override
|
||||
{
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", m_SeaLevel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Initializes the m_MesaPattern with a pattern based on the generator's seed. */
|
||||
void initMesaPattern(int a_Seed)
|
||||
{
|
||||
// In a loop, choose whether to use one, two or three layers of stained clay, then choose a color and width for each layer
|
||||
// Separate each group with another layer of hardened clay
|
||||
cNoise patternNoise((unsigned)a_Seed);
|
||||
static NIBBLETYPE allowedColors[] =
|
||||
{
|
||||
E_META_STAINED_CLAY_YELLOW,
|
||||
E_META_STAINED_CLAY_YELLOW,
|
||||
E_META_STAINED_CLAY_RED,
|
||||
E_META_STAINED_CLAY_RED,
|
||||
E_META_STAINED_CLAY_WHITE,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_LIGHTGRAY,
|
||||
} ;
|
||||
static int layerSizes[] = // Adjust the chance so that thinner layers occur more commonly
|
||||
{
|
||||
1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2,
|
||||
3, 3,
|
||||
} ;
|
||||
int idx = ARRAYCOUNT(m_MesaPattern) - 1;
|
||||
while (idx >= 0)
|
||||
{
|
||||
// A layer group of 1 - 2 color stained clay:
|
||||
int rnd = patternNoise.IntNoise1DInt(idx) / 7;
|
||||
int numLayers = (rnd % 2) + 1;
|
||||
rnd /= 2;
|
||||
for (int lay = 0; lay < numLayers; lay++)
|
||||
{
|
||||
int numBlocks = layerSizes[(rnd % ARRAYCOUNT(layerSizes))];
|
||||
NIBBLETYPE Color = allowedColors[(rnd / 4) % ARRAYCOUNT(allowedColors)];
|
||||
if (
|
||||
((numBlocks == 3) && (numLayers == 2)) || // In two-layer mode disallow the 3-high layers:
|
||||
(Color == E_META_STAINED_CLAY_WHITE)) // White stained clay can ever be only 1 block high
|
||||
{
|
||||
numBlocks = 1;
|
||||
}
|
||||
numBlocks = std::min(idx + 1, numBlocks); // Limit by idx so that we don't have to check inside the loop
|
||||
rnd /= 32;
|
||||
for (int block = 0; block < numBlocks; block++, idx--)
|
||||
{
|
||||
m_MesaPattern[idx].m_BlockMeta = Color;
|
||||
m_MesaPattern[idx].m_BlockType = E_BLOCK_STAINED_CLAY;
|
||||
} // for block
|
||||
} // for lay
|
||||
|
||||
// A layer of hardened clay in between the layer group:
|
||||
int numBlocks = (rnd % 4) + 1; // All heights the same probability
|
||||
if ((numLayers == 2) && (numBlocks < 4))
|
||||
{
|
||||
// For two layers of stained clay, add an extra block of hardened clay:
|
||||
numBlocks++;
|
||||
}
|
||||
numBlocks = std::min(idx + 1, numBlocks); // Limit by idx so that we don't have to check inside the loop
|
||||
for (int block = 0; block < numBlocks; block++, idx--)
|
||||
{
|
||||
m_MesaPattern[idx].m_BlockMeta = 0;
|
||||
m_MesaPattern[idx].m_BlockType = E_BLOCK_HARDENED_CLAY;
|
||||
} // for block
|
||||
} // while (idx >= 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Composes a single column in a_ChunkDesc. Chooses what to do based on the biome in that column. */
|
||||
void ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const Byte * a_ShapeColumn)
|
||||
{
|
||||
// Frequencies for the podzol floor selecting noise:
|
||||
const NOISE_DATATYPE FrequencyX = 8;
|
||||
const NOISE_DATATYPE FrequencyZ = 8;
|
||||
|
||||
EMCSBiome Biome = a_ChunkDesc.GetBiome(a_RelX, a_RelZ);
|
||||
switch (Biome)
|
||||
{
|
||||
case biOcean:
|
||||
case biPlains:
|
||||
case biForest:
|
||||
case biTaiga:
|
||||
case biSwampland:
|
||||
case biRiver:
|
||||
case biFrozenOcean:
|
||||
case biFrozenRiver:
|
||||
case biIcePlains:
|
||||
case biIceMountains:
|
||||
case biForestHills:
|
||||
case biTaigaHills:
|
||||
case biExtremeHillsEdge:
|
||||
case biExtremeHillsPlus:
|
||||
case biExtremeHills:
|
||||
case biJungle:
|
||||
case biJungleHills:
|
||||
case biJungleEdge:
|
||||
case biDeepOcean:
|
||||
case biStoneBeach:
|
||||
case biColdBeach:
|
||||
case biBirchForest:
|
||||
case biBirchForestHills:
|
||||
case biRoofedForest:
|
||||
case biColdTaiga:
|
||||
case biColdTaigaHills:
|
||||
case biSavanna:
|
||||
case biSavannaPlateau:
|
||||
case biSunflowerPlains:
|
||||
case biFlowerForest:
|
||||
case biTaigaM:
|
||||
case biSwamplandM:
|
||||
case biIcePlainsSpikes:
|
||||
case biJungleM:
|
||||
case biJungleEdgeM:
|
||||
case biBirchForestM:
|
||||
case biBirchForestHillsM:
|
||||
case biRoofedForestM:
|
||||
case biColdTaigaM:
|
||||
case biSavannaM:
|
||||
case biSavannaPlateauM:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patGrass.Get(), a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biMegaTaiga:
|
||||
case biMegaTaigaHills:
|
||||
case biMegaSpruceTaiga:
|
||||
case biMegaSpruceTaigaHills:
|
||||
{
|
||||
// Select the pattern to use - podzol, grass or grassless dirt:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
const cPattern::BlockInfo * Pattern = (Val < -0.9) ? patGrassLess.Get() : ((Val > 0) ? patPodzol.Get() : patGrass.Get());
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern, a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biDesertHills:
|
||||
case biDesert:
|
||||
case biDesertM:
|
||||
case biBeach:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patSand.Get(), a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biMushroomIsland:
|
||||
case biMushroomShore:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patMycelium.Get(), a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biMesa:
|
||||
case biMesaPlateauF:
|
||||
case biMesaPlateau:
|
||||
case biMesaBryce:
|
||||
case biMesaPlateauFM:
|
||||
case biMesaPlateauM:
|
||||
{
|
||||
// Mesa biomes need special handling, because they don't follow the usual "4 blocks from top pattern",
|
||||
// instead, they provide a "from bottom" pattern with varying base height,
|
||||
// usually 4 blocks below the ocean level
|
||||
FillColumnMesa(a_ChunkDesc, a_RelX, a_RelZ, a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
case biExtremeHillsPlusM:
|
||||
case biExtremeHillsM:
|
||||
{
|
||||
// Select the pattern to use - gravel, stone or grass:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
const cPattern::BlockInfo * Pattern = (Val < 0.0) ? patStone.Get() : patGrass.Get();
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern, a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ASSERT(!"Unhandled biome");
|
||||
return;
|
||||
}
|
||||
} // switch (Biome)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Fills the specified column with the specified pattern; restarts the pattern when air is reached,
|
||||
switches to ocean floor pattern if ocean is reached. Always adds bedrock at the very bottom. */
|
||||
void FillColumnPattern(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const cPattern::BlockInfo * a_Pattern, const Byte * a_ShapeColumn)
|
||||
{
|
||||
bool HasHadWater = false;
|
||||
int PatternIdx = 0;
|
||||
int top = std::max(m_SeaLevel, a_ChunkDesc.GetHeight(a_RelX, a_RelZ));
|
||||
for (int y = top; y > 0; y--)
|
||||
{
|
||||
if (a_ShapeColumn[y] > 0)
|
||||
{
|
||||
// "ground" part, use the pattern:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, a_Pattern[PatternIdx].m_BlockType, a_Pattern[PatternIdx].m_BlockMeta);
|
||||
PatternIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// "air" or "water" part:
|
||||
// Reset the pattern index to zero, so that the pattern is repeated from the top again:
|
||||
PatternIdx = 0;
|
||||
|
||||
if (y >= m_SeaLevel)
|
||||
{
|
||||
// "air" part, do nothing
|
||||
continue;
|
||||
}
|
||||
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
if (HasHadWater)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
if (a_ChunkDesc.GetBiome(a_RelX, a_RelZ) == biDeepOcean)
|
||||
{
|
||||
a_Pattern = patGravel.Get();
|
||||
}
|
||||
else
|
||||
{
|
||||
a_Pattern = ChooseOceanFloorPattern(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_RelX, a_RelZ);
|
||||
}
|
||||
HasHadWater = true;
|
||||
} // for y
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Fills the specified column with mesa pattern, based on the column height */
|
||||
void FillColumnMesa(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const Byte * a_ShapeColumn)
|
||||
{
|
||||
// Frequencies for the clay floor noise:
|
||||
const NOISE_DATATYPE FrequencyX = 50;
|
||||
const NOISE_DATATYPE FrequencyZ = 50;
|
||||
|
||||
int Top = a_ChunkDesc.GetHeight(a_RelX, a_RelZ);
|
||||
if (Top < m_SeaLevel)
|
||||
{
|
||||
// The terrain is below sealevel, handle as regular ocean with red sand floor:
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patOFOrangeClay.Get(), a_ShapeColumn);
|
||||
return;
|
||||
}
|
||||
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
int ClayFloor = m_SeaLevel - 6 + (int)(4.f * m_MesaFloor.CubicNoise2D(NoiseX, NoiseY));
|
||||
if (ClayFloor >= Top)
|
||||
{
|
||||
ClayFloor = Top - 1;
|
||||
}
|
||||
|
||||
if (Top - m_SeaLevel < 5)
|
||||
{
|
||||
// Simple case: top is red sand, then hardened clay down to ClayFloor, then stone:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, Top, a_RelZ, E_BLOCK_SAND, E_META_SAND_RED);
|
||||
for (int y = Top - 1; y >= ClayFloor; y--)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_HARDENED_CLAY);
|
||||
}
|
||||
for (int y = ClayFloor - 1; y > 0; y--)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
return;
|
||||
}
|
||||
|
||||
// Difficult case: use the mesa pattern and watch for overhangs:
|
||||
int PatternIdx = cChunkDef::Height - (Top - ClayFloor); // We want the block at index ClayFloor to be pattern's 256th block (first stone)
|
||||
const cPattern::BlockInfo * Pattern = m_MesaPattern;
|
||||
bool HasHadWater = false;
|
||||
for (int y = Top; y > 0; y--)
|
||||
{
|
||||
if (a_ShapeColumn[y] > 0)
|
||||
{
|
||||
// "ground" part, use the pattern:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, Pattern[PatternIdx].m_BlockType, Pattern[PatternIdx].m_BlockMeta);
|
||||
PatternIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (y >= m_SeaLevel)
|
||||
{
|
||||
// "air" part, do nothing
|
||||
continue;
|
||||
}
|
||||
|
||||
// "water" part, fill with water and choose new pattern for ocean floor, if not chosen already:
|
||||
PatternIdx = 0;
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
if (HasHadWater)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
Pattern = ChooseOceanFloorPattern(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_RelX, a_RelZ);
|
||||
HasHadWater = true;
|
||||
} // for y
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Returns the pattern to use for an ocean floor in the specified column.
|
||||
The returned pattern is guaranteed to be 256 blocks long. */
|
||||
const cPattern::BlockInfo * ChooseOceanFloorPattern(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ)
|
||||
{
|
||||
// Frequencies for the ocean floor selecting noise:
|
||||
const NOISE_DATATYPE FrequencyX = 3;
|
||||
const NOISE_DATATYPE FrequencyZ = 3;
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
if (Val < -0.95)
|
||||
{
|
||||
return patOFClay.Get();
|
||||
}
|
||||
else if (Val < 0)
|
||||
{
|
||||
return patOFSand.Get();
|
||||
}
|
||||
else
|
||||
{
|
||||
return patDirt.Get();
|
||||
}
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cTerrainCompositionGenPtr CreateCompoGenBiomal(int a_Seed)
|
||||
{
|
||||
return std::make_shared<cCompoGenBiomal>(a_Seed);
|
||||
}
|
||||
|
||||
|
||||
|
21
src/Generating/CompoGenBiomal.h
Normal file
21
src/Generating/CompoGenBiomal.h
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
// CompoGenBiomal.h
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ComposableGenerator.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Returns a new instance of the Biomal composition generator. */
|
||||
cTerrainCompositionGenPtr CreateCompoGenBiomal(int a_Seed);
|
||||
|
||||
|
||||
|
||||
|
@ -17,6 +17,10 @@
|
||||
#include "StructGen.h"
|
||||
#include "FinishGen.h"
|
||||
|
||||
#include "CompoGenBiomal.h"
|
||||
|
||||
#include "CompositedHeiGen.h"
|
||||
|
||||
#include "Caves.h"
|
||||
#include "DistortedHeightmap.h"
|
||||
#include "DungeonRoomsFinisher.h"
|
||||
@ -39,7 +43,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cTerrainCompositionGen:
|
||||
|
||||
cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed)
|
||||
cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainShapeGenPtr a_ShapeGen, int a_Seed)
|
||||
{
|
||||
AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", "");
|
||||
if (CompoGenName.empty())
|
||||
@ -48,63 +52,52 @@ cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile
|
||||
CompoGenName = "Biomal";
|
||||
}
|
||||
|
||||
cTerrainCompositionGen * res = nullptr;
|
||||
if (NoCaseCompare(CompoGenName, "sameblock") == 0)
|
||||
// Compositor list is alpha-sorted
|
||||
cTerrainCompositionGenPtr res;
|
||||
if (NoCaseCompare(CompoGenName, "Biomal") == 0)
|
||||
{
|
||||
res = new cCompoGenSameBlock;
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "debugbiomes") == 0)
|
||||
{
|
||||
res = new cCompoGenDebugBiomes;
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "classic") == 0)
|
||||
{
|
||||
res = new cCompoGenClassic;
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0)
|
||||
{
|
||||
res = new cDistortedHeightmap(a_Seed, a_BiomeGen);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "end") == 0)
|
||||
{
|
||||
res = new cEndGen(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "nether") == 0)
|
||||
{
|
||||
res = new cCompoGenNether(a_Seed);
|
||||
res = CreateCompoGenBiomal(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "BiomalNoise3D") == 0)
|
||||
{
|
||||
res = new cBiomalNoise3DComposable(a_Seed, a_BiomeGen);
|
||||
// The composition that used to be provided with BiomalNoise3D is now provided by the Biomal compositor:
|
||||
res = CreateCompoGenBiomal(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "Classic") == 0)
|
||||
{
|
||||
res = std::make_shared<cCompoGenClassic>();
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "DebugBiomes") == 0)
|
||||
{
|
||||
res = std::make_shared<cCompoGenDebugBiomes>();
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0)
|
||||
{
|
||||
// The composition that used to be provided with DistortedHeightmap is now provided by the Biomal compositor:
|
||||
res = CreateCompoGenBiomal(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "End") == 0)
|
||||
{
|
||||
res = std::make_shared<cEndGen>(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "Nether") == 0)
|
||||
{
|
||||
res = std::make_shared<cCompoGenNether>(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "Noise3D") == 0)
|
||||
{
|
||||
res = new cNoise3DComposable(a_Seed);
|
||||
// The composition that used to be provided with Noise3D is now provided by the Biomal compositor:
|
||||
res = CreateCompoGenBiomal(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(CompoGenName, "biomal") == 0)
|
||||
else if (NoCaseCompare(CompoGenName, "SameBlock") == 0)
|
||||
{
|
||||
res = new cCompoGenBiomal(a_Seed);
|
||||
|
||||
/*
|
||||
// Performance-testing:
|
||||
LOGINFO("Measuring performance of cCompoGenBiomal...");
|
||||
clock_t BeginTick = clock();
|
||||
for (int x = 0; x < 500; x++)
|
||||
{
|
||||
cChunkDesc Desc(200 + x * 8, 200 + x * 8);
|
||||
a_BiomeGen->GenBiomes(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetBiomeMap());
|
||||
a_HeightGen->GenHeightMap(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetHeightMap());
|
||||
res->ComposeTerrain(Desc);
|
||||
}
|
||||
clock_t Duration = clock() - BeginTick;
|
||||
LOGINFO("CompositionGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
|
||||
//*/
|
||||
res = std::make_shared<cCompoGenSameBlock>();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGWARN("Unknown CompositionGen \"%s\", using \"Biomal\" instead.", CompoGenName.c_str());
|
||||
a_IniFile.SetValue("Generator", "CompositionGen", "Biomal");
|
||||
return CreateCompositionGen(a_IniFile, a_BiomeGen, a_HeightGen, a_Seed);
|
||||
return CreateCompositionGen(a_IniFile, a_BiomeGen, a_ShapeGen, a_Seed);
|
||||
}
|
||||
ASSERT(res != nullptr);
|
||||
|
||||
@ -124,7 +117,7 @@ cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile
|
||||
cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) :
|
||||
super(a_ChunkGenerator),
|
||||
m_BiomeGen(),
|
||||
m_HeightGen(),
|
||||
m_ShapeGen(),
|
||||
m_CompositionGen()
|
||||
{
|
||||
}
|
||||
@ -138,7 +131,7 @@ void cComposableGenerator::Initialize(cIniFile & a_IniFile)
|
||||
super::Initialize(a_IniFile);
|
||||
|
||||
InitBiomeGen(a_IniFile);
|
||||
InitHeightGen(a_IniFile);
|
||||
InitShapeGen(a_IniFile);
|
||||
InitCompositionGen(a_IniFile);
|
||||
InitFinishGens(a_IniFile);
|
||||
}
|
||||
@ -166,16 +159,22 @@ void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a
|
||||
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetBiomeMap());
|
||||
}
|
||||
|
||||
cChunkDesc::Shape shape;
|
||||
if (a_ChunkDesc.IsUsingDefaultHeight())
|
||||
{
|
||||
m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetHeightMap());
|
||||
m_ShapeGen->GenShape(a_ChunkX, a_ChunkZ, shape);
|
||||
a_ChunkDesc.SetHeightFromShape(shape);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert the heightmap in a_ChunkDesc into shape:
|
||||
a_ChunkDesc.GetShapeFromHeight(shape);
|
||||
}
|
||||
|
||||
bool ShouldUpdateHeightmap = false;
|
||||
if (a_ChunkDesc.IsUsingDefaultComposition())
|
||||
{
|
||||
m_CompositionGen->ComposeTerrain(a_ChunkDesc);
|
||||
ShouldUpdateHeightmap = true;
|
||||
m_CompositionGen->ComposeTerrain(a_ChunkDesc, shape);
|
||||
}
|
||||
|
||||
if (a_ChunkDesc.IsUsingDefaultFinish())
|
||||
@ -234,13 +233,15 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile)
|
||||
|
||||
|
||||
|
||||
void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
|
||||
void cComposableGenerator::InitShapeGen(cIniFile & a_IniFile)
|
||||
{
|
||||
bool CacheOffByDefault = false;
|
||||
m_HeightGen = cTerrainHeightGen::CreateHeightGen(a_IniFile, m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault);
|
||||
m_ShapeGen = cTerrainShapeGen::CreateShapeGen(a_IniFile, m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault);
|
||||
|
||||
/*
|
||||
// TODO
|
||||
// Add a cache, if requested:
|
||||
int CacheSize = a_IniFile.GetValueSetI("Generator", "HeightGenCacheSize", CacheOffByDefault ? 0 : 64);
|
||||
int CacheSize = a_IniFile.GetValueSetI("Generator", "ShapeGenCacheSize", CacheOffByDefault ? 0 : 64);
|
||||
if (CacheSize > 0)
|
||||
{
|
||||
if (CacheSize < 4)
|
||||
@ -253,6 +254,7 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
|
||||
LOGD("Using a cache for Heightgen of size %d.", CacheSize);
|
||||
m_HeightGen = cTerrainHeightGenPtr(new cHeiGenCache(m_HeightGen, CacheSize));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@ -261,13 +263,19 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
|
||||
|
||||
void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
|
||||
{
|
||||
m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, m_BiomeGen, *m_HeightGen, m_ChunkGenerator.GetSeed());
|
||||
m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, m_BiomeGen, m_ShapeGen, m_ChunkGenerator.GetSeed());
|
||||
|
||||
// Add a cache over the composition generator:
|
||||
// Even a cache of size 1 is useful due to the CompositedHeiGen cache after us doing re-composition on its misses
|
||||
int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64);
|
||||
if (CompoGenCacheSize > 1)
|
||||
if (CompoGenCacheSize > 0)
|
||||
{
|
||||
m_CompositionGen = cTerrainCompositionGenPtr(new cCompoGenCache(m_CompositionGen, 32));
|
||||
m_CompositionGen = std::make_shared<cCompoGenCache>(m_CompositionGen, CompoGenCacheSize);
|
||||
}
|
||||
|
||||
// Create a cache of the composited heightmaps, so that finishers may use it:
|
||||
m_CompositedHeightCache = std::make_shared<cHeiGenMultiCache>(std::make_shared<cCompositedHeiGen>(m_ShapeGen, m_CompositionGen), 16, 24);
|
||||
// 24 subcaches of depth 16 each = 96 KiB of RAM. Acceptable, for the amount of work this saves.
|
||||
}
|
||||
|
||||
|
||||
@ -333,7 +341,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||
int MaxSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMaxSize", 7);
|
||||
int MinSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMinSize", 5);
|
||||
AString HeightDistrib = a_IniFile.GetValueSet ("Generator", "DungeonRoomsHeightDistrib", "0, 0; 10, 10; 11, 500; 40, 500; 60, 40; 90, 1");
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cDungeonRoomsFinisher(m_HeightGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib)));
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cDungeonRoomsFinisher(m_ShapeGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib)));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "Ice") == 0)
|
||||
{
|
||||
@ -342,7 +350,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||
else if (NoCaseCompare(*itr, "LavaLakes") == 0)
|
||||
{
|
||||
int Probability = a_IniFile.GetValueSetI("Generator", "LavaLakesProbability", 10);
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, m_HeightGen, Probability)));
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, m_ShapeGen, Probability)));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "LavaSprings") == 0)
|
||||
{
|
||||
@ -580,7 +588,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "Trees") == 0)
|
||||
{
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen)));
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenTrees(Seed, m_BiomeGen, m_ShapeGen, m_CompositionGen)));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "UnderwaterBases") == 0)
|
||||
{
|
||||
@ -588,7 +596,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||
int MaxOffset = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxOffset", 128);
|
||||
int MaxDepth = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxDepth", 7);
|
||||
int MaxSize = a_IniFile.GetValueSetI("Generator", "UnderwaterBaseMaxSize", 128);
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cUnderwaterBaseGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, m_BiomeGen)));
|
||||
m_FinishGens.push_back(std::make_shared<cUnderwaterBaseGen>(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, m_BiomeGen));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "Villages") == 0)
|
||||
{
|
||||
@ -598,12 +606,12 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||
int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128);
|
||||
int MinDensity = a_IniFile.GetValueSetI("Generator", "VillageMinDensity", 50);
|
||||
int MaxDensity = a_IniFile.GetValueSetI("Generator", "VillageMaxDensity", 80);
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cVillageGen(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, m_BiomeGen, m_HeightGen)));
|
||||
m_FinishGens.push_back(std::make_shared<cVillageGen>(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, m_BiomeGen, m_CompositedHeightCache));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "WaterLakes") == 0)
|
||||
{
|
||||
int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, m_HeightGen, Probability)));
|
||||
m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, m_ShapeGen, Probability)));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "WaterSprings") == 0)
|
||||
{
|
||||
|
@ -26,20 +26,16 @@ See http://forum.mc-server.org/showthread.php?tid=409 for details.
|
||||
|
||||
// Forward-declare the shared pointers to subgenerator classes:
|
||||
class cBiomeGen;
|
||||
class cTerrainShapeGen;
|
||||
class cTerrainHeightGen;
|
||||
class cTerrainCompositionGen;
|
||||
class cFinishGen;
|
||||
typedef SharedPtr<cBiomeGen> cBiomeGenPtr;
|
||||
typedef SharedPtr<cTerrainShapeGen> cTerrainShapeGenPtr;
|
||||
typedef SharedPtr<cTerrainHeightGen> cTerrainHeightGenPtr;
|
||||
typedef SharedPtr<cTerrainCompositionGen> cTerrainCompositionGenPtr;
|
||||
typedef SharedPtr<cFinishGen> cFinishGenPtr;
|
||||
|
||||
// fwd: Noise3DGenerator.h
|
||||
class cNoise3DComposable;
|
||||
|
||||
// fwd: DistortedHeightmap.h
|
||||
class cDistortedHeightmap;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -70,28 +66,54 @@ public:
|
||||
|
||||
|
||||
|
||||
/** The interface that a terrain height generator must implement
|
||||
A terrain height generator takes chunk coords on input and outputs an array of terrain heights for that chunk.
|
||||
The output array is sequenced in the same way as the BiomeGen's biome data.
|
||||
/** The interface that a terrain shape generator must implement
|
||||
A terrain shape generator takes chunk coords on input and outputs a 3D array of "shape" for that chunk. The shape here
|
||||
represents the distinction between air and solid; there's no representation of Water since that is added by the
|
||||
composition geenrator.
|
||||
The output array is indexed [y + 256 * z + 16 * 256 * x], so that it's fast to later compose a single column of the terrain,
|
||||
which is the dominant operation following the shape generation.
|
||||
The generator may request biome information from the underlying BiomeGen, it may even request information for
|
||||
other chunks than the one it's currently generating (possibly neighbors - for averaging)
|
||||
other chunks than the one it's currently generating (neighbors - for averaging)
|
||||
*/
|
||||
class cTerrainShapeGen
|
||||
{
|
||||
public:
|
||||
virtual ~cTerrainShapeGen() {} // Force a virtual destructor in descendants
|
||||
|
||||
/** Generates the shape for the given chunk */
|
||||
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) = 0;
|
||||
|
||||
/** Reads parameters from the ini file, prepares generator for use. */
|
||||
virtual void InitializeShapeGen(cIniFile & a_IniFile) {}
|
||||
|
||||
/** Creates the correct TerrainShapeGen descendant based on the ini file settings and the seed provided.
|
||||
a_BiomeGen is the underlying biome generator, some shape generators may depend on it providing additional biomes data around the chunk
|
||||
a_CacheOffByDefault gets set to whether the cache should be disabled by default
|
||||
Implemented in ShapeGen.cpp!
|
||||
*/
|
||||
static cTerrainShapeGenPtr CreateShapeGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** The interface that is used to query terrain height from the shape generator.
|
||||
Usually the structure generators require only the final heightmap, and generating the whole shape only to
|
||||
consume the heightmap is wasteful, so this interface is used instead; it has a cache implemented over it so
|
||||
that data is retained. */
|
||||
class cTerrainHeightGen
|
||||
{
|
||||
public:
|
||||
virtual ~cTerrainHeightGen() {} // Force a virtual destructor in descendants
|
||||
|
||||
/** Generates heightmap for the given chunk */
|
||||
|
||||
/** Retrieves the heightmap for the specified chunk. */
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) = 0;
|
||||
|
||||
/** Reads parameters from the ini file, prepares generator for use. */
|
||||
|
||||
/** Initializes the generator, reading its parameters from the INI file. */
|
||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) {}
|
||||
|
||||
/** Creates the correct TerrainHeightGen descendant based on the ini file settings and the seed provided.
|
||||
a_BiomeGen is the underlying biome generator, some height generators may depend on it to generate more biomes
|
||||
a_CacheOffByDefault gets set to whether the cache should be disabled by default
|
||||
Implemented in HeiGen.cpp!
|
||||
*/
|
||||
|
||||
/** Creates a cTerrainHeightGen descendant based on the INI file settings. */
|
||||
static cTerrainHeightGenPtr CreateHeightGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault);
|
||||
} ;
|
||||
|
||||
@ -109,16 +131,18 @@ class cTerrainCompositionGen
|
||||
public:
|
||||
virtual ~cTerrainCompositionGen() {} // Force a virtual destructor in descendants
|
||||
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) = 0;
|
||||
/** Generates the chunk's composition into a_ChunkDesc, using the terrain shape provided in a_Shape.
|
||||
Is expected to fill a_ChunkDesc's heightmap with the data from a_Shape. */
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) = 0;
|
||||
|
||||
/** Reads parameters from the ini file, prepares generator for use. */
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) {}
|
||||
|
||||
/** Creates the correct TerrainCompositionGen descendant based on the ini file settings and the seed provided.
|
||||
a_BiomeGen is the underlying biome generator, some composition generators may depend on it to generate more biomes
|
||||
a_HeightGen is the underlying height generator, some composition generators may depend on it providing additional values
|
||||
a_BiomeGen is the underlying biome generator, some composition generators may depend on it providing additional biomes around the chunk
|
||||
a_ShapeGen is the underlying shape generator, some composition generators may depend on it providing additional shape around the chunk
|
||||
*/
|
||||
static cTerrainCompositionGenPtr CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed);
|
||||
static cTerrainCompositionGenPtr CreateCompositionGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, cTerrainShapeGenPtr a_ShapeGen, int a_Seed);
|
||||
} ;
|
||||
|
||||
|
||||
@ -128,7 +152,7 @@ public:
|
||||
/** The interface that a finisher must implement
|
||||
Finisher implements changes to the chunk after the rough terrain has been generated.
|
||||
Examples of finishers are trees, snow, ore, lilypads and others.
|
||||
Note that a worldgenerator may contain multiple finishers.
|
||||
Note that a worldgenerator may contain multiple finishers, chained one after another.
|
||||
Also note that previously we used to distinguish between a structuregen and a finisher; this distinction is
|
||||
no longer relevant, all structure generators are considered finishers now (#398)
|
||||
*/
|
||||
@ -154,23 +178,34 @@ class cComposableGenerator :
|
||||
public:
|
||||
cComposableGenerator(cChunkGenerator & a_ChunkGenerator);
|
||||
|
||||
// cChunkGenerator::cGenerator overrides:
|
||||
virtual void Initialize(cIniFile & a_IniFile) override;
|
||||
virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
|
||||
virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override;
|
||||
|
||||
protected:
|
||||
// The generation composition:
|
||||
cBiomeGenPtr m_BiomeGen;
|
||||
cTerrainHeightGenPtr m_HeightGen;
|
||||
// The generator's composition:
|
||||
/** The biome generator. */
|
||||
cBiomeGenPtr m_BiomeGen;
|
||||
|
||||
/** The terrain shape generator. */
|
||||
cTerrainShapeGenPtr m_ShapeGen;
|
||||
|
||||
/** The terrain composition generator. */
|
||||
cTerrainCompositionGenPtr m_CompositionGen;
|
||||
cFinishGenList m_FinishGens;
|
||||
|
||||
/** The cache for the heights of the composited terrain. */
|
||||
cTerrainHeightGenPtr m_CompositedHeightCache;
|
||||
|
||||
/** The finisher generators, in the order in which they are applied. */
|
||||
cFinishGenList m_FinishGens;
|
||||
|
||||
|
||||
/** Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly */
|
||||
/** Reads the BiomeGen settings from the ini and initializes m_BiomeGen accordingly */
|
||||
void InitBiomeGen(cIniFile & a_IniFile);
|
||||
|
||||
/** Reads the HeightGen settings from the ini and initializes m_HeightGen accordingly */
|
||||
void InitHeightGen(cIniFile & a_IniFile);
|
||||
/** Reads the ShapeGen settings from the ini and initializes m_ShapeGen accordingly */
|
||||
void InitShapeGen(cIniFile & a_IniFile);
|
||||
|
||||
/** Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly */
|
||||
void InitCompositionGen(cIniFile & a_IniFile);
|
||||
|
49
src/Generating/CompositedHeiGen.h
Normal file
49
src/Generating/CompositedHeiGen.h
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
// CompositedHeiGen.h
|
||||
|
||||
// Declares the cCompositedHeiGen class representing a cTerrainHeightGen descendant that calculates heightmap of the composited terrain
|
||||
// This is used to further cache heightmaps for chunks already generated for finishers that require only heightmap information
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ComposableGenerator.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cCompositedHeiGen:
|
||||
public cTerrainHeightGen
|
||||
{
|
||||
public:
|
||||
cCompositedHeiGen(cTerrainShapeGenPtr a_ShapeGen, cTerrainCompositionGenPtr a_CompositionGen):
|
||||
m_ShapeGen(a_ShapeGen),
|
||||
m_CompositionGen(a_CompositionGen)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
// cTerrainheightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override
|
||||
{
|
||||
cChunkDesc::Shape shape;
|
||||
m_ShapeGen->GenShape(a_ChunkX, a_ChunkZ, shape);
|
||||
cChunkDesc desc(a_ChunkX, a_ChunkZ);
|
||||
desc.SetHeightFromShape(shape);
|
||||
m_CompositionGen->ComposeTerrain(desc, shape);
|
||||
memcpy(a_HeightMap, desc.GetHeightMap(), sizeof(a_HeightMap));
|
||||
}
|
||||
|
||||
protected:
|
||||
cTerrainShapeGenPtr m_ShapeGen;
|
||||
cTerrainCompositionGenPtr m_CompositionGen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -14,163 +14,6 @@
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cPattern:
|
||||
|
||||
/// This class is used to store a column pattern initialized at runtime,
|
||||
/// so that the program doesn't need to explicitly set 256 values for each pattern
|
||||
/// Each pattern has 256 blocks so that there's no need to check pattern bounds when assigning the
|
||||
/// pattern - there will always be enough pattern left, even for the whole chunk height
|
||||
class cPattern
|
||||
{
|
||||
public:
|
||||
cPattern(cDistortedHeightmap::sBlockInfo * a_TopBlocks, size_t a_Count)
|
||||
{
|
||||
// Copy the pattern into the top:
|
||||
for (size_t i = 0; i < a_Count; i++)
|
||||
{
|
||||
m_Pattern[i] = a_TopBlocks[i];
|
||||
}
|
||||
|
||||
// Fill the rest with stone:
|
||||
static cDistortedHeightmap::sBlockInfo Stone = {E_BLOCK_STONE, 0};
|
||||
for (size_t i = a_Count; i < cChunkDef::Height; i++)
|
||||
{
|
||||
m_Pattern[i] = Stone;
|
||||
}
|
||||
}
|
||||
|
||||
const cDistortedHeightmap::sBlockInfo * Get(void) const { return m_Pattern; }
|
||||
|
||||
protected:
|
||||
cDistortedHeightmap::sBlockInfo m_Pattern[cChunkDef::Height];
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// The arrays to use for the top block pattern definitions:
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbGrass[] =
|
||||
{
|
||||
{E_BLOCK_GRASS, 0},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbSand[] =
|
||||
{
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SANDSTONE, 0},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbDirt[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbPodzol[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_PODZOL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbGrassLess[] =
|
||||
{
|
||||
{E_BLOCK_DIRT, E_META_DIRT_GRASSLESS},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
{E_BLOCK_DIRT, E_META_DIRT_NORMAL},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbMycelium[] =
|
||||
{
|
||||
{E_BLOCK_MYCELIUM, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
{E_BLOCK_DIRT, 0},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbGravel[] =
|
||||
{
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_GRAVEL, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbStone[] =
|
||||
{
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
{E_BLOCK_STONE, 0},
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Ocean floor pattern top-block definitions:
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbOFSand[] =
|
||||
{
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SAND, 0},
|
||||
{E_BLOCK_SANDSTONE, 0}
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbOFClay[] =
|
||||
{
|
||||
{ E_BLOCK_CLAY, 0},
|
||||
{ E_BLOCK_CLAY, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
{ E_BLOCK_SAND, 0},
|
||||
} ;
|
||||
|
||||
static cDistortedHeightmap::sBlockInfo tbOFRedSand[] =
|
||||
{
|
||||
{ E_BLOCK_SAND, E_META_SAND_RED},
|
||||
{ E_BLOCK_SAND, E_META_SAND_RED},
|
||||
{ E_BLOCK_SAND, E_META_SAND_RED},
|
||||
{ E_BLOCK_SANDSTONE, 0},
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Individual patterns to use:
|
||||
|
||||
static cPattern patGrass (tbGrass, ARRAYCOUNT(tbGrass));
|
||||
static cPattern patSand (tbSand, ARRAYCOUNT(tbSand));
|
||||
static cPattern patDirt (tbDirt, ARRAYCOUNT(tbDirt));
|
||||
static cPattern patPodzol (tbPodzol, ARRAYCOUNT(tbPodzol));
|
||||
static cPattern patGrassLess(tbGrassLess, ARRAYCOUNT(tbGrassLess));
|
||||
static cPattern patMycelium (tbMycelium, ARRAYCOUNT(tbMycelium));
|
||||
static cPattern patGravel (tbGravel, ARRAYCOUNT(tbGravel));
|
||||
static cPattern patStone (tbStone, ARRAYCOUNT(tbStone));
|
||||
|
||||
static cPattern patOFSand (tbOFSand, ARRAYCOUNT(tbOFSand));
|
||||
static cPattern patOFClay (tbOFClay, ARRAYCOUNT(tbOFClay));
|
||||
static cPattern patOFRedSand(tbOFRedSand, ARRAYCOUNT(tbOFRedSand));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cDistortedHeightmap:
|
||||
|
||||
@ -237,7 +80,7 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] =
|
||||
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 110 .. 119
|
||||
{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, // 120 .. 128
|
||||
|
||||
// Release 1.7 /* biome variants:
|
||||
// Release 1.7 biome variants:
|
||||
/* biSunflowerPlains */ { 1.0f, 1.0f}, // 129
|
||||
/* biDesertM */ { 1.0f, 1.0f}, // 130
|
||||
/* biExtremeHillsM */ {16.0f, 16.0f}, // 131
|
||||
@ -279,8 +122,6 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[256] =
|
||||
cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen) :
|
||||
m_NoiseDistortX(a_Seed + 1000),
|
||||
m_NoiseDistortZ(a_Seed + 2000),
|
||||
m_OceanFloorSelect(a_Seed + 3000),
|
||||
m_MesaFloor(a_Seed + 4000),
|
||||
m_BiomeGen(a_BiomeGen),
|
||||
m_UnderlyingHeiGen(new cHeiGenBiomal(a_Seed, a_BiomeGen)),
|
||||
m_HeightGen(m_UnderlyingHeiGen, 64),
|
||||
@ -293,8 +134,6 @@ cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen) :
|
||||
m_NoiseDistortZ.AddOctave((NOISE_DATATYPE)1, (NOISE_DATATYPE)0.5);
|
||||
m_NoiseDistortZ.AddOctave((NOISE_DATATYPE)0.5, (NOISE_DATATYPE)1);
|
||||
m_NoiseDistortZ.AddOctave((NOISE_DATATYPE)0.25, (NOISE_DATATYPE)2);
|
||||
|
||||
InitMesaPattern(a_Seed);
|
||||
}
|
||||
|
||||
|
||||
@ -309,7 +148,7 @@ void cDistortedHeightmap::Initialize(cIniFile & a_IniFile)
|
||||
}
|
||||
|
||||
// Read the params from the INI file:
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "DistortedHeightmapSeaLevel", 62);
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", 62);
|
||||
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyX", 10);
|
||||
m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyY", 10);
|
||||
m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyZ", 10);
|
||||
@ -321,89 +160,6 @@ void cDistortedHeightmap::Initialize(cIniFile & a_IniFile)
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::InitMesaPattern(int a_Seed)
|
||||
{
|
||||
// Stone in the bottom half of the pattern:
|
||||
for (int i = cChunkDef::Height; i < 2 * cChunkDef::Height; i++)
|
||||
{
|
||||
m_MesaPattern[i].BlockMeta = 0;
|
||||
m_MesaPattern[i].BlockType = E_BLOCK_STONE;
|
||||
}
|
||||
|
||||
// Stained and hardened clay in the top half of the pattern
|
||||
// In a loop, choose whether to use one or two layers of stained clay, then choose a color and width for each layer
|
||||
// Separate each group with another layer of hardened clay
|
||||
cNoise PatternNoise((unsigned)a_Seed);
|
||||
static NIBBLETYPE AllowedColors[] =
|
||||
{
|
||||
E_META_STAINED_CLAY_YELLOW,
|
||||
E_META_STAINED_CLAY_YELLOW,
|
||||
E_META_STAINED_CLAY_RED,
|
||||
E_META_STAINED_CLAY_RED,
|
||||
E_META_STAINED_CLAY_WHITE,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_BROWN,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_ORANGE,
|
||||
E_META_STAINED_CLAY_LIGHTGRAY,
|
||||
} ;
|
||||
static int LayerSizes[] = // Adjust the chance so that thinner layers occur more commonly
|
||||
{
|
||||
1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2,
|
||||
3, 3,
|
||||
} ;
|
||||
int Idx = cChunkDef::Height - 1;
|
||||
while (Idx >= 0)
|
||||
{
|
||||
// A layer group of 1 - 2 color stained clay:
|
||||
int Random = PatternNoise.IntNoise1DInt(Idx) / 7;
|
||||
int NumLayers = (Random % 2) + 1;
|
||||
Random /= 2;
|
||||
for (int Lay = 0; Lay < NumLayers; Lay++)
|
||||
{
|
||||
int NumBlocks = LayerSizes[(Random % ARRAYCOUNT(LayerSizes))];
|
||||
NIBBLETYPE Color = AllowedColors[(Random / 4) % ARRAYCOUNT(AllowedColors)];
|
||||
if (
|
||||
((NumBlocks == 3) && (NumLayers == 2)) || // In two-layer mode disallow the 3-high layers:
|
||||
(Color == E_META_STAINED_CLAY_WHITE)) // White stained clay can ever be only 1 block high
|
||||
{
|
||||
NumBlocks = 1;
|
||||
}
|
||||
NumBlocks = std::min(Idx + 1, NumBlocks); // Limit by Idx so that we don't have to check inside the loop
|
||||
Random /= 32;
|
||||
for (int Block = 0; Block < NumBlocks; Block++, Idx--)
|
||||
{
|
||||
m_MesaPattern[Idx].BlockMeta = Color;
|
||||
m_MesaPattern[Idx].BlockType = E_BLOCK_STAINED_CLAY;
|
||||
} // for Block
|
||||
} // for Lay
|
||||
|
||||
// A layer of hardened clay in between the layer group:
|
||||
int NumBlocks = (Random % 4) + 1; // All heights the same probability
|
||||
if ((NumLayers == 2) && (NumBlocks < 4))
|
||||
{
|
||||
// For two layers of stained clay, add an extra block of hardened clay:
|
||||
NumBlocks++;
|
||||
}
|
||||
NumBlocks = std::min(Idx + 1, NumBlocks); // Limit by Idx so that we don't have to check inside the loop
|
||||
for (int Block = 0; Block < NumBlocks; Block++, Idx--)
|
||||
{
|
||||
m_MesaPattern[Idx].BlockMeta = 0;
|
||||
m_MesaPattern[Idx].BlockType = E_BLOCK_HARDENED_CLAY;
|
||||
} // for Block
|
||||
} // while (Idx >= 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::PrepareState(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
if ((m_CurChunkX == a_ChunkX) && (m_CurChunkZ == a_ChunkZ))
|
||||
@ -474,23 +230,17 @@ void cDistortedHeightmap::GenerateHeightArray(void)
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
||||
void cDistortedHeightmap::GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
PrepareState(a_ChunkX, a_ChunkZ);
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
int NoiseArrayIdx = x + 17 * 257 * z;
|
||||
cChunkDef::SetHeight(a_HeightMap, x, z, m_SeaLevel - 1);
|
||||
for (int y = cChunkDef::Height - 1; y > m_SeaLevel - 1; y--)
|
||||
int idx = x + 17 * 257 * z;
|
||||
for (int y = 0; y < cChunkDef::Height; y++)
|
||||
{
|
||||
int HeightMapHeight = (int)m_DistortedHeightmap[NoiseArrayIdx + 17 * y];
|
||||
if (y < HeightMapHeight)
|
||||
{
|
||||
cChunkDef::SetHeight(a_HeightMap, x, z, y);
|
||||
break;
|
||||
}
|
||||
a_Shape[y + x * 256 + z * 16 * 256] = (y < m_DistortedHeightmap[idx + y * 17]) ? 1 : 0;
|
||||
} // for y
|
||||
} // for x
|
||||
} // for z
|
||||
@ -500,36 +250,7 @@ void cDistortedHeightmap::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::He
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::InitializeHeightGen(cIniFile & a_IniFile)
|
||||
{
|
||||
Initialize(a_IniFile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
// Prepare the internal state for generating this chunk:
|
||||
PrepareState(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ());
|
||||
|
||||
// Compose:
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
ComposeColumn(a_ChunkDesc, x, z);
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::InitializeCompoGen(cIniFile & a_IniFile)
|
||||
void cDistortedHeightmap::InitializeShapeGen(cIniFile & a_IniFile)
|
||||
{
|
||||
Initialize(a_IniFile);
|
||||
}
|
||||
@ -654,275 +375,3 @@ void cDistortedHeightmap::GetDistortAmpsAt(BiomeNeighbors & a_Neighbors, int a_R
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ)
|
||||
{
|
||||
// Frequencies for the podzol floor selecting noise:
|
||||
const NOISE_DATATYPE FrequencyX = 8;
|
||||
const NOISE_DATATYPE FrequencyZ = 8;
|
||||
|
||||
EMCSBiome Biome = a_ChunkDesc.GetBiome(a_RelX, a_RelZ);
|
||||
switch (Biome)
|
||||
{
|
||||
case biOcean:
|
||||
case biPlains:
|
||||
case biForest:
|
||||
case biTaiga:
|
||||
case biSwampland:
|
||||
case biRiver:
|
||||
case biFrozenOcean:
|
||||
case biFrozenRiver:
|
||||
case biIcePlains:
|
||||
case biIceMountains:
|
||||
case biForestHills:
|
||||
case biTaigaHills:
|
||||
case biExtremeHillsEdge:
|
||||
case biExtremeHillsPlus:
|
||||
case biExtremeHills:
|
||||
case biJungle:
|
||||
case biJungleHills:
|
||||
case biJungleEdge:
|
||||
case biDeepOcean:
|
||||
case biStoneBeach:
|
||||
case biColdBeach:
|
||||
case biBirchForest:
|
||||
case biBirchForestHills:
|
||||
case biRoofedForest:
|
||||
case biColdTaiga:
|
||||
case biColdTaigaHills:
|
||||
case biSavanna:
|
||||
case biSavannaPlateau:
|
||||
case biSunflowerPlains:
|
||||
case biFlowerForest:
|
||||
case biTaigaM:
|
||||
case biSwamplandM:
|
||||
case biIcePlainsSpikes:
|
||||
case biJungleM:
|
||||
case biJungleEdgeM:
|
||||
case biBirchForestM:
|
||||
case biBirchForestHillsM:
|
||||
case biRoofedForestM:
|
||||
case biColdTaigaM:
|
||||
case biSavannaM:
|
||||
case biSavannaPlateauM:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patGrass.Get());
|
||||
return;
|
||||
}
|
||||
|
||||
case biMegaTaiga:
|
||||
case biMegaTaigaHills:
|
||||
case biMegaSpruceTaiga:
|
||||
case biMegaSpruceTaigaHills:
|
||||
{
|
||||
// Select the pattern to use - podzol, grass or grassless dirt:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
const sBlockInfo * Pattern = (Val < -0.9) ? patGrassLess.Get() : ((Val > 0) ? patPodzol.Get() : patGrass.Get());
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern);
|
||||
return;
|
||||
}
|
||||
|
||||
case biDesertHills:
|
||||
case biDesert:
|
||||
case biDesertM:
|
||||
case biBeach:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patSand.Get());
|
||||
return;
|
||||
}
|
||||
|
||||
case biMushroomIsland:
|
||||
case biMushroomShore:
|
||||
{
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patMycelium.Get());
|
||||
return;
|
||||
}
|
||||
|
||||
case biMesa:
|
||||
case biMesaPlateauF:
|
||||
case biMesaPlateau:
|
||||
case biMesaBryce:
|
||||
case biMesaPlateauFM:
|
||||
case biMesaPlateauM:
|
||||
{
|
||||
// Mesa biomes need special handling, because they don't follow the usual "4 blocks from top pattern",
|
||||
// instead, they provide a "from bottom" pattern with varying base height,
|
||||
// usually 4 blocks below the ocean level
|
||||
FillColumnMesa(a_ChunkDesc, a_RelX, a_RelZ);
|
||||
return;
|
||||
}
|
||||
|
||||
case biExtremeHillsPlusM:
|
||||
case biExtremeHillsM:
|
||||
{
|
||||
// Select the pattern to use - gravel, stone or grass:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
const sBlockInfo * Pattern = (Val < 0.0) ? patStone.Get() : patGrass.Get();
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ASSERT(!"Unhandled biome");
|
||||
return;
|
||||
}
|
||||
} // switch (Biome)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::FillColumnPattern(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const sBlockInfo * a_Pattern)
|
||||
{
|
||||
int NoiseArrayIdx = a_RelX + 17 * 257 * a_RelZ;
|
||||
bool HasHadWater = false;
|
||||
int PatternIdx = 0;
|
||||
for (int y = a_ChunkDesc.GetHeight(a_RelX, a_RelZ); y > 0; y--)
|
||||
{
|
||||
int HeightMapHeight = (int)m_DistortedHeightmap[NoiseArrayIdx + 17 * y];
|
||||
|
||||
if (y < HeightMapHeight)
|
||||
{
|
||||
// "ground" part, use the pattern:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, a_Pattern[PatternIdx].BlockType, a_Pattern[PatternIdx].BlockMeta);
|
||||
PatternIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// "air" or "water" part:
|
||||
// Reset the pattern index to zero, so that the pattern is repeated from the top again:
|
||||
PatternIdx = 0;
|
||||
|
||||
if (y >= m_SeaLevel)
|
||||
{
|
||||
// "air" part, do nothing
|
||||
continue;
|
||||
}
|
||||
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
if (HasHadWater)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
a_Pattern = a_ChunkDesc.GetBiome(a_RelX, a_RelZ) == biDeepOcean ? patGravel.Get() : ChooseOceanFloorPattern(a_RelX, a_RelZ);
|
||||
HasHadWater = true;
|
||||
} // for y
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cDistortedHeightmap::FillColumnMesa(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ)
|
||||
{
|
||||
// Frequencies for the clay floor noise:
|
||||
const NOISE_DATATYPE FrequencyX = 50;
|
||||
const NOISE_DATATYPE FrequencyZ = 50;
|
||||
|
||||
int Top = a_ChunkDesc.GetHeight(a_RelX, a_RelZ);
|
||||
if (Top < m_SeaLevel)
|
||||
{
|
||||
// The terrain is below sealevel, handle as regular ocean:
|
||||
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, patOFRedSand.Get());
|
||||
return;
|
||||
}
|
||||
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
int ClayFloor = m_SeaLevel - 6 + (int)(4.f * m_MesaFloor.CubicNoise2D(NoiseX, NoiseY));
|
||||
if (ClayFloor >= Top)
|
||||
{
|
||||
ClayFloor = Top - 1;
|
||||
}
|
||||
|
||||
if (Top - m_SeaLevel < 5)
|
||||
{
|
||||
// Simple case: top is red sand, then hardened clay down to ClayFloor, then stone:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, Top, a_RelZ, E_BLOCK_SAND, E_META_SAND_RED);
|
||||
for (int y = Top - 1; y >= ClayFloor; y--)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_HARDENED_CLAY);
|
||||
}
|
||||
for (int y = ClayFloor - 1; y > 0; y--)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STONE);
|
||||
}
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
return;
|
||||
}
|
||||
|
||||
// Difficult case: use the mesa pattern and watch for overhangs:
|
||||
int NoiseArrayIdx = a_RelX + 17 * 257 * a_RelZ;
|
||||
int PatternIdx = cChunkDef::Height - (Top - ClayFloor); // We want the block at index ClayFloor to be pattern's 256th block (first stone)
|
||||
const sBlockInfo * Pattern = m_MesaPattern;
|
||||
bool HasHadWater = false;
|
||||
for (int y = Top; y > 0; y--)
|
||||
{
|
||||
int HeightMapHeight = (int)m_DistortedHeightmap[NoiseArrayIdx + 17 * y];
|
||||
if (y < HeightMapHeight)
|
||||
{
|
||||
// "ground" part, use the pattern:
|
||||
a_ChunkDesc.SetBlockTypeMeta(a_RelX, y, a_RelZ, Pattern[PatternIdx].BlockType, Pattern[PatternIdx].BlockMeta);
|
||||
PatternIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (y >= m_SeaLevel)
|
||||
{
|
||||
// "air" part, do nothing
|
||||
continue;
|
||||
}
|
||||
|
||||
// "water" part, fill with water and choose new pattern for ocean floor, if not chosen already:
|
||||
PatternIdx = 0;
|
||||
a_ChunkDesc.SetBlockType(a_RelX, y, a_RelZ, E_BLOCK_STATIONARY_WATER);
|
||||
if (HasHadWater)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
Pattern = ChooseOceanFloorPattern(a_RelX, a_RelZ);
|
||||
HasHadWater = true;
|
||||
} // for y
|
||||
a_ChunkDesc.SetBlockType(a_RelX, 0, a_RelZ, E_BLOCK_BEDROCK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const cDistortedHeightmap::sBlockInfo * cDistortedHeightmap::ChooseOceanFloorPattern(int a_RelX, int a_RelZ)
|
||||
{
|
||||
// Frequencies for the ocean floor selecting noise:
|
||||
const NOISE_DATATYPE FrequencyX = 3;
|
||||
const NOISE_DATATYPE FrequencyZ = 3;
|
||||
|
||||
// Select the ocean-floor pattern to use:
|
||||
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||
if (Val < -0.95)
|
||||
{
|
||||
return patOFClay.Get();
|
||||
}
|
||||
else if (Val < 0)
|
||||
{
|
||||
return patOFSand.Get();
|
||||
}
|
||||
else
|
||||
{
|
||||
return patDirt.Get();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -23,17 +23,9 @@
|
||||
|
||||
|
||||
class cDistortedHeightmap :
|
||||
public cTerrainHeightGen,
|
||||
public cTerrainCompositionGen
|
||||
public cTerrainShapeGen
|
||||
{
|
||||
public:
|
||||
/// Structure used for storing block patterns for columns
|
||||
struct sBlockInfo
|
||||
{
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
} ;
|
||||
|
||||
cDistortedHeightmap(int a_Seed, cBiomeGenPtr a_BiomeGen);
|
||||
|
||||
protected:
|
||||
@ -51,8 +43,6 @@ protected:
|
||||
|
||||
cPerlinNoise m_NoiseDistortX;
|
||||
cPerlinNoise m_NoiseDistortZ;
|
||||
cNoise m_OceanFloorSelect; ///< Used for selecting between dirt and sand on the ocean floor
|
||||
cNoise m_MesaFloor; ///< Used for the floor of the clay blocks in mesa biomes
|
||||
|
||||
int m_SeaLevel;
|
||||
NOISE_DATATYPE m_FrequencyX;
|
||||
@ -70,9 +60,9 @@ protected:
|
||||
cTerrainHeightGenPtr m_UnderlyingHeiGen;
|
||||
|
||||
/** Cache for m_UnderlyingHeiGen. */
|
||||
cHeiGenCache m_HeightGen;
|
||||
cHeiGenCache m_HeightGen;
|
||||
|
||||
/// Heightmap for the current chunk, before distortion (from m_HeightGen). Used for optimization.
|
||||
/** Heightmap for the current chunk, before distortion (from m_HeightGen). Used for optimization. */
|
||||
cChunkDef::HeightMap m_CurChunkHeights;
|
||||
|
||||
// Per-biome terrain generator parameters:
|
||||
@ -87,54 +77,30 @@ protected:
|
||||
NOISE_DATATYPE m_DistortAmpX[DIM_X * DIM_Z];
|
||||
NOISE_DATATYPE m_DistortAmpZ[DIM_X * DIM_Z];
|
||||
|
||||
/// True if Initialize() has been called. Used to initialize-once even with multiple init entrypoints (HeiGen / CompoGen)
|
||||
/** True if Initialize() has been called. Used to initialize-once even with multiple init entrypoints (HeiGen / CompoGen). */
|
||||
bool m_IsInitialized;
|
||||
|
||||
/// The vertical pattern to be used for mesa biomes. Seed-dependant.
|
||||
/// One Height of pattern and one Height of stone to avoid checking pattern dimensions
|
||||
sBlockInfo m_MesaPattern[2 * cChunkDef::Height];
|
||||
|
||||
|
||||
/// Initializes m_MesaPattern with a reasonable pattern of stained clay / hardened clay, based on the seed
|
||||
void InitMesaPattern(int a_Seed);
|
||||
|
||||
/// Unless the LastChunk coords are equal to coords given, prepares the internal state (noise arrays, heightmap)
|
||||
/** Unless the LastChunk coords are equal to coords given, prepares the internal state (noise arrays, heightmap). */
|
||||
void PrepareState(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
/// Generates the m_DistortedHeightmap array for the current chunk
|
||||
/** Generates the m_DistortedHeightmap array for the current chunk. */
|
||||
void GenerateHeightArray(void);
|
||||
|
||||
/// Calculates the heightmap value (before distortion) at the specified (floating-point) coords
|
||||
/** Calculates the heightmap value (before distortion) at the specified (floating-point) coords. */
|
||||
int GetHeightmapAt(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Z);
|
||||
|
||||
/// Updates m_DistortAmpX/Z[] based on m_CurChunkX and m_CurChunkZ
|
||||
/** Updates m_DistortAmpX/Z[] based on m_CurChunkX and m_CurChunkZ. */
|
||||
void UpdateDistortAmps(void);
|
||||
|
||||
/// Calculates the X and Z distortion amplitudes based on the neighbors' biomes
|
||||
/** Calculates the X and Z distortion amplitudes based on the neighbors' biomes. */
|
||||
void GetDistortAmpsAt(BiomeNeighbors & a_Neighbors, int a_RelX, int a_RelZ, NOISE_DATATYPE & a_DistortAmpX, NOISE_DATATYPE & a_DistortAmpZ);
|
||||
|
||||
/// Reads the settings from the ini file. Skips reading if already initialized
|
||||
/** Reads the settings from the ini file. Skips reading if already initialized. */
|
||||
void Initialize(cIniFile & a_IniFile);
|
||||
|
||||
/// Composes a single column in a_ChunkDesc. Chooses what to do based on the biome in that column
|
||||
void ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ);
|
||||
|
||||
/// Fills the specified column with the specified pattern; restarts the pattern when air is reached,
|
||||
/// switches to ocean floor pattern if ocean is reached. Always adds bedrock at the very bottom.
|
||||
void FillColumnPattern(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ, const sBlockInfo * a_Pattern);
|
||||
|
||||
/// Fills the specified column with mesa pattern, based on the column height
|
||||
void FillColumnMesa(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelZ);
|
||||
|
||||
/// Returns the pattern to use for an ocean floor in the specified column
|
||||
const sBlockInfo * ChooseOceanFloorPattern(int a_RelX, int a_RelZ);
|
||||
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override;
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
// cTerrainShapeGen overrides:
|
||||
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeShapeGen(cIniFile & a_IniFile) override;
|
||||
} ;
|
||||
|
@ -78,7 +78,8 @@ protected:
|
||||
|
||||
|
||||
|
||||
/** Decodes the position index along the room walls into a proper 2D position for a chest. */
|
||||
/** Decodes the position index along the room walls into a proper 2D position for a chest.
|
||||
The Y coord of the returned vector specifies the chest's meta value*/
|
||||
Vector3i DecodeChestCoords(int a_PosIdx, int a_SizeX, int a_SizeZ)
|
||||
{
|
||||
if (a_PosIdx < a_SizeX)
|
||||
@ -258,9 +259,9 @@ protected:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cDungeonRoomsFinisher:
|
||||
|
||||
cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGenPtr a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib) :
|
||||
cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainShapeGenPtr a_ShapeGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib) :
|
||||
super(a_Seed + 100, a_GridSize, a_GridSize, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 1024),
|
||||
m_HeightGen(a_HeightGen),
|
||||
m_ShapeGen(a_ShapeGen),
|
||||
m_MaxHalfSize((a_MaxSize + 1) / 2),
|
||||
m_MinHalfSize((a_MinSize + 1) / 2),
|
||||
m_HeightProbability(cChunkDef::Height)
|
||||
@ -293,13 +294,21 @@ cDungeonRoomsFinisher::cStructurePtr cDungeonRoomsFinisher::CreateStructure(int
|
||||
int ChunkX, ChunkZ;
|
||||
int RelX = a_OriginX, RelY = 0, RelZ = a_OriginZ;
|
||||
cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ);
|
||||
cChunkDef::HeightMap HeightMap;
|
||||
m_HeightGen->GenHeightMap(ChunkX, ChunkZ, HeightMap);
|
||||
int Height = cChunkDef::GetHeight(HeightMap, RelX, RelZ); // Max room height at {a_OriginX, a_OriginZ}
|
||||
Height = Clamp(m_HeightProbability.MapValue(rnd % m_HeightProbability.GetSum()), 10, Height - 5);
|
||||
cChunkDesc::Shape shape;
|
||||
m_ShapeGen->GenShape(ChunkX, ChunkZ, shape);
|
||||
int height = 0;
|
||||
int idx = RelX * 256 + RelZ * 16 * 256;
|
||||
for (int y = 6; y < cChunkDef::Height; y++)
|
||||
{
|
||||
if (shape[idx + y] != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
height = Clamp(m_HeightProbability.MapValue(rnd % m_HeightProbability.GetSum()), 10, y - 5);
|
||||
}
|
||||
|
||||
// Create the dungeon room descriptor:
|
||||
return cStructurePtr(new cDungeonRoom(a_GridX, a_GridZ, a_OriginX, a_OriginZ, HalfSizeX, HalfSizeZ, Height, m_Noise));
|
||||
return cStructurePtr(new cDungeonRoom(a_GridX, a_GridZ, a_OriginX, a_OriginZ, HalfSizeX, HalfSizeZ, height, m_Noise));
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,15 +23,15 @@ class cDungeonRoomsFinisher :
|
||||
|
||||
public:
|
||||
/** Creates a new dungeon room finisher.
|
||||
a_HeightGen is the underlying height generator, so that the rooms can always be placed under the terrain.
|
||||
a_ShapeGen is the underlying terrain shape generator, so that the rooms can always be placed under the terrain.
|
||||
a_MaxSize and a_MinSize are the maximum and minimum sizes of the room's internal (air) area, in blocks across.
|
||||
a_HeightDistrib is the string defining the height distribution for the rooms (cProbabDistrib format). */
|
||||
cDungeonRoomsFinisher(cTerrainHeightGenPtr a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib);
|
||||
cDungeonRoomsFinisher(cTerrainShapeGenPtr a_ShapeGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib);
|
||||
|
||||
protected:
|
||||
|
||||
/** The height gen that is used for limiting the rooms' Y coords */
|
||||
cTerrainHeightGenPtr m_HeightGen;
|
||||
/** The shape gen that is used for limiting the rooms' Y coords */
|
||||
cTerrainShapeGenPtr m_ShapeGen;
|
||||
|
||||
/** Maximum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 3 (vanilla). */
|
||||
int m_MaxHalfSize;
|
||||
|
@ -147,13 +147,14 @@ bool cEndGen::IsChunkOutsideRange(int a_ChunkX, int a_ChunkZ)
|
||||
|
||||
|
||||
|
||||
void cEndGen::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
||||
void cEndGen::GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
// If the chunk is outside out range, fill the shape with zeroes:
|
||||
if (IsChunkOutsideRange(a_ChunkX, a_ChunkZ))
|
||||
{
|
||||
for (size_t i = 0; i < ARRAYCOUNT(a_HeightMap); i++)
|
||||
for (size_t i = 0; i < ARRAYCOUNT(a_Shape); i++)
|
||||
{
|
||||
a_HeightMap[i] = 0;
|
||||
a_Shape[i] = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -165,15 +166,14 @@ void cEndGen::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
cChunkDef::SetHeight(a_HeightMap, x, z, MaxY);
|
||||
for (int y = MaxY; y > 0; y--)
|
||||
for (int y = 0; y < MaxY; y++)
|
||||
{
|
||||
if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= 0)
|
||||
{
|
||||
cChunkDef::SetHeight(a_HeightMap, x, z, y);
|
||||
break;
|
||||
}
|
||||
} // for y
|
||||
a_Shape[(x + 16 * z) * 256 + y] = (m_NoiseArray[y * 17 * 17 + z * 17 + z] > 0) ? 1 : 0;
|
||||
}
|
||||
for (int y = MaxY; y < cChunkDef::Height; y++)
|
||||
{
|
||||
a_Shape[(x + 16 * z) * 256 + y] = 0;
|
||||
}
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
@ -182,30 +182,18 @@ void cEndGen::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_
|
||||
|
||||
|
||||
|
||||
void cEndGen::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
void cEndGen::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
if (IsChunkOutsideRange(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ()))
|
||||
{
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
PrepareState(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ());
|
||||
|
||||
int MaxY = std::min((int)(1.75 * m_IslandSizeY + 1), cChunkDef::Height - 1);
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
for (int y = MaxY; y > 0; y--)
|
||||
for (int y = 0; y < cChunkDef::Height; y++)
|
||||
{
|
||||
if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= 0)
|
||||
if (a_Shape[(x + 16 * z) * 256 + y] != 0)
|
||||
{
|
||||
a_ChunkDesc.SetBlockTypeMeta(x, y, z, E_BLOCK_END_STONE, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
a_ChunkDesc.SetBlockTypeMeta(x, y, z, E_BLOCK_AIR, 0);
|
||||
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_END_STONE);
|
||||
}
|
||||
} // for y
|
||||
} // for x
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
|
||||
class cEndGen :
|
||||
public cTerrainHeightGen,
|
||||
public cTerrainShapeGen,
|
||||
public cTerrainCompositionGen
|
||||
{
|
||||
public:
|
||||
@ -59,10 +59,10 @@ protected:
|
||||
/// Returns true if the chunk is outside of the island's dimensions
|
||||
bool IsChunkOutsideRange(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
// cTerrainShapeGen overrides:
|
||||
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override;
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override;
|
||||
} ;
|
||||
|
@ -411,7 +411,7 @@ void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc)
|
||||
case biFrozenOcean:
|
||||
{
|
||||
int Height = a_ChunkDesc.GetHeight(x, z);
|
||||
if (cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)))
|
||||
if (cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)) && (Height < cChunkDef::Height - 1))
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(x, Height + 1, z, E_BLOCK_SNOW);
|
||||
a_ChunkDesc.SetHeight(x, z, Height + 1);
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cHeiGenFlat:
|
||||
|
||||
@ -133,15 +132,6 @@ void cHeiGenCache::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap
|
||||
|
||||
|
||||
|
||||
void cHeiGenCache::InitializeHeightGen(cIniFile & a_IniFile)
|
||||
{
|
||||
m_HeiGenToCache->InitializeHeightGen(a_IniFile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cHeiGenCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height)
|
||||
{
|
||||
for (int i = 0; i < m_CacheSize; i++)
|
||||
@ -159,6 +149,51 @@ bool cHeiGenCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_Rel
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cHeiGenMultiCache:
|
||||
|
||||
cHeiGenMultiCache::cHeiGenMultiCache(cTerrainHeightGenPtr a_HeiGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches):
|
||||
m_NumSubCaches(a_NumSubCaches)
|
||||
{
|
||||
// Create the individual sub-caches:
|
||||
m_SubCaches.reserve(a_NumSubCaches);
|
||||
for (size_t i = 0; i < a_NumSubCaches; i++)
|
||||
{
|
||||
m_SubCaches.push_back(std::make_shared<cHeiGenCache>(a_HeiGenToCache, a_SubCacheSize));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cHeiGenMultiCache::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
||||
{
|
||||
// Get the subcache responsible for this chunk:
|
||||
const size_t cacheIdx = ((size_t)a_ChunkX + m_CoeffZ * (size_t)a_ChunkZ) % m_NumSubCaches;
|
||||
|
||||
// Ask the subcache:
|
||||
m_SubCaches[cacheIdx]->GenHeightMap(a_ChunkX, a_ChunkZ, a_HeightMap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cHeiGenMultiCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height)
|
||||
{
|
||||
// Get the subcache responsible for this chunk:
|
||||
const size_t cacheIdx = ((size_t)a_ChunkX + m_CoeffZ * (size_t)a_ChunkZ) % m_NumSubCaches;
|
||||
|
||||
// Ask the subcache:
|
||||
return m_SubCaches[cacheIdx]->GetHeightAt(a_ChunkX, a_ChunkZ, a_RelX, a_RelZ, a_Height);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cHeiGenClassic:
|
||||
|
||||
@ -750,43 +785,51 @@ cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cB
|
||||
}
|
||||
|
||||
a_CacheOffByDefault = false;
|
||||
cTerrainHeightGen * res = nullptr;
|
||||
if (NoCaseCompare(HeightGenName, "flat") == 0)
|
||||
cTerrainHeightGenPtr res;
|
||||
if (NoCaseCompare(HeightGenName, "Flat") == 0)
|
||||
{
|
||||
res = new cHeiGenFlat;
|
||||
res = std::make_shared<cHeiGenFlat>();
|
||||
a_CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "classic") == 0)
|
||||
{
|
||||
res = new cHeiGenClassic(a_Seed);
|
||||
res = std::make_shared<cHeiGenClassic>(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0)
|
||||
{
|
||||
res = new cDistortedHeightmap(a_Seed, a_BiomeGen);
|
||||
// Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
|
||||
// Return an empty pointer, the caller will create the proper generator:
|
||||
return cTerrainHeightGenPtr();
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "End") == 0)
|
||||
{
|
||||
res = new cEndGen(a_Seed);
|
||||
// Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
|
||||
// Return an empty pointer, the caller will create the proper generator:
|
||||
return cTerrainHeightGenPtr();
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "MinMax") == 0)
|
||||
{
|
||||
res = new cHeiGenMinMax(a_Seed, a_BiomeGen);
|
||||
res = std::make_shared<cHeiGenMinMax>(a_Seed, a_BiomeGen);
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "Mountains") == 0)
|
||||
{
|
||||
res = new cHeiGenMountains(a_Seed);
|
||||
res = std::make_shared<cHeiGenMountains>(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "BiomalNoise3D") == 0)
|
||||
{
|
||||
res = new cBiomalNoise3DComposable(a_Seed, a_BiomeGen);
|
||||
// Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
|
||||
// Return an empty pointer, the caller will create the proper generator:
|
||||
return cTerrainHeightGenPtr();
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "Noise3D") == 0)
|
||||
{
|
||||
res = new cNoise3DComposable(a_Seed);
|
||||
// Not a heightmap-based generator, but it used to be accessible via HeightGen, so we need to skip making the default out of it
|
||||
// Return an empty pointer, the caller will create the proper generator:
|
||||
return cTerrainHeightGenPtr();
|
||||
}
|
||||
else if (NoCaseCompare(HeightGenName, "biomal") == 0)
|
||||
else if (NoCaseCompare(HeightGenName, "Biomal") == 0)
|
||||
{
|
||||
res = new cHeiGenBiomal(a_Seed, a_BiomeGen);
|
||||
res = std::make_shared<cHeiGenBiomal>(a_Seed, a_BiomeGen);
|
||||
|
||||
/*
|
||||
// Performance-testing:
|
||||
@ -805,15 +848,14 @@ cTerrainHeightGenPtr cTerrainHeightGen::CreateHeightGen(cIniFile & a_IniFile, cB
|
||||
{
|
||||
// No match found, force-set the default and retry
|
||||
LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str());
|
||||
a_IniFile.DeleteValue("Generator", "HeightGen");
|
||||
a_IniFile.SetValue("Generator", "HeightGen", "Biomal");
|
||||
return CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
|
||||
}
|
||||
|
||||
// Read the settings:
|
||||
res->InitializeHeightGen(a_IniFile);
|
||||
|
||||
return cTerrainHeightGenPtr(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,10 +2,12 @@
|
||||
// HeiGen.h
|
||||
|
||||
/*
|
||||
Interfaces to the various height generators:
|
||||
Interfaces to the various height-based terrain shape generators:
|
||||
- cHeiGenFlat
|
||||
- cHeiGenClassic
|
||||
- cHeiGenBiomal
|
||||
|
||||
Also implements the heightmap cache
|
||||
*/
|
||||
|
||||
|
||||
@ -21,6 +23,78 @@ Interfaces to the various height generators:
|
||||
|
||||
|
||||
|
||||
/** A simple cache that stores N most recently generated chunks' heightmaps; N being settable upon creation */
|
||||
class cHeiGenCache :
|
||||
public cTerrainHeightGen
|
||||
{
|
||||
public:
|
||||
cHeiGenCache(cTerrainHeightGenPtr a_HeiGenToCache, int a_CacheSize);
|
||||
~cHeiGenCache();
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
|
||||
/** Retrieves height at the specified point in the cache, returns true if found, false if not found */
|
||||
bool GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height);
|
||||
|
||||
protected:
|
||||
struct sCacheData
|
||||
{
|
||||
int m_ChunkX;
|
||||
int m_ChunkZ;
|
||||
cChunkDef::HeightMap m_HeightMap;
|
||||
} ;
|
||||
|
||||
/** The terrain height generator that is being cached. */
|
||||
cTerrainHeightGenPtr m_HeiGenToCache;
|
||||
|
||||
// To avoid moving large amounts of data for the MRU behavior, we MRU-ize indices to an array of the actual data
|
||||
int m_CacheSize;
|
||||
int * m_CacheOrder; // MRU-ized order, indices into m_CacheData array
|
||||
sCacheData * m_CacheData; // m_CacheData[m_CacheOrder[0]] is the most recently used
|
||||
|
||||
// Cache statistics
|
||||
int m_NumHits;
|
||||
int m_NumMisses;
|
||||
int m_TotalChain; // Number of cache items walked to get to a hit (only added for hits)
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Caches heightmaps in multiple underlying caches to improve the distribution and lower the chain length. */
|
||||
class cHeiGenMultiCache:
|
||||
public cTerrainHeightGen
|
||||
{
|
||||
public:
|
||||
cHeiGenMultiCache(cTerrainHeightGenPtr a_HeightGenToCache, size_t a_SubCacheSize, size_t a_NumSubCaches);
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
|
||||
/** Retrieves height at the specified point in the cache, returns true if found, false if not found */
|
||||
bool GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height);
|
||||
|
||||
protected:
|
||||
typedef SharedPtr<cHeiGenCache> cHeiGenCachePtr;
|
||||
typedef std::vector<cHeiGenCachePtr> cHeiGenCachePtrs;
|
||||
|
||||
|
||||
/** The coefficient used to turn Z coords into index (x + Coeff * z). */
|
||||
static const size_t m_CoeffZ = 5;
|
||||
|
||||
/** Number of sub-caches, pulled out of m_SubCaches.size() for performance reasons. */
|
||||
size_t m_NumSubCaches;
|
||||
|
||||
/** The individual sub-caches. */
|
||||
cHeiGenCachePtrs m_SubCaches;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cHeiGenFlat :
|
||||
public cTerrainHeightGen
|
||||
{
|
||||
@ -40,47 +114,6 @@ protected:
|
||||
|
||||
|
||||
|
||||
/// A simple cache that stores N most recently generated chunks' heightmaps; N being settable upon creation
|
||||
class cHeiGenCache :
|
||||
public cTerrainHeightGen
|
||||
{
|
||||
public:
|
||||
cHeiGenCache(cTerrainHeightGenPtr a_HeiGenToCache, int a_CacheSize);
|
||||
~cHeiGenCache();
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override;
|
||||
|
||||
/// Retrieves height at the specified point in the cache, returns true if found, false if not found
|
||||
bool GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelZ, HEIGHTTYPE & a_Height);
|
||||
|
||||
protected:
|
||||
|
||||
cTerrainHeightGenPtr m_HeiGenToCache;
|
||||
|
||||
struct sCacheData
|
||||
{
|
||||
int m_ChunkX;
|
||||
int m_ChunkZ;
|
||||
cChunkDef::HeightMap m_HeightMap;
|
||||
} ;
|
||||
|
||||
// To avoid moving large amounts of data for the MRU behavior, we MRU-ize indices to an array of the actual data
|
||||
int m_CacheSize;
|
||||
int * m_CacheOrder; // MRU-ized order, indices into m_CacheData array
|
||||
sCacheData * m_CacheData; // m_CacheData[m_CacheOrder[0]] is the most recently used
|
||||
|
||||
// Cache statistics
|
||||
int m_NumHits;
|
||||
int m_NumMisses;
|
||||
int m_TotalChain; // Number of cache items walked to get to a hit (only added for hits)
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cHeiGenClassic :
|
||||
public cTerrainHeightGen
|
||||
{
|
||||
@ -137,7 +170,11 @@ public:
|
||||
m_BiomeGen(a_BiomeGen)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override;
|
||||
|
||||
protected:
|
||||
|
||||
typedef cChunkDef::BiomeMap BiomeNeighbors[3][3];
|
||||
@ -154,11 +191,8 @@ protected:
|
||||
float m_BaseHeight;
|
||||
} ;
|
||||
static const sGenParam m_GenParam[256];
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override;
|
||||
|
||||
|
||||
|
||||
NOISE_DATATYPE GetHeightAt(int a_RelX, int a_RelZ, int a_ChunkX, int a_ChunkZ, const BiomeNeighbors & a_BiomeNeighbors);
|
||||
} ;
|
||||
|
||||
|
@ -165,69 +165,6 @@ cNoise3DGenerator::cNoise3DGenerator(cChunkGenerator & a_ChunkGenerator) :
|
||||
m_Cubic.AddOctave(4, 0.25);
|
||||
m_Cubic.AddOctave(8, 0.125);
|
||||
m_Cubic.AddOctave(16, 0.0625);
|
||||
|
||||
#if 0
|
||||
// DEBUG: Test the noise generation:
|
||||
// NOTE: In order to be able to run MCS with this code, you need to increase the default thread stack size
|
||||
// In MSVC, it is done in Project Settings -> Configuration Properties -> Linker -> System, set Stack reserve size to at least 64M
|
||||
m_SeaLevel = 62;
|
||||
m_HeightAmplification = 0;
|
||||
m_MidPoint = 75;
|
||||
m_FrequencyX = 4;
|
||||
m_FrequencyY = 4;
|
||||
m_FrequencyZ = 4;
|
||||
m_AirThreshold = 0.5;
|
||||
|
||||
const int NumChunks = 4;
|
||||
NOISE_DATATYPE Noise[NumChunks][cChunkDef::Width * cChunkDef::Width * cChunkDef::Height];
|
||||
for (int x = 0; x < NumChunks; x++)
|
||||
{
|
||||
GenerateNoiseArray(x, 5, Noise[x]);
|
||||
}
|
||||
|
||||
// Save in XY cuts:
|
||||
cFile f1;
|
||||
if (f1.Open("Test_XY.grab", cFile::fmWrite))
|
||||
{
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int y = 0; y < cChunkDef::Height; y++)
|
||||
{
|
||||
for (int i = 0; i < NumChunks; i++)
|
||||
{
|
||||
int idx = y * cChunkDef::Width + z * cChunkDef::Width * cChunkDef::Height;
|
||||
unsigned char buf[cChunkDef::Width];
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
buf[x] = (unsigned char)(std::min(256, std::max(0, (int)(128 + 32 * Noise[i][idx++]))));
|
||||
}
|
||||
f1.Write(buf, cChunkDef::Width);
|
||||
}
|
||||
} // for y
|
||||
} // for z
|
||||
} // if (XY file open)
|
||||
|
||||
cFile f2;
|
||||
if (f2.Open("Test_XZ.grab", cFile::fmWrite))
|
||||
{
|
||||
for (int y = 0; y < cChunkDef::Height; y++)
|
||||
{
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int i = 0; i < NumChunks; i++)
|
||||
{
|
||||
int idx = y * cChunkDef::Width + z * cChunkDef::Width * cChunkDef::Height;
|
||||
unsigned char buf[cChunkDef::Width];
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
buf[x] = (unsigned char)(std::min(256, std::max(0, (int)(128 + 32 * Noise[i][idx++]))));
|
||||
}
|
||||
f2.Write(buf, cChunkDef::Width);
|
||||
}
|
||||
} // for z
|
||||
} // for y
|
||||
} // if (XZ file open)
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
|
||||
@ -246,7 +183,7 @@ cNoise3DGenerator::~cNoise3DGenerator()
|
||||
void cNoise3DGenerator::Initialize(cIniFile & a_IniFile)
|
||||
{
|
||||
// Params:
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "Noise3DSeaLevel", 62);
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", 62);
|
||||
m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0.1);
|
||||
m_MidPoint = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DMidPoint", 68);
|
||||
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyX", 8);
|
||||
@ -454,7 +391,6 @@ void cNoise3DComposable::Initialize(cIniFile & a_IniFile)
|
||||
{
|
||||
// Params:
|
||||
// The defaults generate extreme hills terrain
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "Noise3DSeaLevel", 62);
|
||||
m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0.045);
|
||||
m_MidPoint = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DMidPoint", 75);
|
||||
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DFrequencyX", 40);
|
||||
@ -522,110 +458,60 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ)
|
||||
NOISE_DATATYPE BaseNoise[5 * 5];
|
||||
NOISE_DATATYPE BlockX = static_cast<NOISE_DATATYPE>(a_ChunkX * cChunkDef::Width);
|
||||
NOISE_DATATYPE BlockZ = static_cast<NOISE_DATATYPE>(a_ChunkZ * cChunkDef::Width);
|
||||
// Note that we have to swap the coords, because noise generator uses [x + SizeX * y + SizeX * SizeY * z] ordering and we want "BlockY" to be "z":
|
||||
m_ChoiceNoise.Generate3D (ChoiceNoise, 5, 5, 33, BlockX / m_ChoiceFrequencyX, (BlockX + 17) / m_ChoiceFrequencyX, BlockZ / m_ChoiceFrequencyZ, (BlockZ + 17) / m_ChoiceFrequencyZ, 0, 257 / m_ChoiceFrequencyY, Workspace);
|
||||
m_DensityNoiseA.Generate3D(DensityNoiseA, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace);
|
||||
m_DensityNoiseB.Generate3D(DensityNoiseB, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace);
|
||||
// Note that we have to swap the X and Y coords, because noise generator uses [x + SizeX * y + SizeX * SizeY * z] ordering and we want "BlockY" to be "x":
|
||||
m_ChoiceNoise.Generate3D (ChoiceNoise, 33, 5, 5, 0, 257 / m_ChoiceFrequencyY, BlockX / m_ChoiceFrequencyX, (BlockX + 17) / m_ChoiceFrequencyX, BlockZ / m_ChoiceFrequencyZ, (BlockZ + 17) / m_ChoiceFrequencyZ, Workspace);
|
||||
m_DensityNoiseA.Generate3D(DensityNoiseA, 33, 5, 5, 0, 257 / m_FrequencyY, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace);
|
||||
m_DensityNoiseB.Generate3D(DensityNoiseB, 33, 5, 5, 0, 257 / m_FrequencyY, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace);
|
||||
m_BaseNoise.Generate2D (BaseNoise, 5, 5, BlockX / m_BaseFrequencyX, (BlockX + 17) / m_BaseFrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace);
|
||||
|
||||
// Calculate the final noise based on the partial noises:
|
||||
for (int y = 0; y < 33; y++)
|
||||
for (int z = 0; z < 5; z++)
|
||||
{
|
||||
NOISE_DATATYPE AddHeight = (static_cast<NOISE_DATATYPE>(y * 8) - m_MidPoint) * m_HeightAmplification;
|
||||
|
||||
// If "underground", make the terrain smoother by forcing the vertical linear gradient into steeper slope:
|
||||
if (AddHeight < 0)
|
||||
for (int x = 0; x < 5; x++)
|
||||
{
|
||||
AddHeight *= 4;
|
||||
}
|
||||
|
||||
for (int z = 0; z < 5; z++)
|
||||
{
|
||||
for (int x = 0; x < 5; x++)
|
||||
NOISE_DATATYPE curBaseNoise = BaseNoise[x + 5 * z];
|
||||
for (int y = 0; y < 33; y++)
|
||||
{
|
||||
int idx = x + 5 * z + 5 * 5 * y;
|
||||
Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + BaseNoise[x + 5 * z];
|
||||
NOISE_DATATYPE AddHeight = (static_cast<NOISE_DATATYPE>(y * 8) - m_MidPoint) * m_HeightAmplification;
|
||||
|
||||
// If "underground", make the terrain smoother by forcing the vertical linear gradient into steeper slope:
|
||||
if (AddHeight < 0)
|
||||
{
|
||||
AddHeight *= 4;
|
||||
}
|
||||
|
||||
// If too high, cut off any terrain:
|
||||
if (y > 28)
|
||||
{
|
||||
AddHeight = AddHeight + static_cast<NOISE_DATATYPE>(y - 28) / 4;
|
||||
}
|
||||
|
||||
// Decide between the two density noises:
|
||||
int idx = 33 * x + 33 * 5 * z + y;
|
||||
Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + curBaseNoise;
|
||||
}
|
||||
}
|
||||
}
|
||||
LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 5, 5, 33, m_NoiseArray, 4, 4, 8);
|
||||
LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 33, 5, 5, m_NoiseArray, 8, 4, 4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
||||
void cNoise3DComposable::GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ);
|
||||
|
||||
// Translate the noise array into Shape:
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
cChunkDef::SetHeight(a_HeightMap, x, z, m_SeaLevel);
|
||||
for (int y = cChunkDef::Height - 1; y > m_SeaLevel; y--)
|
||||
for (int y = 0; y < cChunkDef::Height; y++)
|
||||
{
|
||||
if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= m_AirThreshold)
|
||||
{
|
||||
cChunkDef::SetHeight(a_HeightMap, x, z, y);
|
||||
break;
|
||||
}
|
||||
} // for y
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
GenerateNoiseArrayIfNeeded(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ());
|
||||
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
|
||||
// Make basic terrain composition:
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
int LastAir = a_ChunkDesc.GetHeight(x, z) + 1;
|
||||
bool HasHadWater = false;
|
||||
for (int y = LastAir; y < m_SeaLevel; y++)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STATIONARY_WATER);
|
||||
a_Shape[y + x * 256 + z * 256 * 16] = (m_NoiseArray[y + 257 * x + 257 * 17 * z] > m_AirThreshold) ? 0 : 1;
|
||||
}
|
||||
for (int y = LastAir - 1; y > 0; y--)
|
||||
{
|
||||
if (m_NoiseArray[x + 17 * z + 17 * 17 * y] > m_AirThreshold)
|
||||
{
|
||||
// "air" part
|
||||
LastAir = y;
|
||||
if (y < m_SeaLevel)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STATIONARY_WATER);
|
||||
HasHadWater = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// "ground" part:
|
||||
if (LastAir - y > 4)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STONE);
|
||||
continue;
|
||||
}
|
||||
if (HasHadWater)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_SAND);
|
||||
}
|
||||
else
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(x, y, z, (LastAir == y + 1) ? E_BLOCK_GRASS : E_BLOCK_DIRT);
|
||||
}
|
||||
} // for y
|
||||
a_ChunkDesc.SetBlockType(x, 0, z, E_BLOCK_BEDROCK);
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
@ -650,7 +536,7 @@ cBiomalNoise3DComposable::cBiomalNoise3DComposable(int a_Seed, cBiomeGenPtr a_Bi
|
||||
{
|
||||
for (int x = 0; x <= AVERAGING_SIZE * 2; x++)
|
||||
{
|
||||
m_Weight[z][x] = static_cast<NOISE_DATATYPE>((5 - std::abs(5 - x)) + (5 - std::abs(5 - z)));
|
||||
m_Weight[z][x] = static_cast<NOISE_DATATYPE>((AVERAGING_SIZE - std::abs(AVERAGING_SIZE - x)) + (AVERAGING_SIZE - std::abs(AVERAGING_SIZE - z)));
|
||||
m_WeightSum += m_Weight[z][x];
|
||||
}
|
||||
}
|
||||
@ -664,7 +550,7 @@ void cBiomalNoise3DComposable::Initialize(cIniFile & a_IniFile)
|
||||
{
|
||||
// Params:
|
||||
// The defaults generate extreme hills terrain
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "BiomalNoise3DSeaLevel", 62);
|
||||
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "SeaLevel", 62);
|
||||
m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyX", 40);
|
||||
m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyY", 40);
|
||||
m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "BiomalNoise3DFrequencyZ", 40);
|
||||
@ -735,34 +621,42 @@ void cBiomalNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_Ch
|
||||
NOISE_DATATYPE BaseNoise[5 * 5];
|
||||
NOISE_DATATYPE BlockX = static_cast<NOISE_DATATYPE>(a_ChunkX * cChunkDef::Width);
|
||||
NOISE_DATATYPE BlockZ = static_cast<NOISE_DATATYPE>(a_ChunkZ * cChunkDef::Width);
|
||||
// Note that we have to swap the coords, because noise generator uses [x + SizeX * y + SizeX * SizeY * z] ordering and we want "BlockY" to be "z":
|
||||
m_ChoiceNoise.Generate3D (ChoiceNoise, 5, 5, 33, BlockX / m_ChoiceFrequencyX, (BlockX + 17) / m_ChoiceFrequencyX, BlockZ / m_ChoiceFrequencyZ, (BlockZ + 17) / m_ChoiceFrequencyZ, 0, 257 / m_ChoiceFrequencyY, Workspace);
|
||||
m_DensityNoiseA.Generate3D(DensityNoiseA, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace);
|
||||
m_DensityNoiseB.Generate3D(DensityNoiseB, 5, 5, 33, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, 0, 257 / m_FrequencyY, Workspace);
|
||||
// Note that we have to swap the X and Y coords, because noise generator uses [x + SizeX * y + SizeX * SizeY * z] ordering and we want "BlockY" to be "x":
|
||||
m_ChoiceNoise.Generate3D (ChoiceNoise, 33, 5, 5, 0, 257 / m_ChoiceFrequencyY, BlockX / m_ChoiceFrequencyX, (BlockX + 17) / m_ChoiceFrequencyX, BlockZ / m_ChoiceFrequencyZ, (BlockZ + 17) / m_ChoiceFrequencyZ, Workspace);
|
||||
m_DensityNoiseA.Generate3D(DensityNoiseA, 33, 5, 5, 0, 257 / m_FrequencyY, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace);
|
||||
m_DensityNoiseB.Generate3D(DensityNoiseB, 33, 5, 5, 0, 257 / m_FrequencyY, BlockX / m_FrequencyX, (BlockX + 17) / m_FrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace);
|
||||
m_BaseNoise.Generate2D (BaseNoise, 5, 5, BlockX / m_BaseFrequencyX, (BlockX + 17) / m_BaseFrequencyX, BlockZ / m_FrequencyZ, (BlockZ + 17) / m_FrequencyZ, Workspace);
|
||||
|
||||
// Calculate the final noise based on the partial noises:
|
||||
for (int y = 0; y < 33; y++)
|
||||
for (int z = 0; z < 5; z++)
|
||||
{
|
||||
NOISE_DATATYPE BlockHeight = static_cast<NOISE_DATATYPE>(y * 8);
|
||||
for (int z = 0; z < 5; z++)
|
||||
for (int x = 0; x < 5; x++)
|
||||
{
|
||||
for (int x = 0; x < 5; x++)
|
||||
NOISE_DATATYPE curMidPoint = MidPoint[x + 5 * z];
|
||||
NOISE_DATATYPE curHeightAmp = HeightAmp[x + 5 * z];
|
||||
NOISE_DATATYPE curBaseNoise = BaseNoise[x + 5 * z];
|
||||
for (int y = 0; y < 33; y++)
|
||||
{
|
||||
NOISE_DATATYPE AddHeight = (BlockHeight - MidPoint[x + 5 * z]) * HeightAmp[x + 5 * z];
|
||||
NOISE_DATATYPE AddHeight = (static_cast<NOISE_DATATYPE>(y * 8) - curMidPoint) * curHeightAmp;
|
||||
|
||||
// If "underground", make the terrain smoother by forcing the vertical linear gradient into steeper slope:
|
||||
if (AddHeight < 0)
|
||||
{
|
||||
AddHeight *= 4;
|
||||
}
|
||||
// If too high, cut off any terrain:
|
||||
if (y > 28)
|
||||
{
|
||||
AddHeight = AddHeight + static_cast<NOISE_DATATYPE>(y - 28) / 4;
|
||||
}
|
||||
|
||||
int idx = x + 5 * z + 5 * 5 * y;
|
||||
Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + BaseNoise[x + 5 * z];
|
||||
// Decide between the two density noises:
|
||||
int idx = 33 * x + y + 33 * 5 * z;
|
||||
Workspace[idx] = ClampedLerp(DensityNoiseA[idx], DensityNoiseB[idx], 8 * (ChoiceNoise[idx] + 0.5f)) + AddHeight + curBaseNoise;
|
||||
}
|
||||
}
|
||||
}
|
||||
LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 5, 5, 33, m_NoiseArray, 4, 4, 8);
|
||||
LinearUpscale3DArray<NOISE_DATATYPE>(Workspace, 33, 5, 5, m_NoiseArray, 8, 4, 4);
|
||||
}
|
||||
|
||||
|
||||
@ -820,72 +714,67 @@ void cBiomalNoise3DComposable::GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE
|
||||
{
|
||||
switch (a_Biome)
|
||||
{
|
||||
case biBeach: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biBirchForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biBirchForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biBirchForestHillsM: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biBirchForestM: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biColdBeach: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biDesertHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biDeepOcean: a_HeightAmp = 0.17f; a_MidPoint = 35; break;
|
||||
case biDesert: a_HeightAmp = 0.29f; a_MidPoint = 62; break;
|
||||
case biEnd: a_HeightAmp = 0.15f; a_MidPoint = 64; break;
|
||||
case biExtremeHills: a_HeightAmp = 0.045f; a_MidPoint = 75; break;
|
||||
case biExtremeHillsPlus: a_HeightAmp = 0.04f; a_MidPoint = 80; break;
|
||||
case biFlowerForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biFrozenRiver: a_HeightAmp = 0.4f; a_MidPoint = 53; break;
|
||||
case biFrozenOcean: a_HeightAmp = 0.17f; a_MidPoint = 47; break;
|
||||
case biIceMountains: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biIcePlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biIcePlainsSpikes: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biJungle: a_HeightAmp = 0.1f; a_MidPoint = 63; break;
|
||||
case biJungleHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biJungleM: a_HeightAmp = 0.1f; a_MidPoint = 63; break;
|
||||
case biMegaSpruceTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biMegaTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biMushroomShore: a_HeightAmp = 0.15f; a_MidPoint = 15; break;
|
||||
case biOcean: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biPlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biRiver: a_HeightAmp = 0.4f; a_MidPoint = 53; break;
|
||||
case biSwampland: a_HeightAmp = 0.25f; a_MidPoint = 59; break;
|
||||
case biSwamplandM: a_HeightAmp = 0.11f; a_MidPoint = 59; break;
|
||||
case biTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
|
||||
/*
|
||||
// Still missing:
|
||||
case biColdTaiga: a_HeightAmp = 0.15f; a_MidPoint = 30; break;
|
||||
case biColdTaigaHills: a_HeightAmp = 0.15f; a_MidPoint = 31; break;
|
||||
case biColdTaigaM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biDesertM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biExtremeHillsEdge: a_HeightAmp = 0.15f; a_MidPoint = 20; break;
|
||||
case biExtremeHillsM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biExtremeHillsPlusM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biJungleEdge: a_HeightAmp = 0.15f; a_MidPoint = 23; break;
|
||||
case biJungleEdgeM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biMegaSpruceTaiga: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biMegaTaiga: a_HeightAmp = 0.15f; a_MidPoint = 32; break;
|
||||
case biMesa: a_HeightAmp = 0.15f; a_MidPoint = 37; break;
|
||||
case biMesaBryce: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biMesaPlateau: a_HeightAmp = 0.15f; a_MidPoint = 39; break;
|
||||
case biMesaPlateauF: a_HeightAmp = 0.15f; a_MidPoint = 38; break;
|
||||
case biMesaPlateauFM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biMesaPlateauM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biMushroomIsland: a_HeightAmp = 0.15f; a_MidPoint = 14; break;
|
||||
case biNether: a_HeightAmp = 0.15f; a_MidPoint = 68; break;
|
||||
case biRoofedForest: a_HeightAmp = 0.15f; a_MidPoint = 29; break;
|
||||
case biRoofedForestM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biSavanna: a_HeightAmp = 0.15f; a_MidPoint = 35; break;
|
||||
case biSavannaM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biSavannaPlateau: a_HeightAmp = 0.15f; a_MidPoint = 36; break;
|
||||
case biSavannaPlateauM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biStoneBeach: a_HeightAmp = 0.15f; a_MidPoint = 25; break;
|
||||
case biSunflowerPlains: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
case biTaiga: a_HeightAmp = 0.15f; a_MidPoint = 65; break;
|
||||
case biTaigaM: a_HeightAmp = 0.15f; a_MidPoint = 70; break;
|
||||
*/
|
||||
|
||||
case biBeach: a_HeightAmp = 0.2f; a_MidPoint = 60; break;
|
||||
case biBirchForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biBirchForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biBirchForestHillsM: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biBirchForestM: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biColdBeach: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biColdTaiga: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biColdTaigaM: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biColdTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biDesertHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biDeepOcean: a_HeightAmp = 0.17f; a_MidPoint = 35; break;
|
||||
case biDesert: a_HeightAmp = 0.29f; a_MidPoint = 62; break;
|
||||
case biDesertM: a_HeightAmp = 0.29f; a_MidPoint = 62; break;
|
||||
case biEnd: a_HeightAmp = 0.15f; a_MidPoint = 64; break;
|
||||
case biExtremeHills: a_HeightAmp = 0.045f; a_MidPoint = 75; break;
|
||||
case biExtremeHillsEdge: a_HeightAmp = 0.1f; a_MidPoint = 70; break;
|
||||
case biExtremeHillsM: a_HeightAmp = 0.045f; a_MidPoint = 75; break;
|
||||
case biExtremeHillsPlus: a_HeightAmp = 0.04f; a_MidPoint = 80; break;
|
||||
case biExtremeHillsPlusM: a_HeightAmp = 0.04f; a_MidPoint = 80; break;
|
||||
case biFlowerForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biForestHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biFrozenRiver: a_HeightAmp = 0.4f; a_MidPoint = 57; break;
|
||||
case biFrozenOcean: a_HeightAmp = 0.12f; a_MidPoint = 45; break;
|
||||
case biIceMountains: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biIcePlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biIcePlainsSpikes: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biJungle: a_HeightAmp = 0.1f; a_MidPoint = 63; break;
|
||||
case biJungleEdge: a_HeightAmp = 0.15f; a_MidPoint = 62; break;
|
||||
case biJungleEdgeM: a_HeightAmp = 0.15f; a_MidPoint = 62; break;
|
||||
case biJungleHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biJungleM: a_HeightAmp = 0.1f; a_MidPoint = 63; break;
|
||||
case biMegaSpruceTaiga: a_HeightAmp = 0.09f; a_MidPoint = 64; break;
|
||||
case biMegaSpruceTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biMegaTaiga: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biMegaTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
case biMesa: a_HeightAmp = 0.09f; a_MidPoint = 61; break;
|
||||
case biMesaBryce: a_HeightAmp = 0.15f; a_MidPoint = 61; break;
|
||||
case biMesaPlateau: a_HeightAmp = 0.25f; a_MidPoint = 86; break;
|
||||
case biMesaPlateauF: a_HeightAmp = 0.25f; a_MidPoint = 96; break;
|
||||
case biMesaPlateauFM: a_HeightAmp = 0.25f; a_MidPoint = 96; break;
|
||||
case biMesaPlateauM: a_HeightAmp = 0.25f; a_MidPoint = 86; break;
|
||||
case biMushroomShore: a_HeightAmp = 0.075f; a_MidPoint = 60; break;
|
||||
case biMushroomIsland: a_HeightAmp = 0.06f; a_MidPoint = 80; break;
|
||||
case biNether: a_HeightAmp = 0.01f; a_MidPoint = 64; break;
|
||||
case biOcean: a_HeightAmp = 0.12f; a_MidPoint = 45; break;
|
||||
case biPlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biRiver: a_HeightAmp = 0.4f; a_MidPoint = 57; break;
|
||||
case biRoofedForest: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biRoofedForestM: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biSavanna: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biSavannaM: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biSavannaPlateau: a_HeightAmp = 0.3f; a_MidPoint = 85; break;
|
||||
case biSavannaPlateauM: a_HeightAmp = 0.012f; a_MidPoint = 105; break;
|
||||
case biStoneBeach: a_HeightAmp = 0.075f; a_MidPoint = 60; break;
|
||||
case biSunflowerPlains: a_HeightAmp = 0.3f; a_MidPoint = 62; break;
|
||||
case biSwampland: a_HeightAmp = 0.25f; a_MidPoint = 59; break;
|
||||
case biSwamplandM: a_HeightAmp = 0.11f; a_MidPoint = 59; break;
|
||||
case biTaiga: a_HeightAmp = 0.1f; a_MidPoint = 64; break;
|
||||
case biTaigaM: a_HeightAmp = 0.1f; a_MidPoint = 70; break;
|
||||
case biTaigaHills: a_HeightAmp = 0.075f; a_MidPoint = 68; break;
|
||||
default:
|
||||
{
|
||||
// Make a crazy terrain so that it stands out
|
||||
@ -899,78 +788,19 @@ void cBiomalNoise3DComposable::GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE
|
||||
|
||||
|
||||
|
||||
|
||||
void cBiomalNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
||||
void cBiomalNoise3DComposable::GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape)
|
||||
{
|
||||
GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ);
|
||||
|
||||
// Translate the noise array into Shape:
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
cChunkDef::SetHeight(a_HeightMap, x, z, m_SeaLevel);
|
||||
for (int y = cChunkDef::Height - 1; y > m_SeaLevel; y--)
|
||||
for (int y = 0; y < cChunkDef::Height; y++)
|
||||
{
|
||||
if (m_NoiseArray[y * 17 * 17 + z * 17 + x] <= m_AirThreshold)
|
||||
{
|
||||
cChunkDef::SetHeight(a_HeightMap, x, z, y);
|
||||
break;
|
||||
}
|
||||
} // for y
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBiomalNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
GenerateNoiseArrayIfNeeded(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ());
|
||||
|
||||
a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
|
||||
|
||||
// Make basic terrain composition:
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
int LastAir = a_ChunkDesc.GetHeight(x, z) + 1;
|
||||
bool HasHadWater = false;
|
||||
for (int y = LastAir; y < m_SeaLevel; y++)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STATIONARY_WATER);
|
||||
a_Shape[y + x * 256 + z * 256 * 16] = (m_NoiseArray[y + 257 * x + 257 * 17 * z] > m_AirThreshold) ? 0 : 1;
|
||||
}
|
||||
for (int y = LastAir - 1; y > 0; y--)
|
||||
{
|
||||
if (m_NoiseArray[x + 17 * z + 17 * 17 * y] > m_AirThreshold)
|
||||
{
|
||||
// "air" part
|
||||
LastAir = y;
|
||||
if (y < m_SeaLevel)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STATIONARY_WATER);
|
||||
HasHadWater = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// "ground" part:
|
||||
if (LastAir - y > 4)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_STONE);
|
||||
continue;
|
||||
}
|
||||
if (HasHadWater)
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_SAND);
|
||||
}
|
||||
else
|
||||
{
|
||||
a_ChunkDesc.SetBlockType(x, y, z, (LastAir == y + 1) ? E_BLOCK_GRASS : E_BLOCK_DIRT);
|
||||
}
|
||||
} // for y
|
||||
a_ChunkDesc.SetBlockType(x, 0, z, E_BLOCK_BEDROCK);
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
@ -978,3 +808,4 @@ void cBiomalNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc)
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -73,8 +73,7 @@ protected:
|
||||
|
||||
|
||||
class cNoise3DComposable :
|
||||
public cTerrainHeightGen,
|
||||
public cTerrainCompositionGen
|
||||
public cTerrainShapeGen
|
||||
{
|
||||
public:
|
||||
cNoise3DComposable(int a_Seed);
|
||||
@ -82,21 +81,18 @@ public:
|
||||
void Initialize(cIniFile & a_IniFile);
|
||||
|
||||
protected:
|
||||
/** The noise that is used to choose between density noise A and B. */
|
||||
cPerlinNoise m_ChoiceNoise;
|
||||
/** The 3D noise that is used to choose between density noise A and B. */
|
||||
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_ChoiceNoise;
|
||||
|
||||
/** Density 3D noise, variant A. */
|
||||
cPerlinNoise m_DensityNoiseA;
|
||||
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_DensityNoiseA;
|
||||
|
||||
/** Density 3D noise, variant B. */
|
||||
cPerlinNoise m_DensityNoiseB;
|
||||
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_DensityNoiseB;
|
||||
|
||||
/** Heightmap-like noise used to provide variance for low-amplitude biomes. */
|
||||
cPerlinNoise m_BaseNoise;
|
||||
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_BaseNoise;
|
||||
|
||||
/** Block height of the sealevel, used for composing the terrain. */
|
||||
int m_SeaLevel;
|
||||
|
||||
/** The main parameter of the generator, specifies the slope of the vertical linear gradient.
|
||||
A higher value means a steeper slope and a smaller total amplitude of the generated terrain. */
|
||||
NOISE_DATATYPE m_HeightAmplification;
|
||||
@ -131,12 +127,8 @@ protected:
|
||||
void GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
|
||||
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeShapeGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
|
||||
} ;
|
||||
|
||||
|
||||
@ -144,8 +136,7 @@ protected:
|
||||
|
||||
|
||||
class cBiomalNoise3DComposable :
|
||||
public cTerrainHeightGen,
|
||||
public cTerrainCompositionGen
|
||||
public cTerrainShapeGen
|
||||
{
|
||||
public:
|
||||
cBiomalNoise3DComposable(int a_Seed, cBiomeGenPtr a_BiomeGen);
|
||||
@ -153,24 +144,24 @@ public:
|
||||
void Initialize(cIniFile & a_IniFile);
|
||||
|
||||
protected:
|
||||
/** Number of columns around the pixel to query for biomes for averaging. */
|
||||
static const int AVERAGING_SIZE = 5;
|
||||
/** Number of columns around the pixel to query for biomes for averaging. Must be less than or equal to 16. */
|
||||
static const int AVERAGING_SIZE = 9;
|
||||
|
||||
/** Type used for a single parameter across the entire (downscaled) chunk. */
|
||||
typedef NOISE_DATATYPE ChunkParam[5 * 5];
|
||||
|
||||
|
||||
/** The noise that is used to choose between density noise A and B. */
|
||||
cPerlinNoise m_ChoiceNoise;
|
||||
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_ChoiceNoise;
|
||||
|
||||
/** Density 3D noise, variant A. */
|
||||
cPerlinNoise m_DensityNoiseA;
|
||||
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_DensityNoiseA;
|
||||
|
||||
/** Density 3D noise, variant B. */
|
||||
cPerlinNoise m_DensityNoiseB;
|
||||
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_DensityNoiseB;
|
||||
|
||||
/** Heightmap-like noise used to provide variance for low-amplitude biomes. */
|
||||
cPerlinNoise m_BaseNoise;
|
||||
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_BaseNoise;
|
||||
|
||||
/** The underlying biome generator. */
|
||||
cBiomeGenPtr m_BiomeGen;
|
||||
@ -198,7 +189,7 @@ protected:
|
||||
// Cache for the last calculated chunk (reused between heightmap and composition queries):
|
||||
int m_LastChunkX;
|
||||
int m_LastChunkZ;
|
||||
NOISE_DATATYPE m_NoiseArray[17 * 17 * 257]; // x + 17 * z + 17 * 17 * y
|
||||
NOISE_DATATYPE m_NoiseArray[17 * 17 * 257]; // 257 * x + y + 257 * 17 * z
|
||||
|
||||
/** Weights for summing up neighboring biomes. */
|
||||
NOISE_DATATYPE m_Weight[AVERAGING_SIZE * 2 + 1][AVERAGING_SIZE * 2 + 1];
|
||||
@ -216,13 +207,9 @@ protected:
|
||||
/** Returns the parameters for the specified biome. */
|
||||
void GetBiomeParams(EMCSBiome a_Biome, NOISE_DATATYPE & a_HeightAmp, NOISE_DATATYPE & a_MidPoint);
|
||||
|
||||
// cTerrainHeightGen overrides:
|
||||
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||
virtual void InitializeHeightGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
|
||||
|
||||
// cTerrainCompositionGen overrides:
|
||||
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override;
|
||||
virtual void InitializeCompoGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
|
||||
// cTerrainShapeGen overrides:
|
||||
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override;
|
||||
virtual void InitializeShapeGen(cIniFile & a_IniFile) override { Initialize(a_IniFile); }
|
||||
} ;
|
||||
|
||||
|
||||
|
145
src/Generating/ShapeGen.cpp
Normal file
145
src/Generating/ShapeGen.cpp
Normal file
@ -0,0 +1,145 @@
|
||||
|
||||
// ShapeGen.cpp
|
||||
|
||||
// Implements the function to create a cTerrainShapeGen descendant based on INI file settings
|
||||
|
||||
#include "Globals.h"
|
||||
#include "HeiGen.h"
|
||||
#include "../IniFile.h"
|
||||
#include "DistortedHeightmap.h"
|
||||
#include "EndGen.h"
|
||||
#include "Noise3DGenerator.h"
|
||||
#include "TwoHeights.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cTerrainHeightToShapeGen:
|
||||
|
||||
/** Converts old-style height-generators into new-style shape-generators. */
|
||||
class cTerrainHeightToShapeGen:
|
||||
public cTerrainShapeGen
|
||||
{
|
||||
public:
|
||||
cTerrainHeightToShapeGen(cTerrainHeightGenPtr a_HeightGen):
|
||||
m_HeightGen(a_HeightGen)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// cTerrainShapeGen overrides:
|
||||
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override
|
||||
{
|
||||
// Generate the heightmap:
|
||||
cChunkDef::HeightMap heightMap;
|
||||
m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, heightMap);
|
||||
|
||||
// Convert from heightmap to shape:
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
HEIGHTTYPE height = cChunkDef::GetHeight(heightMap, x, z) + 1;
|
||||
Byte * shapeColumn = &(a_Shape[(x + 16 * z) * 256]);
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
shapeColumn[y] = 1;
|
||||
}
|
||||
for (int y = height; y < cChunkDef::Height; y++)
|
||||
{
|
||||
shapeColumn[y] = 0;
|
||||
}
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
virtual void InitializeShapeGen(cIniFile & a_IniFile) override
|
||||
{
|
||||
m_HeightGen->InitializeHeightGen(a_IniFile);
|
||||
}
|
||||
|
||||
protected:
|
||||
/** The height generator being converted. */
|
||||
cTerrainHeightGenPtr m_HeightGen;
|
||||
};
|
||||
|
||||
typedef SharedPtr<cTerrainHeightToShapeGen> cTerrainHeightToShapeGenPtr;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cTerrainShapeGen:
|
||||
|
||||
cTerrainShapeGenPtr cTerrainShapeGen::CreateShapeGen(cIniFile & a_IniFile, cBiomeGenPtr a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault)
|
||||
{
|
||||
AString shapeGenName = a_IniFile.GetValueSet("Generator", "ShapeGen", "");
|
||||
if (shapeGenName.empty())
|
||||
{
|
||||
LOGWARN("[Generator] ShapeGen value not set in world.ini, using \"BiomalNoise3D\".");
|
||||
shapeGenName = "BiomalNoise3D";
|
||||
}
|
||||
|
||||
// If the shapegen is HeightMap, redirect to older HeightMap-based generators:
|
||||
if (NoCaseCompare(shapeGenName, "HeightMap") == 0)
|
||||
{
|
||||
cTerrainHeightGenPtr heightGen = cTerrainHeightGen::CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
|
||||
if (heightGen != nullptr)
|
||||
{
|
||||
return std::make_shared<cTerrainHeightToShapeGen>(heightGen);
|
||||
}
|
||||
|
||||
// The height gen was not recognized; several heightgens were promoted to shape gens, so let's try them instead:
|
||||
shapeGenName = a_IniFile.GetValue("Generator", "HeightGen", "");
|
||||
if (shapeGenName.empty())
|
||||
{
|
||||
LOGWARNING("[Generator] ShapeGen set to HeightMap, but HeightGen not set. Reverting to \"BiomalNoise3D\".");
|
||||
shapeGenName = "BiomalNoise3D";
|
||||
a_IniFile.SetValue("Generator", "ShapeGen", shapeGenName);
|
||||
}
|
||||
}
|
||||
|
||||
// Choose the shape generator based on the name:
|
||||
a_CacheOffByDefault = false;
|
||||
cTerrainShapeGenPtr res;
|
||||
if (NoCaseCompare(shapeGenName, "DistortedHeightmap") == 0)
|
||||
{
|
||||
res = std::make_shared<cDistortedHeightmap>(a_Seed, a_BiomeGen);
|
||||
}
|
||||
else if (NoCaseCompare(shapeGenName, "End") == 0)
|
||||
{
|
||||
res = std::make_shared<cEndGen>(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(shapeGenName, "BiomalNoise3D") == 0)
|
||||
{
|
||||
res = std::make_shared<cBiomalNoise3DComposable>(a_Seed, a_BiomeGen);
|
||||
}
|
||||
else if (NoCaseCompare(shapeGenName, "Noise3D") == 0)
|
||||
{
|
||||
res = std::make_shared<cNoise3DComposable>(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(shapeGenName, "TwoHeights") == 0)
|
||||
{
|
||||
res = CreateShapeGenTwoHeights(a_Seed, a_BiomeGen);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No match found, force-set the default and retry
|
||||
LOGWARN("Unknown ShapeGen \"%s\", using \"BiomalNoise3D\" instead.", shapeGenName.c_str());
|
||||
a_IniFile.SetValue("Generator", "ShapeGen", "BiomalNoise3D");
|
||||
return CreateShapeGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
|
||||
}
|
||||
|
||||
// Read the settings:
|
||||
res->InitializeShapeGen(a_IniFile);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -37,10 +37,13 @@ void cStructGenTrees::GenFinish(cChunkDesc & a_ChunkDesc)
|
||||
Dest = &WorkerDesc;
|
||||
WorkerDesc.SetChunkCoords(BaseX, BaseZ);
|
||||
|
||||
// TODO: This may cause a lot of wasted calculations, instead of pulling data out of a single (cChunkDesc) cache
|
||||
|
||||
cChunkDesc::Shape workerShape;
|
||||
m_BiomeGen->GenBiomes (BaseX, BaseZ, WorkerDesc.GetBiomeMap());
|
||||
m_HeightGen->GenHeightMap (BaseX, BaseZ, WorkerDesc.GetHeightMap());
|
||||
m_CompositionGen->ComposeTerrain(WorkerDesc);
|
||||
// TODO: Free the entity lists
|
||||
m_ShapeGen->GenShape (BaseX, BaseZ, workerShape);
|
||||
WorkerDesc.SetHeightFromShape (workerShape);
|
||||
m_CompositionGen->ComposeTerrain(WorkerDesc, workerShape);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -97,7 +100,7 @@ void cStructGenTrees::GenerateSingleTree(
|
||||
|
||||
int Height = a_ChunkDesc.GetHeight(x, z);
|
||||
|
||||
if ((Height <= 0) || (Height > 240))
|
||||
if ((Height <= 0) || (Height >= 230))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -125,6 +128,11 @@ void cStructGenTrees::GenerateSingleTree(
|
||||
// Outside the chunk
|
||||
continue;
|
||||
}
|
||||
if (itr->y >= cChunkDef::Height)
|
||||
{
|
||||
// Above the chunk, cut off (this shouldn't happen too often, we're limiting trees to y < 230)
|
||||
continue;
|
||||
}
|
||||
|
||||
BLOCKTYPE Block = a_ChunkDesc.GetBlockType(itr->x, itr->y, itr->z);
|
||||
switch (Block)
|
||||
@ -159,7 +167,7 @@ void cStructGenTrees::ApplyTreeImage(
|
||||
// Put the generated image into a_BlockTypes, push things outside this chunk into a_Blocks
|
||||
for (sSetBlockVector::const_iterator itr = a_Image.begin(), end = a_Image.end(); itr != end; ++itr)
|
||||
{
|
||||
if ((itr->ChunkX == a_ChunkX) && (itr->ChunkZ == a_ChunkZ))
|
||||
if ((itr->ChunkX == a_ChunkX) && (itr->ChunkZ == a_ChunkZ) && (itr->y < cChunkDef::Height))
|
||||
{
|
||||
// Inside this chunk, integrate into a_ChunkDesc:
|
||||
switch (a_ChunkDesc.GetBlockType(itr->x, itr->y, itr->z))
|
||||
@ -390,7 +398,7 @@ void cStructGenLakes::GenFinish(cChunkDesc & a_ChunkDesc)
|
||||
}
|
||||
|
||||
cBlockArea Lake;
|
||||
CreateLakeImage(ChunkX + x, ChunkZ + z, Lake);
|
||||
CreateLakeImage(ChunkX + x, ChunkZ + z, a_ChunkDesc.GetMinHeight(), Lake);
|
||||
|
||||
int OfsX = Lake.GetOriginX() + x * cChunkDef::Width;
|
||||
int OfsZ = Lake.GetOriginZ() + z * cChunkDef::Width;
|
||||
@ -404,25 +412,13 @@ void cStructGenLakes::GenFinish(cChunkDesc & a_ChunkDesc)
|
||||
|
||||
|
||||
|
||||
void cStructGenLakes::CreateLakeImage(int a_ChunkX, int a_ChunkZ, cBlockArea & a_Lake)
|
||||
void cStructGenLakes::CreateLakeImage(int a_ChunkX, int a_ChunkZ, int a_MaxLakeHeight, cBlockArea & a_Lake)
|
||||
{
|
||||
a_Lake.Create(16, 8, 16);
|
||||
a_Lake.Fill(cBlockArea::baTypes, E_BLOCK_SPONGE); // Sponge is the NOP blocktype for lake merging strategy
|
||||
|
||||
// Find the minimum height in this chunk:
|
||||
cChunkDef::HeightMap HeightMap;
|
||||
m_HeiGen->GenHeightMap(a_ChunkX, a_ChunkZ, HeightMap);
|
||||
HEIGHTTYPE MinHeight = HeightMap[0];
|
||||
for (size_t i = 1; i < ARRAYCOUNT(HeightMap); i++)
|
||||
{
|
||||
if (HeightMap[i] < MinHeight)
|
||||
{
|
||||
MinHeight = HeightMap[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Make a random position in the chunk by using a random 16 block XZ offset and random height up to chunk's max height minus 6
|
||||
MinHeight = std::max(MinHeight - 6, 2);
|
||||
int MinHeight = std::max(a_MaxLakeHeight - 6, 2);
|
||||
int Rnd = m_Noise.IntNoise3DInt(a_ChunkX, 128, a_ChunkZ) / 11;
|
||||
// Random offset [-8 .. 8], with higher probability around 0; add up four three-bit-wide randoms [0 .. 28], divide and subtract to get range
|
||||
int OffsetX = 4 * ((Rnd & 0x07) + ((Rnd & 0x38) >> 3) + ((Rnd & 0x1c0) >> 6) + ((Rnd & 0xe00) >> 9)) / 7 - 8;
|
||||
|
@ -24,11 +24,11 @@ class cStructGenTrees :
|
||||
public cFinishGen
|
||||
{
|
||||
public:
|
||||
cStructGenTrees(int a_Seed, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen, cTerrainCompositionGenPtr a_CompositionGen) :
|
||||
cStructGenTrees(int a_Seed, cBiomeGenPtr a_BiomeGen, cTerrainShapeGenPtr a_ShapeGen, cTerrainCompositionGenPtr a_CompositionGen) :
|
||||
m_Seed(a_Seed),
|
||||
m_Noise(a_Seed),
|
||||
m_BiomeGen(a_BiomeGen),
|
||||
m_HeightGen(a_HeightGen),
|
||||
m_ShapeGen(a_ShapeGen),
|
||||
m_CompositionGen(a_CompositionGen)
|
||||
{}
|
||||
|
||||
@ -37,12 +37,12 @@ protected:
|
||||
int m_Seed;
|
||||
cNoise m_Noise;
|
||||
cBiomeGenPtr m_BiomeGen;
|
||||
cTerrainHeightGenPtr m_HeightGen;
|
||||
cTerrainShapeGenPtr m_ShapeGen;
|
||||
cTerrainCompositionGenPtr m_CompositionGen;
|
||||
|
||||
/** Generates and applies an image of a single tree.
|
||||
Parts of the tree inside the chunk are applied to a_BlockX.
|
||||
Parts of the tree outside the chunk are stored in a_OutsideX
|
||||
Parts of the tree inside the chunk are applied to a_ChunkDesc.
|
||||
Parts of the tree outside the chunk are stored in a_OutsideXYZ
|
||||
*/
|
||||
void GenerateSingleTree(
|
||||
int a_ChunkX, int a_ChunkZ, int a_Seq,
|
||||
@ -51,7 +51,7 @@ protected:
|
||||
sSetBlockVector & a_OutsideOther
|
||||
) ;
|
||||
|
||||
/// Applies an image into chunk blockdata; all blocks outside the chunk will be appended to a_Overflow
|
||||
/** Applies an image into chunk blockdata; all blocks outside the chunk will be appended to a_Overflow. */
|
||||
void ApplyTreeImage(
|
||||
int a_ChunkX, int a_ChunkZ,
|
||||
cChunkDesc & a_ChunkDesc,
|
||||
@ -124,27 +124,30 @@ class cStructGenLakes :
|
||||
public cFinishGen
|
||||
{
|
||||
public:
|
||||
cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainHeightGenPtr a_HeiGen, int a_Probability) :
|
||||
cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainShapeGenPtr a_ShapeGen, int a_Probability) :
|
||||
m_Noise(a_Seed),
|
||||
m_Seed(a_Seed),
|
||||
m_Fluid(a_Fluid),
|
||||
m_HeiGen(a_HeiGen),
|
||||
m_ShapeGen(a_ShapeGen),
|
||||
m_Probability(a_Probability)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
cNoise m_Noise;
|
||||
int m_Seed;
|
||||
BLOCKTYPE m_Fluid;
|
||||
cTerrainHeightGenPtr m_HeiGen;
|
||||
int m_Probability; ///< Chance, 0 .. 100, of a chunk having the lake
|
||||
cNoise m_Noise;
|
||||
int m_Seed;
|
||||
BLOCKTYPE m_Fluid;
|
||||
cTerrainShapeGenPtr m_ShapeGen;
|
||||
|
||||
/** Chance, [0 .. 100], of a chunk having the lake. */
|
||||
int m_Probability;
|
||||
|
||||
|
||||
// cFinishGen override:
|
||||
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
|
||||
|
||||
/// Creates a lake image for the specified chunk into a_Lake
|
||||
void CreateLakeImage(int a_ChunkX, int a_ChunkZ, cBlockArea & a_Lake);
|
||||
/** Creates a lake image for the specified chunk into a_Lake. */
|
||||
void CreateLakeImage(int a_ChunkX, int a_ChunkZ, int a_MaxLakeHeight, cBlockArea & a_Lake);
|
||||
} ;
|
||||
|
||||
|
||||
|
121
src/Generating/TwoHeights.cpp
Normal file
121
src/Generating/TwoHeights.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
|
||||
// TwoHeights.cpp
|
||||
|
||||
// Implements the cTwoHeights class representing the terrain shape generator using two switched heightmaps
|
||||
|
||||
#include "Globals.h"
|
||||
#include "TwoHeights.h"
|
||||
#include "../Noise/InterpolNoise.h"
|
||||
#include "HeiGen.h"
|
||||
#include "../LinearUpscale.h"
|
||||
#include "../IniFile.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cTwoHeights:
|
||||
public cTerrainShapeGen
|
||||
{
|
||||
typedef cTerrainShapeGen super;
|
||||
public:
|
||||
cTwoHeights(int a_Seed, cBiomeGenPtr a_BiomeGen):
|
||||
m_Seed(a_Seed),
|
||||
m_Choice(a_Seed),
|
||||
m_HeightA(a_Seed + 1, a_BiomeGen),
|
||||
m_HeightB(a_Seed + 2, a_BiomeGen)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// cTerrainShapeGen override:
|
||||
virtual void GenShape(int a_ChunkX, int a_ChunkZ, cChunkDesc::Shape & a_Shape) override
|
||||
{
|
||||
// Generate the two heightmaps:
|
||||
cChunkDef::HeightMap heightsA;
|
||||
cChunkDef::HeightMap heightsB;
|
||||
m_HeightA.GenHeightMap(a_ChunkX, a_ChunkZ, heightsA);
|
||||
m_HeightB.GenHeightMap(a_ChunkX, a_ChunkZ, heightsB);
|
||||
|
||||
// Generate the choice noise:
|
||||
NOISE_DATATYPE smallChoice[33 * 5 * 5];
|
||||
NOISE_DATATYPE workspace[33 * 5 * 5];
|
||||
NOISE_DATATYPE startX = 0;
|
||||
NOISE_DATATYPE endX = 256 * m_FrequencyY;
|
||||
NOISE_DATATYPE startY = a_ChunkX * cChunkDef::Width * m_FrequencyX;
|
||||
NOISE_DATATYPE endY = (a_ChunkX * cChunkDef::Width + cChunkDef::Width + 1) * m_FrequencyX;
|
||||
NOISE_DATATYPE startZ = a_ChunkZ * cChunkDef::Width * m_FrequencyZ;
|
||||
NOISE_DATATYPE endZ = (a_ChunkZ * cChunkDef::Width + cChunkDef::Width + 1) * m_FrequencyZ;
|
||||
m_Choice.Generate3D(smallChoice, 33, 5, 5, startX, endX, startY, endY, startZ, endZ, workspace);
|
||||
NOISE_DATATYPE choice[257 * 17 * 17];
|
||||
LinearUpscale3DArray(smallChoice, 33, 5, 5, choice, 8, 4, 4);
|
||||
|
||||
// Generate the shape:
|
||||
int idxShape = 0;
|
||||
for (int z = 0; z < cChunkDef::Width; z++)
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
int idxChoice = 257 * 17 * z + 257 * x;
|
||||
NOISE_DATATYPE heightA = static_cast<NOISE_DATATYPE>(cChunkDef::GetHeight(heightsA, x, z));
|
||||
NOISE_DATATYPE heightB = static_cast<NOISE_DATATYPE>(cChunkDef::GetHeight(heightsB, x, z));
|
||||
for (int y = 0; y < cChunkDef::Height; y++)
|
||||
{
|
||||
int height = static_cast<int>(ClampedLerp(heightA, heightB, choice[idxChoice++]));
|
||||
a_Shape[idxShape++] = (y < height) ? 1 : 0;
|
||||
}
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
virtual void InitializeShapeGen(cIniFile & a_IniFile)
|
||||
{
|
||||
m_FrequencyX = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "TwoHeightsFrequencyX", 40));
|
||||
m_FrequencyY = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "TwoHeightsFrequencyY", 40));
|
||||
m_FrequencyZ = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "TwoHeightsFrequencyZ", 40));
|
||||
|
||||
// Initialize the two underlying height generators from an empty INI file:
|
||||
cIniFile empty;
|
||||
m_HeightA.InitializeHeightGen(empty);
|
||||
m_HeightB.InitializeHeightGen(empty);
|
||||
|
||||
// Add the choice octaves:
|
||||
NOISE_DATATYPE freq = 0.001f;
|
||||
NOISE_DATATYPE ampl = 1;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
m_Choice.AddOctave(freq, ampl);
|
||||
freq = freq * 2;
|
||||
ampl = ampl / 2;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
int m_Seed;
|
||||
|
||||
/** The noise used to decide between the two heightmaps. */
|
||||
cOctavedNoise<cInterpolNoise<Interp5Deg>> m_Choice;
|
||||
|
||||
/** The first height generator. */
|
||||
cHeiGenBiomal m_HeightA;
|
||||
|
||||
/** The second height generator. */
|
||||
cHeiGenBiomal m_HeightB;
|
||||
|
||||
/** The base frequencies for m_Choice in each of the world axis directions. */
|
||||
NOISE_DATATYPE m_FrequencyX, m_FrequencyY, m_FrequencyZ;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cTerrainShapeGenPtr CreateShapeGenTwoHeights(int a_Seed, cBiomeGenPtr a_BiomeGen)
|
||||
{
|
||||
return std::make_shared<cTwoHeights>(a_Seed, a_BiomeGen);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
23
src/Generating/TwoHeights.h
Normal file
23
src/Generating/TwoHeights.h
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
// TwoHeights.h
|
||||
|
||||
// Declares the function to create a new instance of the cTwoHeights terrain shape generator
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ComposableGenerator.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/** Creates and returns a new instance of the cTwoHeights terrain shape generator.
|
||||
The instance must be Initialize()-d before it is used. */
|
||||
extern cTerrainShapeGenPtr CreateShapeGenTwoHeights(int a_Seed, cBiomeGenPtr a_BiomeGen);
|
||||
|
||||
|
||||
|
||||
|
@ -18,8 +18,8 @@
|
||||
|
||||
/*
|
||||
How village generating works:
|
||||
By descending from a cGridStructGen, a semi-random grid is generated. A village may be generated for each of
|
||||
the grid's cells. Each cell checks the biomes in an entire chunk around it, only generating a village if all
|
||||
By descending from a cGridStructGen, a semi-random (jitter) grid is generated. A village may be generated for each
|
||||
of the grid's cells. Each cell checks the biomes in an entire chunk around it, only generating a village if all
|
||||
biomes are village-friendly. If yes, the entire village structure is built for that cell. If not, the cell
|
||||
is left village-less.
|
||||
|
||||
@ -125,7 +125,7 @@ public:
|
||||
m_Noise(a_Seed),
|
||||
m_MaxSize(a_MaxSize),
|
||||
m_Density(a_Density),
|
||||
m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, 255, a_OriginZ + a_MaxSize),
|
||||
m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, cChunkDef::Height - 1, a_OriginZ + a_MaxSize),
|
||||
m_Prefabs(a_Prefabs),
|
||||
m_HeightGen(a_HeightGen),
|
||||
m_RoadBlock(a_RoadBlock),
|
||||
|
@ -184,9 +184,9 @@ template class SizeChecker<UInt16, 2>;
|
||||
|
||||
// OS-dependent stuff:
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#define _WIN32_WINNT_WS03 // We want to target Windows XP with Service Pack 2 & Windows Server 2003 with Service Pack 1 and higher
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define _WIN32_WINNT _WIN32_WINNT_WS03 // We want to target Windows XP with Service Pack 2 & Windows Server 2003 with Service Pack 1 and higher
|
||||
|
||||
#include <Windows.h>
|
||||
#include <winsock2.h>
|
||||
|
@ -159,7 +159,7 @@ void cMonster::TickPathFinding()
|
||||
BLOCKTYPE BlockAtYP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 1, gCrossCoords[i].z + PosZ);
|
||||
BLOCKTYPE BlockAtYPP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ);
|
||||
int LowestY = FindFirstNonAirBlockPosition(gCrossCoords[i].x + PosX, gCrossCoords[i].z + PosZ);
|
||||
BLOCKTYPE BlockAtLowestY = m_World->GetBlock(gCrossCoords[i].x + PosX, LowestY, gCrossCoords[i].z + PosZ);
|
||||
BLOCKTYPE BlockAtLowestY = (LowestY >= cChunkDef::Height) ? E_BLOCK_AIR : m_World->GetBlock(gCrossCoords[i].x + PosX, LowestY, gCrossCoords[i].z + PosZ);
|
||||
|
||||
if (
|
||||
(!cBlockInfo::IsSolid(BlockAtY)) &&
|
||||
@ -452,7 +452,7 @@ int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
|
||||
}
|
||||
else
|
||||
{
|
||||
while (cBlockInfo::IsSolid(m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))) && (PosY < cChunkDef::Height))
|
||||
while ((PosY < cChunkDef::Height) && cBlockInfo::IsSolid(m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))))
|
||||
{
|
||||
PosY++;
|
||||
}
|
||||
|
@ -169,10 +169,12 @@ protected:
|
||||
/** Stores if mobile is currently moving towards the ultimate, final destination */
|
||||
bool m_bMovingToDestination;
|
||||
|
||||
/** Finds the first non-air block position (not the highest, as cWorld::GetHeight does)
|
||||
If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
|
||||
If current Y is solid, goes up to find first nonsolid block, and returns that */
|
||||
/** Finds the lowest non-air block position (not the highest, as cWorld::GetHeight does)
|
||||
If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
|
||||
If current Y is solid, goes up to find first nonsolid block, and returns that.
|
||||
If no suitable position is found, returns cChunkDef::Height. */
|
||||
int FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ);
|
||||
|
||||
/** Returns if a monster can actually reach a given height by jumping or walking */
|
||||
inline bool IsNextYPosReachable(int a_PosY)
|
||||
{
|
||||
|
271
src/World.cpp
271
src/World.cpp
@ -72,99 +72,130 @@ const int TIME_SPAWN_DIVISOR = 148;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cWorldLoadProgress:
|
||||
// cSpawnPrepare:
|
||||
|
||||
/// A simple thread that displays the progress of world loading / saving in cWorld::InitializeSpawn()
|
||||
class cWorldLoadProgress :
|
||||
public cIsThread
|
||||
/** Generates and lights the spawn area of the world. Runs as a separate thread. */
|
||||
class cSpawnPrepare:
|
||||
public cIsThread,
|
||||
public cChunkCoordCallback
|
||||
{
|
||||
public:
|
||||
cWorldLoadProgress(cWorld * a_World) :
|
||||
cIsThread("cWorldLoadProgress"),
|
||||
m_World(a_World)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
|
||||
void Stop(void)
|
||||
{
|
||||
m_ShouldTerminate = true;
|
||||
Wait();
|
||||
}
|
||||
|
||||
protected:
|
||||
typedef cIsThread super;
|
||||
|
||||
cWorld * m_World;
|
||||
|
||||
public:
|
||||
cSpawnPrepare(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance):
|
||||
super("SpawnPrepare"),
|
||||
m_World(a_World),
|
||||
m_SpawnChunkX(a_SpawnChunkX),
|
||||
m_SpawnChunkZ(a_SpawnChunkZ),
|
||||
m_PrepareDistance(a_PrepareDistance),
|
||||
m_MaxIdx(a_PrepareDistance * a_PrepareDistance),
|
||||
m_NumPrepared(0),
|
||||
m_LastReportChunkCount(0)
|
||||
{
|
||||
// Start the thread:
|
||||
Start();
|
||||
|
||||
// Wait for start confirmation, so that the thread can be waited-upon after the constructor returns:
|
||||
m_EvtStarted.Wait();
|
||||
}
|
||||
|
||||
|
||||
// cIsThread override:
|
||||
virtual void Execute(void) override
|
||||
{
|
||||
for (;;)
|
||||
// Confirm thread start:
|
||||
m_EvtStarted.Set();
|
||||
|
||||
// Queue the initial chunks:
|
||||
m_MaxIdx = m_PrepareDistance * m_PrepareDistance;
|
||||
int maxQueue = std::min(m_MaxIdx - 1, 100); // Number of chunks to queue at once
|
||||
m_NextIdx = maxQueue;
|
||||
m_LastReportTime = std::chrono::steady_clock::now();
|
||||
for (int i = 0; i < maxQueue; i++)
|
||||
{
|
||||
LOG("" SIZE_T_FMT " chunks to load, %d chunks to generate",
|
||||
m_World->GetStorage().GetLoadQueueLength(),
|
||||
m_World->GetGenerator().GetQueueLength()
|
||||
);
|
||||
|
||||
// Wait for 2 sec, but be "reasonably wakeable" when the thread is to finish
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
if (m_ShouldTerminate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // for (-ever)
|
||||
int chunkX, chunkZ;
|
||||
DecodeChunkCoords(i, chunkX, chunkZ);
|
||||
m_World.GetLightingThread().QueueChunk(chunkX, chunkZ, this);
|
||||
} // for i
|
||||
|
||||
// Wait for the lighting thread to prepare everything. Event is set in the Call() callback:
|
||||
m_EvtFinished.Wait();
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cWorldLightingProgress:
|
||||
|
||||
/// A simple thread that displays the progress of world lighting in cWorld::InitializeSpawn()
|
||||
class cWorldLightingProgress :
|
||||
public cIsThread
|
||||
{
|
||||
public:
|
||||
cWorldLightingProgress(cLightingThread * a_Lighting) :
|
||||
cIsThread("cWorldLightingProgress"),
|
||||
m_Lighting(a_Lighting)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
|
||||
void Stop(void)
|
||||
{
|
||||
m_ShouldTerminate = true;
|
||||
Wait();
|
||||
}
|
||||
|
||||
protected:
|
||||
cWorld & m_World;
|
||||
int m_SpawnChunkX;
|
||||
int m_SpawnChunkZ;
|
||||
int m_PrepareDistance;
|
||||
|
||||
cLightingThread * m_Lighting;
|
||||
|
||||
virtual void Execute(void) override
|
||||
/** The index of the next chunk to be queued in the lighting thread. */
|
||||
int m_NextIdx;
|
||||
|
||||
/** The maximum index of the prepared chunks. Queueing stops when m_NextIdx reaches this number. */
|
||||
int m_MaxIdx;
|
||||
|
||||
/** Total number of chunks already finished preparing. Preparation finishes when this number reaches m_MaxIdx. */
|
||||
int m_NumPrepared;
|
||||
|
||||
/** Event used to signal that the thread has started. */
|
||||
cEvent m_EvtStarted;
|
||||
|
||||
/** Event used to signal that the preparation is finished. */
|
||||
cEvent m_EvtFinished;
|
||||
|
||||
/** The timestamp of the last progress report emitted. */
|
||||
std::chrono::steady_clock::time_point m_LastReportTime;
|
||||
|
||||
/** Number of chunks prepared when the last progress report was emitted. */
|
||||
int m_LastReportChunkCount;
|
||||
|
||||
// cChunkCoordCallback override:
|
||||
virtual void Call(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
for (;;)
|
||||
// Check if this was the last chunk:
|
||||
m_NumPrepared += 1;
|
||||
if (m_NumPrepared >= m_MaxIdx)
|
||||
{
|
||||
LOG("" SIZE_T_FMT " chunks remaining to light", m_Lighting->GetQueueLength()
|
||||
m_EvtFinished.Set();
|
||||
}
|
||||
|
||||
// Queue another chunk, if appropriate:
|
||||
if (m_NextIdx < m_MaxIdx)
|
||||
{
|
||||
int chunkX, chunkZ;
|
||||
DecodeChunkCoords(m_NextIdx, chunkX, chunkZ);
|
||||
m_World.GetLightingThread().QueueChunk(chunkX, chunkZ, this);
|
||||
m_NextIdx += 1;
|
||||
}
|
||||
|
||||
// Report progress every 1 second:
|
||||
auto Now = std::chrono::steady_clock::now();
|
||||
if (Now - m_LastReportTime > std::chrono::seconds(1))
|
||||
{
|
||||
float PercentDone = static_cast<float>(m_NumPrepared * 100) / m_MaxIdx;
|
||||
float ChunkSpeed = static_cast<float>((m_NumPrepared - m_LastReportChunkCount) * 1000) / std::chrono::duration_cast<std::chrono::milliseconds>(Now - m_LastReportTime).count();
|
||||
LOG("Preparing spawn (%s): %.02f%% (%d/%d; %.02f chunks/s)",
|
||||
m_World.GetName().c_str(), PercentDone, m_NumPrepared, m_MaxIdx, ChunkSpeed
|
||||
);
|
||||
|
||||
// Wait for 2 sec, but be "reasonably wakeable" when the thread is to finish
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
if (m_ShouldTerminate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // for (-ever)
|
||||
m_LastReportTime = Now;
|
||||
m_LastReportChunkCount = m_NumPrepared;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Decodes the index into chunk coords. Provides the specific chunk ordering. */
|
||||
void DecodeChunkCoords(int a_Idx, int & a_ChunkX, int & a_ChunkZ)
|
||||
{
|
||||
// A zigzag pattern from the top to bottom, each row alternating between forward-x and backward-x:
|
||||
int z = a_Idx / m_PrepareDistance;
|
||||
int x = a_Idx % m_PrepareDistance;
|
||||
if ((z & 1) == 0)
|
||||
{
|
||||
// Reverse every second row:
|
||||
x = m_PrepareDistance - 1 - x;
|
||||
}
|
||||
a_ChunkZ = m_SpawnChunkZ + z - m_PrepareDistance / 2;
|
||||
a_ChunkX = m_SpawnChunkX + x - m_PrepareDistance / 2;
|
||||
}
|
||||
};
|
||||
|
||||
@ -206,7 +237,7 @@ void cWorld::cTickThread::Execute(void)
|
||||
while (!m_ShouldTerminate)
|
||||
{
|
||||
auto NowTime = std::chrono::steady_clock::now();
|
||||
m_World.Tick(std::chrono::duration_cast<std::chrono::milliseconds>(NowTime - LastTime).count(), std::chrono::duration_cast<std::chrono::duration<int>>(TickTime).count());
|
||||
m_World.Tick(static_cast<float>(std::chrono::duration_cast<std::chrono::milliseconds>(NowTime - LastTime).count()), std::chrono::duration_cast<std::chrono::duration<int>>(TickTime).count());
|
||||
TickTime = std::chrono::steady_clock::now() - NowTime;
|
||||
|
||||
if (TickTime < msPerTick)
|
||||
@ -426,53 +457,9 @@ void cWorld::InitializeSpawn(void)
|
||||
IniFile.ReadFile(m_IniFileName);
|
||||
int ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist);
|
||||
IniFile.WriteFile(m_IniFileName);
|
||||
|
||||
LOG("Preparing spawn area in world \"%s\", %d x %d chunks, total %d chunks...", m_WorldName.c_str(), ViewDist, ViewDist, ViewDist * ViewDist);
|
||||
for (int x = 0; x < ViewDist; x++)
|
||||
{
|
||||
for (int z = 0; z < ViewDist; z++)
|
||||
{
|
||||
m_ChunkMap->TouchChunk(x + ChunkX-(ViewDist - 1) / 2, z + ChunkZ-(ViewDist - 1) / 2); // Queue the chunk in the generator / loader
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Display progress during this process:
|
||||
cWorldLoadProgress Progress(this);
|
||||
|
||||
// Wait for the loader to finish loading
|
||||
m_Storage.WaitForLoadQueueEmpty();
|
||||
|
||||
// Wait for the generator to finish generating
|
||||
m_Generator.WaitForQueueEmpty();
|
||||
|
||||
// Wait for the loader to finish saving
|
||||
m_Storage.WaitForSaveQueueEmpty();
|
||||
|
||||
Progress.Stop();
|
||||
}
|
||||
|
||||
// Light all chunks that have been newly generated:
|
||||
LOG("Lighting spawn area in world \"%s\"...", m_WorldName.c_str());
|
||||
|
||||
for (int x = 0; x < ViewDist; x++)
|
||||
{
|
||||
int ChX = x + ChunkX-(ViewDist - 1) / 2;
|
||||
for (int z = 0; z < ViewDist; z++)
|
||||
{
|
||||
int ChZ = z + ChunkZ-(ViewDist - 1) / 2;
|
||||
if (!m_ChunkMap->IsChunkLighted(ChX, ChZ))
|
||||
{
|
||||
m_Lighting.QueueChunk(ChX, ChZ); // Queue the chunk in the lighting thread
|
||||
}
|
||||
} // for z
|
||||
} // for x
|
||||
|
||||
{
|
||||
cWorldLightingProgress Progress(&m_Lighting);
|
||||
m_Lighting.WaitForQueueEmpty();
|
||||
Progress.Stop();
|
||||
}
|
||||
cSpawnPrepare prep(*this, ChunkX, ChunkZ, ViewDist);
|
||||
prep.Wait();
|
||||
|
||||
#ifdef TEST_LINEBLOCKTRACER
|
||||
// DEBUG: Test out the cLineBlockTracer class by tracing a few lines:
|
||||
@ -735,28 +722,32 @@ void cWorld::InitialiseGeneratorDefaults(cIniFile & a_IniFile)
|
||||
{
|
||||
case dimEnd:
|
||||
{
|
||||
a_IniFile.GetValueSet("Generator", "BiomeGen", "Constant");
|
||||
a_IniFile.GetValueSet("Generator", "ConstantBiome", "End");
|
||||
a_IniFile.GetValueSet("Generator", "HeightGen", "Biomal");
|
||||
a_IniFile.GetValueSet("Generator", "Generator", "Composable");
|
||||
a_IniFile.GetValueSet("Generator", "BiomeGen", "Constant");
|
||||
a_IniFile.GetValueSet("Generator", "ConstantBiome", "End");
|
||||
a_IniFile.GetValueSet("Generator", "ShapeGen", "End");
|
||||
a_IniFile.GetValueSet("Generator", "CompositionGen", "End");
|
||||
break;
|
||||
}
|
||||
case dimOverworld:
|
||||
{
|
||||
a_IniFile.GetValueSet("Generator", "BiomeGen", "MultiStepMap");
|
||||
a_IniFile.GetValueSet("Generator", "HeightGen", "DistortedHeightmap");
|
||||
a_IniFile.GetValueSet("Generator", "CompositionGen", "DistortedHeightmap");
|
||||
a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator");
|
||||
a_IniFile.GetValueSet("Generator", "Generator", "Composable");
|
||||
a_IniFile.GetValueSet("Generator", "BiomeGen", "Grown");
|
||||
a_IniFile.GetValueSet("Generator", "ShapeGen", "BiomalNoise3D");
|
||||
a_IniFile.GetValueSet("Generator", "CompositionGen", "Biomal");
|
||||
a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, Villages, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator");
|
||||
break;
|
||||
}
|
||||
case dimNether:
|
||||
{
|
||||
a_IniFile.GetValueSet("Generator", "BiomeGen", "Constant");
|
||||
a_IniFile.GetValueSet("Generator", "ConstantBiome", "Nether");
|
||||
a_IniFile.GetValueSet("Generator", "HeightGen", "Flat");
|
||||
a_IniFile.GetValueSet("Generator", "FlatHeight", "128");
|
||||
a_IniFile.GetValueSet("Generator", "CompositionGen", "Nether");
|
||||
a_IniFile.GetValueSet("Generator", "Finishers", "WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator");
|
||||
a_IniFile.GetValueSet("Generator", "Generator", "Composable");
|
||||
a_IniFile.GetValueSet("Generator", "BiomeGen", "Constant");
|
||||
a_IniFile.GetValueSet("Generator", "ConstantBiome", "Nether");
|
||||
a_IniFile.GetValueSet("Generator", "ShapeGen", "HeightMap");
|
||||
a_IniFile.GetValueSet("Generator", "HeightGen", "Flat");
|
||||
a_IniFile.GetValueSet("Generator", "FlatHeight", "128");
|
||||
a_IniFile.GetValueSet("Generator", "CompositionGen", "Nether");
|
||||
a_IniFile.GetValueSet("Generator", "Finishers", "WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator");
|
||||
a_IniFile.GetValueSet("Generator", "BottomLavaHeight", "30");
|
||||
break;
|
||||
}
|
||||
|
@ -696,6 +696,8 @@ public:
|
||||
inline size_t GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export
|
||||
inline size_t GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export
|
||||
|
||||
cLightingThread & GetLightingThread(void) { return m_Lighting; }
|
||||
|
||||
void InitializeSpawn(void);
|
||||
|
||||
/** Starts threads that belong to this world */
|
||||
|
Loading…
Reference in New Issue
Block a user