From 76a92a21d11265ad17dffd11101ea87ce5c60e6a Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sat, 18 Feb 2012 19:18:16 +0000 Subject: Re-implemented tree-growing. May produce artefacts on old-world / new-world boundaries. git-svn-id: http://mc-server.googlecode.com/svn/trunk@293 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cChunk.cpp | 10 ++ source/cChunk.h | 9 +- source/cChunkGenerator.cpp | 1 + source/cChunkMap.cpp | 16 +++ source/cChunkMap.h | 1 + source/cWorld.cpp | 43 ++++++-- source/cWorld.h | 1 + source/cWorldGenerator.cpp | 221 +++++++++++++++++++++++----------------- source/cWorldGenerator.h | 6 +- source/cWorldGenerator_Test.cpp | 6 +- source/cWorldGenerator_Test.h | 2 +- 11 files changed, 205 insertions(+), 111 deletions(-) diff --git a/source/cChunk.cpp b/source/cChunk.cpp index b5e56f3c6..afa69fb68 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -248,6 +248,16 @@ void cChunk::SetAllData(const char * a_BlockData, cEntityList & a_Entities, cBlo +/// Copies m_BlockData into a_Blocks, only the block types +void cChunk::GetBlocks(char * a_Blocks) +{ + memcpy(a_Blocks, m_BlockData, cChunk::c_NumBlocks); +} + + + + + /// Returns true if there is a block entity at the coords specified bool cChunk::HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ) { diff --git a/source/cChunk.h b/source/cChunk.h index 60e11b133..2576e2412 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -73,6 +73,9 @@ public: class cChunk { public: + static const int c_NumBlocks = 16 * 128 * 16; + static const int c_BlockDataSize = c_NumBlocks * 2 + (c_NumBlocks/2); // 2.5 * numblocks + cChunk(int a_X, int a_Y, int a_Z, cWorld* a_World); ~cChunk(); @@ -98,6 +101,9 @@ public: /// Sets all chunk data void SetAllData(const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); + /// Copies m_BlockData into a_Blocks, only the block types + void GetBlocks(char a_Blocks[cChunk::c_NumBlocks]); + /// Returns true if there is a block entity at the coords specified bool HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ); @@ -183,9 +189,6 @@ public: m_IsSaving = false; } - static const int c_NumBlocks = 16*128*16; - static const int c_BlockDataSize = c_NumBlocks * 2 + (c_NumBlocks/2); // 2.5 * numblocks - private: bool m_IsValid; // True if the chunk is loaded / generated diff --git a/source/cChunkGenerator.cpp b/source/cChunkGenerator.cpp index c0fea1fae..c66d20082 100644 --- a/source/cChunkGenerator.cpp +++ b/source/cChunkGenerator.cpp @@ -182,6 +182,7 @@ void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) cBlockEntityList BlockEntities; m_pWorldGenerator->GenerateChunk(a_ChunkX, a_ChunkY, a_ChunkZ, BlockData, Entities, BlockEntities); m_World->ChunkDataGenerated(a_ChunkX, a_ChunkY, a_ChunkZ, BlockData, Entities, BlockEntities); + m_pWorldGenerator->PostGenerateChunk(a_ChunkX, a_ChunkY, a_ChunkZ); } diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index 96d3b14e0..c5512dd68 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -271,6 +271,22 @@ void cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDat +bool cChunkMap::GetChunkBlocks(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_Blocks) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + if ((Chunk == NULL) || !Chunk->IsValid()) + { + return false; + } + Chunk->GetBlocks(a_Blocks); + return true; +} + + + + + bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { cCSLock Lock(m_CSLayers); diff --git a/source/cChunkMap.h b/source/cChunkMap.h index ffea1d504..7c26a14c0 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -42,6 +42,7 @@ public: void ChunkDataLoaded (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); void ChunkDataGenerated (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback); + bool GetChunkBlocks (int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_Blocks); bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ); bool HasChunkAnyClients (int a_ChunkX, int a_ChunkY, int a_ChunkZ); void SpreadChunkLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ); diff --git a/source/cWorld.cpp b/source/cWorld.cpp index f57c8b5cf..2cde3ac7b 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -431,7 +431,9 @@ void cWorld::InitializeSpawn() int ChunkX = 0, ChunkY = 0, ChunkZ = 0; BlockToChunk( (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ ); - int ViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is + // DEBUG: + // int ViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is + int ViewDist = 5; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is LOG("Preparing spawn area in world \"%s\"", m_WorldName.c_str()); for (int x = 0; x < ViewDist; x++) @@ -744,32 +746,42 @@ void cWorld::GrowTree( int a_X, int a_Y, int a_Z ) int trunk = r1.randInt() % (7 - 5 + 1) + 5; for (int i = 0; i < trunk; i++) { - if( GetBlock( a_X, a_Y + i, a_Z ) == E_BLOCK_AIR ) - FastSetBlock( a_X, a_Y + i, a_Z, E_BLOCK_LOG, 0 ); + FastSetBlock( a_X, a_Y + i, a_Z, E_BLOCK_LOG, 0 ); } // build tree - for (int j = 0; j < trunk; j++) { + for (int j = 0; j < trunk; j++) + { int radius = trunk - j; - if (radius < 4) { - if (radius > 2) { + if (radius < 4) + { + if (radius > 2) + { radius = 2; } - for (int i = a_X - radius; i <= a_X + radius; i++) { - for (int k = a_Z-radius; k <= a_Z + radius; k++) { + for (int i = a_X - radius; i <= a_X + radius; i++) + { + for (int k = a_Z-radius; k <= a_Z + radius; k++) + { // small chance to be missing a block to add a little random - if (k != a_Z || i != a_X && (r1.randInt() % 100 + 1) > 20) { + if (k != a_Z || i != a_X && (r1.randInt() % 100 + 1) > 20) + { if( GetBlock( i, a_Y + j, k ) == E_BLOCK_AIR ) + { FastSetBlock(i, a_Y+j, k, E_BLOCK_LEAVES, 0 ); + } } - else { + else + { //if( m_BlockType[ MakeIndex(i, TopY+j, k) ] == E_BLOCK_AIR ) // m_BlockType[ MakeIndex(i, TopY+j, k) ] = E_BLOCK_LEAVES; } } } - if( GetBlock( a_X, a_Y+j, a_Z ) == E_BLOCK_AIR ) + if (GetBlock( a_X, a_Y+j, a_Z ) == E_BLOCK_AIR ) + { FastSetBlock( a_X, a_Y+j, a_Z, E_BLOCK_LOG, 0 ); + } } } @@ -1069,6 +1081,15 @@ void cWorld::GetChunkData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCa +bool cWorld::GetChunkBlocks(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_Blocks) +{ + return m_ChunkMap->GetChunkBlocks(a_ChunkX, a_ChunkY, a_ChunkZ, a_Blocks); +} + + + + + bool cWorld::IsChunkValid(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const { return m_ChunkMap->IsChunkValid(a_ChunkX, a_ChunkY, a_ChunkZ); diff --git a/source/cWorld.h b/source/cWorld.h index 131361d21..569fe8d32 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -76,6 +76,7 @@ public: void ChunkDataLoaded (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); void ChunkDataGenerated(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback); + bool GetChunkBlocks (int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_Blocks); bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ) const; bool HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const; void UnloadUnusedChunks(void); diff --git a/source/cWorldGenerator.cpp b/source/cWorldGenerator.cpp index 284b4c478..b1f868cad 100644 --- a/source/cWorldGenerator.cpp +++ b/source/cWorldGenerator.cpp @@ -14,6 +14,27 @@ +// An array describing an 8-way neighbor coords deltas +static struct +{ + int m_X; + int m_Z; +} g_NeighborCoords[] = +{ + {-1, -1}, + {-1, 0}, + {-1, 1}, + {0, -1}, + {0, 1}, + {1, -1}, + {1, 0}, + {1, 1}, +} ; + + + + + cWorldGenerator::cWorldGenerator(cWorld * a_World) : m_World(a_World) { @@ -40,6 +61,46 @@ void cWorldGenerator::GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, ch +void cWorldGenerator::PostGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +{ + // Check the chunk just generated and all its 8-way neighbors + CheckNeighbors(a_ChunkX, a_ChunkY, a_ChunkZ); + for (int i = 0; i < ARRAYCOUNT(g_NeighborCoords); i++) + { + CheckNeighbors(a_ChunkX + g_NeighborCoords[i].m_X, a_ChunkY, a_ChunkZ + g_NeighborCoords[i].m_Z); + } // for i - g_NeighborCoords[] +} + + + + + +void cWorldGenerator::CheckNeighbors(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +{ + if (!m_World->IsChunkValid(a_ChunkX, a_ChunkY, a_ChunkZ)) + { + return; + } + + // Check all 8-way neighbors, if they are all valid, generate foliage in this chunk: + int NumNeighbors = 0; + for (int i = 0; i < ARRAYCOUNT(g_NeighborCoords); i++) + { + if (m_World->IsChunkValid(a_ChunkX + g_NeighborCoords[i].m_X, a_ChunkY, a_ChunkZ + g_NeighborCoords[i].m_Z)) + { + NumNeighbors++; + } + } // for i - g_NeighborCoords[] + if (NumNeighbors == 8) + { + GenerateFoliage(a_ChunkX, a_ChunkY, a_ChunkZ); + } +} + + + + + static float GetNoise( float x, float y, cNoise & a_Noise ) { float oct1 = a_Noise.CubicNoise2D( x*cGenSettings::HeightFreq1, y*cGenSettings::HeightFreq1 )*cGenSettings::HeightAmp1; @@ -187,7 +248,8 @@ void cWorldGenerator::GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_ChunkZ, { a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_DIRT; } - } + } // for y + if (Top + 1 >= WATER_LEVEL + SAND_LEVEL) { // Replace top dirt with grass: @@ -201,111 +263,84 @@ void cWorldGenerator::GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_ChunkZ, a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_STATIONARY_WATER; } } - } - } + + // Generate small foliage (1-block): + int index = MakeIndex(x, Top - 1, z); + int TopY = Top - 1; + float val1 = Noise.CubicNoise2D(xx * 0.1f, zz * 0.1f ); + float val2 = Noise.CubicNoise2D(xx * 0.01f, zz * 0.01f ); + if( a_BlockData[index] == E_BLOCK_SAND ) + { + if ((val1 + val2 > 0.f) && ((r1.randInt() % 128) > 124)) + { + a_BlockData[ MakeIndex(x, TopY + 1, z) ] = E_BLOCK_CACTUS; + if ((r1.randInt() & 3) == 3) + { + a_BlockData[ MakeIndex(x, TopY + 2, z) ] = E_BLOCK_CACTUS; + } + continue; + } + } + else if( a_BlockData[index] == E_BLOCK_GRASS ) + { + float val3 = Noise.CubicNoise2D(xx * 0.01f + 10, zz * 0.01f + 10 ); + float val4 = Noise.CubicNoise2D(xx * 0.05f + 20, zz * 0.05f + 20 ); + if( val3 > 0.2f && (r1.randInt()%128) > 124 ) + { + a_BlockData[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_YELLOW_FLOWER; + } + else if( val4 > 0.2f && (r1.randInt()%128) > 124 ) + { + a_BlockData[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_RED_ROSE; + } + else if( val1+val2+val3+val4 > 0.2f && (r1.randInt()%128) > 124 ) + { + a_BlockData[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_RED_MUSHROOM; + } + else if( val1+val2+val3+val4 > 0.2f && (r1.randInt()%128) > 124 ) + { + a_BlockData[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_BROWN_MUSHROOM; + } + } + } // for x + } // for z } -void cWorldGenerator::GenerateFoliage( cChunkPtr & a_Chunk ) +void cWorldGenerator::GenerateFoliage(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { - const ENUM_BLOCK_ID GrassID = E_BLOCK_GRASS; - const ENUM_BLOCK_ID DirtID = E_BLOCK_DIRT; - const ENUM_BLOCK_ID SandID = E_BLOCK_SAND; - const ENUM_BLOCK_ID SandStoneID = E_BLOCK_SANDSTONE; - const ENUM_BLOCK_ID CaveID = E_BLOCK_AIR; - - int PosX = a_Chunk->GetPosX(); - int PosZ = a_Chunk->GetPosZ(); - - cWorld* World = a_Chunk->GetWorld(); - cNoise m_Noise( World->GetWorldSeed() ); - char* BlockType = a_Chunk->pGetType(); - - for(int z = 0; z < 16; z++) for(int x = 0; x < 16; x++) + char BlockType[cChunk::c_NumBlocks]; + + if (!m_World->GetChunkBlocks(a_ChunkX, a_ChunkY, a_ChunkZ, BlockType)) { - // Find top most Y - int TopY = -1; - for(int y = 127; y > 0; y--) - { - int index = MakeIndex( x, y, z ); - if( BlockType[index] != E_BLOCK_AIR ) - { - TopY = y; - break; - } - } - if( TopY > 0 ) + LOGWARNING("Cannot generate foliage on chunk [%d, %d]", a_ChunkX, a_ChunkZ); + return; + } + + cNoise Noise(m_World->GetWorldSeed()); + for (int z = 0; z < 16; z++) + { + int zz = z + a_ChunkZ * 16; + for (int x = 0; x < 16; x++) { - // Change top dirt into grass and prevent sand from floating over caves - int index = MakeIndex( x, TopY, z ); - int index1 = MakeIndex( x, TopY-1, z ); - int index2 = MakeIndex( x, TopY-2, z ); - int index3 = MakeIndex( x, TopY-3, z ); - int index4 = MakeIndex( x, TopY-4, z ); - int index5 = MakeIndex( x, TopY-5, z ); - - if( BlockType[index] == SandID ) { - - if( BlockType[index1] == CaveID ) { - BlockType[ index ] = (char)SandStoneID; - } else if( BlockType[index2] == CaveID ) { - BlockType[ index1 ] = (char)SandStoneID; - } else if( BlockType[index3] == CaveID ) { - BlockType[ index2 ] = (char)SandStoneID; - } else if( BlockType[index4] == CaveID ) { - BlockType[ index3 ] = (char)SandStoneID; - } else if( BlockType[index5] == CaveID ) { - BlockType[ index4 ] = (char)SandStoneID; - } - - } - - if( BlockType[index] == DirtID ) - { - BlockType[ index ] = (char)GrassID; - } + int xx = x + a_ChunkX * 16; - // Plant sum trees + int TopY = m_World->GetHeight(xx, zz); + int index = MakeIndex(x, TopY - 1, z); + if (BlockType[index] == E_BLOCK_GRASS ) { - int xx = x + PosX*16; - int zz = z + PosZ*16; - - float val1 = m_Noise.CubicNoise2D( xx*0.1f, zz*0.1f ); - float val2 = m_Noise.CubicNoise2D( xx*0.01f, zz*0.01f ); - if( BlockType[index] == SandID ) - { - if( (val1 + val2 > 0.f) && (r1.randInt()%128) > 124 && BlockType[index] == E_BLOCK_SAND ) - { - BlockType[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_CACTUS; - if( (r1.randInt() & 3) == 3 ) - { - BlockType[ MakeIndex(x, TopY+2, z) ] = E_BLOCK_CACTUS; - } - continue; - } - } - else if( BlockType[index] == GrassID ) + float val1 = Noise.CubicNoise2D( xx * 0.1f, zz * 0.1f ); + float val2 = Noise.CubicNoise2D( xx * 0.01f, zz * 0.01f ); + if ((val1 + val2 > 0.2f) && ((r1.randInt() % 128) > 124)) { - float val3 = m_Noise.CubicNoise2D( xx*0.01f+10, zz*0.01f+10 ); - float val4 = m_Noise.CubicNoise2D( xx*0.05f+20, zz*0.05f+20 ); - if( val1 + val2 > 0.2f && (r1.randInt()%128) > 124 ) - World->GrowTree( xx, TopY, zz ); - else if( val3 > 0.2f && (r1.randInt()%128) > 124 ) - BlockType[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_YELLOW_FLOWER; - else if( val4 > 0.2f && (r1.randInt()%128) > 124 ) - BlockType[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_RED_ROSE; - else if( val1+val2+val3+val4 > 0.2f && (r1.randInt()%128) > 124 ) - BlockType[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_RED_MUSHROOM; - else if( val1+val2+val3+val4 > 0.2f && (r1.randInt()%128) > 124 ) - BlockType[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_BROWN_MUSHROOM; + m_World->GrowTree( xx, TopY, zz ); } - } - - } - } + } // if (Grass) + } // for x + } // for z } diff --git a/source/cWorldGenerator.h b/source/cWorldGenerator.h index 92c2a1d0c..1852e74d2 100644 --- a/source/cWorldGenerator.h +++ b/source/cWorldGenerator.h @@ -19,6 +19,8 @@ public: ~cWorldGenerator(); virtual void GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); + + virtual void PostGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Called when the chunk has been already generated and set valid protected: @@ -31,8 +33,10 @@ protected: virtual void GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData); - virtual void GenerateFoliage(cChunkPtr & a_Chunk ); + virtual void GenerateFoliage(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + /// Checks if the chunk has all 8 neighbors valid, if so, foliage is generated on that chunk + void CheckNeighbors(int a_ChunkX, int a_ChunkY, int a_ChunkZ); }; diff --git a/source/cWorldGenerator_Test.cpp b/source/cWorldGenerator_Test.cpp index 1ffcdbfbe..7f0c58bb8 100644 --- a/source/cWorldGenerator_Test.cpp +++ b/source/cWorldGenerator_Test.cpp @@ -25,9 +25,11 @@ void cWorldGenerator_Test::GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_Chu -void cWorldGenerator_Test::GenerateFoliage( cChunkPtr & a_Chunk ) +void cWorldGenerator_Test::GenerateFoliage(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { - (void)a_Chunk; + (void)a_ChunkX; + (void)a_ChunkY; + (void)a_ChunkZ; } diff --git a/source/cWorldGenerator_Test.h b/source/cWorldGenerator_Test.h index 8c4dc0e99..d5580ffc8 100644 --- a/source/cWorldGenerator_Test.h +++ b/source/cWorldGenerator_Test.h @@ -17,7 +17,7 @@ public: protected: virtual void GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData) override; - virtual void GenerateFoliage(cChunkPtr & a_Chunk ) override; + virtual void GenerateFoliage(int a_ChunkX, int a_ChunkY, int a_ChunkZ) override; }; -- cgit v1.2.3