diff --git a/source/BlockArea.cpp b/source/BlockArea.cpp index 66994f613..61abae716 100644 --- a/source/BlockArea.cpp +++ b/source/BlockArea.cpp @@ -92,6 +92,70 @@ static void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, N +/// Combinator used for cBlockArea::msLake merging +static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + // Sponge is the NOP block + if (a_SrcType == E_BLOCK_SPONGE) + { + return; + } + + // Air is always hollowed out + if (a_SrcType == E_BLOCK_AIR) + { + a_DstType = E_BLOCK_AIR; + a_DstMeta = 0; + return; + } + + // Water and lava are never overwritten + switch (a_DstType) + { + case E_BLOCK_WATER: + case E_BLOCK_STATIONARY_WATER: + case E_BLOCK_LAVA: + case E_BLOCK_STATIONARY_LAVA: + { + return; + } + } + + // Water and lava always overwrite + switch (a_SrcType) + { + case E_BLOCK_WATER: + case E_BLOCK_STATIONARY_WATER: + case E_BLOCK_LAVA: + case E_BLOCK_STATIONARY_LAVA: + { + a_DstType = a_SrcType; + a_DstMeta = a_DstMeta; + return; + } + } + + if (a_SrcType == E_BLOCK_STONE) + { + switch (a_DstType) + { + case E_BLOCK_DIRT: + case E_BLOCK_GRASS: + case E_BLOCK_MYCELIUM: + { + a_DstType = E_BLOCK_STONE; + a_DstMeta = 0; + return; + } + } + } + // Everything else is left as it is +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cBlockArea: @@ -611,6 +675,21 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R break; } // case msImprint + case msLake: + { + InternalMergeBlocks( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_SizeX, m_SizeY, m_SizeZ, + MergeCombinatorLake + ); + break; + } // case msLake + default: { LOGWARNING("Unknown block area merge strategy: %d", a_Strategy); diff --git a/source/BlockArea.h b/source/BlockArea.h index 653e52a70..94ad67e7f 100644 --- a/source/BlockArea.h +++ b/source/BlockArea.h @@ -49,6 +49,7 @@ public: msOverwrite, msFillAir, msImprint, + msLake, } ; cBlockArea(void); @@ -107,11 +108,29 @@ public: | A | air | air | A | A | | air | B | B | B | B | | A | B | B | A | B | - + So to sum up: - msOverwrite completely overwrites all blocks with the Src's blocks - msFillAir overwrites only those blocks that were air - msImprint overwrites with only those blocks that are non-air + + Special strategies: + msLake (evaluate top-down, first match wins): + | area block | | + | this | Src | result | + +----------+--------+--------+ + | A | sponge | A | Sponge is the NOP block + | * | air | air | Air always gets hollowed out, even under the oceans + | water | * | water | Water is never overwritten + | lava | * | lava | Lava is never overwritten + | * | water | water | Water always overwrites anything + | * | lava | lava | Lava always overwrites anything + | dirt | stone | stone | Stone overwrites dirt + | grass | stone | stone | ... and grass + | mycelium | stone | stone | ... and mycelium + | A | stone | A | ... but nothing else + | A | * | A | Everything else is left as it is + */ void Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy); diff --git a/source/Generating/ChunkDesc.cpp b/source/Generating/ChunkDesc.cpp index 9a2f2eff5..21ebf90ec 100644 --- a/source/Generating/ChunkDesc.cpp +++ b/source/Generating/ChunkDesc.cpp @@ -20,8 +20,11 @@ cChunkDesc::cChunkDesc(int a_ChunkX, int a_ChunkZ) : m_bUseDefaultStructures(true), m_bUseDefaultFinish(true) { + m_BlockArea.Create(cChunkDef::Width, cChunkDef::Height, cChunkDef::Width); + /* memset(m_BlockTypes, 0, sizeof(cChunkDef::BlockTypes)); memset(m_BlockMeta, 0, sizeof(cChunkDef::BlockNibbles)); + */ memset(m_BiomeMap, 0, sizeof(cChunkDef::BiomeMap)); memset(m_HeightMap, 0, sizeof(cChunkDef::HeightMap)); } @@ -51,9 +54,7 @@ void cChunkDesc::SetChunkCoords(int a_ChunkX, int a_ChunkZ) void cChunkDesc::FillBlocks(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - const NIBBLETYPE CompressedMeta = a_BlockMeta | (a_BlockMeta << 4); - memset(m_BlockTypes, a_BlockType, sizeof(cChunkDef::BlockTypes)); - memset(m_BlockMeta, CompressedMeta, sizeof(cChunkDef::BlockNibbles)); + m_BlockArea.Fill(cBlockArea::baTypes | cBlockArea::baMetas, a_BlockType, a_BlockMeta); } @@ -62,9 +63,7 @@ void cChunkDesc::FillBlocks(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) void cChunkDesc::SetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - int Index = cChunkDef::MakeIndex(a_RelX, a_RelY, a_RelZ); - cChunkDef::SetBlock(m_BlockTypes, Index, a_BlockType); - cChunkDef::SetNibble(m_BlockMeta, Index, a_BlockMeta); + m_BlockArea.SetRelBlockTypeMeta(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); } @@ -73,9 +72,7 @@ void cChunkDesc::SetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE void cChunkDesc::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) { - int Index = cChunkDef::MakeIndex(a_RelX, a_RelY, a_RelZ); - a_BlockType = cChunkDef::GetBlock(m_BlockTypes, Index); - a_BlockMeta = cChunkDef::GetNibble(m_BlockMeta, Index); + m_BlockArea.GetRelBlockTypeMeta(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); } @@ -84,7 +81,7 @@ void cChunkDesc::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE void cChunkDesc::SetBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType) { - cChunkDef::SetBlock(m_BlockTypes, a_RelX, a_RelY, a_RelZ, a_BlockType); + cChunkDef::SetBlock(m_BlockArea.GetBlockTypes(), a_RelX, a_RelY, a_RelZ, a_BlockType); } @@ -93,7 +90,7 @@ void cChunkDesc::SetBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl BLOCKTYPE cChunkDesc::GetBlockType(int a_RelX, int a_RelY, int a_RelZ) { - return cChunkDef::GetBlock(m_BlockTypes, a_RelX, a_RelY, a_RelZ); + return cChunkDef::GetBlock(m_BlockArea.GetBlockTypes(), a_RelX, a_RelY, a_RelZ); } @@ -102,7 +99,7 @@ BLOCKTYPE cChunkDesc::GetBlockType(int a_RelX, int a_RelY, int a_RelZ) NIBBLETYPE cChunkDesc::GetBlockMeta(int a_RelX, int a_RelY, int a_RelZ) { - return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); + return m_BlockArea.GetRelBlockMeta(a_RelX, a_RelY, a_RelZ); } @@ -111,7 +108,7 @@ NIBBLETYPE cChunkDesc::GetBlockMeta(int a_RelX, int a_RelY, int a_RelZ) void cChunkDesc::SetBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockMeta) { - cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_BlockMeta); + m_BlockArea.SetRelBlockMeta(a_RelX, a_RelY, a_RelZ, a_BlockMeta); } @@ -242,62 +239,9 @@ bool cChunkDesc::IsUsingDefaultFinish(void) const -void cChunkDesc::WriteBlockArea(const cBlockArea & a_BlockArea, int a_RelX, int a_RelY, int a_RelZ) +void cChunkDesc::WriteBlockArea(const cBlockArea & a_BlockArea, int a_RelX, int a_RelY, int a_RelZ, cBlockArea::eMergeStrategy a_MergeStrategy) { - if (!a_BlockArea.HasBlockTypes() && !a_BlockArea.HasBlockMetas()) - { - LOGWARNING("Request was made to write a block area without BlockTypes nor BlockMetas into cChunkDesc. Ignoring."); - return; - } - int BAOffX = std::max(0, -a_RelX); // Offset in BA where to start reading - int CDOffX = std::max(0, a_RelX); // Offset in CD where to start writing - int SizeX = std::min(a_BlockArea.GetSizeX() - BAOffX, cChunkDef::Width - CDOffX); // Number of slices to write - int BAOffY = std::max(0, -a_RelY); // Offset in BA where to start reading - int CDOffY = std::max(0, a_RelY); // Offset in CD where to start writing - int SizeY = std::min(a_BlockArea.GetSizeY() - BAOffY, cChunkDef::Height - CDOffY); // Number of layers to write - int BAOffZ = std::max(0, -a_RelZ); // Offset in BA where to start reading - int CDOffZ = std::max(0, a_RelZ); // Offset in CD where to start writing - int SizeZ = std::min(a_BlockArea.GetSizeZ() - BAOffZ, cChunkDef::Width - CDOffZ); // Number of slices to write - - if (a_BlockArea.HasBlockTypes()) - { - for (int y = 0; y < SizeY; y++) - { - int BAY = BAOffY + y; - int CDY = CDOffY + y; - for (int z = 0; z < SizeZ; z++) - { - int BAZ = BAOffZ + z; - int CDZ = CDOffZ + z; - for (int x = 0; x < SizeX; x++) - { - int BAX = BAOffX + x; - int CDX = CDOffX + x; - cChunkDef::SetBlock(m_BlockTypes, CDX, CDY, CDZ, a_BlockArea.GetRelBlockType(BAX, BAY, BAZ)); - } // for x - } // for z - } // for y - } // HasBlockTypes() - - if (a_BlockArea.HasBlockMetas()) - { - for (int y = 0; y < SizeY; y++) - { - int BAY = BAOffY + y; - int CDY = CDOffY + y; - for (int z = 0; z < SizeZ; z++) - { - int BAZ = BAOffZ + z; - int CDZ = CDOffZ + z; - for (int x = 0; x < SizeX; x++) - { - int BAX = BAOffX + x; - int CDX = CDOffX + x; - cChunkDef::SetNibble(m_BlockMeta, CDX, CDY, CDZ, a_BlockArea.GetRelBlockMeta(BAX, BAY, BAZ)); - } // for x - } // for z - } // for y - } // HasBlockMetas() + m_BlockArea.Merge(a_BlockArea, a_RelX, a_RelY, a_RelZ, a_MergeStrategy); } @@ -437,3 +381,16 @@ HEIGHTTYPE cChunkDesc::GetMaxHeight(void) const + +void cChunkDesc::CompressBlockMetas(cChunkDef::BlockNibbles & a_DestMetas) +{ + const NIBBLETYPE * AreaMetas = m_BlockArea.GetBlockMetas(); + for (int i = 0; i < ARRAYCOUNT(a_DestMetas); i++) + { + a_DestMetas[i] = AreaMetas[2 * i] | (AreaMetas[2 * i + 1] << 4); + } +} + + + + diff --git a/source/Generating/ChunkDesc.h b/source/Generating/ChunkDesc.h index 7df7a1d35..226d22429 100644 --- a/source/Generating/ChunkDesc.h +++ b/source/Generating/ChunkDesc.h @@ -10,6 +10,7 @@ #pragma once #include "../ChunkDef.h" +#include "../BlockArea.h" @@ -67,7 +68,7 @@ public: 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. - void WriteBlockArea(const cBlockArea & a_BlockArea, int a_RelX, int a_RelY, int a_RelZ); + 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 void ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX, int a_MinRelY, int a_MaxRelY, int a_MinRelZ, int a_MaxRelZ); @@ -80,24 +81,26 @@ public: // Accessors used by cChunkGenerator::Generator descendants: inline cChunkDef::BiomeMap & GetBiomeMap (void) { return m_BiomeMap; } - inline cChunkDef::BlockTypes & GetBlockTypes (void) { return m_BlockTypes; } - inline cChunkDef::BlockNibbles & GetBlockMetas (void) { return m_BlockMeta; } + inline cChunkDef::BlockTypes & GetBlockTypes (void) { return *((cChunkDef::BlockTypes *)m_BlockArea.GetBlockTypes()); } + // CANNOT, different compression! + // inline cChunkDef::BlockNibbles & GetBlockMetas (void) { return *((cChunkDef::BlockNibbles *)m_BlockArea.GetBlockMetas()); } inline cChunkDef::HeightMap & GetHeightMap (void) { return m_HeightMap; } 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) + void CompressBlockMetas(cChunkDef::BlockNibbles & a_DestMetas); + private: int m_ChunkX; int m_ChunkZ; cChunkDef::BiomeMap m_BiomeMap; - cChunkDef::BlockTypes m_BlockTypes; - cChunkDef::BlockNibbles m_BlockMeta; + cBlockArea m_BlockArea; cChunkDef::HeightMap m_HeightMap; cEntityList m_Entities; // Individual entities are NOT owned by this object! cBlockEntityList m_BlockEntities; // Individual block entities are NOT owned by this object! - bool m_bUseDefaultBiomes; bool m_bUseDefaultHeight; bool m_bUseDefaultComposition; diff --git a/source/Generating/ChunkGenerator.cpp b/source/Generating/ChunkGenerator.cpp index f235215da..b3c25cf46 100644 --- a/source/Generating/ChunkGenerator.cpp +++ b/source/Generating/ChunkGenerator.cpp @@ -271,9 +271,12 @@ void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) m_Generator->DoGenerate(a_ChunkX, a_ChunkZ, ChunkDesc); cRoot::Get()->GetPluginManager()->CallHookChunkGenerated(m_World, a_ChunkX, a_ChunkZ, &ChunkDesc); + cChunkDef::BlockNibbles BlockMetas; + ChunkDesc.CompressBlockMetas(BlockMetas); + m_World->SetChunkData( a_ChunkX, a_ChunkY, a_ChunkZ, - ChunkDesc.GetBlockTypes(), ChunkDesc.GetBlockMetas(), + ChunkDesc.GetBlockTypes(), BlockMetas, NULL, NULL, // We don't have lighting, chunk will be lighted when needed &ChunkDesc.GetHeightMap(), &ChunkDesc.GetBiomeMap(), ChunkDesc.GetEntities(), ChunkDesc.GetBlockEntities(), diff --git a/source/Generating/CompoGen.cpp b/source/Generating/CompoGen.cpp index 34a83bd52..2e0ec5d18 100644 --- a/source/Generating/CompoGen.cpp +++ b/source/Generating/CompoGen.cpp @@ -20,8 +20,7 @@ void cCompoGenSameBlock::ComposeTerrain(cChunkDesc & a_ChunkDesc) { - memset(a_ChunkDesc.GetBlockTypes(), E_BLOCK_AIR, sizeof(a_ChunkDesc.GetBlockTypes())); - memset(a_ChunkDesc.GetBlockMetas(), 0, sizeof(a_ChunkDesc.GetBlockMetas())); + a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0); for (int z = 0; z < cChunkDef::Width; z++) { for (int x = 0; x < cChunkDef::Width; x++) @@ -80,8 +79,7 @@ void cCompoGenDebugBiomes::ComposeTerrain(cChunkDesc & a_ChunkDesc) E_BLOCK_BEDROCK, } ; - memset(a_ChunkDesc.GetBlockTypes(), E_BLOCK_AIR, sizeof(a_ChunkDesc.GetBlockTypes())); - memset(a_ChunkDesc.GetBlockMetas(), 0, sizeof(a_ChunkDesc.GetBlockMetas())); + a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0); for (int z = 0; z < cChunkDef::Width; z++) { @@ -134,8 +132,7 @@ void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc) - bedrock at the bottom */ - memset(a_ChunkDesc.GetBlockTypes(), E_BLOCK_AIR, sizeof(a_ChunkDesc.GetBlockTypes())); - memset(a_ChunkDesc.GetBlockMetas(), 0, sizeof(a_ChunkDesc.GetBlockMetas())); + a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0); // The patterns to use for different situations, must be same length! const BLOCKTYPE PatternGround[] = {m_BlockTop, m_BlockMiddle, m_BlockMiddle, m_BlockMiddle} ; @@ -191,8 +188,7 @@ void cCompoGenClassic::ComposeTerrain(cChunkDesc & a_ChunkDesc) void cCompoGenBiomal::ComposeTerrain(cChunkDesc & a_ChunkDesc) { - memset(a_ChunkDesc.GetBlockTypes(), E_BLOCK_AIR, sizeof(a_ChunkDesc.GetBlockTypes())); - memset(a_ChunkDesc.GetBlockMetas(), 0, sizeof(a_ChunkDesc.GetBlockMetas())); + a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0); int ChunkX = a_ChunkDesc.GetChunkX(); int ChunkZ = a_ChunkDesc.GetChunkZ(); diff --git a/source/Generating/ComposableGenerator.cpp b/source/Generating/ComposableGenerator.cpp index b88fb90c7..e349d73f7 100644 --- a/source/Generating/ComposableGenerator.cpp +++ b/source/Generating/ComposableGenerator.cpp @@ -94,21 +94,14 @@ void cComposableGenerator::GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef: void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) { - cChunkDef::BiomeMap & BiomeMap = a_ChunkDesc.GetBiomeMap(); - cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes(); - cChunkDef::BlockNibbles & BlockMeta = a_ChunkDesc.GetBlockMetas(); - cChunkDef::HeightMap & HeightMap = a_ChunkDesc.GetHeightMap(); - cEntityList & Entities = a_ChunkDesc.GetEntities(); - cBlockEntityList & BlockEntities = a_ChunkDesc.GetBlockEntities(); - if (a_ChunkDesc.IsUsingDefaultBiomes()) { - m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, BiomeMap); + m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetBiomeMap()); } if (a_ChunkDesc.IsUsingDefaultHeight()) { - m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, HeightMap); + m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetHeightMap()); } if (a_ChunkDesc.IsUsingDefaultComposition()) @@ -336,13 +329,18 @@ void cComposableGenerator::InitStructureGens(cIniFile & a_IniFile) { m_StructureGens.push_back(new cStructGenRavines(Seed, 128)); } - //* - // TODO: Not implemented yet; need a name else if (NoCaseCompare(*itr, "wormnestcaves") == 0) { m_StructureGens.push_back(new cStructGenWormNestCaves(Seed)); } - //*/ + else if (NoCaseCompare(*itr, "waterlakes") == 0) + { + m_StructureGens.push_back(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, *m_HeightGen)); + } + else if (NoCaseCompare(*itr, "lavalakes") == 0) + { + m_StructureGens.push_back(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, *m_HeightGen)); + } else { LOGWARNING("Unknown structure generator: \"%s\". Ignoring.", itr->c_str()); diff --git a/source/Generating/FinishGen.cpp b/source/Generating/FinishGen.cpp index 6a7d53b14..df9b2f265 100644 --- a/source/Generating/FinishGen.cpp +++ b/source/Generating/FinishGen.cpp @@ -598,7 +598,7 @@ void cFinishGenFluidSprings::GenFinish(cChunkDesc & a_ChunkDesc) case E_BLOCK_NETHERRACK: case E_BLOCK_STONE: { - if (TryPlaceSpring(a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetBlockMetas(), x, y, z)) + if (TryPlaceSpring(a_ChunkDesc, x, y, z)) { // Succeeded, bail out return; @@ -614,15 +614,11 @@ void cFinishGenFluidSprings::GenFinish(cChunkDesc & a_ChunkDesc) -bool cFinishGenFluidSprings::TryPlaceSpring( - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::BlockNibbles & a_BlockMetas, - int x, int y, int z -) +bool cFinishGenFluidSprings::TryPlaceSpring(cChunkDesc & a_ChunkDesc, int x, int y, int z) { // In order to place a spring, it needs exactly one of the XZ neighbors or a below neighbor to be air // Also, its neighbor on top of it must be non-air - if (cChunkDef::GetBlock(a_BlockTypes, x, y + 1, z) == E_BLOCK_AIR) + if (a_ChunkDesc.GetBlockType(x, y + 1, z) == E_BLOCK_AIR) { return false; } @@ -641,7 +637,7 @@ bool cFinishGenFluidSprings::TryPlaceSpring( int NumAirNeighbors = 0; for (int i = 0; i < ARRAYCOUNT(Coords); i++) { - switch (cChunkDef::GetBlock(a_BlockTypes, x + Coords[i].x, y + Coords[i].y, z + Coords[i].z)) + switch (a_ChunkDesc.GetBlockType(x + Coords[i].x, y + Coords[i].y, z + Coords[i].z)) { case E_BLOCK_AIR: { @@ -659,8 +655,7 @@ bool cFinishGenFluidSprings::TryPlaceSpring( } // Has exactly one air neighbor, place a spring: - cChunkDef::SetBlock(a_BlockTypes, x, y, z, m_Fluid); - cChunkDef::SetNibble(a_BlockMetas, x, y, z, 0); + a_ChunkDesc.SetBlockTypeMeta(x, y, z, m_Fluid, 0); return true; } diff --git a/source/Generating/FinishGen.h b/source/Generating/FinishGen.h index b4bf67022..ed7df5909 100644 --- a/source/Generating/FinishGen.h +++ b/source/Generating/FinishGen.h @@ -177,11 +177,7 @@ protected: virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; /// Tries to place a spring at the specified coords, checks neighbors. Returns true if successful - bool TryPlaceSpring( - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::BlockNibbles & a_BlockMetas, - int x, int y, int z - ); + bool TryPlaceSpring(cChunkDesc & a_ChunkDesc, int x, int y, int z); } ; diff --git a/source/Generating/StructGen.cpp b/source/Generating/StructGen.cpp index 6d139da2a..6c5bf6491 100644 --- a/source/Generating/StructGen.cpp +++ b/source/Generating/StructGen.cpp @@ -5,6 +5,7 @@ #include "StructGen.h" #include "../BlockID.h" #include "Trees.h" +#include "../BlockArea.h" @@ -85,18 +86,11 @@ void cStructGenTrees::GenStructures(cChunkDesc & a_ChunkDesc) { int BaseZ = ChunkZ + z - 1; - cChunkDef::BlockTypes * BlT; - cChunkDef::BlockNibbles * BlM; - cChunkDef::HeightMap * Hei; - cChunkDef::BiomeMap * Bio; - + cChunkDesc * Dest; if ((x != 1) || (z != 1)) { - BlT = &(WorkerDesc.GetBlockTypes()); - BlM = &(WorkerDesc.GetBlockMetas()); - Hei = &(WorkerDesc.GetHeightMap()); - Bio = &(WorkerDesc.GetBiomeMap()); + Dest = &WorkerDesc; WorkerDesc.SetChunkCoords(BaseX, BaseZ); m_BiomeGen->GenBiomes (BaseX, BaseZ, WorkerDesc.GetBiomeMap()); @@ -106,26 +100,23 @@ void cStructGenTrees::GenStructures(cChunkDesc & a_ChunkDesc) } else { - BlT = &(a_ChunkDesc.GetBlockTypes()); - BlM = &(a_ChunkDesc.GetBlockMetas()); - Hei = &(a_ChunkDesc.GetHeightMap()); - Bio = &(a_ChunkDesc.GetBiomeMap()); + Dest = &a_ChunkDesc; } - int NumTrees = GetNumTrees(BaseX, BaseZ, *Bio); + int NumTrees = GetNumTrees(BaseX, BaseZ, Dest->GetBiomeMap()); sSetBlockVector OutsideLogs, OutsideOther; for (int i = 0; i < NumTrees; i++) { - GenerateSingleTree(BaseX, BaseZ, i, *BlT, *BlM, *Hei, *Bio, OutsideLogs, OutsideOther); + GenerateSingleTree(BaseX, BaseZ, i, *Dest, OutsideLogs, OutsideOther); } sSetBlockVector IgnoredOverflow; IgnoredOverflow.reserve(OutsideOther.size()); - ApplyTreeImage(ChunkX, ChunkZ, a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetBlockMetas(), OutsideOther, IgnoredOverflow); + ApplyTreeImage(ChunkX, ChunkZ, a_ChunkDesc, OutsideOther, IgnoredOverflow); IgnoredOverflow.clear(); IgnoredOverflow.reserve(OutsideLogs.size()); - ApplyTreeImage(ChunkX, ChunkZ, a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetBlockMetas(), OutsideLogs, IgnoredOverflow); + ApplyTreeImage(ChunkX, ChunkZ, a_ChunkDesc, OutsideLogs, IgnoredOverflow); } // for z } // for x @@ -136,9 +127,9 @@ void cStructGenTrees::GenStructures(cChunkDesc & a_ChunkDesc) { for (int y = cChunkDef::Height - 1; y >= 0; y--) { - if (cChunkDef::GetBlock(a_ChunkDesc.GetBlockTypes(), x, y, z) != E_BLOCK_AIR) + if (a_ChunkDesc.GetBlockType(x, y, z) != E_BLOCK_AIR) { - cChunkDef::SetHeight(a_ChunkDesc.GetHeightMap(), x, z, y); + a_ChunkDesc.SetHeight(x, z, y); break; } } // for y @@ -152,10 +143,7 @@ void cStructGenTrees::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenTrees::GenerateSingleTree( int a_ChunkX, int a_ChunkZ, int a_Seq, - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::BlockNibbles & a_BlockMetas, - const cChunkDef::HeightMap & a_Height, - const cChunkDef::BiomeMap & a_Biomes, + cChunkDesc & a_ChunkDesc, sSetBlockVector & a_OutsideLogs, sSetBlockVector & a_OutsideOther ) @@ -163,7 +151,7 @@ void cStructGenTrees::GenerateSingleTree( int x = (m_Noise.IntNoise3DInt(a_ChunkX + a_ChunkZ, a_ChunkZ, a_Seq) / 19) % cChunkDef::Width; int z = (m_Noise.IntNoise3DInt(a_ChunkX - a_ChunkZ, a_Seq, a_ChunkZ) / 19) % cChunkDef::Width; - int Height = cChunkDef::GetHeight(a_Height, x, z); + int Height = a_ChunkDesc.GetHeight(x, z); if ((Height <= 0) || (Height > 240)) { @@ -171,7 +159,7 @@ void cStructGenTrees::GenerateSingleTree( } // Check the block underneath the tree: - BLOCKTYPE TopBlock = cChunkDef::GetBlock(a_BlockTypes, x, Height, z); + BLOCKTYPE TopBlock = a_ChunkDesc.GetBlockType(x, Height, z); if ((TopBlock != E_BLOCK_DIRT) && (TopBlock != E_BLOCK_GRASS) && (TopBlock != E_BLOCK_FARMLAND)) { return; @@ -181,7 +169,7 @@ void cStructGenTrees::GenerateSingleTree( GetTreeImageByBiome( a_ChunkX * cChunkDef::Width + x, Height + 1, a_ChunkZ * cChunkDef::Width + z, m_Noise, a_Seq, - cChunkDef::GetBiome(a_Biomes, x, z), + a_ChunkDesc.GetBiome(x, z), TreeLogs, TreeOther ); @@ -194,7 +182,7 @@ void cStructGenTrees::GenerateSingleTree( continue; } - BLOCKTYPE Block = cChunkDef::GetBlock(a_BlockTypes, itr->x, itr->y, itr->z); + BLOCKTYPE Block = a_ChunkDesc.GetBlockType(itr->x, itr->y, itr->z); switch (Block) { CASE_TREE_ALLOWED_BLOCKS: @@ -209,8 +197,8 @@ void cStructGenTrees::GenerateSingleTree( } } - ApplyTreeImage(a_ChunkX, a_ChunkZ, a_BlockTypes, a_BlockMetas, TreeOther, a_OutsideOther); - ApplyTreeImage(a_ChunkX, a_ChunkZ, a_BlockTypes, a_BlockMetas, TreeLogs, a_OutsideLogs); + ApplyTreeImage(a_ChunkX, a_ChunkZ, a_ChunkDesc, TreeOther, a_OutsideOther); + ApplyTreeImage(a_ChunkX, a_ChunkZ, a_ChunkDesc, TreeLogs, a_OutsideLogs); } @@ -219,19 +207,18 @@ void cStructGenTrees::GenerateSingleTree( void cStructGenTrees::ApplyTreeImage( int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::BlockNibbles & a_BlockMetas, + cChunkDesc & a_ChunkDesc, const sSetBlockVector & a_Image, sSetBlockVector & a_Overflow ) { // Put the generated image into a_BlockTypes, push things outside this chunk into a_Blocks - for (sSetBlockVector::const_iterator itr = a_Image.begin(); itr != a_Image.end(); ++itr) + for (sSetBlockVector::const_iterator itr = a_Image.begin(), end = a_Image.end(); itr != end; ++itr) { if ((itr->ChunkX == a_ChunkX) && (itr->ChunkZ == a_ChunkZ)) { - // Inside this chunk, integrate into a_BlockTypes: - switch (cChunkDef::GetBlock(a_BlockTypes, itr->x, itr->y, itr->z)) + // Inside this chunk, integrate into a_ChunkDesc: + switch (a_ChunkDesc.GetBlockType(itr->x, itr->y, itr->z)) { case E_BLOCK_LEAVES: { @@ -243,8 +230,7 @@ void cStructGenTrees::ApplyTreeImage( } CASE_TREE_OVERWRITTEN_BLOCKS: { - cChunkDef::SetBlock (a_BlockTypes, itr->x, itr->y, itr->z, itr->BlockType); - cChunkDef::SetNibble(a_BlockMetas, itr->x, itr->y, itr->z, itr->BlockMeta); + a_ChunkDesc.SetBlockTypeMeta(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta); break; } @@ -271,22 +257,22 @@ int cStructGenTrees::GetNumTrees( for (int x = 0; x < cChunkDef::Width; x++) for (int z = 0; z < cChunkDef::Width; z++) { int Add = 0; - switch (a_Biomes[x + cChunkDef::Width * z]) + switch (cChunkDef::GetBiome(a_Biomes, x, z)) { - case biPlains: Add = 1; break; - case biExtremeHills: Add = 3; break; - case biForest: Add = 30; break; - case biTaiga: Add = 30; break; - case biSwampland: Add = 8; break; - case biIcePlains: Add = 1; break; - case biIceMountains: Add = 1; break; - case biMushroomIsland: Add = 3; break; - case biMushroomShore: Add = 3; break; - case biForestHills: Add = 20; break; - case biTaigaHills: Add = 20; break; - case biExtremeHillsEdge: Add = 5; break; + case biPlains: Add = 1; break; + case biExtremeHills: Add = 3; break; + case biForest: Add = 30; break; + case biTaiga: Add = 30; break; + case biSwampland: Add = 8; break; + case biIcePlains: Add = 1; break; + case biIceMountains: Add = 1; break; + case biMushroomIsland: Add = 3; break; + case biMushroomShore: Add = 3; break; + case biForestHills: Add = 20; break; + case biTaigaHills: Add = 20; break; + case biExtremeHillsEdge: Add = 5; break; case biJungle: Add = 120; break; - case biJungleHills: Add = 90; break; + case biJungleHills: Add = 90; break; } NumTrees += Add; } @@ -403,3 +389,118 @@ void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_Ore + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cStructGenLakes: + +void cStructGenLakes::GenStructures(cChunkDesc & a_ChunkDesc) +{ + int ChunkX = a_ChunkDesc.GetChunkX(); + int ChunkZ = a_ChunkDesc.GetChunkZ(); + + for (int z = -1; z < 2; z++) for (int x = -1; x < 2; x++) + { + cBlockArea Lake; + CreateLakeImage(ChunkX + x, ChunkZ + z, Lake); + + int OfsX = Lake.GetOriginX() + x * cChunkDef::Width; + int OfsZ = Lake.GetOriginZ() + z * cChunkDef::Width; + + // Merge the lake into the current data + a_ChunkDesc.WriteBlockArea(Lake, OfsX, Lake.GetOriginY(), OfsZ, cBlockArea::msLake); + } // for x, z - neighbor chunks +} + + + + + +void cStructGenLakes::CreateLakeImage(int a_ChunkX, int a_ChunkZ, cBlockArea & a_Lake) +{ + a_Lake.Create(16, 8, 16); + a_Lake.Fill(cBlockArea::baTypes, E_BLOCK_SPONGE); // Sponge is the NOP blocktype for lake merging strategy + + // Find the maximum height in this chunk: + cChunkDef::HeightMap HeightMap; + m_HeiGen.GenHeightMap(a_ChunkX, a_ChunkZ, HeightMap); + HEIGHTTYPE MaxHeight = HeightMap[0]; + for (int i = 1; i < ARRAYCOUNT(HeightMap); i++) + { + if (HeightMap[i] > MaxHeight) + { + MaxHeight = HeightMap[i]; + } + } + + // Make a random position in the chunk by using a random 16 block XZ offset and random height up to chunk's max height + int Rnd = m_Noise.IntNoise3DInt(a_ChunkX, 128, a_ChunkZ) / 11; + // Random offset [-8 .. 8], with higher probability around 0; add up four three-bit-wide randoms [0 .. 28], divide and subtract to get range + int OffsetX = 4 * ((Rnd & 0x07) + ((Rnd & 0x38) >> 3) + ((Rnd & 0x1c0) >> 6) + ((Rnd & 0xe00) >> 9)) / 7 - 8; + Rnd >>= 12; + // Random offset [-8 .. 8], with higher probability around 0; add up four three-bit-wide randoms [0 .. 28], divide and subtract to get range + int OffsetZ = 4 * ((Rnd & 0x07) + ((Rnd & 0x38) >> 3) + ((Rnd & 0x1c0) >> 6) + ((Rnd & 0xe00) >> 9)) / 7 - 8; + Rnd = m_Noise.IntNoise3DInt(a_ChunkX, 512, a_ChunkZ) / 13; + // Random height [0 .. MaxHeight] with preference to center heights + int HeightY = (((Rnd & 0x1ff) % (MaxHeight + 1)) + (((Rnd >> 9) & 0x1ff) % (MaxHeight + 1))) / 2; + a_Lake.SetOrigin(OffsetX, HeightY, OffsetZ); + + // Hollow out a few bubbles inside the blockarea: + int NumBubbles = 4 + ((Rnd >> 18) & 0x03); // 4 .. 7 bubbles + BLOCKTYPE * BlockTypes = a_Lake.GetBlockTypes(); + for (int i = 0; i < NumBubbles; i++) + { + int Rnd = m_Noise.IntNoise3DInt(a_ChunkX, i, a_ChunkZ) / 13; + const int BubbleR = 2 + (Rnd & 0x03); // 2 .. 5 + const int Range = 16 - 2 * BubbleR; + const int BubbleX = BubbleR + (Rnd % Range); + Rnd >>= 4; + const int BubbleY = 4 + (Rnd & 0x01); // 4 .. 5 + Rnd >>= 1; + const int BubbleZ = BubbleR + (Rnd % Range); + Rnd >>= 4; + const int HalfR = BubbleR / 2; // 1 .. 2 + const int RSquared = BubbleR * BubbleR; + for (int y = -HalfR; y <= HalfR; y++) + { + // BubbleY + y is in the [0, 7] bounds + int DistY = 4 * y * y / 3; + int IdxY = (BubbleY + y) * 16 * 16; + for (int z = -BubbleR; z <= BubbleR; z++) + { + int DistYZ = DistY + z * z; + if (DistYZ >= RSquared) + { + continue; + } + int IdxYZ = BubbleX + IdxY + (BubbleZ + z) * 16; + for (int x = -BubbleR; x <= BubbleR; x++) + { + if (x * x + DistYZ < RSquared) + { + BlockTypes[x + IdxYZ] = E_BLOCK_AIR; + } + } // for x + } // for z + } // for y + } // for i - bubbles + + // Turn air in the bottom half into liquid: + for (int y = 0; y < 4; y++) + { + for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++) + { + if (BlockTypes[x + z * 16 + y * 16 * 16] == E_BLOCK_AIR) + { + BlockTypes[x + z * 16 + y * 16 * 16] = m_Fluid; + } + } // for z, x + } // for y + + // TODO: Turn sponge next to lava into stone + + // a_Lake.SaveToSchematicFile(Printf("Lake_%d_%d.schematic", a_ChunkX, a_ChunkZ)); +} + + + + diff --git a/source/Generating/StructGen.h b/source/Generating/StructGen.h index c627499e2..ffb62e327 100644 --- a/source/Generating/StructGen.h +++ b/source/Generating/StructGen.h @@ -46,10 +46,7 @@ protected: */ void GenerateSingleTree( int a_ChunkX, int a_ChunkZ, int a_Seq, - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::BlockNibbles & a_BlockMetas, - const cChunkDef::HeightMap & a_Height, - const cChunkDef::BiomeMap & a_Biomes, + cChunkDesc & a_ChunkDesc, sSetBlockVector & a_OutsideLogs, sSetBlockVector & a_OutsideOther ) ; @@ -57,8 +54,7 @@ protected: /// Applies an image into chunk blockdata; all blocks outside the chunk will be appended to a_Overflow void ApplyTreeImage( int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::BlockNibbles & a_BlockMetas, + cChunkDesc & a_ChunkDesc, const sSetBlockVector & a_Image, sSetBlockVector & a_Overflow ); @@ -100,15 +96,25 @@ class cStructGenLakes : public cStructureGen { public: - cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid) : m_Noise(a_Seed), m_Seed(a_Seed), m_Fluid(a_Fluid) {} + cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainHeightGen & a_HeiGen) : + m_Noise(a_Seed), + m_Seed(a_Seed), + m_Fluid(a_Fluid), + m_HeiGen(a_HeiGen) + { + } protected: - cNoise m_Noise; - int m_Seed; - BLOCKTYPE m_Fluid; + cNoise m_Noise; + int m_Seed; + BLOCKTYPE m_Fluid; + cTerrainHeightGen & m_HeiGen; // cStructureGen override: virtual void GenStructures(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); } ;