summaryrefslogtreecommitdiffstats
path: root/src/Generating
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Generating/BioGen.cpp26
-rw-r--r--src/Generating/CMakeLists.txt2
-rw-r--r--src/Generating/Caves.cpp6
-rw-r--r--src/Generating/Caves.h16
-rw-r--r--src/Generating/ChunkDesc.cpp37
-rw-r--r--src/Generating/ChunkDesc.h42
-rw-r--r--src/Generating/ChunkGenerator.cpp13
-rw-r--r--src/Generating/CompoGen.cpp4
-rw-r--r--src/Generating/ComposableGenerator.cpp171
-rw-r--r--src/Generating/ComposableGenerator.h56
-rw-r--r--src/Generating/FinishGen.cpp6
-rw-r--r--src/Generating/HeiGen.cpp2
-rw-r--r--src/Generating/MineShafts.cpp6
-rw-r--r--src/Generating/MineShafts.h6
-rw-r--r--src/Generating/NetherFortGen.cpp275
-rw-r--r--src/Generating/NetherFortGen.h86
-rw-r--r--src/Generating/Noise3DGenerator.cpp2
-rw-r--r--src/Generating/POCPieceGenerator.cpp270
-rw-r--r--src/Generating/POCPieceGenerator.h54
-rw-r--r--src/Generating/PieceGenerator.cpp625
-rw-r--r--src/Generating/PieceGenerator.h247
-rw-r--r--src/Generating/Prefab.cpp316
-rw-r--r--src/Generating/Prefab.h105
-rw-r--r--src/Generating/Prefabs/CMakeLists.txt13
-rw-r--r--src/Generating/Prefabs/NetherFortPrefabs.cpp2758
-rw-r--r--src/Generating/Prefabs/NetherFortPrefabs.h15
-rw-r--r--src/Generating/Ravines.cpp2
-rw-r--r--src/Generating/Ravines.h6
-rw-r--r--src/Generating/StructGen.cpp32
-rw-r--r--src/Generating/StructGen.h30
-rw-r--r--src/Generating/Trees.cpp20
-rw-r--r--src/Generating/Trees.h6
32 files changed, 5027 insertions, 228 deletions
diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp
index f89b1800d..32a687201 100644
--- a/src/Generating/BioGen.cpp
+++ b/src/Generating/BioGen.cpp
@@ -97,7 +97,7 @@ void cBioGenConstant::InitializeBiomeGen(cIniFile & a_IniFile)
{
AString Biome = a_IniFile.GetValueSet("Generator", "ConstantBiome", "Plains");
m_Biome = StringToBiome(Biome);
- if (m_Biome == -1)
+ if (m_Biome == biInvalidBiome)
{
LOGWARN("[Generator]::ConstantBiome value \"%s\" not recognized, using \"Plains\".", Biome.c_str());
m_Biome = biPlains;
@@ -233,7 +233,7 @@ void cBiomeGenList::InitializeBiomes(const AString & a_Biomes)
}
}
EMCSBiome Biome = StringToBiome(Split2[0]);
- if (Biome != -1)
+ if (Biome != biInvalidBiome)
{
for (int i = 0; i < Count; i++)
{
@@ -371,8 +371,8 @@ void cBioGenDistortedVoronoi::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::B
Distort(BaseX + x * 4, BaseZ + z * 4, DistortX[4 * x][4 * z], DistortZ[4 * x][4 * z]);
}
- LinearUpscale2DArrayInPlace(&DistortX[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4);
- LinearUpscale2DArrayInPlace(&DistortZ[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4);
+ LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
+ LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortZ[0][0]);
for (int z = 0; z < cChunkDef::Width; z++)
{
@@ -477,8 +477,8 @@ void cBioGenMultiStepMap::DecideOceanLandMushroom(int a_ChunkX, int a_ChunkZ, cC
{
Distort(BaseX + x * 4, BaseZ + z * 4, DistortX[4 * x][4 * z], DistortZ[4 * x][4 * z], DistortSize);
}
- LinearUpscale2DArrayInPlace(&DistortX[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4);
- LinearUpscale2DArrayInPlace(&DistortZ[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4);
+ LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
+ LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortZ[0][0]);
// Prepare a 9x9 area of neighboring cell seeds
// (assuming that 7x7 cell area is larger than a chunk being generated)
@@ -500,7 +500,7 @@ void cBioGenMultiStepMap::DecideOceanLandMushroom(int a_ChunkX, int a_ChunkZ, cC
int OffsetZ = (m_Noise4.IntNoise3DInt(RealCellX, 32 * RealCellX - 16 * RealCellZ, RealCellZ) / 8) % m_OceanCellSize;
SeedX[xc][zc] = CellBlockX + OffsetX;
SeedZ[xc][zc] = CellBlockZ + OffsetZ;
- SeedV[xc][zc] = (((m_Noise6.IntNoise3DInt(RealCellX, RealCellX - RealCellZ + 1000, RealCellZ) / 11) % 256) > 90) ? biOcean : ((EMCSBiome)(-1));
+ SeedV[xc][zc] = (((m_Noise6.IntNoise3DInt(RealCellX, RealCellX - RealCellZ + 1000, RealCellZ) / 11) % 256) > 90) ? biOcean : (biInvalidBiome);
} // for z
} // for x
@@ -573,7 +573,7 @@ void cBioGenMultiStepMap::AddRivers(int a_ChunkX, int a_ChunkZ, cChunkDef::Biome
float NoiseCoordZ = (float)(a_ChunkZ * cChunkDef::Width + z) / m_RiverCellSize;
for (int x = 0; x < cChunkDef::Width; x++)
{
- if (cChunkDef::GetBiome(a_BiomeMap, x, z) != -1)
+ if (cChunkDef::GetBiome(a_BiomeMap, x, z) != biInvalidBiome)
{
// Biome already set, skip this column
continue;
@@ -651,8 +651,8 @@ void cBioGenMultiStepMap::BuildTemperatureHumidityMaps(int a_ChunkX, int a_Chunk
HumidityMap[x + 17 * z] = NoiseH;
} // for x
} // for z
- LinearUpscale2DArrayInPlace(TemperatureMap, 17, 17, 8, 8);
- LinearUpscale2DArrayInPlace(HumidityMap, 17, 17, 8, 8);
+ LinearUpscale2DArrayInPlace<17, 17, 8, 8>(TemperatureMap);
+ LinearUpscale2DArrayInPlace<17, 17, 8, 8>(HumidityMap);
// Re-map into integral values in [0 .. 255] range:
for (size_t idx = 0; idx < ARRAYCOUNT(a_TemperatureMap); idx++)
@@ -693,7 +693,7 @@ void cBioGenMultiStepMap::DecideLandBiomes(cChunkDef::BiomeMap & a_BiomeMap, con
int idxZ = 17 * z;
for (int x = 0; x < cChunkDef::Width; x++)
{
- if (cChunkDef::GetBiome(a_BiomeMap, x, z) != -1)
+ if (cChunkDef::GetBiome(a_BiomeMap, x, z) != biInvalidBiome)
{
// Already set before
continue;
@@ -778,8 +778,8 @@ void cBioGenTwoLevel::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap
DistortZ[4 * x][4 * z] = BlockZ + (int)(64 * NoiseZ);
}
- LinearUpscale2DArrayInPlace(&DistortX[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4);
- LinearUpscale2DArrayInPlace(&DistortZ[0][0], cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4);
+ LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortX[0][0]);
+ LinearUpscale2DArrayInPlace<cChunkDef::Width + 1, cChunkDef::Width + 1, 4, 4>(&DistortZ[0][0]);
// Apply distortion to each block coord, then query the voronoi maps for biome group and biome index and choose biome based on that:
for (int z = 0; z < cChunkDef::Width; z++)
diff --git a/src/Generating/CMakeLists.txt b/src/Generating/CMakeLists.txt
index e1ba299fc..1147744c0 100644
--- a/src/Generating/CMakeLists.txt
+++ b/src/Generating/CMakeLists.txt
@@ -9,3 +9,5 @@ file(GLOB SOURCE
)
add_library(Generating ${SOURCE})
+
+target_link_libraries(Generating OSSupport iniFile Blocks)
diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp
index 2571e6b77..98b7c8681 100644
--- a/src/Generating/Caves.cpp
+++ b/src/Generating/Caves.cpp
@@ -762,7 +762,7 @@ void cStructGenWormNestCaves::ClearCache(void)
-void cStructGenWormNestCaves::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenWormNestCaves::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
@@ -902,7 +902,7 @@ static float GetMarbleNoise( float x, float y, float z, cNoise & a_Noise )
-void cStructGenMarbleCaves::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenMarbleCaves::GenFinish(cChunkDesc & a_ChunkDesc)
{
cNoise Noise(m_Seed);
for (int z = 0; z < cChunkDef::Width; z++)
@@ -938,7 +938,7 @@ void cStructGenMarbleCaves::GenStructures(cChunkDesc & a_ChunkDesc)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenDualRidgeCaves:
-void cStructGenDualRidgeCaves::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenDualRidgeCaves::GenFinish(cChunkDesc & a_ChunkDesc)
{
for (int z = 0; z < cChunkDef::Width; z++)
{
diff --git a/src/Generating/Caves.h b/src/Generating/Caves.h
index ea7f10bf4..7c45c056b 100644
--- a/src/Generating/Caves.h
+++ b/src/Generating/Caves.h
@@ -20,7 +20,7 @@
class cStructGenMarbleCaves :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenMarbleCaves(int a_Seed) : m_Seed(a_Seed) {}
@@ -29,8 +29,8 @@ protected:
int m_Seed;
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -38,7 +38,7 @@ protected:
class cStructGenDualRidgeCaves :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenDualRidgeCaves(int a_Seed, float a_Threshold) :
@@ -55,8 +55,8 @@ protected:
int m_Seed;
float m_Threshold;
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -64,7 +64,7 @@ protected:
class cStructGenWormNestCaves :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenWormNestCaves(int a_Seed, int a_Size = 64, int a_Grid = 96, int a_MaxOffset = 128) :
@@ -94,7 +94,7 @@ protected:
void GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cCaveSystems & a_Caves);
// cStructGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp
index af1a8a6c7..7711723fc 100644
--- a/src/Generating/ChunkDesc.cpp
+++ b/src/Generating/ChunkDesc.cpp
@@ -118,9 +118,9 @@ void cChunkDesc::SetBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_B
-void cChunkDesc::SetBiome(int a_RelX, int a_RelZ, int a_BiomeID)
+void cChunkDesc::SetBiome(int a_RelX, int a_RelZ, EMCSBiome a_BiomeID)
{
- cChunkDef::SetBiome(m_BiomeMap, a_RelX, a_RelZ, (EMCSBiome)a_BiomeID);
+ cChunkDef::SetBiome(m_BiomeMap, a_RelX, a_RelZ, a_BiomeID);
}
@@ -209,6 +209,7 @@ bool cChunkDesc::IsUsingDefaultComposition(void) const
void cChunkDesc::SetUseDefaultStructures(bool a_bUseDefaultStructures)
{
+ LOGWARNING("%s: Structures are no longer accounted for, use Finishers instead", __FUNCTION__);
m_bUseDefaultStructures = a_bUseDefaultStructures;
}
@@ -218,6 +219,7 @@ void cChunkDesc::SetUseDefaultStructures(bool a_bUseDefaultStructures)
bool cChunkDesc::IsUsingDefaultStructures(void) const
{
+ LOGWARNING("%s: Structures are no longer accounted for, use Finishers instead", __FUNCTION__);
return m_bUseDefaultStructures;
}
@@ -341,9 +343,9 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
int SizeY = a_MaxRelY - a_MinRelY;
int SizeZ = a_MaxRelZ - a_MinRelZ;
a_Dest.Clear();
- a_Dest.m_OriginX = m_ChunkX * cChunkDef::Width + a_MinRelX;
- a_Dest.m_OriginY = a_MinRelY;
- a_Dest.m_OriginZ = m_ChunkZ * cChunkDef::Width + a_MinRelZ;
+ a_Dest.m_Origin.x = m_ChunkX * cChunkDef::Width + a_MinRelX;
+ a_Dest.m_Origin.y = a_MinRelY;
+ a_Dest.m_Origin.z = m_ChunkZ * cChunkDef::Width + a_MinRelZ;
a_Dest.SetSize(SizeX, SizeY, SizeZ, cBlockArea::baTypes | cBlockArea::baMetas);
for (int y = 0; y < SizeY; y++)
@@ -562,6 +564,31 @@ cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ)
+void cChunkDesc::UpdateHeightmap(void)
+{
+ for (int x = 0; x < cChunkDef::Width; x++)
+ {
+ for (int z = 0; z < cChunkDef::Width; z++)
+ {
+ int Height = 0;
+ for (int y = cChunkDef::Height - 1; y > 0; y--)
+ {
+ BLOCKTYPE BlockType = GetBlockType(x, y, z);
+ if (BlockType != E_BLOCK_AIR)
+ {
+ Height = y;
+ break;
+ }
+ } // for y
+ SetHeight(x, z, Height);
+ } // for z
+ } // for x
+}
+
+
+
+
+
void cChunkDesc::CompressBlockMetas(cChunkDef::BlockNibbles & a_DestMetas)
{
const NIBBLETYPE * AreaMetas = m_BlockArea.GetBlockMetas();
diff --git a/src/Generating/ChunkDesc.h b/src/Generating/ChunkDesc.h
index e130c463f..8edc2800b 100644
--- a/src/Generating/ChunkDesc.h
+++ b/src/Generating/ChunkDesc.h
@@ -30,7 +30,7 @@ class cChunkDesc
public:
// tolua_end
- /// Uncompressed block metas, 1 meta per byte
+ /** Uncompressed block metas, 1 meta per byte */
typedef NIBBLETYPE BlockNibbleBytes[cChunkDef::NumBlocks];
cChunkDesc(int a_ChunkX, int a_ChunkZ);
@@ -53,9 +53,11 @@ public:
void SetBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockMeta);
NIBBLETYPE GetBlockMeta(int a_RelX, int a_RelY, int a_RelZ);
- void SetBiome(int a_RelX, int a_RelZ, int a_BiomeID);
+ void SetBiome(int a_RelX, int a_RelZ, EMCSBiome a_BiomeID);
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
void SetHeight(int a_RelX, int a_RelZ, int a_Height);
int GetHeight(int a_RelX, int a_RelZ);
@@ -71,16 +73,16 @@ public:
void SetUseDefaultFinish(bool a_bUseDefaultFinish);
bool IsUsingDefaultFinish(void) const;
- /// Writes the block area into the chunk, with its origin set at the specified relative coords. Area's data overwrite everything in the chunk.
+ /** Writes the block area into the chunk, with its origin set at the specified relative coords. Area's data overwrite everything in the chunk. */
void WriteBlockArea(const cBlockArea & a_BlockArea, int a_RelX, int a_RelY, int a_RelZ, cBlockArea::eMergeStrategy a_MergeStrategy = cBlockArea::msOverwrite);
- /// Reads an area from the chunk into a cBlockArea, blocktypes and blockmetas
+ /** 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;
- /// Fills the relative cuboid with specified block; allows cuboid out of range of this chunk
+ /** Fills the relative cuboid with specified block; allows cuboid out of range of this chunk */
void FillRelCuboid(
int a_MinX, int a_MaxX,
int a_MinY, int a_MaxY,
@@ -88,7 +90,7 @@ public:
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
);
- /// Fills the relative cuboid with specified block; allows cuboid out of range of this chunk
+ /** Fills the relative cuboid with specified block; allows cuboid out of range of this chunk */
void FillRelCuboid(const cCuboid & a_RelCuboid, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
FillRelCuboid(
@@ -99,7 +101,7 @@ public:
);
}
- /// Replaces the specified src blocks in the cuboid by the dst blocks; allows cuboid out of range of this chunk
+ /** Replaces the specified src blocks in the cuboid by the dst blocks; allows cuboid out of range of this chunk */
void ReplaceRelCuboid(
int a_MinX, int a_MaxX,
int a_MinY, int a_MaxY,
@@ -108,7 +110,7 @@ public:
BLOCKTYPE a_DstType, NIBBLETYPE a_DstMeta
);
- /// Replaces the specified src blocks in the cuboid by the dst blocks; allows cuboid out of range of this chunk
+ /** Replaces the specified src blocks in the cuboid by the dst blocks; allows cuboid out of range of this chunk */
void ReplaceRelCuboid(
const cCuboid & a_RelCuboid,
BLOCKTYPE a_SrcType, NIBBLETYPE a_SrcMeta,
@@ -124,7 +126,7 @@ public:
);
}
- /// Replaces the blocks in the cuboid by the dst blocks if they are considered non-floor (air, water); allows cuboid out of range of this chunk
+ /** Replaces the blocks in the cuboid by the dst blocks if they are considered non-floor (air, water); allows cuboid out of range of this chunk */
void FloorRelCuboid(
int a_MinX, int a_MaxX,
int a_MinY, int a_MaxY,
@@ -132,7 +134,7 @@ public:
BLOCKTYPE a_DstType, NIBBLETYPE a_DstMeta
);
- /// Replaces the blocks in the cuboid by the dst blocks if they are considered non-floor (air, water); allows cuboid out of range of this chunk
+ /** Replaces the blocks in the cuboid by the dst blocks if they are considered non-floor (air, water); allows cuboid out of range of this chunk */
void FloorRelCuboid(
const cCuboid & a_RelCuboid,
BLOCKTYPE a_DstType, NIBBLETYPE a_DstMeta
@@ -146,7 +148,7 @@ public:
);
}
- /// Fills the relative cuboid with specified block with a random chance; allows cuboid out of range of this chunk
+ /** Fills the relative cuboid with specified block with a random chance; allows cuboid out of range of this chunk */
void RandomFillRelCuboid(
int a_MinX, int a_MaxX,
int a_MinY, int a_MaxY,
@@ -155,7 +157,7 @@ public:
int a_RandomSeed, int a_ChanceOutOf10k
);
- /// Fills the relative cuboid with specified block with a random chance; allows cuboid out of range of this chunk
+ /** Fills the relative cuboid with specified block with a random chance; allows cuboid out of range of this chunk */
void RandomFillRelCuboid(
const cCuboid & a_RelCuboid, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
int a_RandomSeed, int a_ChanceOutOf10k
@@ -170,11 +172,15 @@ public:
);
}
- /// Returns the block entity at the specified coords.
- /// If there is no block entity at those coords, tries to create one, based on the block type
- /// If the blocktype doesn't support a block entity, returns NULL.
+ /** Returns the block entity at the specified coords.
+ If there is no block entity at those coords, tries to create one, based on the block type
+ If the blocktype doesn't support a block entity, returns NULL. */
cBlockEntity * GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ);
+ /** Updates the heightmap to match the current contents.
+ Useful for plugins when writing custom block areas into the chunk */
+ void UpdateHeightmap(void);
+
// tolua_end
// Accessors used by cChunkGenerator::Generator descendants:
@@ -187,11 +193,11 @@ public:
inline cEntityList & GetEntities (void) { return m_Entities; }
inline cBlockEntityList & GetBlockEntities (void) { return m_BlockEntities; }
- /// Compresses the metas from the BlockArea format (1 meta per byte) into regular format (2 metas per byte)
+ /** Compresses the metas from the BlockArea format (1 meta per byte) into regular format (2 metas per byte) */
void CompressBlockMetas(cChunkDef::BlockNibbles & a_DestMetas);
#ifdef _DEBUG
- /// Verifies that the heightmap corresponds to blocktype contents; if not, asserts on that column
+ /** Verifies that the heightmap corresponds to blocktype contents; if not, asserts on that column */
void VerifyHeightmap(void);
#endif // _DEBUG
diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp
index baa5b76b8..73f0223e8 100644
--- a/src/Generating/ChunkGenerator.cpp
+++ b/src/Generating/ChunkGenerator.cpp
@@ -116,7 +116,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk
// Add to queue, issue a warning if too many:
if (m_Queue.size() >= QUEUE_WARNING_LIMIT)
{
- LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (%i)", a_ChunkX, a_ChunkZ, m_Queue.size());
+ LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (" SIZE_T_FMT ")", a_ChunkX, a_ChunkZ, m_Queue.size());
}
m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
}
@@ -180,7 +180,7 @@ BLOCKTYPE cChunkGenerator::GetIniBlock(cIniFile & a_IniFile, const AString & a_S
BLOCKTYPE Block = BlockStringToType(BlockType);
if (Block < 0)
{
- LOGWARN("[&s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(),a_Default.c_str());
+ LOGWARN("[%s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(),a_Default.c_str());
return BlockStringToType(a_Default);
}
return Block;
@@ -201,7 +201,7 @@ void cChunkGenerator::Execute(void)
while (!m_ShouldTerminate)
{
cCSLock Lock(m_CS);
- while (m_Queue.size() == 0)
+ while (m_Queue.empty())
{
if ((NumChunksGenerated > 16) && (clock() - LastReportTick > CLOCKS_PER_SEC))
{
@@ -221,6 +221,13 @@ void cChunkGenerator::Execute(void)
LastReportTick = clock();
}
+ if (m_Queue.empty())
+ {
+ // Sometimes the queue remains empty
+ // If so, we can't do any front() operations on it!
+ continue;
+ }
+
cChunkCoords coords = m_Queue.front(); // Get next coord from queue
m_Queue.erase( m_Queue.begin() ); // Remove coordinate from queue
bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT);
diff --git a/src/Generating/CompoGen.cpp b/src/Generating/CompoGen.cpp
index 60356fe46..578bb2481 100644
--- a/src/Generating/CompoGen.cpp
+++ b/src/Generating/CompoGen.cpp
@@ -566,7 +566,7 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc)
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_X * x, 0, BaseZ + INTERPOL_Z * z) /
256;
} // for x, z - FloorLo[]
- LinearUpscale2DArrayInPlace(FloorLo, 17, 17, INTERPOL_X, INTERPOL_Z);
+ LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorLo);
// Interpolate segments:
for (int Segment = 0; Segment < MaxHeight; Segment += SEGMENT_HEIGHT)
@@ -579,7 +579,7 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc)
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) /
256;
} // for x, z - FloorLo[]
- LinearUpscale2DArrayInPlace(FloorHi, 17, 17, INTERPOL_X, INTERPOL_Z);
+ LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorHi);
// Interpolate between FloorLo and FloorHi:
for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index cfa7e9c6f..2e886336f 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -21,7 +21,9 @@
#include "DistortedHeightmap.h"
#include "EndGen.h"
#include "MineShafts.h"
+#include "NetherFortGen.h"
#include "Noise3DGenerator.h"
+#include "POCPieceGenerator.h"
#include "Ravines.h"
@@ -133,11 +135,6 @@ cComposableGenerator::~cComposableGenerator()
delete *itr;
}
m_FinishGens.clear();
- for (cStructureGenList::const_iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr)
- {
- delete *itr;
- }
- m_StructureGens.clear();
delete m_CompositionGen;
m_CompositionGen = NULL;
@@ -164,7 +161,6 @@ void cComposableGenerator::Initialize(cIniFile & a_IniFile)
InitBiomeGen(a_IniFile);
InitHeightGen(a_IniFile);
InitCompositionGen(a_IniFile);
- InitStructureGens(a_IniFile);
InitFinishGens(a_IniFile);
}
@@ -196,25 +192,25 @@ void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a
m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetHeightMap());
}
+ bool ShouldUpdateHeightmap = false;
if (a_ChunkDesc.IsUsingDefaultComposition())
{
m_CompositionGen->ComposeTerrain(a_ChunkDesc);
+ ShouldUpdateHeightmap = true;
}
- if (a_ChunkDesc.IsUsingDefaultStructures())
- {
- for (cStructureGenList::iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr)
- {
- (*itr)->GenStructures(a_ChunkDesc);
- } // for itr - m_StructureGens[]
- }
-
if (a_ChunkDesc.IsUsingDefaultFinish())
{
for (cFinishGenList::iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr)
{
(*itr)->GenFinish(a_ChunkDesc);
} // for itr - m_FinishGens[]
+ ShouldUpdateHeightmap = true;
+ }
+
+ if (ShouldUpdateHeightmap)
+ {
+ a_ChunkDesc.UpdateHeightmap();
}
}
@@ -290,35 +286,69 @@ void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
-void cComposableGenerator::InitStructureGens(cIniFile & a_IniFile)
+void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
- AString Structures = a_IniFile.GetValueSet("Generator", "Structures", "Ravines, WormNestCaves, WaterLakes, LavaLakes, OreNests, Trees");
-
int Seed = m_ChunkGenerator.GetSeed();
- AStringVector Str = StringSplitAndTrim(Structures, ",");
+ eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld"));
+
+ // Older configuration used "Structures" in addition to "Finishers"; we don't distinguish between the two anymore (#398)
+ // Therefore, we load Structures from the ini file for compatibility, but move its contents over to Finishers:
+ AString Structures = a_IniFile.GetValue("Generator", "Structures", "");
+ AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, LavaLakes, OreNests, Trees, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator");
+ if (!Structures.empty())
+ {
+ LOGINFO("[Generator].Structures is deprecated, moving the contents to [Generator].Finishers.");
+ // Structures used to generate before Finishers, so place them first:
+ Structures.append(", ");
+ Finishers = Structures + Finishers;
+ a_IniFile.SetValue("Generator", "Finishers", Finishers);
+ }
+ a_IniFile.DeleteValue("Generator", "Structures");
+
+ // Create all requested finishers:
+ AStringVector Str = StringSplitAndTrim(Finishers, ",");
for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
{
- if (NoCaseCompare(*itr, "DualRidgeCaves") == 0)
+ // Finishers, alpha-sorted:
+ if (NoCaseCompare(*itr, "BottomLava") == 0)
{
- float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3);
- m_StructureGens.push_back(new cStructGenDualRidgeCaves(Seed, Threshold));
+ int DefaultBottomLavaLevel = (Dimension == dimNether) ? 30 : 10;
+ int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel);
+ m_FinishGens.push_back(new cFinishGenBottomLava(BottomLavaLevel));
+ }
+ else if (NoCaseCompare(*itr, "DeadBushes") == 0)
+ {
+ m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_DEAD_BUSH, biDesert, 2, E_BLOCK_SAND, E_BLOCK_SAND));
}
else if (NoCaseCompare(*itr, "DirectOverhangs") == 0)
{
- m_StructureGens.push_back(new cStructGenDirectOverhangs(Seed));
+ m_FinishGens.push_back(new cStructGenDirectOverhangs(Seed));
}
else if (NoCaseCompare(*itr, "DistortedMembraneOverhangs") == 0)
{
- m_StructureGens.push_back(new cStructGenDistortedMembraneOverhangs(Seed));
+ m_FinishGens.push_back(new cStructGenDistortedMembraneOverhangs(Seed));
+ }
+ else if (NoCaseCompare(*itr, "DualRidgeCaves") == 0)
+ {
+ float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3);
+ m_FinishGens.push_back(new cStructGenDualRidgeCaves(Seed, Threshold));
+ }
+ else if (NoCaseCompare(*itr, "Ice") == 0)
+ {
+ m_FinishGens.push_back(new cFinishGenIce);
}
else if (NoCaseCompare(*itr, "LavaLakes") == 0)
{
int Probability = a_IniFile.GetValueSetI("Generator", "LavaLakesProbability", 10);
- m_StructureGens.push_back(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, *m_HeightGen, Probability));
+ m_FinishGens.push_back(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, *m_HeightGen, Probability));
+ }
+ else if (NoCaseCompare(*itr, "LavaSprings") == 0)
+ {
+ m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension));
}
else if (NoCaseCompare(*itr, "MarbleCaves") == 0)
{
- m_StructureGens.push_back(new cStructGenMarbleCaves(Seed));
+ m_FinishGens.push_back(new cStructGenMarbleCaves(Seed));
}
else if (NoCaseCompare(*itr, "MineShafts") == 0)
{
@@ -327,94 +357,69 @@ void cComposableGenerator::InitStructureGens(cIniFile & a_IniFile)
int ChanceCorridor = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCorridor", 600);
int ChanceCrossing = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCrossing", 200);
int ChanceStaircase = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceStaircase", 200);
- m_StructureGens.push_back(new cStructGenMineShafts(
- Seed, GridSize, MaxSystemSize,
+ m_FinishGens.push_back(new cStructGenMineShafts(
+ Seed, GridSize, MaxSystemSize,
ChanceCorridor, ChanceCrossing, ChanceStaircase
));
}
- else if (NoCaseCompare(*itr, "OreNests") == 0)
- {
- m_StructureGens.push_back(new cStructGenOreNests(Seed));
- }
- else if (NoCaseCompare(*itr, "Ravines") == 0)
- {
- m_StructureGens.push_back(new cStructGenRavines(Seed, 128));
- }
- else if (NoCaseCompare(*itr, "Trees") == 0)
+ else if (NoCaseCompare(*itr, "Lilypads") == 0)
{
- m_StructureGens.push_back(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen));
+ m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_LILY_PAD, biSwampland, 4, E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER));
}
- else if (NoCaseCompare(*itr, "WaterLakes") == 0)
+ else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0)
{
- int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
- m_StructureGens.push_back(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, *m_HeightGen, Probability));
+ m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed));
}
- else if (NoCaseCompare(*itr, "WormNestCaves") == 0)
+ else if (NoCaseCompare(*itr, "NetherForts") == 0)
{
- m_StructureGens.push_back(new cStructGenWormNestCaves(Seed));
+ int GridSize = a_IniFile.GetValueSetI("Generator", "NetherFortsGridSize", 512);
+ int MaxDepth = a_IniFile.GetValueSetI("Generator", "NetherFortsMaxDepth", 12);
+ m_FinishGens.push_back(new cNetherFortGen(Seed, GridSize, MaxDepth));
}
- else
+ else if (NoCaseCompare(*itr, "OreNests") == 0)
{
- LOGWARNING("Unknown structure generator: \"%s\". Ignoring.", itr->c_str());
+ m_FinishGens.push_back(new cStructGenOreNests(Seed));
}
- } // for itr - Str[]
-}
-
-
-
-
-
-void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
-{
- int Seed = m_ChunkGenerator.GetSeed();
- eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld"));
-
- AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator");
- AStringVector Str = StringSplitAndTrim(Finishers, ",");
- for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
- {
- // Finishers, alpha-sorted:
- if (NoCaseCompare(*itr, "BottomLava") == 0)
+ else if (NoCaseCompare(*itr, "POCPieces") == 0)
{
- int DefaultBottomLavaLevel = (Dimension == dimNether) ? 30 : 10;
- int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel);
- m_FinishGens.push_back(new cFinishGenBottomLava(BottomLavaLevel));
+ m_FinishGens.push_back(new cPOCPieceGenerator(Seed));
}
- else if (NoCaseCompare(*itr, "DeadBushes") == 0)
+ else if (NoCaseCompare(*itr, "PreSimulator") == 0)
{
- m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_DEAD_BUSH, biDesert, 2, E_BLOCK_SAND, E_BLOCK_SAND));
+ m_FinishGens.push_back(new cFinishGenPreSimulator);
}
- else if (NoCaseCompare(*itr, "Ice") == 0)
+ else if (NoCaseCompare(*itr, "Ravines") == 0)
{
- m_FinishGens.push_back(new cFinishGenIce);
+ m_FinishGens.push_back(new cStructGenRavines(Seed, 128));
}
- else if (NoCaseCompare(*itr, "LavaSprings") == 0)
+ else if (NoCaseCompare(*itr, "Snow") == 0)
{
- m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension));
+ m_FinishGens.push_back(new cFinishGenSnow);
}
- else if (NoCaseCompare(*itr, "Lilypads") == 0)
+ else if (NoCaseCompare(*itr, "SprinkleFoliage") == 0)
{
- m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_LILY_PAD, biSwampland, 4, E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER));
+ m_FinishGens.push_back(new cFinishGenSprinkleFoliage(Seed));
}
- else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0)
+ else if (NoCaseCompare(*itr, "Trees") == 0)
{
- m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed));
+ m_FinishGens.push_back(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen));
}
- else if (NoCaseCompare(*itr, "PreSimulator") == 0)
+ else if (NoCaseCompare(*itr, "WaterLakes") == 0)
{
- m_FinishGens.push_back(new cFinishGenPreSimulator);
+ int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
+ m_FinishGens.push_back(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, *m_HeightGen, Probability));
}
- else if (NoCaseCompare(*itr, "Snow") == 0)
+ else if (NoCaseCompare(*itr, "WaterSprings") == 0)
{
- m_FinishGens.push_back(new cFinishGenSnow);
+ m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension));
}
- else if (NoCaseCompare(*itr, "SprinkleFoliage") == 0)
+ else if (NoCaseCompare(*itr, "WormNestCaves") == 0)
{
- m_FinishGens.push_back(new cFinishGenSprinkleFoliage(Seed));
+ m_FinishGens.push_back(new cStructGenWormNestCaves(Seed));
}
- else if (NoCaseCompare(*itr, "WaterSprings") == 0)
+ else
{
- m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension));
+ LOGWARNING("Unknown Finisher in the [Generator] section: \"%s\". Ignoring.", itr->c_str());
}
} // for itr - Str[]
}
diff --git a/src/Generating/ComposableGenerator.h b/src/Generating/ComposableGenerator.h
index 29add0636..6b7627d2e 100644
--- a/src/Generating/ComposableGenerator.h
+++ b/src/Generating/ComposableGenerator.h
@@ -43,16 +43,16 @@ class cBiomeGen
public:
virtual ~cBiomeGen() {} // Force a virtual destructor in descendants
- /// Generates biomes for the given chunk
+ /** Generates biomes for the given chunk */
virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0;
- /// Reads parameters from the ini file, prepares generator for use.
+ /** Reads parameters from the ini file, prepares generator for use. */
virtual void InitializeBiomeGen(cIniFile & a_IniFile) {}
- /// Creates the correct BiomeGen descendant based on the ini file settings and the seed provided.
- /// a_CacheOffByDefault gets set to whether the cache should be disabled by default
- /// Used in BiomeVisualiser, too.
- /// Implemented in BioGen.cpp!
+ /** Creates the correct BiomeGen descendant based on the ini file settings and the seed provided.
+ a_CacheOffByDefault gets set to whether the cache should be disabled by default.
+ Used in BiomeVisualiser, too.
+ Implemented in BioGen.cpp! */
static cBiomeGen * CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault);
} ;
@@ -72,10 +72,10 @@ class cTerrainHeightGen
public:
virtual ~cTerrainHeightGen() {} // Force a virtual destructor in descendants
- /// Generates heightmap for the given chunk
+ /** Generates heightmap for the given 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.
+ /** Reads parameters from the ini file, prepares generator for use. */
virtual void InitializeHeightGen(cIniFile & a_IniFile) {}
/** Creates the correct TerrainHeightGen descendant based on the ini file settings and the seed provided.
@@ -102,7 +102,7 @@ public:
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) = 0;
- /// Reads parameters from the ini file, prepares generator for use.
+ /** 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.
@@ -116,28 +116,12 @@ public:
-/** The interface that a structure generator must implement
-Structures are generated after the terrain composition took place. It should modify the blocktype data to account
-for whatever structures the generator is generating.
-Note that ores are considered structures too, at least from the interface point of view.
-Also note that a worldgenerator may contain multiple structure generators, one for each type of structure
-*/
-class cStructureGen
-{
-public:
- virtual ~cStructureGen() {} // Force a virtual destructor in descendants
-
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) = 0;
-} ;
-
-typedef std::list<cStructureGen *> cStructureGenList;
-
-
-
-
-
/** The interface that a finisher must implement
-Finisher implements small additions after all structures have been generated.
+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.
+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)
*/
class cFinishGen
{
@@ -171,7 +155,6 @@ protected:
cBiomeGen * m_BiomeGen;
cTerrainHeightGen * m_HeightGen;
cTerrainCompositionGen * m_CompositionGen;
- cStructureGenList m_StructureGens;
cFinishGenList m_FinishGens;
// Generators underlying the caches:
@@ -180,19 +163,16 @@ protected:
cTerrainCompositionGen * m_UnderlyingCompositionGen;
- /// Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly
+ /** Reads the biome gen 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
+ /** Reads the HeightGen settings from the ini and initializes m_HeightGen accordingly */
void InitHeightGen(cIniFile & a_IniFile);
- /// Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly
+ /** Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly */
void InitCompositionGen(cIniFile & a_IniFile);
- /// Reads the structures to generate from the ini and initializes m_StructureGens accordingly
- void InitStructureGens(cIniFile & a_IniFile);
-
- /// Reads the finishers from the ini and initializes m_FinishGens accordingly
+ /** Reads the finishers from the ini and initializes m_FinishGens accordingly */
void InitFinishGens(cIniFile & a_IniFile);
} ;
diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp
index 02045f76a..f2d66af70 100644
--- a/src/Generating/FinishGen.cpp
+++ b/src/Generating/FinishGen.cpp
@@ -88,7 +88,7 @@ void cFinishGenNetherClumpFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
{
continue;
}
- if (!g_BlockIsSolid[a_ChunkDesc.GetBlockType(PosX, y - 1, PosZ)]) // Only place on solid blocks
+ if (!cBlockInfo::IsSolid(a_ChunkDesc.GetBlockType(PosX, y - 1, PosZ))) // Only place on solid blocks
{
continue;
}
@@ -131,7 +131,7 @@ void cFinishGenNetherClumpFoliage::TryPlaceClump(cChunkDesc & a_ChunkDesc, int a
}
BLOCKTYPE BlockBelow = a_ChunkDesc.GetBlockType(x, y - 1, z);
- if (!g_BlockIsSolid[BlockBelow]) // Only place on solid blocks
+ if (!cBlockInfo::IsSolid(BlockBelow)) // Only place on solid blocks
{
continue;
}
@@ -329,7 +329,7 @@ void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc)
case biFrozenOcean:
{
int Height = a_ChunkDesc.GetHeight(x, z);
- if (g_BlockIsSnowable[a_ChunkDesc.GetBlockType(x, Height, z)])
+ if (cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)))
{
a_ChunkDesc.SetBlockType(x, Height + 1, z, E_BLOCK_SNOW);
a_ChunkDesc.SetHeight(x, z, Height + 1);
diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp
index 10710b4a1..3621421c2 100644
--- a/src/Generating/HeiGen.cpp
+++ b/src/Generating/HeiGen.cpp
@@ -428,7 +428,7 @@ void cHeiGenBiomal::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMa
Height[x + 17 * z] = GetHeightAt(x, z, a_ChunkX, a_ChunkZ, Biomes);
}
}
- LinearUpscale2DArrayInPlace(Height, 17, 17, STEPX, STEPZ);
+ LinearUpscale2DArrayInPlace<17, 17, STEPX, STEPZ>(Height);
// Copy into the heightmap
for (int z = 0; z < cChunkDef::Width; z++)
diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp
index cc39cef7b..231295c3f 100644
--- a/src/Generating/MineShafts.cpp
+++ b/src/Generating/MineShafts.cpp
@@ -69,6 +69,8 @@ public:
m_BoundingBox(a_BoundingBox)
{
}
+
+ virtual ~cMineShaft() {}
/// Returns true if this mineshaft intersects the specified cuboid
bool DoesIntersect(const cCuboid & a_Other)
@@ -1338,7 +1340,7 @@ void cStructGenMineShafts::GetMineShaftSystemsForChunk(
BaseX -= NEIGHBORHOOD_SIZE / 2;
BaseZ -= NEIGHBORHOOD_SIZE / 2;
- // Walk the cache, move each cave system that we want into a_Caves:
+ // Walk the cache, move each cave system that we want into a_Mineshafts:
int StartX = BaseX * m_GridSize;
int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
int StartZ = BaseZ * m_GridSize;
@@ -1407,7 +1409,7 @@ void cStructGenMineShafts::GetMineShaftSystemsForChunk(
-void cStructGenMineShafts::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenMineShafts::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
diff --git a/src/Generating/MineShafts.h b/src/Generating/MineShafts.h
index c53d3bc53..ba32e75ad 100644
--- a/src/Generating/MineShafts.h
+++ b/src/Generating/MineShafts.h
@@ -17,7 +17,7 @@
class cStructGenMineShafts :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenMineShafts(
@@ -52,8 +52,8 @@ protected:
*/
void GetMineShaftSystemsForChunk(int a_ChunkX, int a_ChunkZ, cMineShaftSystems & a_MineShaftSystems);
- // cStructureGen overrides:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen overrides:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
diff --git a/src/Generating/NetherFortGen.cpp b/src/Generating/NetherFortGen.cpp
new file mode 100644
index 000000000..02779a8a3
--- /dev/null
+++ b/src/Generating/NetherFortGen.cpp
@@ -0,0 +1,275 @@
+
+// NetherFortGen.cpp
+
+// Implements the cNetherFortGen class representing the nether fortress generator
+
+#include "Globals.h"
+#include "NetherFortGen.h"
+#include "Prefabs/NetherFortPrefabs.h"
+
+
+
+
+
+static const int NEIGHBORHOOD_SIZE = 3;
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cNetherFortGen::cNetherFort:
+
+class cNetherFortGen::cNetherFort
+{
+public:
+ cNetherFortGen & m_ParentGen;
+ int m_BlockX, m_BlockZ;
+ int m_GridSize;
+ int m_Seed;
+ cPlacedPieces m_Pieces;
+
+
+ cNetherFort(cNetherFortGen & a_ParentGen, int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxDepth, int a_Seed) :
+ m_ParentGen(a_ParentGen),
+ m_BlockX(a_BlockX),
+ m_BlockZ(a_BlockZ),
+ m_GridSize(a_GridSize),
+ m_Seed(a_Seed)
+ {
+ // TODO: Proper Y-coord placement
+ int BlockY = 64;
+
+ // Generate pieces:
+ for (int i = 0; m_Pieces.size() < (size_t)(a_MaxDepth * a_MaxDepth / 8 + a_MaxDepth); i++)
+ {
+ cBFSPieceGenerator pg(m_ParentGen, a_Seed + i);
+ pg.PlacePieces(a_BlockX, BlockY, a_BlockZ, a_MaxDepth, m_Pieces);
+ }
+ }
+
+
+ ~cNetherFort()
+ {
+ cPieceGenerator::FreePieces(m_Pieces);
+ }
+
+
+ /** Carves the system into the chunk data */
+ void ProcessChunk(cChunkDesc & a_Chunk)
+ {
+ for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ const cPrefab & Prefab = (const cPrefab &)((*itr)->GetPiece());
+ Prefab.Draw(a_Chunk, *itr);
+ } // for itr - m_PlacedPieces[]
+ }
+};
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cNetherFortGen:
+
+cNetherFortGen::cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth) :
+ m_Seed(a_Seed),
+ m_Noise(a_Seed),
+ m_GridSize(a_GridSize),
+ m_MaxDepth(a_MaxDepth)
+{
+ // Initialize the prefabs:
+ for (size_t i = 0; i < g_NetherFortPrefabs1Count; i++)
+ {
+ cPrefab * Prefab = new cPrefab(g_NetherFortPrefabs1[i]);
+ m_AllPieces.push_back(Prefab);
+ if (Prefab->HasConnectorType(0))
+ {
+ m_OuterPieces.push_back(Prefab);
+ }
+ if (Prefab->HasConnectorType(1))
+ {
+ m_InnerPieces.push_back(Prefab);
+ }
+ }
+
+ // Initialize the starting piece prefabs:
+ for (size_t i = 0; i < g_NetherFortStartingPrefabs1Count; i++)
+ {
+ m_StartingPieces.push_back(new cPrefab(g_NetherFortStartingPrefabs1[i]));
+ }
+
+ // DEBUG: Try one round of placement:
+ cPlacedPieces Pieces;
+ cBFSPieceGenerator pg(*this, a_Seed);
+ pg.PlacePieces(0, 64, 0, a_MaxDepth, Pieces);
+}
+
+
+
+
+
+cNetherFortGen::~cNetherFortGen()
+{
+ ClearCache();
+ for (cPieces::iterator itr = m_AllPieces.begin(), end = m_AllPieces.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ } // for itr - m_AllPieces[]
+ m_AllPieces.clear();
+}
+
+
+
+
+
+void cNetherFortGen::ClearCache(void)
+{
+ // TODO
+}
+
+
+
+
+
+void cNetherFortGen::GetFortsForChunk(int a_ChunkX, int a_ChunkZ, cNetherForts & a_Forts)
+{
+ int BaseX = a_ChunkX * cChunkDef::Width / m_GridSize;
+ int BaseZ = a_ChunkZ * cChunkDef::Width / m_GridSize;
+ if (BaseX < 0)
+ {
+ --BaseX;
+ }
+ if (BaseZ < 0)
+ {
+ --BaseZ;
+ }
+ BaseX -= NEIGHBORHOOD_SIZE / 2;
+ BaseZ -= NEIGHBORHOOD_SIZE / 2;
+
+ // Walk the cache, move each cave system that we want into a_Forts:
+ int StartX = BaseX * m_GridSize;
+ int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
+ int StartZ = BaseZ * m_GridSize;
+ int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
+ for (cNetherForts::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
+ {
+ if (
+ ((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) &&
+ ((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ)
+ )
+ {
+ // want
+ a_Forts.push_back(*itr);
+ itr = m_Cache.erase(itr);
+ }
+ else
+ {
+ // don't want
+ ++itr;
+ }
+ } // for itr - m_Cache[]
+
+ // Create those forts that haven't been in the cache:
+ for (int x = 0; x < NEIGHBORHOOD_SIZE; x++)
+ {
+ int RealX = (BaseX + x) * m_GridSize;
+ for (int z = 0; z < NEIGHBORHOOD_SIZE; z++)
+ {
+ int RealZ = (BaseZ + z) * m_GridSize;
+ bool Found = false;
+ for (cNetherForts::const_iterator itr = a_Forts.begin(), end = a_Forts.end(); itr != end; ++itr)
+ {
+ if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ))
+ {
+ Found = true;
+ break;
+ }
+ } // for itr - a_Mineshafts
+ if (!Found)
+ {
+ a_Forts.push_back(new cNetherFort(*this, RealX, RealZ, m_GridSize, m_MaxDepth, m_Seed));
+ }
+ } // for z
+ } // for x
+
+ // Copy a_Forts into m_Cache to the beginning:
+ cNetherForts FortsCopy (a_Forts);
+ m_Cache.splice(m_Cache.begin(), FortsCopy, FortsCopy.begin(), FortsCopy.end());
+
+ // Trim the cache if it's too long:
+ if (m_Cache.size() > 100)
+ {
+ cNetherForts::iterator itr = m_Cache.begin();
+ std::advance(itr, 100);
+ for (cNetherForts::iterator end = m_Cache.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ }
+ itr = m_Cache.begin();
+ std::advance(itr, 100);
+ m_Cache.erase(itr, m_Cache.end());
+ }
+}
+
+
+
+
+
+void cNetherFortGen::GenFinish(cChunkDesc & a_ChunkDesc)
+{
+ int ChunkX = a_ChunkDesc.GetChunkX();
+ int ChunkZ = a_ChunkDesc.GetChunkZ();
+ cNetherForts Forts;
+ GetFortsForChunk(ChunkX, ChunkZ, Forts);
+ for (cNetherForts::const_iterator itr = Forts.begin(); itr != Forts.end(); ++itr)
+ {
+ (*itr)->ProcessChunk(a_ChunkDesc);
+ } // for itr - Forts[]
+}
+
+
+
+
+
+cPieces cNetherFortGen::GetPiecesWithConnector(int a_ConnectorType)
+{
+ switch (a_ConnectorType)
+ {
+ case 0: return m_OuterPieces;
+ case 1: return m_InnerPieces;
+ default: return cPieces();
+ }
+}
+
+
+
+
+
+cPieces cNetherFortGen::GetStartingPieces(void)
+{
+ return m_StartingPieces;
+}
+
+
+
+
+
+void cNetherFortGen::PiecePlaced(const cPiece & a_Piece)
+{
+ UNUSED(a_Piece);
+}
+
+
+
+
+
+void cNetherFortGen::Reset(void)
+{
+ // Nothing needed
+}
+
+
+
+
diff --git a/src/Generating/NetherFortGen.h b/src/Generating/NetherFortGen.h
new file mode 100644
index 000000000..10ba01396
--- /dev/null
+++ b/src/Generating/NetherFortGen.h
@@ -0,0 +1,86 @@
+
+// NetherFortGen.h
+
+// Declares the cNetherFortGen class representing the nether fortress generator
+
+
+
+
+
+#pragma once
+
+#include "ComposableGenerator.h"
+#include "PieceGenerator.h"
+
+
+
+
+
+class cNetherFortGen :
+ public cFinishGen,
+ public cPiecePool
+{
+public:
+ cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth);
+
+ virtual ~cNetherFortGen();
+
+protected:
+ class cNetherFort; // fwd: NetherFortGen.cpp
+ typedef std::list<cNetherFort *> cNetherForts;
+
+
+ /** The seed used for generating*/
+ int m_Seed;
+
+ /** The noise used for generating */
+ cNoise m_Noise;
+
+ /** Average spacing between the fortresses*/
+ int m_GridSize;
+
+ /** Maximum depth of the piece-generator tree */
+ int m_MaxDepth;
+
+ /** Cache of the most recently used systems. MoveToFront used. */
+ cNetherForts m_Cache;
+
+ /** All the pieces that are allowed for building.
+ This is the list that's used for memory allocation and deallocation for the pieces. */
+ cPieces m_AllPieces;
+
+ /** The pieces that are used as starting pieces.
+ This list is not shared and the pieces need deallocation. */
+ cPieces m_StartingPieces;
+
+ /** The pieces that have an "outer" connector.
+ The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */
+ cPieces m_OuterPieces;
+
+ /** The pieces that have an "inner" connector.
+ The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */
+ cPieces m_InnerPieces;
+
+
+ /** Clears everything from the cache.
+ Also invalidates the forst returned by GetFortsForChunk(). */
+ void ClearCache(void);
+
+ /** Returns all forts that *may* intersect the given chunk.
+ The returned forts live within m_Cache.They are valid until the next call
+ to this function (which may delete some of the pointers). */
+ void GetFortsForChunk(int a_ChunkX, int a_ChunkZ, cNetherForts & a_Forts);
+
+ // cFinishGen overrides:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
+
+ // cPiecePool overrides:
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
+ virtual cPieces GetStartingPieces(void) override;
+ virtual void PiecePlaced(const cPiece & a_Piece) override;
+ virtual void Reset(void) override;
+} ;
+
+
+
+
diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp
index afa40c647..15a588d45 100644
--- a/src/Generating/Noise3DGenerator.cpp
+++ b/src/Generating/Noise3DGenerator.cpp
@@ -420,7 +420,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ)
}
}
// Linear-interpolate this XZ floor:
- LinearUpscale2DArrayInPlace(CurFloor, 17, 17, UPSCALE_X, UPSCALE_Z);
+ LinearUpscale2DArrayInPlace<17, 17, UPSCALE_X, UPSCALE_Z>(CurFloor);
}
// Finish the 3D linear interpolation by interpolating between each XZ-floors on the Y axis
diff --git a/src/Generating/POCPieceGenerator.cpp b/src/Generating/POCPieceGenerator.cpp
new file mode 100644
index 000000000..9ed4b565e
--- /dev/null
+++ b/src/Generating/POCPieceGenerator.cpp
@@ -0,0 +1,270 @@
+
+// POCPieceGenerator.cpp
+
+// Implements the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique
+// The generator generates a maze of rooms at {0, 50, 0}
+
+#include "Globals.h"
+#include "POCPieceGenerator.h"
+#include "ChunkDesc.h"
+
+
+
+
+
+/** POC pieces are simple boxes that have connectors in the middle of their walls.
+Each wall has one connector, there are 3 connector types that get assigned semi-randomly.
+The piece also knows how to imprint itself in a cChunkDesc, each piece has a different color glass
+and each connector is uses a different color wool frame. */
+class cPOCPiece :
+ public cPiece
+{
+public:
+ cPOCPiece(int a_SizeXZ, int a_Height) :
+ m_SizeXZ(a_SizeXZ),
+ m_Height(a_Height)
+ {
+ m_Connectors.push_back(cConnector(m_SizeXZ / 2, a_Height / 2, 0, 0, BLOCK_FACE_ZM));
+ m_Connectors.push_back(cConnector(m_SizeXZ / 2, a_Height / 2, m_SizeXZ - 1, 1, BLOCK_FACE_ZP));
+ m_Connectors.push_back(cConnector(0, a_Height / 2, m_SizeXZ / 2, 2, BLOCK_FACE_XM));
+ m_Connectors.push_back(cConnector(m_SizeXZ - 1, a_Height - 1, m_SizeXZ / 2, m_SizeXZ % 3, BLOCK_FACE_XP));
+ }
+
+
+ /** Imprints the piece in the specified chunk. Assumes they intersect. */
+ void ImprintInChunk(cChunkDesc & a_ChunkDesc, const Vector3i & a_Pos, int a_NumCCWRotations)
+ {
+ int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ Vector3i Min = a_Pos;
+ Min.Move(-BlockX, 0, -BlockZ);
+ Vector3i Max = Min;
+ Max.Move(m_SizeXZ - 1, m_Height - 1, m_SizeXZ - 1);
+ ASSERT(Min.x < cChunkDef::Width);
+ ASSERT(Min.z < cChunkDef::Width);
+ ASSERT(Max.x >= 0);
+ ASSERT(Max.z >= 0);
+ if (Min.x >= 0)
+ {
+ // Draw the XM wall:
+ a_ChunkDesc.FillRelCuboid(Min.x, Min.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
+ }
+ if (Min.z >= 0)
+ {
+ // Draw the ZM wall:
+ a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Min.z, Min.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
+ }
+ if (Max.x < cChunkDef::Width)
+ {
+ // Draw the XP wall:
+ a_ChunkDesc.FillRelCuboid(Max.x, Max.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
+ }
+ if (Max.z < cChunkDef::Width)
+ {
+ // Draw the ZP wall:
+ a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Max.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
+ }
+
+ // Draw all the connectors:
+ for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr)
+ {
+ cConnector Conn = cPiece::RotateMoveConnector(*itr, a_NumCCWRotations, a_Pos.x, a_Pos.y, a_Pos.z);
+ Conn.m_Pos.Move(-BlockX, 0, -BlockZ);
+ if (
+ (Conn.m_Pos.x >= 0) && (Conn.m_Pos.x < cChunkDef::Width) &&
+ (Conn.m_Pos.z >= 0) && (Conn.m_Pos.z < cChunkDef::Width)
+ )
+ {
+ a_ChunkDesc.SetBlockTypeMeta(Conn.m_Pos.x, Conn.m_Pos.y, Conn.m_Pos.z, E_BLOCK_WOOL, itr->m_Type % 16);
+ }
+
+ /*
+ // TODO: Frame the connectors
+ switch (itr->m_Direction)
+ {
+ case BLOCK_FACE_XM:
+ case BLOCK_FACE_XP:
+ {
+ // TODO
+ break;
+ }
+
+ case BLOCK_FACE_ZM:
+ case BLOCK_FACE_ZP:
+ {
+ // TODO
+ break;
+ }
+ }
+ */
+ } // for itr - m_Connectors[]
+ }
+
+protected:
+ int m_SizeXZ;
+ int m_Height;
+ cConnectors m_Connectors;
+
+ // cPiece overrides:
+ virtual cConnectors GetConnectors(void) const override
+ {
+ return m_Connectors;
+ }
+
+ virtual Vector3i GetSize(void) const override
+ {
+ return Vector3i(m_SizeXZ, m_Height, m_SizeXZ);
+ }
+
+ virtual cCuboid GetHitBox(void) const override
+ {
+ return cCuboid(0, 0, 0, m_SizeXZ - 1, m_Height - 1, m_SizeXZ - 1);
+ }
+
+ virtual bool CanRotateCCW(int a_NumRotations) const override
+ {
+ return true;
+ }
+};
+
+
+
+
+
+/*
+static void DebugPieces(const cPlacedPieces & a_Pieces)
+{
+ size_t idx = 0;
+ for (cPlacedPieces::const_iterator itr = a_Pieces.begin(), end = a_Pieces.end(); itr != end; ++itr, ++idx)
+ {
+ const cCuboid & HitBox = (*itr)->GetHitBox();
+ printf(" %u: %d rotations, {%d - %d, %d - %d}\n",
+ idx, (*itr)->GetNumCCWRotations(),
+ HitBox.p1.x, HitBox.p2.x, HitBox.p1.z, HitBox.p2.z
+ );
+ } // for itr - a_Pieces[]
+}
+//*/
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPOCPieceGenerator:
+
+cPOCPieceGenerator::cPOCPieceGenerator(int a_Seed) :
+ m_Seed(a_Seed)
+{
+ // Prepare a vector of available pieces:
+ m_AvailPieces.push_back(new cPOCPiece(5, 3));
+ m_AvailPieces.push_back(new cPOCPiece(7, 5));
+ m_AvailPieces.push_back(new cPOCPiece(9, 5));
+ m_AvailPieces.push_back(new cPOCPiece(5, 7));
+
+ // Generate the structure:
+ cBFSPieceGenerator Gen(*this, a_Seed);
+ Gen.PlacePieces(0, 50, 0, 6, m_Pieces);
+
+ // DebugPieces(m_Pieces);
+
+ // Get the smallest cuboid encompassing the entire generated structure:
+ cCuboid Bounds(0, 50, 0, 0, 50, 0);
+ for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ Vector3i MinCoords = (*itr)->GetCoords();
+ Bounds.Engulf(MinCoords);
+ Bounds.Engulf(MinCoords + (*itr)->GetPiece().GetSize());
+ } // for itr - m_Pieces[]
+ m_Bounds = Bounds;
+}
+
+
+
+
+
+cPOCPieceGenerator::~cPOCPieceGenerator()
+{
+ cPieceGenerator::FreePieces(m_Pieces);
+}
+
+
+
+
+
+void cPOCPieceGenerator::GenFinish(cChunkDesc & a_ChunkDesc)
+{
+ int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ if (
+ (BlockX + 16 < m_Bounds.p1.x) || (BlockX > m_Bounds.p2.x) || // X coords out of bounds of the generated structure
+ (BlockZ + 16 < m_Bounds.p1.z) || (BlockZ > m_Bounds.p2.z) // Z coords out of bounds of the generated structure
+ )
+ {
+ return;
+ }
+
+ // Imprint each piece in the chunk:
+ for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ const Vector3i & Pos = (*itr)->GetCoords();
+ Vector3i Size = (*itr)->GetPiece().GetSize();
+ if (((*itr)->GetNumCCWRotations() % 2) == 1)
+ {
+ std::swap(Size.x, Size.z);
+ }
+ if (
+ (Pos.x >= BlockX + 16) || (Pos.x + Size.x - 1 < BlockX) ||
+ (Pos.z >= BlockZ + 16) || (Pos.z + Size.z - 1 < BlockZ)
+ )
+ {
+ // This piece doesn't intersect the chunk
+ continue;
+ }
+
+ ((cPOCPiece &)(*itr)->GetPiece()).ImprintInChunk(a_ChunkDesc, Pos, (*itr)->GetNumCCWRotations());
+ } // for itr - m_Pieces[]
+ a_ChunkDesc.UpdateHeightmap();
+}
+
+
+
+
+
+cPieces cPOCPieceGenerator::GetPiecesWithConnector(int a_ConnectorType)
+{
+ // Each piece has each connector
+ return m_AvailPieces;
+}
+
+
+
+
+
+cPieces cPOCPieceGenerator::GetStartingPieces(void)
+{
+ // Any piece can be a starting piece
+ return m_AvailPieces;
+}
+
+
+
+
+
+void cPOCPieceGenerator::PiecePlaced(const cPiece & a_Piece)
+{
+ UNUSED(a_Piece);
+}
+
+
+
+
+
+void cPOCPieceGenerator::Reset(void)
+{
+ // Nothing needed
+}
+
+
+
+
diff --git a/src/Generating/POCPieceGenerator.h b/src/Generating/POCPieceGenerator.h
new file mode 100644
index 000000000..de3114ce0
--- /dev/null
+++ b/src/Generating/POCPieceGenerator.h
@@ -0,0 +1,54 @@
+
+// POCPieceGenerator.h
+
+// Declares the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique
+// The generator generates a maze of rooms at {0, 100, 0}
+
+
+
+
+
+#pragma once
+
+#include "PieceGenerator.h"
+#include "ComposableGenerator.h"
+
+
+
+
+
+class cPOCPieceGenerator :
+ public cFinishGen,
+ protected cPiecePool
+{
+public:
+ cPOCPieceGenerator(int a_Seed);
+ ~cPOCPieceGenerator();
+
+protected:
+ int m_Seed;
+
+ /** The pieces from which the generated structure is built. */
+ cPieces m_AvailPieces;
+
+ /** The placed pieces of the generated structure. */
+ cPlacedPieces m_Pieces;
+
+ /** Bounds of the complete structure, to save on processing outside chunks. */
+ cCuboid m_Bounds;
+
+
+ // cFinishGen overrides:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
+
+ // cPiecePool overrides:
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
+ virtual cPieces GetStartingPieces(void) override;
+ virtual void PiecePlaced(const cPiece & a_Piece) override;
+ virtual void Reset(void) override;
+} ;
+
+
+
+
+
diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp
new file mode 100644
index 000000000..8999a5ff7
--- /dev/null
+++ b/src/Generating/PieceGenerator.cpp
@@ -0,0 +1,625 @@
+
+// PieceGenerator.cpp
+
+// Implements the cBFSPieceGenerator class and cDFSPieceGenerator class
+// representing base classes for generating structures composed of individual "pieces"
+
+#include "Globals.h"
+#include "PieceGenerator.h"
+
+
+
+
+
+#ifdef SELF_TEST
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Self-test:
+
+static class cPieceGeneratorSelfTest :
+ public cPiecePool
+{
+public:
+ cPieceGeneratorSelfTest(void)
+ {
+ // Prepare the internal state:
+ InitializePieces();
+
+ // Generate:
+ cBFSPieceGenerator Gen(*this, 0);
+ cPlacedPieces OutPieces;
+ Gen.PlacePieces(500, 50, 500, 3, OutPieces);
+
+ // Print out the pieces:
+ printf("OutPieces.size() = " SIZE_T_FMT "\n", OutPieces.size());
+ size_t idx = 0;
+ for (cPlacedPieces::const_iterator itr = OutPieces.begin(), end = OutPieces.end(); itr != end; ++itr, ++idx)
+ {
+ const Vector3i & Coords = (*itr)->GetCoords();
+ cCuboid Hitbox = (*itr)->GetHitBox();
+ Hitbox.Sort();
+ printf(SIZE_T_FMT ": {%d, %d, %d}, rot %d, hitbox {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n", idx,
+ Coords.x, Coords.y, Coords.z,
+ (*itr)->GetNumCCWRotations(),
+ Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
+ Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
+ Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
+ );
+ } // itr - OutPieces[]
+ printf("Done.\n");
+
+ // Free the placed pieces properly:
+ Gen.FreePieces(OutPieces);
+ }
+
+ ~cPieceGeneratorSelfTest()
+ {
+ // Dealloc all the pieces:
+ for (cPieces::iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ }
+ m_Pieces.clear();
+ }
+
+protected:
+ class cTestPiece :
+ public cPiece
+ {
+ int m_Size;
+ public:
+ cTestPiece(int a_Size) :
+ m_Size(a_Size)
+ {
+ }
+
+ virtual cConnectors GetConnectors(void) const override
+ {
+ // Each piece has 4 connectors, one of each type, plus one extra, at the center of its walls:
+ cConnectors res;
+ res.push_back(cConnector(m_Size / 2, 1, 0, 0, BLOCK_FACE_ZM));
+ res.push_back(cConnector(m_Size / 2, 1, m_Size - 1, 1, BLOCK_FACE_ZP));
+ res.push_back(cConnector(0, 1, m_Size / 2, 2, BLOCK_FACE_XM));
+ res.push_back(cConnector(m_Size - 1, 1, m_Size / 2, m_Size % 3, BLOCK_FACE_XP));
+ return res;
+ }
+
+ virtual Vector3i GetSize(void) const override
+ {
+ return Vector3i(m_Size, 5, m_Size);
+ }
+
+ virtual cCuboid GetHitBox(void) const override
+ {
+ return cCuboid(0, 0, 0, m_Size - 1, 4, m_Size - 1);
+ }
+
+ virtual bool CanRotateCCW(int a_NumCCWRotations) const override
+ {
+ return true;
+ }
+ };
+
+ cPieces m_Pieces;
+
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override
+ {
+ // Each piece contains each connector
+ return m_Pieces;
+ }
+
+
+ virtual cPieces GetStartingPieces(void) override
+ {
+ return m_Pieces;
+ }
+
+
+ virtual void PiecePlaced(const cPiece & a_Piece) override
+ {
+ UNUSED(a_Piece);
+ }
+
+
+ virtual void Reset(void) override
+ {
+ }
+
+
+ void InitializePieces(void)
+ {
+ m_Pieces.push_back(new cTestPiece(5));
+ m_Pieces.push_back(new cTestPiece(7));
+ m_Pieces.push_back(new cTestPiece(9));
+ }
+} g_Test;
+
+#endif // SELF_TEST
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPiece:
+
+
+Vector3i cPiece::RotatePos(const Vector3i & a_Pos, int a_NumCCWRotations) const
+{
+ Vector3i Size = GetSize();
+ switch (a_NumCCWRotations)
+ {
+ case 0:
+ {
+ // No rotation needed
+ return a_Pos;
+ }
+ case 1:
+ {
+ // 1 CCW rotation:
+ return Vector3i(a_Pos.z, a_Pos.y, Size.x - a_Pos.x - 1);
+ }
+ case 2:
+ {
+ // 2 rotations ( = axis flip):
+ return Vector3i(Size.x - a_Pos.x - 1, a_Pos.y, Size.z - a_Pos.z - 1);
+ }
+ case 3:
+ {
+ // 1 CW rotation:
+ return Vector3i(Size.z - a_Pos.z - 1, a_Pos.y, a_Pos.x);
+ }
+ }
+ ASSERT(!"Unhandled rotation");
+ return a_Pos;
+}
+
+
+
+
+
+cPiece::cConnector cPiece::RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const
+{
+ cPiece::cConnector res(a_Connector);
+
+ // Rotate the res connector:
+ switch (a_NumCCWRotations)
+ {
+ case 0:
+ {
+ // No rotation needed
+ break;
+ }
+ case 1:
+ {
+ // 1 CCW rotation:
+ res.m_Direction = RotateBlockFaceCCW(res.m_Direction);
+ break;
+ }
+ case 2:
+ {
+ // 2 rotations ( = axis flip):
+ res.m_Direction = MirrorBlockFaceY(res.m_Direction);
+ break;
+ }
+ case 3:
+ {
+ // 1 CW rotation:
+ res.m_Direction = RotateBlockFaceCW(res.m_Direction);
+ break;
+ }
+ }
+ res.m_Pos = RotatePos(a_Connector.m_Pos, a_NumCCWRotations);
+
+ // Move the res connector:
+ res.m_Pos.x += a_MoveX;
+ res.m_Pos.y += a_MoveY;
+ res.m_Pos.z += a_MoveZ;
+
+ return res;
+}
+
+
+
+
+
+cCuboid cPiece::RotateHitBoxToConnector(
+ const cPiece::cConnector & a_MyConnector,
+ const Vector3i & a_ToConnectorPos,
+ int a_NumCCWRotations
+) const
+{
+ ASSERT(a_NumCCWRotations == (a_NumCCWRotations % 4));
+ Vector3i ConnPos = RotatePos(a_MyConnector.m_Pos, a_NumCCWRotations);
+ ConnPos = a_ToConnectorPos - ConnPos;
+ return RotateMoveHitBox(a_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z);
+}
+
+
+
+
+
+cCuboid cPiece::RotateMoveHitBox(int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const
+{
+ ASSERT(a_NumCCWRotations == (a_NumCCWRotations % 4));
+ cCuboid res = GetHitBox();
+ res.p1 = RotatePos(res.p1, a_NumCCWRotations);
+ res.p2 = RotatePos(res.p2, a_NumCCWRotations);
+ res.p1.Move(a_MoveX, a_MoveY, a_MoveZ);
+ res.p2.Move(a_MoveX, a_MoveY, a_MoveZ);
+ return res;
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPiece::cConnector:
+
+cPiece::cConnector::cConnector(int a_X, int a_Y, int a_Z, int a_Type, eBlockFace a_Direction) :
+ m_Pos(a_X, a_Y, a_Z),
+ m_Type(a_Type),
+ m_Direction(a_Direction)
+{
+}
+
+
+
+
+
+cPiece::cConnector::cConnector(const Vector3i & a_Pos, int a_Type, eBlockFace a_Direction) :
+ m_Pos(a_Pos),
+ m_Type(a_Type),
+ m_Direction(a_Direction)
+{
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPlacedPiece:
+
+cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations) :
+ m_Parent(a_Parent),
+ m_Piece(&a_Piece),
+ m_Coords(a_Coords),
+ m_NumCCWRotations(a_NumCCWRotations)
+{
+ m_Depth = (m_Parent == NULL) ? 0 : (m_Parent->GetDepth() + 1);
+ m_HitBox = a_Piece.RotateMoveHitBox(a_NumCCWRotations, a_Coords.x, a_Coords.y, a_Coords.z);
+ m_HitBox.Sort();
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPieceGenerator:
+
+cPieceGenerator::cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) :
+ m_PiecePool(a_PiecePool),
+ m_Noise(a_Seed),
+ m_Seed(a_Seed)
+{
+}
+
+
+
+
+
+void cPieceGenerator::FreePieces(cPlacedPieces & a_PlacedPieces)
+{
+ for (cPlacedPieces::iterator itr = a_PlacedPieces.begin(), end = a_PlacedPieces.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ } // for itr - a_PlacedPieces[]
+ a_PlacedPieces.clear();
+}
+
+
+
+
+
+cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors)
+{
+ m_PiecePool.Reset();
+ int rnd = m_Noise.IntNoise3DInt(a_BlockX, a_BlockY, a_BlockZ) / 7;
+
+ // Choose a random one of the starting pieces:
+ cPieces StartingPieces = m_PiecePool.GetStartingPieces();
+ cPiece * StartingPiece = StartingPieces[rnd % StartingPieces.size()];
+ rnd = rnd >> 16;
+
+ // Choose a random supported rotation:
+ int Rotations[4] = {0};
+ int NumRotations = 1;
+ for (size_t i = 1; i < ARRAYCOUNT(Rotations); i++)
+ {
+ if (StartingPiece->CanRotateCCW(i))
+ {
+ Rotations[NumRotations] = i;
+ NumRotations += 1;
+ }
+ }
+ int Rotation = Rotations[rnd % NumRotations];
+
+ cPlacedPiece * res = new cPlacedPiece(NULL, *StartingPiece, Vector3i(a_BlockX, a_BlockY, a_BlockZ), Rotation);
+
+ // Place the piece's connectors into a_OutConnectors:
+ const cPiece::cConnectors & Conn = StartingPiece->GetConnectors();
+ for (cPiece::cConnectors::const_iterator itr = Conn.begin(), end = Conn.end(); itr != end; ++itr)
+ {
+ a_OutConnectors.push_back(
+ cFreeConnector(res, StartingPiece->RotateMoveConnector(*itr, Rotation, a_BlockX, a_BlockY, a_BlockZ))
+ );
+ }
+
+ return res;
+}
+
+
+
+
+
+bool cPieceGenerator::TryPlacePieceAtConnector(
+ const cPlacedPiece & a_ParentPiece,
+ const cPiece::cConnector & a_Connector,
+ cPlacedPieces & a_OutPieces,
+ cPieceGenerator::cFreeConnectors & a_OutConnectors
+)
+{
+ // Translation of direction - direction -> number of CCW rotations needed:
+ // You need DirectionRotationTable[rot1][rot2] CCW turns to connect rot1 to rot2 (they are opposite)
+ static const int DirectionRotationTable[6][6] =
+ {
+ /* YM, YP, ZM, ZP, XM, XP */
+ /* YM */ { 0, 0, 0, 0, 0, 0},
+ /* YP */ { 0, 0, 0, 0, 0, 0},
+ /* ZM */ { 0, 0, 2, 0, 1, 3},
+ /* ZP */ { 0, 0, 0, 2, 3, 1},
+ /* XM */ { 0, 0, 3, 1, 2, 0},
+ /* XP */ { 0, 0, 1, 3, 0, 2},
+ };
+
+ // Get a list of available connections:
+ const int * RotTable = DirectionRotationTable[a_Connector.m_Direction];
+ cConnections Connections;
+ cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(a_Connector.m_Type);
+ Connections.reserve(AvailablePieces.size());
+ Vector3i ConnPos = a_Connector.m_Pos; // The position at which the new connector should be placed - 1 block away from the connector
+ AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction);
+
+ /*
+ // DEBUG:
+ printf("Placing piece at connector pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str());
+ //*/
+
+ for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP)
+ {
+ cPiece::cConnectors Connectors = (*itrP)->GetConnectors();
+ for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC)
+ {
+ if (itrC->m_Type != a_Connector.m_Type)
+ {
+ continue;
+ }
+ // This is a same-type connector, find out how to rotate to it:
+ int NumCCWRotations = RotTable[itrC->m_Direction];
+ if (!(*itrP)->CanRotateCCW(NumCCWRotations))
+ {
+ // Doesn't support this rotation
+ continue;
+ }
+ if (!CheckConnection(a_Connector, ConnPos, **itrP, *itrC, NumCCWRotations, a_OutPieces))
+ {
+ // Doesn't fit in this rotation
+ continue;
+ }
+ Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations));
+ } // for itrC - Connectors[]
+ } // for itrP - AvailablePieces[]
+ if (Connections.empty())
+ {
+ // No available connections, bail out
+ return false;
+ }
+
+ // Choose a random connection from the list:
+ int rnd = m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7;
+ cConnection & Conn = Connections[rnd % Connections.size()];
+
+ // Place the piece:
+ /*
+ // DEBUG
+ printf("Chosen connector at {%d, %d, %d}, direction %s, needs %d rotations\n",
+ Conn.m_Connector.m_Pos.x, Conn.m_Connector.m_Pos.y, Conn.m_Connector.m_Pos.z,
+ BlockFaceToString(Conn.m_Connector.m_Direction).c_str(),
+ Conn.m_NumCCWRotations
+ );
+ //*/
+
+ Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations);
+ ConnPos -= NewPos;
+ cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations);
+ a_OutPieces.push_back(PlacedPiece);
+
+ // Add the new piece's connectors to the list of free connectors:
+ cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors();
+
+ /*
+ // DEBUG:
+ printf("Adding %u connectors to the pool\n", Connectors.size() - 1);
+ //*/
+
+ for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
+ {
+ if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos))
+ {
+ // This is the connector through which we have been connected to the parent, don't add
+ continue;
+ }
+ a_OutConnectors.push_back(cFreeConnector(PlacedPiece, Conn.m_Piece->RotateMoveConnector(*itr, Conn.m_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z)));
+ }
+
+ return true;
+}
+
+
+
+
+
+bool cPieceGenerator::CheckConnection(
+ const cPiece::cConnector & a_ExistingConnector,
+ const Vector3i & a_ToPos,
+ const cPiece & a_Piece,
+ const cPiece::cConnector & a_NewConnector,
+ int a_NumCCWRotations,
+ const cPlacedPieces & a_OutPieces
+)
+{
+ // For each placed piece, test the hitbox against the new piece:
+ cCuboid RotatedHitBox = a_Piece.RotateHitBoxToConnector(a_NewConnector, a_ToPos, a_NumCCWRotations);
+ RotatedHitBox.Sort();
+ for (cPlacedPieces::const_iterator itr = a_OutPieces.begin(), end = a_OutPieces.end(); itr != end; ++itr)
+ {
+ if ((*itr)->GetHitBox().DoesIntersect(RotatedHitBox))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+
+
+
+//*
+// DEBUG:
+void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed)
+{
+ printf(" Connector pool: " SIZE_T_FMT " items\n", a_ConnectorPool.size() - a_NumProcessed);
+ size_t idx = 0;
+ for (cPieceGenerator::cFreeConnectors::const_iterator itr = a_ConnectorPool.begin() + a_NumProcessed, end = a_ConnectorPool.end(); itr != end; ++itr, ++idx)
+ {
+ printf(" " SIZE_T_FMT ": {%d, %d, %d}, type %d, direction %s, depth %d\n",
+ idx,
+ itr->m_Connector.m_Pos.x, itr->m_Connector.m_Pos.y, itr->m_Connector.m_Pos.z,
+ itr->m_Connector.m_Type,
+ BlockFaceToString(itr->m_Connector.m_Direction).c_str(),
+ itr->m_Piece->GetDepth()
+ );
+ } // for itr - a_ConnectorPool[]
+}
+//*/
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPieceGenerator::cConnection:
+
+cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations) :
+ m_Piece(&a_Piece),
+ m_Connector(a_Connector),
+ m_NumCCWRotations(a_NumCCWRotations)
+{
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPieceGenerator::cFreeConnector:
+
+cPieceGenerator::cFreeConnector::cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector) :
+ m_Piece(a_Piece),
+ m_Connector(a_Connector)
+{
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cBFSPieceGenerator:
+
+cBFSPieceGenerator::cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) :
+ super(a_PiecePool, a_Seed)
+{
+}
+
+
+
+
+
+void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces)
+{
+ a_OutPieces.clear();
+ cFreeConnectors ConnectorPool;
+
+ // Place the starting piece:
+ a_OutPieces.push_back(PlaceStartingPiece(a_BlockX, a_BlockY, a_BlockZ, ConnectorPool));
+
+ /*
+ // DEBUG:
+ printf("Placed the starting piece at {%d, %d, %d}\n", a_BlockX, a_BlockY, a_BlockZ);
+ cCuboid Hitbox = a_OutPieces[0]->GetHitBox();
+ Hitbox.Sort();
+ printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n",
+ Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
+ Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
+ Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
+ );
+ DebugConnectorPool(ConnectorPool, 0);
+ //*/
+
+ // Place pieces at the available connectors:
+ /*
+ Instead of removing them one by one from the pool, we process them sequentially and take note of the last
+ processed one. To save on memory, once the number of processed connectors reaches a big number, a chunk
+ of the connectors is removed.
+ */
+ size_t NumProcessed = 0;
+ while (ConnectorPool.size() > NumProcessed)
+ {
+ cFreeConnector & Conn = ConnectorPool[NumProcessed];
+ if (Conn.m_Piece->GetDepth() < a_MaxDepth)
+ {
+ if (TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces, ConnectorPool))
+ {
+ /*
+ // DEBUG:
+ const cPlacedPiece * NewPiece = a_OutPieces.back();
+ const Vector3i & Coords = NewPiece->GetCoords();
+ printf("Placed a new piece at {%d, %d, %d}, rotation %d\n", Coords.x, Coords.y, Coords.z, NewPiece->GetNumCCWRotations());
+ cCuboid Hitbox = NewPiece->GetHitBox();
+ Hitbox.Sort();
+ printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n",
+ Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
+ Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
+ Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
+ );
+ DebugConnectorPool(ConnectorPool, NumProcessed + 1);
+ //*/
+ }
+ }
+ NumProcessed++;
+ if (NumProcessed > 1000)
+ {
+ ConnectorPool.erase(ConnectorPool.begin(), ConnectorPool.begin() + NumProcessed);
+ NumProcessed = 0;
+ }
+ }
+}
+
+
+
+
diff --git a/src/Generating/PieceGenerator.h b/src/Generating/PieceGenerator.h
new file mode 100644
index 000000000..bef9d3463
--- /dev/null
+++ b/src/Generating/PieceGenerator.h
@@ -0,0 +1,247 @@
+
+// PieceGenerator.h
+
+// Declares the cBFSPieceGenerator class and cDFSPieceGenerator class
+// representing base classes for generating structures composed of individual "pieces"
+
+/*
+Each uses a slightly different approach to generating:
+ - DFS extends pieces one by one until it hits the configured depth (or can't connect another piece anymore),
+ then starts looking at adjacent connectors (like depth-first search).
+ - BFS keeps a pool of currently-open connectors, chooses one at random and tries to place a piece on it,
+ thus possibly extending the pool of open connectors (like breadth-first search).
+*/
+
+
+
+
+
+#pragma once
+
+#include "../Defines.h"
+#include "../Cuboid.h"
+#include "../Noise.h"
+
+
+
+
+
+/** Represents a single piece. Can have multiple connectors of different types where other pieces can connect. */
+class cPiece
+{
+public:
+ // Force a virtual destructor in all descendants
+ virtual ~cPiece() {}
+
+ struct cConnector
+ {
+ /** Position relative to the piece */
+ Vector3i m_Pos;
+
+ /** Type of the connector. Any arbitrary number; the generator connects only connectors of the same type. */
+ int m_Type;
+
+ /** Direction in which the connector is facing.
+ Will be matched by the opposite direction for the connecting connector. */
+ eBlockFace m_Direction;
+
+ cConnector(int a_X, int a_Y, int a_Z, int a_Type, eBlockFace a_Direction);
+ cConnector(const Vector3i & a_Pos, int a_Type, eBlockFace a_Direction);
+ };
+
+ typedef std::vector<cConnector> cConnectors;
+
+ /** Returns all of the available connectors that the piece has.
+ Each connector has a (relative) position in the piece, and a type associated with it. */
+ virtual cConnectors GetConnectors(void) const = 0;
+
+ /** Returns the dimensions of this piece.
+ The dimensions cover the entire piece, there is no block that the piece generates outside of this size. */
+ virtual Vector3i GetSize(void) const = 0;
+
+ /** Returns the "hitbox" of this piece.
+ A hitbox is what is compared and must not intersect other pieces' hitboxes when generating. */
+ virtual cCuboid GetHitBox(void) const = 0;
+
+ /** Returns true if the piece can be rotated CCW the specific number of 90-degree turns. */
+ virtual bool CanRotateCCW(int a_NumRotations) const = 0;
+
+ /** Returns a copy of the a_Pos after rotating the piece the specified number of CCW rotations. */
+ Vector3i RotatePos(const Vector3i & a_Pos, int a_NumCCWRotations) const;
+
+ /** Returns a copy of the connector that is rotated and then moved by the specified amounts. */
+ cConnector RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const;
+
+ /** Returns the hitbox after the specified number of rotations and moved so that a_MyConnector is placed at a_ToConnectorPos. */
+ cCuboid RotateHitBoxToConnector(const cConnector & a_MyConnector, const Vector3i & a_ToConnectorPos, int a_NumCCWRotations) const;
+
+ /** Returns the hitbox after the specified number of CCW rotations and moved by the specified amounts. */
+ cCuboid RotateMoveHitBox(int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const;
+};
+
+typedef std::vector<cPiece *> cPieces;
+
+
+
+
+
+/** This class is an interface that provides pieces for the generator. It can keep track of what pieces were
+placed and adjust the returned piece vectors. */
+class cPiecePool
+{
+public:
+ // Force a virtual destructor in all descendants:
+ virtual ~cPiecePool() {}
+
+ /** Returns a list of pieces that contain the specified connector type.
+ The cPiece pointers returned are managed by the pool and the caller doesn't free them. */
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) = 0;
+
+ /** Returns the pieces that should be used as the starting point.
+ Multiple starting points are supported, one of the returned piece will be chosen. */
+ virtual cPieces GetStartingPieces(void) = 0;
+
+ /** Called after a piece is placed, to notify the pool that it has been used.
+ The pool may adjust the pieces it will return the next time. */
+ virtual void PiecePlaced(const cPiece & a_Piece) = 0;
+
+ /** Called when the pool has finished the current structure and should reset any piece-counters it has
+ for a new structure. */
+ virtual void Reset(void) = 0;
+};
+
+
+
+
+
+/** Represents a single piece that has been placed to specific coords in the world. */
+class cPlacedPiece
+{
+public:
+ cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations);
+
+ const cPiece & GetPiece (void) const { return *m_Piece; }
+ const Vector3i & GetCoords (void) const { return m_Coords; }
+ int GetNumCCWRotations(void) const { return m_NumCCWRotations; }
+ const cCuboid & GetHitBox (void) const { return m_HitBox; }
+ int GetDepth (void) const { return m_Depth; }
+
+protected:
+ const cPlacedPiece * m_Parent;
+ const cPiece * m_Piece;
+ Vector3i m_Coords;
+ int m_NumCCWRotations;
+ cCuboid m_HitBox;
+ int m_Depth;
+};
+
+typedef std::vector<cPlacedPiece *> cPlacedPieces;
+
+
+
+
+
+class cPieceGenerator
+{
+public:
+ cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
+
+ /** Cleans up all the memory used by the placed pieces.
+ Call this utility function instead of freeing the items on your own. */
+ static void FreePieces(cPlacedPieces & a_PlacedPieces);
+
+protected:
+ /** The type used for storing a connection from one piece to another, while building the piece tree. */
+ struct cConnection
+ {
+ cPiece * m_Piece; // The piece being connected
+ cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords)
+ int m_NumCCWRotations; // Number of rotations necessary to match the two connectors
+
+ cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations);
+ };
+ typedef std::vector<cConnection> cConnections;
+
+ /** The type used for storing a pool of connectors that will be attempted to expand by another piece. */
+ struct cFreeConnector
+ {
+ cPlacedPiece * m_Piece;
+ cPiece::cConnector m_Connector;
+
+ cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector);
+ };
+ typedef std::vector<cFreeConnector> cFreeConnectors;
+
+
+ cPiecePool & m_PiecePool;
+ cNoise m_Noise;
+ int m_Seed;
+
+
+ /** Selects a starting piece and places it, including the rotations.
+ Also puts the piece's connectors in a_OutConnectors. */
+ cPlacedPiece * PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors);
+
+ /** Tries to place a new piece at the specified (placed) connector. Returns true if successful. */
+ bool TryPlacePieceAtConnector(
+ const cPlacedPiece & a_ParentPiece, // The existing piece to a new piece should be placed
+ const cPiece::cConnector & a_Connector, // The existing connector (world-coords) to which a new piece should be placed
+ cPlacedPieces & a_OutPieces, // Already placed pieces, to be checked for intersections
+ cFreeConnectors & a_OutConnectors // List of free connectors to which the new connectors will be placed
+ );
+
+ /** Checks if the specified piece would fit with the already-placed pieces, using the specified connector
+ and number of CCW rotations.
+ a_ExistingConnector is in world-coords and is already rotated properly
+ a_ToPos is the world-coords position on which the new connector should be placed (1 block away from a_ExistingConnector, in its Direction)
+ a_NewConnector is in the original (non-rotated) coords.
+ Returns true if the piece fits, false if not. */
+ bool CheckConnection(
+ const cPiece::cConnector & a_ExistingConnector, // The existing connector
+ const Vector3i & a_ToPos, // The position on which the new connector should be placed
+ const cPiece & a_Piece, // The new piece
+ const cPiece::cConnector & a_NewConnector, // The connector of the new piece
+ int a_NumCCWRotations, // Number of rotations for the new piece to align the connector
+ const cPlacedPieces & a_OutPieces // All the already-placed pieces to check
+ );
+
+ /** DEBUG: Outputs all the connectors in the pool into stdout.
+ a_NumProcessed signals the number of connectors from the pool that should be considered processed (not listed). */
+ void DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed);
+} ;
+
+
+
+
+
+class cBFSPieceGenerator :
+ public cPieceGenerator
+{
+ typedef cPieceGenerator super;
+
+public:
+ cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
+
+ /** Generates a placement for pieces at the specified coords.
+ Caller must free each individual cPlacedPiece in a_OutPieces. */
+ void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces);
+};
+
+
+
+
+
+class cDFSPieceGenerator :
+ public cPieceGenerator
+{
+public:
+ cDFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
+
+ /** Generates a placement for pieces at the specified coords.
+ Caller must free each individual cPlacedPiece in a_OutPieces. */
+ void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, cPlacedPieces & a_OutPieces);
+};
+
+
+
+
diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp
new file mode 100644
index 000000000..131b6acb2
--- /dev/null
+++ b/src/Generating/Prefab.cpp
@@ -0,0 +1,316 @@
+
+// Prefab.cpp
+
+/*
+Implements the cPrefab class, representing a cPiece descendant for the cPieceGenerator that
+uses a prefabricate in a cBlockArea for drawing itself.
+*/
+
+#include "Globals.h"
+#include "Prefab.h"
+#include "../WorldStorage/SchematicFileSerializer.h"
+#include "ChunkDesc.h"
+
+
+
+
+
+#ifdef SELF_TEST
+
+// Create one static prefab to test the parser:
+static const cPrefab::sDef g_TestPrefabDef =
+{
+ // Size:
+ 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* 0 */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "b.....b"
+ "b.....b"
+ "a.....a"
+ "aabbbaa"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa",
+
+ // Connections:
+ "0: 0, 3, 2: 4\n"
+ "0: 2, 3, 0: 2\n",
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msImprint
+};
+
+static cPrefab g_TestPrefab(g_TestPrefabDef);
+#endif
+
+
+
+
+
+cPrefab::cPrefab(const cPrefab::sDef & a_Def) :
+ m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ),
+ m_HitBox(0, 0, 0, a_Def.m_SizeX - 1, a_Def.m_SizeY - 1, a_Def.m_SizeZ - 1),
+ m_AllowedRotations(a_Def.m_AllowedRotations),
+ m_MergeStrategy(a_Def.m_MergeStrategy)
+{
+ m_BlockArea[0].Create(m_Size);
+ CharMap cm;
+ ParseCharMap(cm, a_Def.m_CharMap);
+ ParseBlockImage(cm, a_Def.m_Image);
+ ParseConnectors(a_Def.m_Connectors);
+
+ // 1 CCW rotation:
+ if ((m_AllowedRotations & 0x01) != 0)
+ {
+ m_BlockArea[1].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[1].RotateCCW();
+ }
+
+ // 2 rotations are the same as mirroring twice; mirroring is faster because it has no reallocations
+ if ((m_AllowedRotations & 0x02) != 0)
+ {
+ m_BlockArea[2].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[2].MirrorXY();
+ m_BlockArea[2].MirrorYZ();
+ }
+
+ // 3 CCW rotations = 1 CW rotation:
+ if ((m_AllowedRotations & 0x04) != 0)
+ {
+ m_BlockArea[3].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[3].RotateCW();
+ }
+}
+
+
+
+
+
+void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const
+{
+ Vector3i Placement = a_Placement->GetCoords();
+ int ChunkStartX = a_Dest.GetChunkX() * cChunkDef::Width;
+ int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width;
+ Placement.Move(-ChunkStartX, 0, -ChunkStartZ);
+ a_Dest.WriteBlockArea(m_BlockArea[a_Placement->GetNumCCWRotations()], Placement.x, Placement.y, Placement.z, m_MergeStrategy);
+
+}
+
+
+
+
+
+bool cPrefab::HasConnectorType(int a_ConnectorType) const
+{
+ for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr)
+ {
+ if (itr->m_Type == a_ConnectorType)
+ {
+ return true;
+ }
+ } // for itr - m_Connectors[]
+ return false;
+}
+
+
+
+
+
+void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
+{
+ ASSERT(a_CharMapDef != NULL);
+
+ // Initialize the charmap to all-invalid values:
+ for (size_t i = 0; i < ARRAYCOUNT(a_CharMapOut); i++)
+ {
+ a_CharMapOut[i].m_BlockType = 0;
+ a_CharMapOut[i].m_BlockMeta = 16; // Mark unassigned entries with a meta that is impossible otherwise
+ }
+
+ // Process the lines in the definition:
+ AStringVector Lines = StringSplitAndTrim(a_CharMapDef, "\n");
+ for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
+ {
+ AStringVector CharDef = StringSplitAndTrim(*itr, ":");
+ size_t NumElements = CharDef.size();
+ if ((NumElements < 2) || CharDef[0].empty() || CharDef[1].empty())
+ {
+ LOGWARNING("Bad prefab CharMap definition line: \"%s\", skipping.", itr->c_str());
+ continue;
+ }
+ unsigned char Src = (unsigned char)CharDef[0][0];
+ ASSERT(a_CharMapOut[Src].m_BlockMeta == 16); // This letter has not been assigned yet?
+ a_CharMapOut[Src].m_BlockType = (BLOCKTYPE)atoi(CharDef[1].c_str());
+ NIBBLETYPE BlockMeta = 0;
+ if ((NumElements >= 3) && !CharDef[2].empty())
+ {
+ BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str());
+ ASSERT((BlockMeta >= 0) && (BlockMeta <= 15));
+ }
+ a_CharMapOut[Src].m_BlockMeta = BlockMeta;
+ } // for itr - Lines[]
+}
+
+
+
+
+
+void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockImage)
+{
+ // Map each letter in the a_BlockImage (from the in-source definition) to real blocktype / blockmeta:
+ for (int y = 0; y < m_Size.y; y++)
+ {
+ for (int z = 0; z < m_Size.z; z++)
+ {
+ const unsigned char * BlockImage = (const unsigned char *)a_BlockImage + y * m_Size.x * m_Size.z + z * m_Size.x;
+ for (int x = 0; x < m_Size.x; x++)
+ {
+ const sBlockTypeDef & MappedValue = a_CharMap[BlockImage[x]];
+ ASSERT(MappedValue.m_BlockMeta != 16); // Using a letter not defined in the CharMap?
+ m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, MappedValue.m_BlockType, MappedValue.m_BlockMeta);
+ }
+ }
+ }
+}
+
+
+
+
+
+void cPrefab::ParseConnectors(const char * a_ConnectorsDef)
+{
+ ASSERT(a_ConnectorsDef != NULL);
+
+ AStringVector Lines = StringSplitAndTrim(a_ConnectorsDef, "\n");
+ for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
+ {
+ if (itr->empty())
+ {
+ continue;
+ }
+ // Split into components: "Type: X, Y, Z: Face":
+ AStringVector Defs = StringSplitAndTrim(*itr, ":");
+ if (Defs.size() != 3)
+ {
+ LOGWARNING("Bad prefab Connector definition line: \"%s\", skipping.", itr->c_str());
+ continue;
+ }
+ AStringVector Coords = StringSplitAndTrim(Defs[1], ",");
+ if (Coords.size() != 3)
+ {
+ LOGWARNING("Bad prefab Connector coords definition: \"%s\", skipping.", Defs[1].c_str());
+ continue;
+ }
+
+ // Check that the BlockFace is within range:
+ int BlockFace = atoi(Defs[2].c_str());
+ if ((BlockFace < 0) || (BlockFace >= 6))
+ {
+ LOGWARNING("Bad prefab Connector Blockface: \"%s\", skipping.", Defs[2].c_str());
+ continue;
+ }
+
+ // Add the connector:
+ m_Connectors.push_back(cPiece::cConnector(
+ atoi(Coords[0].c_str()), atoi(Coords[1].c_str()), atoi(Coords[2].c_str()), // Connector pos
+ atoi(Defs[0].c_str()), // Connector type
+ (eBlockFace)BlockFace
+ ));
+ } // for itr - Lines[]
+}
+
+
+
+
+
+cPiece::cConnectors cPrefab::GetConnectors(void) const
+{
+ return m_Connectors;
+}
+
+
+
+
+
+Vector3i cPrefab::GetSize(void) const
+{
+ return m_Size;
+}
+
+
+
+
+
+cCuboid cPrefab::GetHitBox(void) const
+{
+ return m_HitBox;
+}
+
+
+
+
+
+bool cPrefab::CanRotateCCW(int a_NumRotations) const
+{
+ // Either zero rotations
+ // Or the proper bit in m_AllowedRotations is set
+ return (a_NumRotations == 0) || ((m_AllowedRotations & (1 << ((a_NumRotations + 3) % 4))) != 0);
+}
+
+
+
+
diff --git a/src/Generating/Prefab.h b/src/Generating/Prefab.h
new file mode 100644
index 000000000..04c4f09da
--- /dev/null
+++ b/src/Generating/Prefab.h
@@ -0,0 +1,105 @@
+
+// Prefab.h
+
+/*
+Declares the cPrefab class, representing a cPiece descendant for the cPieceGenerator that
+uses a prefabricate in a cBlockArea for drawing itself.
+The class can be constructed from data that is stored directly in the executable, in a sPrefabDef structure
+declared in this file as well; the Gallery server exports areas in this format.
+*/
+
+
+
+
+
+#pragma once
+
+#include "PieceGenerator.h"
+#include "../BlockArea.h"
+
+
+
+
+
+// fwd:
+class cChunkDesc;
+
+
+
+
+
+class cPrefab :
+ public cPiece
+{
+public:
+ struct sDef
+ {
+ int m_SizeX;
+ int m_SizeY;
+ int m_SizeZ;
+ const char * m_CharMap;
+ const char * m_Image;
+ const char * m_Connectors;
+ int m_AllowedRotations;
+ cBlockArea::eMergeStrategy m_MergeStrategy;
+ };
+
+ cPrefab(const sDef & a_Def);
+
+ /** Draws the prefab into the specified chunk, according to the placement stored in the PlacedPiece. */
+ void Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const;
+
+ /** Returns true if the prefab has any connector of the specified type. */
+ bool HasConnectorType(int a_ConnectorType) const;
+
+protected:
+ /** Packs complete definition of a single block, for per-letter assignment. */
+ struct sBlockTypeDef
+ {
+ BLOCKTYPE m_BlockType;
+ NIBBLETYPE m_BlockMeta;
+ };
+
+ /** Maps letters in the sDef::m_Image onto a number, BlockType * 16 | BlockMeta */
+ typedef sBlockTypeDef CharMap[256];
+
+
+ /** The cBlockArea that contains the block definitions for the prefab.
+ The index identifies the number of CCW rotations applied (0 = no rotation, 1 = 1 CCW rotation, ...). */
+ cBlockArea m_BlockArea[4];
+
+ /** The size of the prefab */
+ Vector3i m_Size;
+
+ /** The hitbox of the prefab. In first version is the same as the m_BlockArea dimensions */
+ cCuboid m_HitBox;
+
+ /** The connectors through which the piece connects to other pieces */
+ cConnectors m_Connectors;
+
+ /** Bitmask, bit N set -> N rotations CCW supported */
+ int m_AllowedRotations;
+
+ /** The merge strategy to use when drawing the prefab into a block area */
+ cBlockArea::eMergeStrategy m_MergeStrategy;
+
+
+ // cPiece overrides:
+ virtual cConnectors GetConnectors(void) const override;
+ virtual Vector3i GetSize(void) const override;
+ virtual cCuboid GetHitBox(void) const override;
+ virtual bool CanRotateCCW(int a_NumRotations) const override;
+
+ /** Parses the CharMap in the definition into a CharMap binary data used for translating the definition into BlockArea. */
+ void ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef);
+
+ /** Parses the Image in the definition into m_BlockArea[0]'s block types and metas, using the specified CharMap. */
+ void ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockImage);
+
+ /** Parses the connectors definition text into m_Connectors member. */
+ void ParseConnectors(const char * a_ConnectorsDef);
+};
+
+
+
+
diff --git a/src/Generating/Prefabs/CMakeLists.txt b/src/Generating/Prefabs/CMakeLists.txt
new file mode 100644
index 000000000..1e60447e7
--- /dev/null
+++ b/src/Generating/Prefabs/CMakeLists.txt
@@ -0,0 +1,13 @@
+
+cmake_minimum_required (VERSION 2.6)
+project (MCServer)
+
+include_directories ("${PROJECT_SOURCE_DIR}/../../")
+
+file(GLOB SOURCE
+ "*.cpp"
+)
+
+add_library(Generating_Prefabs ${SOURCE})
+
+target_link_libraries(Generating_Prefabs OSSupport iniFile Blocks)
diff --git a/src/Generating/Prefabs/NetherFortPrefabs.cpp b/src/Generating/Prefabs/NetherFortPrefabs.cpp
new file mode 100644
index 000000000..5e8685e32
--- /dev/null
+++ b/src/Generating/Prefabs/NetherFortPrefabs.cpp
@@ -0,0 +1,2758 @@
+
+// NetherFortPrefabs.cpp
+
+// Defines all the prefabs for nether forts
+
+#include "Globals.h"
+#include "NetherFortPrefabs.h"
+
+
+
+
+
+/*
+The nether fortress has two types of connectors, Outer and Inner. Outer is Type 0, Inner is Type 1.
+*/
+
+
+
+
+
+const cPrefab::sDef g_NetherFortPrefabs1[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BalconyCorridor:
+ // The data has been exported from gallery Nether, area index 37, ID 288
+ {
+ // Size:
+ 13, 7, 9, // SizeX = 13, SizeY = 7, SizeZ = 9
+
+ // Block definitions:
+ "a:112: 0\n" /* netherbrick */
+ "b: 19: 0\n" /* sponge */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d:114: 7\n" /* netherbrickstairs */
+ "e:114: 5\n" /* netherbrickstairs */
+ "f: 44: 6\n" /* step */
+ "g:113: 0\n" /* netherbrickfence */
+ "h:114: 2\n" /* netherbrickstairs */
+ "i:114: 3\n" /* netherbrickstairs */
+ "j:114: 0\n" /* netherbrickstairs */
+ "k:114: 1\n" /* netherbrickstairs */
+ ".: 0: 0\n" /* air */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "bbbbaaaaabbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+
+ // Level 2
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaa.aaa.aaaa"
+ "bbcdaaaaadebb"
+ "bbbcdddddebbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+
+ // Level 3
+ "aaaaaaaaaaaaa"
+ "............."
+ "............."
+ "............."
+ "aaaa.fff.aaaa"
+ "bbaaaaaaaaabb"
+ "bbaaaaaaaaabb"
+ "bbaaaaaaaaabb"
+ "bbaaaaaaaaabb"
+
+ // Level 4
+ "agagagagagaga"
+ "............."
+ "............."
+ "............."
+ "agaa.....aaga"
+ "bbaaa...aaabb"
+ "bbg.......gbb"
+ "bbg.......gbb"
+ "bbgggggggggbb"
+
+ // Level 5
+ "agagagagagaga"
+ "............."
+ "............."
+ "............."
+ "agaa.....aaga"
+ "bbaaa...aaabb"
+ "bb.........bb"
+ "bb.........bb"
+ "bb.........bb"
+
+ // Level 6
+ "agagagagagaga"
+ "............."
+ "............."
+ "............."
+ "agaa.....aaga"
+ "bbaaa...aaabb"
+ "bb.........bb"
+ "bb.........bb"
+ "bb.........bb"
+
+ // Level 7
+ "hhhhhhhhhhhhh"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "iijaaaaaaaiii"
+ "bbjiiiiiiikbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb",
+
+ // Connections:
+ "1: 0, 2, 2: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 2, 2: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BalconyCorridor
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BalconyTee2:
+ // The data has been exported from gallery Nether, area index 38, ID 289
+ {
+ // Size:
+ 13, 7, 11, // SizeX = 13, SizeY = 7, SizeZ = 11
+
+ // Block definitions:
+ "a: 19: 0\n" /* sponge */
+ "b:112: 0\n" /* netherbrick */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d:114: 7\n" /* netherbrickstairs */
+ "e:114: 5\n" /* netherbrickstairs */
+ "f: 44: 6\n" /* step */
+ "g:113: 0\n" /* netherbrickfence */
+ "h:114: 0\n" /* netherbrickstairs */
+ "i:114: 1\n" /* netherbrickstairs */
+ "j:114: 2\n" /* netherbrickstairs */
+ "k:114: 3\n" /* netherbrickstairs */
+ ".: 0: 0\n" /* air */,
+
+ // Block data:
+ // Level 1
+ "aaaabbbbbaaaa"
+ "aaaabbbbbaaaa"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "aaaabbbbbaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaabbbbbaaaa"
+ "aaaabbbbbaaaa"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbb.bbb.bbbb"
+ "aacdbbbbbdeaa"
+ "aaacdddddeaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "aaaab...baaaa"
+ "aaaab...baaaa"
+ "bbbbb...bbbbb"
+ "............."
+ "............."
+ "............."
+ "bbbb.fff.bbbb"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+
+ // Level 4
+ "aaaab...baaaa"
+ "aaaag...gaaaa"
+ "bgbgb...bgbgb"
+ "............."
+ "............."
+ "............."
+ "bgbb.....bbgb"
+ "aabbb...bbbaa"
+ "aag.......gaa"
+ "aag.......gaa"
+ "aagggggggggaa"
+
+ // Level 5
+ "aaaab...baaaa"
+ "aaaag...gaaaa"
+ "bgbgb...bgbgb"
+ "............."
+ "............."
+ "............."
+ "bgbb.....bbgb"
+ "aabbb...bbbaa"
+ "aa.........aa"
+ "aa.........aa"
+ "aa.........aa"
+
+ // Level 6
+ "aaaab...baaaa"
+ "aaaag...gaaaa"
+ "bgbgb...bgbgb"
+ "............."
+ "............."
+ "............."
+ "bgbb.....bbgb"
+ "aabbb...bbbaa"
+ "aa.........aa"
+ "aa.........aa"
+ "aa.........aa"
+
+ // Level 7
+ "aaaahbbbiaaaa"
+ "aaaahbbbiaaaa"
+ "jjjjjbbbjjjjj"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "bbbbbbbbbbbbb"
+ "kkhbbbbbbbkkk"
+ "aahkkkkkkkiaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa",
+
+ // Connections:
+ "1: 0, 2, 4: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 2, 4: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 6, 2, 0: 2\n" /* Type 1, BLOCK_FACE_ZM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BalconyTee2
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BlazePlatform
+ // The data has been exported from gallery Nether, area index 26, ID 276
+ {
+ // Size:
+ 10, 7, 7, // SizeX = 10, SizeY = 7, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 52: 0\n" /* mobspawner */
+ "c:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ ".........."
+ "aaaaaaaaaa"
+ "aaaaaaaaaa"
+ "aaaaaaaaaa"
+ "aaaaaaaaaa"
+ "aaaaaaaaaa"
+ ".........."
+
+ // Level 2
+ ".........."
+ "aaaaaaaaaa"
+ "..aaaaaaaa"
+ "..aaaaaaaa"
+ "..aaaaaaaa"
+ "aaaaaaaaaa"
+ ".........."
+
+ // Level 3
+ "....aaaaaa"
+ "aaaaaaaaaa"
+ "...aaaaaaa"
+ "...aaaaaaa"
+ "...aaaaaaa"
+ "aaaaaaaaaa"
+ "....aaaaaa"
+
+ // Level 4
+ "....aaaaaa"
+ "..aaa....a"
+ ".........a"
+ "......b..a"
+ ".........a"
+ "..aaa....a"
+ "....aaaaaa"
+
+ // Level 5
+ "....cccccc"
+ "...cc....c"
+ ".........c"
+ ".........c"
+ ".........c"
+ "...cc....c"
+ "....cccccc"
+
+ // Level 6
+ ".........."
+ ".........c"
+ ".........c"
+ ".........c"
+ ".........c"
+ ".........c"
+ ".........."
+
+ // Level 7
+ ".........."
+ ".........."
+ ".........c"
+ ".........c"
+ ".........c"
+ ".........."
+ "..........",
+
+ // Connections:
+ "0: 0, 1, 3: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BlazePlatform
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BlazePlatformOverhang:
+ // The data has been exported from gallery Nether, area index 20, ID 162
+ {
+ // Size:
+ 14, 9, 7, // SizeX = 14, SizeY = 9, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c: 44:14\n" /* step */
+ "d:114: 6\n" /* netherbrickstairs */
+ "e:114: 7\n" /* netherbrickstairs */
+ "f:114: 0\n" /* netherbrickstairs */
+ "g:114: 4\n" /* netherbrickstairs */
+ "h:113: 0\n" /* netherbrickfence */
+ "i: 52: 0\n" /* mobspawner */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "aammmmmmmmmmmm"
+ "aammmmmmmmmmmm"
+ "aammmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 2
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "aabcmmmmmmmmmm"
+ "aabcmmmmmmmmmm"
+ "aabcmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 3
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "aaaaabmmmmmmmm"
+ "aaaaabmmmmmmmm"
+ "aaaaabmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 4
+ "mmmmmmmmmmmmmm"
+ "dddddddmmmmmmm"
+ "aaaaaabmmmmmmm"
+ "aaaaaabmmmmmmm"
+ "aaaaaabmmmmmmm"
+ "eeeeeeemmmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 5
+ "mmmmmmmmmmmmmm"
+ "aaaaaaadmmmmmm"
+ "aaaaaaabmmmmmm"
+ "aaaaaaabmmmmmm"
+ "aaaaaaabmmmmmm"
+ "aaaaaaaemmmmmm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 6
+ "mmmmmmmmmmmmmm"
+ "aaaaaaaabddddm"
+ "......faaaaabm"
+ "......faaaaabm"
+ "......faaaaabm"
+ "aaaaaaaaabeebm"
+ "mmmmmmmmmmmmmm"
+
+ // Level 7
+ "mmmmmmmmgdddbm"
+ "......aaaaaaad"
+ ".......faaaaab"
+ ".......faaaaab"
+ ".......faaaaab"
+ "......aaaaaaae"
+ "mmmmmmmmgeeebm"
+
+ // Level 8
+ "mmmmmmmmaaaaam"
+ "......haa...aa"
+ ".............a"
+ "..........i..a"
+ ".............a"
+ "......haa...aa"
+ "mmmmmmmmaaaaam"
+
+ // Level 9
+ "mmmmmmmmhhhhhm"
+ "......hhh...hh"
+ ".............h"
+ ".............h"
+ ".............h"
+ "......hhh...hh"
+ "mmmmmmmmhhhhhm",
+
+ // Connections:
+ "0: 0, 5, 3: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BlazePlatformOverhang
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCrossing:
+ // The data has been exported from gallery Nether, area index 17, ID 159
+ {
+ // Size:
+ 15, 8, 15, // SizeX = 15, SizeY = 8, SizeZ = 15
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 7\n" /* netherbrickstairs */
+ "c:114: 5\n" /* netherbrickstairs */
+ "d:114: 4\n" /* netherbrickstairs */
+ "e:114: 6\n" /* netherbrickstairs */
+ "f: 44:14\n" /* step */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 2
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmbbbmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "aacmmmmmmmmmdaa"
+ "aacmmmmmmmmmdaa"
+ "aacmmmmmmmmmdaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmeeemmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 3
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmbbbmmmmmm"
+ "mmmmmmfffmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "aaacfmmmmmfdaaa"
+ "aaacfmmmmmfdaaa"
+ "aaacfmmmmmfdaaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmfffmmmmmm"
+ "mmmmmmeeemmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 4
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "eeeeeeaaaeeeeee"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "bbbbbdaaacbbbbb"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+ "mmmmmdaaacmmmmm"
+
+ // Level 5
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+
+ // Level 6
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "aaaaaa...aaaaaa"
+ "..............."
+ "..............."
+ "..............."
+ "aaaaaa...aaaaaa"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+
+ // Level 7
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+
+ // Level 8
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm",
+
+ // Connections:
+ "0: 0, 5, 7: 4\n" /* Type 0, BLOCK_FACE_XM */
+ "0: 7, 5, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 14, 5, 7: 5\n" /* Type 0, BLOCK_FACE_XP */
+ "0: 7, 5, 14: 3\n" /* Type 0, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeCrossing
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCrumble1:
+ // The data has been exported from gallery Nether, area index 19, ID 161
+ {
+ // Size:
+ 9, 6, 5, // SizeX = 9, SizeY = 6, SizeZ = 5
+
+ // Block definitions:
+ ".: 19: 0\n" /* sponge */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c: 44:14\n" /* step */
+ "d:114: 6\n" /* netherbrickstairs */
+ "e:114: 7\n" /* netherbrickstairs */,
+
+ // Block data:
+ // Level 1
+ "........."
+ "aa......."
+ "aa......."
+ "aa......."
+ "........."
+
+ // Level 2
+ "........."
+ "aab......"
+ "aab......"
+ "aab......"
+ "........."
+
+ // Level 3
+ "........."
+ "aaabc...."
+ "aaabc...."
+ "aaabc...."
+ "........."
+
+ // Level 4
+ "ddddddd.."
+ "aaaaaaaa."
+ "aaaaaaaaa"
+ "aaaaaaa.."
+ "eeeee...."
+
+ // Level 5
+ "aaaaaaaaa"
+ "aaaaa...."
+ "aaaaaa..."
+ "aaaaaa..."
+ "aaaaaaaa."
+
+ // Level 6
+ "aaaaaa..."
+ "........."
+ "........."
+ "........."
+ "aaaaaaa..",
+
+ // Connections:
+ "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeCrumble1
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeCrumble2
+ // The data has been exported from gallery Nether, area index 18, ID 160
+ {
+ // Size:
+ 13, 6, 5, // SizeX = 13, SizeY = 6, SizeZ = 5
+
+ // Block definitions:
+ ".: 19: 0\n" /* sponge */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c: 44:14\n" /* step */
+ "d:114: 6\n" /* netherbrickstairs */
+ "e:114: 7\n" /* netherbrickstairs */,
+
+ // Block data:
+ // Level 1
+ "............."
+ "aa..........."
+ "aa..........."
+ "aa..........."
+ "............."
+
+ // Level 2
+ "............."
+ "aab.........."
+ "aab.........."
+ "aab.........."
+ "............."
+
+ // Level 3
+ "............."
+ "aaabc........"
+ "aaabc........"
+ "aaabc........"
+ "............."
+
+ // Level 4
+ "ddddddddd...."
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaa...."
+ "aaaaaaaaaaaa."
+ "eeeeeeeee...."
+
+ // Level 5
+ "aaaaaaaaaaaa."
+ "aaaaaaaaaa..."
+ "aaaaaaaaaaa.."
+ "aaaaaaaaa...."
+ "aaaaaaaaaaaaa"
+
+ // Level 6
+ "aaaaaaaaa...."
+ "............."
+ "............."
+ "............."
+ "aaaaaaaaaa...",
+
+ // Connections:
+ "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeCrumble2
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // BridgeSegment:
+ // The data has been exported from gallery Nether, area index 16, ID 158
+ {
+ // Size:
+ 15, 8, 5, // SizeX = 15, SizeY = 8, SizeZ = 5
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d: 44:14\n" /* step */
+ "e:114: 6\n" /* netherbrickstairs */
+ "f:114: 7\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmmmmmmmmmmmm"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "mmmmmmmmmmmmmmm"
+
+ // Level 2
+ "mmmmmmmmmmmmmmm"
+ "aabmmmmmmmmmcaa"
+ "aabmmmmmmmmmcaa"
+ "aabmmmmmmmmmcaa"
+ "mmmmmmmmmmmmmmm"
+
+ // Level 3
+ "mmmmmmmmmmmmmmm"
+ "aaabdmmmmmdcaaa"
+ "aaabdmmmmmdcaaa"
+ "aaabdmmmmmdcaaa"
+ "mmmmmmmmmmmmmmm"
+
+ // Level 4
+ "eeeeeeeeeeeeeee"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "fffffffffffffff"
+
+ // Level 5
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+
+ // Level 6
+ "aaaaaaaaaaaaaaa"
+ "..............."
+ "..............."
+ "..............."
+ "aaaaaaaaaaaaaaa"
+
+ // Level 7
+ "mmmmmmmmmmmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmmmmmmmmmmm"
+
+ // Level 8
+ "mmmmmmmmmmmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmmmmmmmmmmm",
+
+ // Connections:
+ "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */
+ "0: 14, 5, 2: 5\n" /* Type 0, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeSegment
+
+
+ // BridgeTee:
+ // The data has been exported from gallery Nether, area index 39, ID 290
+ {
+ // Size:
+ 15, 8, 10, // SizeX = 15, SizeY = 8, SizeZ = 10
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 5\n" /* netherbrickstairs */
+ "c:114: 4\n" /* netherbrickstairs */
+ "d:114: 6\n" /* netherbrickstairs */
+ "e: 44:14\n" /* step */
+ "f:114: 7\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmmmmmmmmmmmm"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "aammmmmmmmmmmaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 2
+ "mmmmmmmmmmmmmmm"
+ "aabmmmmmmmmmcaa"
+ "aabmmmmmmmmmcaa"
+ "aabmmmmmmmmmcaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmdddmmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 3
+ "mmmmmmmmmmmmmmm"
+ "aaabemmmmmecaaa"
+ "aaabemmmmmecaaa"
+ "aaabemmmmmecaaa"
+ "mmmmmmmmmmmmmmm"
+ "mmmmmmeeemmmmmm"
+ "mmmmmmdddmmmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+ "mmmmmmaaammmmmm"
+
+ // Level 4
+ "ddddddddddddddd"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "fffffcaaabfffff"
+ "mmmmmcaaabmmmmm"
+ "mmmmmcaaabmmmmm"
+ "mmmmmcaaabmmmmm"
+ "mmmmmcaaabmmmmm"
+ "mmmmmcaaabmmmmm"
+
+ // Level 5
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+ "mmmmmaaaaammmmm"
+
+ // Level 6
+ "aaaaaaaaaaaaaaa"
+ "..............."
+ "..............."
+ "..............."
+ "aaaaaa...aaaaaa"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+ "mmmmma...ammmmm"
+
+ // Level 7
+ "mmmmmmmmmmmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+
+ // Level 8
+ "mmmmmmmmmmmmmmm"
+ "..............."
+ "..............."
+ "..............."
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm"
+ "mmmmmm...mmmmmm",
+
+ // Connections:
+ "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */
+ "0: 14, 5, 2: 5\n" /* Type 0, BLOCK_FACE_XP */
+ "0: 7, 5, 9: 3\n" /* Type 0, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // BridgeTee
+
+
+ // Corridor11:
+ // The data has been exported from gallery Nether, area index 36, ID 287
+ {
+ // Size:
+ 11, 6, 5, // SizeX = 11, SizeY = 6, SizeZ = 5
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 2\n" /* netherbrickstairs */
+ "d:114: 3\n" /* netherbrickstairs */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaaaa"
+ "..........."
+ "..........."
+ "..........."
+ "aaaaaaaaaaa"
+
+ // Level 3
+ "abababababa"
+ "..........."
+ "..........."
+ "..........."
+ "abababababa"
+
+ // Level 4
+ "abababababa"
+ "..........."
+ "..........."
+ "..........."
+ "abababababa"
+
+ // Level 5
+ "abababababa"
+ "..........."
+ "..........."
+ "..........."
+ "abababababa"
+
+ // Level 6
+ "ccccccccccc"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "ddddddddddd",
+
+ // Connections:
+ "1: 0, 1, 2: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 10, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Corridor11
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Corridor13:
+ // The data has been exported from gallery Nether, area index 35, ID 286
+ {
+ // Size:
+ 13, 6, 5, // SizeX = 13, SizeY = 6, SizeZ = 5
+
+ // Block definitions:
+ "a:112: 0\n" /* netherbrick */
+ ".: 0: 0\n" /* air */
+ "c:113: 0\n" /* netherbrickfence */
+ "d:114: 2\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaaaaaa"
+ "............."
+ "............."
+ "............."
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "acacacacacaca"
+ "............."
+ "............."
+ "............."
+ "acacacacacaca"
+
+ // Level 4
+ "acacacacacaca"
+ "............."
+ "............."
+ "............."
+ "acacacacacaca"
+
+ // Level 5
+ "acacacacacaca"
+ "............."
+ "............."
+ "............."
+ "acacacacacaca"
+
+ // Level 6
+ "ddddddddddddd"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "eeeeeeeeeeeee",
+
+ // Connections:
+ "1: 0, 1, 2: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Corridor13
+
+
+ // CorridorCorner5:
+ // The data has been exported from gallery Nether, area index 10, ID 40
+ {
+ // Size:
+ 11, 6, 11, // SizeX = 11, SizeY = 6, SizeZ = 11
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 2\n" /* netherbrickstairs */
+ "d:114: 0\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */
+ "f:114: 1\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+
+ // Level 2
+ "aaaaaaaaaaa"
+ "a.........."
+ "a.........."
+ "a.........."
+ "a...aaaaaaa"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+
+ // Level 3
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 4
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 5
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 6
+ "ccccccccccc"
+ "daaaaaaaaaa"
+ "daaaaaaaaaa"
+ "daaaaaaaaaa"
+ "daaaeeeeeee"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm",
+
+ // Connections:
+ "1: 10, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 2, 1, 10: 3\n" /* Type 1, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // CorridorCorner5
+
+
+ // CorridorCorner5:
+ // The data has been exported from gallery Nether, area index 10, ID 40
+ {
+ // Size:
+ 11, 6, 11, // SizeX = 11, SizeY = 6, SizeZ = 11
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 2\n" /* netherbrickstairs */
+ "d:114: 0\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */
+ "f:114: 1\n" /* netherbrickstairs */
+ "g: 54: 5\n" /* chest */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaaaaaaaa"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+ "aaaaammmmmm"
+
+ // Level 2
+ "aaaaaaaaaaa"
+ "ag........."
+ "a.........."
+ "a.........."
+ "a...aaaaaaa"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+ "a...ammmmmm"
+
+ // Level 3
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 4
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 5
+ "abababababa"
+ "b.........."
+ "a.........."
+ "b.........."
+ "a...abababa"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+ "b...bmmmmmm"
+ "a...ammmmmm"
+
+ // Level 6
+ "ccccccccccc"
+ "daaaaaaaaaa"
+ "daaaaaaaaaa"
+ "daaaaaaaaaa"
+ "daaaeeeeeee"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm"
+ "daaafmmmmmm",
+
+ // Connections:
+ "1: 10, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 2, 1, 10: 3\n" /* Type 1, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // CorridorCorner5Chest
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CorridorStairs:
+ // The data has been exported from gallery Nether, area index 12, ID 42
+ {
+ // Size:
+ 9, 13, 5, // SizeX = 9, SizeY = 13, SizeZ = 5
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:114: 0\n" /* netherbrickstairs */
+ "c:113: 0\n" /* netherbrickfence */
+ "d:114: 2\n" /* netherbrickstairs */
+ "e:114: 3\n" /* netherbrickstairs */
+ "f: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaa"
+ "aaaaaaaaa"
+ "aaaaaaaaa"
+ "aaaaaaaaa"
+ "aaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaa"
+ ".baaaaaaa"
+ ".baaaaaaa"
+ ".baaaaaaa"
+ "aaaaaaaaa"
+
+ // Level 3
+ "acaaaaaaa"
+ "..baaaaaa"
+ "..baaaaaa"
+ "..baaaaaa"
+ "acaaaaaaa"
+
+ // Level 4
+ "acaaaaaaa"
+ "...baaaaa"
+ "...baaaaa"
+ "...baaaaa"
+ "acaaaaaaa"
+
+ // Level 5
+ "acacaaaaa"
+ "....baaaa"
+ "....baaaa"
+ "....baaaa"
+ "acacaaaaa"
+
+ // Level 6
+ "aaacaaaaa"
+ ".....baaa"
+ ".....baaa"
+ ".....baaa"
+ "aaacaaaaa"
+
+ // Level 7
+ "daacacaaa"
+ "a.....baa"
+ "a.....baa"
+ "a.....baa"
+ "eaacacaaa"
+
+ // Level 8
+ "fdaaacaaa"
+ "fa.....ba"
+ "fa.....ba"
+ "fa.....ba"
+ "feaaacaaa"
+
+ // Level 9
+ "ffdaacaca"
+ "ffa......"
+ "ffa......"
+ "ffa......"
+ "ffeaacaca"
+
+ // Level 10
+ "fffdaaaca"
+ "fffa....."
+ "fffa....."
+ "fffa....."
+ "fffeaaaca"
+
+ // Level 11
+ "ffffdaaca"
+ "ffffa...."
+ "ffffa...."
+ "ffffa...."
+ "ffffeaaca"
+
+ // Level 12
+ "fffffdaaa"
+ "fffffa..."
+ "fffffa..."
+ "fffffa..."
+ "fffffeaaa"
+
+ // Level 13
+ "ffffffddd"
+ "ffffffaaa"
+ "ffffffaaa"
+ "ffffffaaa"
+ "ffffffeee",
+
+ // Connections:
+ "1: 0, 1, 2: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 8, 8, 2: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // CorridorStairs
+
+
+ // LavaStaircase:
+ // The data has been exported from gallery Nether, area index 28, ID 278
+ {
+ // Size:
+ 15, 11, 15, // SizeX = 15, SizeY = 11, SizeZ = 15
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c: 11: 0\n" /* lava */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaa...aaaa"
+ "aaaaa.........a"
+ "aaaaa.........a"
+ "aaaaab........a"
+ "accca...aaaa..a"
+ "accca...acca..a"
+ "acccaaaaacca..a"
+ "acccccccccca..a"
+ "acccaaaaacca..a"
+ "accca...acca..a"
+ "accca...aaaa..a"
+ "aaaaab........a"
+ "aaaaa.........a"
+ "aaaaa.........a"
+ "aaaaaaaa...aaaa"
+
+ // Level 3
+ "aaaaaaaa...aaaa"
+ "aaaa..........a"
+ "aaaa..........a"
+ "aaaabb........a"
+ "aaaa..........a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "aaaa..........a"
+ "aaaabb........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "aaaaaaaa...aaaa"
+
+ // Level 4
+ "aaaaaaaa...aaaa"
+ "a.............a"
+ "a.............a"
+ "a..bb.........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a..bb.........a"
+ "a.............a"
+ "a.............a"
+ "aaaaaaaa...aaaa"
+
+ // Level 5
+ "aaaaaaaabbbaaaa"
+ "a.............a"
+ "a.............a"
+ "a..b..........a"
+ "a..b..........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a.............a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a..b..........a"
+ "a..b..........a"
+ "a.............a"
+ "a.............a"
+ "aaaaaaaabbbaaaa"
+
+ // Level 6
+ "aaaaaaaaaaaaaaa"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a..b..........a"
+ "a..b..........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "aaaa..........a"
+ "a..b..........a"
+ "a..b..........a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "aaaaaaaaaaaaaaa"
+
+ // Level 7
+ "aaaaaaaaaaaaaaa"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a..b..........a"
+ "...b..........a"
+ "...b..........a"
+ "...b..........a"
+ "a..b..........a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "a.............a"
+ "aaaaaaaaaaaaaaa"
+
+ // Level 8
+ "aababababababaa"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "..............b"
+ "..............a"
+ "..............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "aababababababaa"
+
+ // Level 9
+ "aababababababaa"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "..............b"
+ "..............a"
+ "..............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "aababababababaa"
+
+ // Level 10
+ "aababababababaa"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "..............b"
+ "..............a"
+ "..............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "b.............b"
+ "a.............a"
+ "aababababababaa"
+
+ // Level 11
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaa",
+
+ // Connections:
+ "1: 0, 6, 7: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "0: 9, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 9, 1, 14: 3\n" /* Type 0, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // LavaStaircase
+
+
+ // LavaStaircaseBig:
+ // The data has been exported from gallery Nether, area index 31, ID 282
+ {
+ // Size:
+ 12, 15, 15, // SizeX = 12, SizeY = 15, SizeZ = 15
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 10: 0\n" /* lava */
+ "c:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "abbbbbaaaaaa"
+ "abbbbbbaaaaa"
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbbaaaaa"
+ "abbbbb.aaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 3
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "abbbbbaaaaaa"
+ "abbbbbba...a"
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...a"
+ "abbbbb.aaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 4
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "abbbbbaa...a"
+ "abbbbbba...a"
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...."
+ "abbbbbba...a"
+ "abbbbbaa...a"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 5
+ "aaaaaaaaaaaa"
+ "aaaaa......a"
+ "aaaaa......a"
+ "aaaaacc....a"
+ "a.....cc...a"
+ "a......c...a"
+ "a......c...."
+ "a......c...."
+ "a......c...."
+ "a......c...a"
+ "a.....cc...a"
+ "aaaaacc....a"
+ "aaaaa......a"
+ "aaaaa......a"
+ "aaaaaaaaaaaa"
+
+ // Level 6
+ "aaaaaaaaaaaa"
+ "aaaa.......a"
+ "aaaa.......a"
+ "aaaacc.....a"
+ "aaaa.......a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaa.......a"
+ "aaaacc.....a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "aaaaaaaaaaaa"
+
+ // Level 7
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..cc......a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..cc......a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 8
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..c.......a"
+ "a..c.......a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..........a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..c.......a"
+ "a..c.......a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 9
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..c.......a"
+ "a..c.......a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "aaaa.......a"
+ "a..c.......a"
+ "a..c.......a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 10
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..c.......a"
+ "...c.......a"
+ "...c.......a"
+ "...c.......a"
+ "a..c.......a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 11
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "...........a"
+ "...........a"
+ "...........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 12
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "...........a"
+ "...........a"
+ "...........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 13
+ "aaaaaaaaaaaa"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "...........a"
+ "...........a"
+ "...........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "a..........a"
+ "aaaaaaaaaaaa"
+
+ // Level 14
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+ "aaaaaaaaaaaa"
+
+ // Level 15
+ "aaaaaaaaaaaa"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "abbbbbbbbbba"
+ "aaaaaaaaaaaa",
+
+ // Connections:
+ "1: 0, 9, 7: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 11, 1, 7: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // LavaStaircaseBig
+
+
+ // MidStaircase:
+ // The data has been exported from gallery Nether, area index 23, ID 165
+ {
+ // Size:
+ 13, 8, 13, // SizeX = 13, SizeY = 8, SizeZ = 13
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b: 88: 0\n" /* soulsand */
+ "c:115: 7\n" /* netherwartblock */
+ "d:114: 3\n" /* netherbrickstairs */
+ "e:114: 0\n" /* netherbrickstairs */
+ "f:114: 1\n" /* netherbrickstairs */
+ "g:114: 2\n" /* netherbrickstairs */
+ "h: 10: 0\n" /* lava */
+ "i:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaabbbbbaaaa"
+ "aaaabbbbbaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaabbbbbaaaa"
+ "aaaabbbbbaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaacccccaaaa"
+ "addecccccfdda"
+ "...eaaaaad..."
+ "...eaaaaa...."
+ "...eaaaaag..."
+ "agggcccccfgga"
+ "aaaacccccaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "aaaaaaaaaaaaa"
+ "aha.......aha"
+ "aaa.......aaa"
+ "a...........a"
+ "a...........a"
+ "....eaaaa...."
+ "....eaaaa...."
+ "....eaaaa...."
+ "a...........a"
+ "a...........a"
+ "aaa.......aaa"
+ "aha.......aha"
+ "aaaaaaaaaaaaa"
+
+ // Level 4
+ "aaaiiaaaiiaaa"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ ".....eaaa...."
+ ".....eaaa...."
+ ".....eaaa...."
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "aaaiiaaaiiaaa"
+
+ // Level 5
+ "aaaiiaaaiiaaa"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "......eaa...."
+ "......eaa...."
+ "......eaa...."
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "aaaiiaaaiiaaa"
+
+ // Level 6
+ "aaaaaaaaaaaaa"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a......ea...a"
+ "a......ea...a"
+ "a......ea...a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "a...........a"
+ "aaaaaaaaaaaaa"
+
+ // Level 7
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaa....eaaaa"
+ "aaaa....eaaaa"
+ "aaaa....eaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 8
+ "iaiaiaiaiaiai"
+ "a...........a"
+ "i...........i"
+ "a...........a"
+ "i...........i"
+ "a............"
+ "i............"
+ "a............"
+ "i...........i"
+ "a...........a"
+ "i...........i"
+ "a...........a"
+ "iaiaiaiaiaiai",
+
+ // Connections:
+ "1: 0, 1, 6: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 1, 6: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 12, 7, 6: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // MidStaircase
+
+
+ // StairsToOpen1:
+ // The data has been exported from gallery Nether, area index 27, ID 277
+ {
+ // Size:
+ 7, 10, 7, // SizeX = 7, SizeY = 10, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a.aaaaa"
+ "aabaaba"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a..aaaa"
+ "aabaaba"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a...aaa"
+ "aabaaba"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a....aa"
+ "aaaaaaa"
+
+ // Level 7
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "a.....a"
+ "aaaaaaa"
+
+ // Level 8
+ "aaaaaaa"
+ "a.....a"
+ "a......"
+ "a......"
+ "a......"
+ "a.....a"
+ "aaaaaaa"
+
+ // Level 9
+ "mmmmmmm"
+ "m.....m"
+ "m......"
+ "m......"
+ "m......"
+ "m.....m"
+ "mmmmmmm"
+
+ // Level 10
+ "mmmmmmm"
+ "m.....m"
+ "m......"
+ "m......"
+ "m......"
+ "m.....m"
+ "mmmmmmm",
+
+ // Connections:
+ "0: 3, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 6, 7, 3: 5\n" /* Type 0, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // StairsToOpen1
+
+
+ // StairsToOpen2:
+ // The data has been exported from gallery Nether, area index 8, ID 35
+ {
+ // Size:
+ 7, 10, 7, // SizeX = 7, SizeY = 10, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a.aaaaa"
+ "aabaaba"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a..aaaa"
+ "aabaaba"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "a.....a"
+ "b.....b"
+ "a...aaa"
+ "aabaaba"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a....aa"
+ "aaaaaaa"
+
+ // Level 7
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "a.....a"
+ "aaaaaaa"
+
+ // Level 8
+ "aaaaaaa"
+ "a.....a"
+ "......a"
+ "......a"
+ "......a"
+ "a.....a"
+ "aaaaaaa"
+
+ // Level 9
+ "mmmmmmm"
+ "m.....m"
+ "......m"
+ "......m"
+ "......m"
+ "m.....m"
+ "mmmmmmm"
+
+ // Level 10
+ "mmmmmmm"
+ "m.....m"
+ "......m"
+ "......m"
+ "......m"
+ "m.....m"
+ "mmmmmmm",
+
+ // Connections:
+ "0: 3, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 0, 7, 3: 4\n" /* Type 0, BLOCK_FACE_XM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // StairsToOpen2
+
+
+ // Tee2x4:
+ // The data has been exported from gallery Nether, area index 40, ID 291
+ {
+ // Size:
+ 13, 6, 7, // SizeX = 13, SizeY = 6, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 0\n" /* netherbrickstairs */
+ "d:114: 1\n" /* netherbrickstairs */
+ "e:114: 2\n" /* netherbrickstairs */
+ "f:114: 3\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmaaaaammmm"
+ "mmmmaaaaammmm"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "mmmma...ammmm"
+ "mmmma...ammmm"
+ "aaaaa...aaaaa"
+ "............."
+ "............."
+ "............."
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 4
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 5
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 6
+ "mmmmcaaadmmmm"
+ "mmmmcaaadmmmm"
+ "eeeecaaadeeee"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "fffffffffffff",
+
+ // Connections:
+ "1: 0, 1, 4: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 6, 1, 0: 2\n" /* Type 1, BLOCK_FACE_ZM */
+ "1: 12, 1, 4: 5\n" /* Type 1, BLOCK_FACE_XP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Tee2x4
+
+
+ // Tee4x4:
+ // The data has been exported from gallery Nether, area index 41, ID 292
+ {
+ // Size:
+ 13, 6, 9, // SizeX = 13, SizeY = 6, SizeZ = 9
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */
+ "c:114: 0\n" /* netherbrickstairs */
+ "d:114: 1\n" /* netherbrickstairs */
+ "e:114: 2\n" /* netherbrickstairs */
+ "f:114: 3\n" /* netherbrickstairs */
+ "m: 19: 0\n" /* sponge */,
+
+ // Block data:
+ // Level 1
+ "mmmmaaaaammmm"
+ "mmmmaaaaammmm"
+ "mmmmaaaaammmm"
+ "mmmmaaaaammmm"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "mmmma...ammmm"
+ "mmmma...ammmm"
+ "mmmma...ammmm"
+ "mmmma...ammmm"
+ "aaaaa...aaaaa"
+ "............."
+ "............."
+ "............."
+ "aaaaaaaaaaaaa"
+
+ // Level 3
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 4
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 5
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "mmmma...ammmm"
+ "mmmmb...bmmmm"
+ "ababa...ababa"
+ "............."
+ "............."
+ "............."
+ "ababababababa"
+
+ // Level 6
+ "mmmmcaaadmmmm"
+ "mmmmcaaadmmmm"
+ "mmmmcaaadmmmm"
+ "mmmmcaaadmmmm"
+ "eeeecaaadeeee"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "fffffffffffff",
+
+ // Connections:
+ "1: 0, 1, 6: 4\n" /* Type 1, BLOCK_FACE_XM */
+ "1: 12, 1, 6: 5\n" /* Type 1, BLOCK_FACE_XP */
+ "1: 6, 1, 0: 2\n" /* Type 1, BLOCK_FACE_ZM */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Tee4x4
+
+ // Turret:
+ // The data has been exported from gallery Nether, area index 7, ID 34
+ {
+ // Size:
+ 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* air */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "b.....b"
+ "b.....b"
+ "a.....a"
+ "aabbbaa"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa",
+
+ // Connections:
+ "0: 0, 1, 3: 4\n" /* Type 0, BLOCK_FACE_XM */
+ "0: 3, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "0: 6, 1, 3: 5\n" /* Type 0, BLOCK_FACE_XP */
+ "0: 3, 1, 6: 3\n" /* Type 0, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ }, // Turret
+
+} ; // g_NetherFortPrefabs1
+
+
+
+
+
+const cPrefab::sDef g_NetherFortStartingPrefabs1[] =
+{
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // CentralRoom:
+ // The data has been exported from gallery Nether, area index 22, ID 164
+ {
+ // Size:
+ 13, 9, 13, // SizeX = 13, SizeY = 9, SizeZ = 13
+
+ // Block definitions:
+ "a:112: 0\n" /* netherbrick */
+ "b: 0: 0\n" /* air */
+ "c: 10: 0\n" /* lava */
+ "d:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 2
+ "aaaaabbbaaaaa"
+ "aaaaabbbaaaaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbaaabbbaa"
+ "aabbbacabbbaa"
+ "aabbbaaabbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aabbbbbbbbbaa"
+ "aaaaabbbaaaaa"
+ "aaaaabbbaaaaa"
+
+ // Level 3
+ "aaaaabbbaaaaa"
+ "aaadabbbadaaa"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "aaadabbbadaaa"
+ "aaaaabbbaaaaa"
+
+ // Level 4
+ "aaaaabbbaaaaa"
+ "aaadabbbadaaa"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "adbbbbbbbbbda"
+ "aabbbbbbbbbaa"
+ "aaadabbbadaaa"
+ "aaaaabbbaaaaa"
+
+ // Level 5
+ "adadadddadada"
+ "daaaabbbaaaad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "daaaabbbaaaad"
+ "adadabbbadada"
+
+ // Level 6
+ "adadaaaaadada"
+ "daaaaaaaaaaad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "dabbbbbbbbbad"
+ "aabbbbbbbbbaa"
+ "daaaaaaaaaaad"
+ "adadaaaaadada"
+
+ // Level 7
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 8
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+ "aaaaaaaaaaaaa"
+
+ // Level 9
+ "dadadadadadad"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dbbbbbbbbbbbd"
+ "abbbbbbbbbbba"
+ "dadadadadadad",
+
+ // Connections:
+ "0: 6, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */
+ "1: 6, 1, 12: 3\n" /* Type 1, BLOCK_FACE_ZP */,
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msSpongePrint,
+ },
+} ; // g_NetherFortStartingPrefabs1
+
+const size_t g_NetherFortPrefabs1Count = ARRAYCOUNT(g_NetherFortPrefabs1);
+const size_t g_NetherFortStartingPrefabs1Count = ARRAYCOUNT(g_NetherFortStartingPrefabs1);
+
+
+
+
diff --git a/src/Generating/Prefabs/NetherFortPrefabs.h b/src/Generating/Prefabs/NetherFortPrefabs.h
new file mode 100644
index 000000000..37a91689d
--- /dev/null
+++ b/src/Generating/Prefabs/NetherFortPrefabs.h
@@ -0,0 +1,15 @@
+
+// NetherFortPrefabs.h
+
+// Declares the data used for nether fortress prefabs
+
+#include "../Prefab.h"
+
+
+
+
+
+extern const cPrefab::sDef g_NetherFortPrefabs1[];
+extern const cPrefab::sDef g_NetherFortStartingPrefabs1[];
+extern const size_t g_NetherFortPrefabs1Count;
+extern const size_t g_NetherFortStartingPrefabs1Count;
diff --git a/src/Generating/Ravines.cpp b/src/Generating/Ravines.cpp
index cfda47e32..e64f55214 100644
--- a/src/Generating/Ravines.cpp
+++ b/src/Generating/Ravines.cpp
@@ -117,7 +117,7 @@ void cStructGenRavines::ClearCache(void)
-void cStructGenRavines::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenRavines::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
diff --git a/src/Generating/Ravines.h b/src/Generating/Ravines.h
index 05164a5b2..c76b9f19f 100644
--- a/src/Generating/Ravines.h
+++ b/src/Generating/Ravines.h
@@ -17,7 +17,7 @@
class cStructGenRavines :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenRavines(int a_Seed, int a_Size);
@@ -37,8 +37,8 @@ protected:
/// Returns all ravines that *may* intersect the given chunk. All the ravines are valid until the next call to this function.
void GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cRavines & a_Ravines);
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp
index da6227801..db9d5578c 100644
--- a/src/Generating/StructGen.cpp
+++ b/src/Generating/StructGen.cpp
@@ -51,28 +51,10 @@ const int NEST_SIZE_GRAVEL = 32;
-template <typename T> T Clamp(T a_Value, T a_Min, T a_Max)
-{
- return (a_Value < a_Min) ? a_Min : ((a_Value > a_Max) ? a_Max : a_Value);
-}
-
-
-
-
-
-static bool SortTreeBlocks(const sSetBlock & a_First, const sSetBlock & a_Second)
-{
- return (a_First.BlockType == E_BLOCK_LOG) && (a_Second.BlockType != E_BLOCK_LOG);
-}
-
-
-
-
-
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenTrees:
-void cStructGenTrees::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenTrees::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
@@ -324,7 +306,7 @@ int cStructGenTrees::GetNumTrees(
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenOreNests:
-void cStructGenOreNests::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenOreNests::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
@@ -431,7 +413,7 @@ void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_Ore
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenLakes:
-void cStructGenLakes::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenLakes::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
@@ -563,7 +545,7 @@ cStructGenDirectOverhangs::cStructGenDirectOverhangs(int a_Seed) :
-void cStructGenDirectOverhangs::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenDirectOverhangs::GenFinish(cChunkDesc & a_ChunkDesc)
{
// If there is no column of the wanted biome, bail out:
if (!HasWantedBiome(a_ChunkDesc))
@@ -596,7 +578,7 @@ void cStructGenDirectOverhangs::GenStructures(cChunkDesc & a_ChunkDesc)
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_X * x, BaseY, BaseZ + INTERPOL_Z * z) /
256;
} // for x, z - FloorLo[]
- LinearUpscale2DArrayInPlace(FloorLo, 17, 17, INTERPOL_X, INTERPOL_Z);
+ LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorLo);
// Interpolate segments:
for (int Segment = BaseY; Segment < MaxHeight; Segment += SEGMENT_HEIGHT)
@@ -609,7 +591,7 @@ void cStructGenDirectOverhangs::GenStructures(cChunkDesc & a_ChunkDesc)
m_Noise2.IntNoise3DInt(BaseX + INTERPOL_Z * x, Segment + SEGMENT_HEIGHT, BaseZ + INTERPOL_Z * z) /
256;
} // for x, z - FloorLo[]
- LinearUpscale2DArrayInPlace(FloorHi, 17, 17, INTERPOL_X, INTERPOL_Z);
+ LinearUpscale2DArrayInPlace<17, 17, INTERPOL_X, INTERPOL_Z>(FloorHi);
// Interpolate between FloorLo and FloorHi:
for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)
@@ -683,7 +665,7 @@ cStructGenDistortedMembraneOverhangs::cStructGenDistortedMembraneOverhangs(int a
-void cStructGenDistortedMembraneOverhangs::GenStructures(cChunkDesc & a_ChunkDesc)
+void cStructGenDistortedMembraneOverhangs::GenFinish(cChunkDesc & a_ChunkDesc)
{
const NOISE_DATATYPE Frequency = (NOISE_DATATYPE)16;
const NOISE_DATATYPE Amount = (NOISE_DATATYPE)1;
diff --git a/src/Generating/StructGen.h b/src/Generating/StructGen.h
index 853748bb8..9176bc192 100644
--- a/src/Generating/StructGen.h
+++ b/src/Generating/StructGen.h
@@ -21,7 +21,7 @@
class cStructGenTrees :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenTrees(int a_Seed, cBiomeGen * a_BiomeGen, cTerrainHeightGen * a_HeightGen, cTerrainCompositionGen * a_CompositionGen) :
@@ -64,8 +64,8 @@ protected:
const cChunkDef::BiomeMap & a_Biomes
);
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
@@ -73,7 +73,7 @@ protected:
class cStructGenOreNests :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenOreNests(int a_Seed) : m_Noise(a_Seed), m_Seed(a_Seed) {}
@@ -82,8 +82,8 @@ protected:
cNoise m_Noise;
int m_Seed;
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
void GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, int a_Seq);
} ;
@@ -93,7 +93,7 @@ protected:
class cStructGenLakes :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainHeightGen & a_HeiGen, int a_Probability) :
@@ -112,8 +112,8 @@ protected:
cTerrainHeightGen & m_HeiGen;
int m_Probability; ///< Chance, 0 .. 100, of a chunk having the lake
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // 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);
@@ -125,7 +125,7 @@ protected:
class cStructGenDirectOverhangs :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenDirectOverhangs(int a_Seed);
@@ -134,8 +134,8 @@ protected:
cNoise m_Noise1;
cNoise m_Noise2;
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
bool HasWantedBiome(cChunkDesc & a_ChunkDesc) const;
} ;
@@ -145,7 +145,7 @@ protected:
class cStructGenDistortedMembraneOverhangs :
- public cStructureGen
+ public cFinishGen
{
public:
cStructGenDistortedMembraneOverhangs(int a_Seed);
@@ -156,8 +156,8 @@ protected:
cNoise m_NoiseZ;
cNoise m_NoiseH;
- // cStructureGen override:
- virtual void GenStructures(cChunkDesc & a_ChunkDesc) override;
+ // cFinishGen override:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp
index 7e8a3c75f..4909587b1 100644
--- a/src/Generating/Trees.cpp
+++ b/src/Generating/Trees.cpp
@@ -382,6 +382,24 @@ void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Nois
+void GetAcaciaTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks)
+{
+ // TODO
+}
+
+
+
+
+
+void GetDarkoakTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks)
+{
+ // TODO
+}
+
+
+
+
+
void GetTallBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks)
{
int Height = 9 + (a_Noise.IntNoise3DInt(a_BlockX + 64 * a_Seq, a_BlockY, a_BlockZ) % 3);
@@ -577,7 +595,7 @@ void GetPineTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise
{
break;
}
- ASSERT(LayerSize < ARRAYCOUNT(BigOs));
+ ASSERT((size_t)LayerSize < ARRAYCOUNT(BigOs));
PushCoordBlocks(a_BlockX, h, a_BlockZ, a_OtherBlocks, BigOs[LayerSize].Coords, BigOs[LayerSize].Count, E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
h--;
}
diff --git a/src/Generating/Trees.h b/src/Generating/Trees.h
index 514158eb7..00f343a3d 100644
--- a/src/Generating/Trees.h
+++ b/src/Generating/Trees.h
@@ -63,6 +63,12 @@ void GetLargeAppleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a
/// Generates an image of a random birch tree
void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks);
+/// Generates an image of a random acacia tree
+void GetAcaciaTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks);
+
+/// Generates an image of a random darkoak tree
+void GetDarkoakTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks);
+
/// Generates an image of a random large birch tree
void GetTallBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks,sSetBlockVector & a_OtherBlocks);