Browse Source

add structure template system to world generator

Kolja Strohm 3 years ago
parent
commit
bc47a43da6

+ 1 - 2
FactoryCraft/BasicBlocks.h

@@ -6,8 +6,7 @@
 
 class BlockType;
 class ItemType;
-class DirtBlockType;
-class DirtBlockItemType;
+class BasicBlockType;
 
 class BasicBlock : public Block
 {

+ 11 - 1
FactoryCraft/BiomGenerator.cpp

@@ -3,4 +3,14 @@
 
 BiomGenerator::BiomGenerator()
     : ReferenceCounter()
-{}
+{}
+
+void BiomGenerator::addTemplateGenerator( GenerationTemplate* gTemplate )
+{
+    templates.add( gTemplate );
+}
+
+const Framework::RCArray<GenerationTemplate>& BiomGenerator::getTemplates()
+{
+    return templates;
+}

+ 11 - 1
FactoryCraft/BiomGenerator.h

@@ -3,13 +3,23 @@
 #include <ReferenceCounter.h>
 #include <Either.h> 
 
+#include "GenerationTemplate.h"
+
 class Block;
 class Noise;
 
 class BiomGenerator : public virtual Framework::ReferenceCounter
 {
+private:
+    Framework::RCArray<GenerationTemplate> templates;
+
+protected:
+    void addTemplateGenerator( GenerationTemplate* gTemplate );
+
 public:
     BiomGenerator();
-    virtual Framework::Either<Block*, int> getBlock( int x, int y, int z ) = 0;
+    virtual Framework::Either<Block*, int> generateSurfaceBlock( int x, int y, int z ) = 0;
+    virtual Framework::Either<Block*, int> generateBelowSurfaceBlock( int x, int y, int z ) = 0;
     virtual Noise* zHeightMapNoise( int seed ) = 0;
+    const Framework::RCArray<GenerationTemplate>& getTemplates();
 };

+ 3 - 1
FactoryCraft/Constants.h

@@ -9,4 +9,6 @@
 #define MAX_AIR_LEVEL 400
 #define NUM_TICK_WORKERS 4
 #define ITEM_CACHE_SIZE 256
-#define DEFAULT_VIEW_DISTANCE 5
+#define DEFAULT_VIEW_DISTANCE 5
+#define MAX_SURFACE_HEIGHT 50
+#define VARIABLE_SURFACE_PART 0.5f 

+ 94 - 5
FactoryCraft/DimensionGenerator.cpp

@@ -8,7 +8,9 @@
 
 DimensionGenerator::DimensionGenerator( int dimensionId )
     : ReferenceCounter(),
-    dimensionId( dimensionId )
+    dimensionId( dimensionId ),
+    minTemplateAffectedPosition( 0, 0, 0 ),
+    maxTemplateAffectedPosition( 0, 0, 0 )
 {
     StaticRegistry<DimensionGenerator>::INSTANCE.registerT( this, dimensionId );
 }
@@ -35,10 +37,64 @@ void DimensionGenerator::registerBiom( BiomGenerator* generator, double possibil
 {
     biomGenerators.add( generator );
     biomDistribution.add( possibility );
+    for( auto t : generator->getTemplates() )
+    {
+        minTemplateAffectedPosition.x = MIN( minTemplateAffectedPosition.x, t->getMinAffectedOffset().x );
+        minTemplateAffectedPosition.y = MIN( minTemplateAffectedPosition.y, t->getMinAffectedOffset().y );
+        minTemplateAffectedPosition.z = MIN( minTemplateAffectedPosition.z, t->getMinAffectedOffset().z );
+        maxTemplateAffectedPosition.x = MAX( maxTemplateAffectedPosition.x, t->getMaxAffectedOffset().x );
+        maxTemplateAffectedPosition.y = MAX( maxTemplateAffectedPosition.y, t->getMaxAffectedOffset().y );
+        maxTemplateAffectedPosition.z = MAX( maxTemplateAffectedPosition.z, t->getMaxAffectedOffset().z );
+    }
+}
+
+Framework::RCArray<GeneratedStructure>* DimensionGenerator::getGeneratedStructoresForArea( int seed, Framework::Vec3<int> minPos, Framework::Vec3<int> maxPos )
+{
+    Framework::RCArray<GeneratedStructure>* result = new Framework::RCArray<GeneratedStructure>();
+
+    int minSearchX = minPos.x - maxTemplateAffectedPosition.x;
+    int minSearchY = minPos.y - maxTemplateAffectedPosition.y;
+    int minSearchZ = MAX( minPos.z - maxTemplateAffectedPosition.z, 0 );
+    int maxSearchX = maxPos.x - minTemplateAffectedPosition.x;
+    int maxSearchY = maxPos.y - minTemplateAffectedPosition.y;
+    int maxSearchZ = MIN( maxPos.z - minTemplateAffectedPosition.z, WORLD_HEIGHT - 1 );
+
+    Noise* structureNoise = zStructureNoise( seed + dimensionId );
+    for( int x = minSearchX; x <= maxSearchX; x++ )
+    {
+        for( int y = minSearchY; y <= maxSearchY; y++ )
+        {
+            BiomGenerator* biom = zBiomGenerator( seed + dimensionId, x, y );
+            int height = MIN_AIR_LEVEL + (int)(biom->zHeightMapNoise( seed + dimensionId )->getNoise( (double)(x), (double)(y), 0.0 ) * (MAX_AIR_LEVEL - MIN_AIR_LEVEL));
+            for( int z = minSearchZ; z <= maxSearchZ; z++ )
+            {
+                if( z < height )
+                {
+                    double rValue = structureNoise->getNoise( (double)x, (double)y, (double)z );
+                    double probSum = 0;
+                    for( auto t : biom->getTemplates() )
+                    {
+                        if( t->isGenerationPossable( Framework::Vec3<int>( x, y, z ), height - z ) )
+                        {
+                            if( rValue - probSum <= t->getPropability() )
+                            {
+                                result->add( t->generateAt( Framework::Vec3<int>( x, y, z ), structureNoise ) );
+                                break;
+                            }
+                        }
+                        probSum += t->getPropability();
+                    }
+                }
+            }
+        }
+    }
+
+    return result;
 }
 
 Chunk* DimensionGenerator::generateChunk( int seed, int centerX, int centerY )
 {
+    Framework::RCArray<GeneratedStructure>* structures = getGeneratedStructoresForArea( seed, Framework::Vec3<int>( centerX - CHUNK_SIZE / 2, centerY - CHUNK_SIZE / 2, 0 ), Framework::Vec3<int>( centerX + CHUNK_SIZE / 2, centerY + CHUNK_SIZE / 2, WORLD_HEIGHT - 1 ) );
     std::cout << "generating chunk " << centerX << ", " << centerY << "\n";
     Chunk* chunk = new Chunk( Framework::Punkt( centerX, centerY ), dimensionId );
     for( int x = -CHUNK_SIZE / 2; x < CHUNK_SIZE / 2; x++ )
@@ -48,11 +104,28 @@ Chunk* DimensionGenerator::generateChunk( int seed, int centerX, int centerY )
             BiomGenerator* biom = zBiomGenerator( seed + dimensionId, x + centerX, y + centerY );
             // TODO: use Noise interpolator for height map between different bioms
             int height = MIN_AIR_LEVEL + (int)(biom->zHeightMapNoise( seed + dimensionId )->getNoise( (double)(x + centerX), (double)(y + centerY), 0.0 ) * (MAX_AIR_LEVEL - MIN_AIR_LEVEL));
+            int maxSurfaceHeight = (1 - (height - MIN_AIR_LEVEL) / (MAX_AIR_LEVEL - MIN_AIR_LEVEL));
+            int actualSurfaceHeight = (int)((float)maxSurfaceHeight * (1.f - VARIABLE_SURFACE_PART) + ((float)maxSurfaceHeight * VARIABLE_SURFACE_PART * (float)biom->zHeightMapNoise( seed + dimensionId )->getNoise( (double)(x + centerX), (double)(y + centerY), 10.0 )));
             for( int z = 0; z < WORLD_HEIGHT; z++ )
             {
                 Framework::Either<Block*, int> generated = AirBlockBlockType::ID;
-                if( z < height )
-                    generated = biom->getBlock( x + centerX, y + centerY, z );
+                bool structureAffected = 0;
+                for( auto structure : *structures )
+                {
+                    if( structure->isBlockAffected( Framework::Vec3<int>( x + centerX, y + centerY, z ) ) )
+                    {
+                        generated = structure->generateBlockAt( Framework::Vec3<int>( x + centerX, y + centerY, z ) );
+                        structureAffected = 1;
+                        break;
+                    }
+                }
+                if( !structureAffected )
+                {
+                    if( z < height && z >= height - actualSurfaceHeight )
+                        generated = biom->generateSurfaceBlock( x + centerX, y + centerY, z );
+                    else if( z < height )
+                        generated = biom->generateBelowSurfaceBlock( x + centerX, y + centerY, z );
+                }
                 if( generated.isA() )
                     chunk->putBlockAt( Framework::Vec3<int>( x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z ), generated );
                 else
@@ -60,16 +133,32 @@ Chunk* DimensionGenerator::generateChunk( int seed, int centerX, int centerY )
             }
         }
     }
+    structures->release();
     return chunk;
 }
 
 Framework::Either<Block*, int> DimensionGenerator::generateBlock( int seed, Framework::Vec3<int> location )
 {
+    Framework::RCArray<GeneratedStructure>* structures = getGeneratedStructoresForArea( seed, location, location );
     BiomGenerator* biom = zBiomGenerator( seed + dimensionId, location.x, location.y );
     // TODO: use Noise interpolator for height map between different bioms
     int height = MIN_AIR_LEVEL + (int)(biom->zHeightMapNoise( seed + dimensionId )->getNoise( (double)(location.x), (double)(location.y), 0.0 ) * (MAX_AIR_LEVEL - MIN_AIR_LEVEL));
-    if( location.z < height )
-        return biom->getBlock( location.x, location.y, location.z );
+    int maxSurfaceHeight = (1 - (height - MIN_AIR_LEVEL) / (MAX_AIR_LEVEL - MIN_AIR_LEVEL));
+    int actualSurfaceHeight = (int)((float)maxSurfaceHeight * (1.f - VARIABLE_SURFACE_PART) + ((float)maxSurfaceHeight * VARIABLE_SURFACE_PART * (float)biom->zHeightMapNoise( seed + dimensionId )->getNoise( (double)(location.x), (double)(location.y), 10.0 )));
+    for( auto structure : *structures )
+    {
+        if( structure->isBlockAffected( location ) )
+        {
+            auto generated = structure->generateBlockAt( location );
+            structures->release();
+            return generated;
+        }
+    }
+    structures->release();
+    if( location.z < height && location.z >= height - actualSurfaceHeight )
+        return biom->generateSurfaceBlock( location.x, location.y, location.z );
+    else if( location.z < height )
+        return biom->generateBelowSurfaceBlock( location.x, location.y, location.z );
     return AirBlockBlockType::ID;
 }
 

+ 4 - 0
FactoryCraft/DimensionGenerator.h

@@ -13,6 +13,8 @@ private:
     Framework::RCArray<BiomGenerator> biomGenerators;
     Framework::Array<double> biomDistribution;
     const int dimensionId;
+    Framework::Vec3<int> minTemplateAffectedPosition;
+    Framework::Vec3<int> maxTemplateAffectedPosition;
 
     BiomGenerator* zBiomGenerator( int seed, int x, int y );
 
@@ -20,10 +22,12 @@ protected:
     DimensionGenerator( int dimensionId );
     ~DimensionGenerator();
     void registerBiom( BiomGenerator* generator, double possibility );
+    Framework::RCArray<GeneratedStructure>* getGeneratedStructoresForArea( int seed, Framework::Vec3<int> minPos, Framework::Vec3<int> maxPos );
 
 public:
     Chunk* generateChunk( int seed, int centerX, int centerY );
     Framework::Either<Block*, int> generateBlock( int seed, Framework::Vec3<int> location );
     int getDimensionId() const;
     virtual Noise* zBiomNoise( int seed ) = 0;
+    virtual Noise* zStructureNoise( int seed ) = 0;
 };

+ 6 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -114,6 +114,8 @@
     <ClInclude Include="FastNoiseLite.h" />
     <ClInclude Include="FastNoiseWrapper.h" />
     <ClInclude Include="Game.h" />
+    <ClInclude Include="GeneratedStructure.h" />
+    <ClInclude Include="GenerationTemplate.h" />
     <ClInclude Include="GrasslandBiom.h" />
     <ClInclude Include="Inventory.h" />
     <ClInclude Include="Item.h" />
@@ -137,6 +139,7 @@
     <ClInclude Include="TickOrganizer.h" />
     <ClInclude Include="TickQueue.h" />
     <ClInclude Include="TickWorker.h" />
+    <ClInclude Include="TreeTemplate.h" />
     <ClInclude Include="WorldGenerator.h" />
     <ClInclude Include="WorldLoader.h" />
     <ClInclude Include="WorldUpdate.h" />
@@ -161,6 +164,8 @@
     <ClCompile Include="EntityType.cpp" />
     <ClCompile Include="FastNoiseWrapper.cpp" />
     <ClCompile Include="Game.cpp" />
+    <ClCompile Include="GeneratedStructure.cpp" />
+    <ClCompile Include="GenerationTemplate.cpp" />
     <ClCompile Include="GrasslandBiom.cpp" />
     <ClCompile Include="Inventory.cpp" />
     <ClCompile Include="Item.cpp" />
@@ -184,6 +189,7 @@
     <ClCompile Include="TickOrganizer.cpp" />
     <ClCompile Include="TickQueue.cpp" />
     <ClCompile Include="TickWorker.cpp" />
+    <ClCompile Include="TreeTemplate.cpp" />
     <ClCompile Include="WorldGenerator.cpp" />
     <ClCompile Include="WorldLoader.cpp" />
     <ClCompile Include="WorldUpdate.cpp" />

+ 24 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -55,6 +55,12 @@
     <Filter Include="inventory\items">
       <UniqueIdentifier>{eb49f18d-6127-4d38-87db-e8427471535f}</UniqueIdentifier>
     </Filter>
+    <Filter Include="world\generator\templates">
+      <UniqueIdentifier>{99cadedd-b0ee-484d-8a9d-1edd793f169d}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="world\generator\templates\implementations">
+      <UniqueIdentifier>{c2b3a832-eac2-4bf5-bb1f-3e804afd7e71}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Chunk.h">
@@ -201,6 +207,15 @@
     <ClInclude Include="EntityRemovedUpdate.h">
       <Filter>world\update</Filter>
     </ClInclude>
+    <ClInclude Include="GenerationTemplate.h">
+      <Filter>world\generator\templates</Filter>
+    </ClInclude>
+    <ClInclude Include="GeneratedStructure.h">
+      <Filter>world\generator\templates</Filter>
+    </ClInclude>
+    <ClInclude Include="TreeTemplate.h">
+      <Filter>world\generator\templates\implementations</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -338,5 +353,14 @@
     <ClCompile Include="EntityRemovedUpdate.cpp">
       <Filter>world\update</Filter>
     </ClCompile>
+    <ClCompile Include="GeneratedStructure.cpp">
+      <Filter>world\generator\templates</Filter>
+    </ClCompile>
+    <ClCompile Include="GenerationTemplate.cpp">
+      <Filter>world\generator\templates</Filter>
+    </ClCompile>
+    <ClCompile Include="TreeTemplate.cpp">
+      <Filter>world\generator\templates\implementations</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 72 - 0
FactoryCraft/GeneratedStructure.cpp

@@ -0,0 +1,72 @@
+#include "GeneratedStructure.h"
+#include "GenerationTemplate.h"
+
+
+GeneratedStructure::GeneratedStructure( GenerationTemplate* t, Framework::Vec3<int> originPos, Framework::Vec3<int> size, Framework::Vec3<int> minAffectedPos )
+    : ReferenceCounter(),
+    size( size ),
+    minAffectedPos( minAffectedPos ),
+    originPos( originPos ),
+    t( t )
+{
+    blockIds = new int[ size.x * size.y * size.z ];
+    blocks = new Block * [ size.x * size.y * size.z ];
+    memset( blockIds, 0, sizeof( int ) * size.x * size.y * size.z );
+    memset( blocks, 0, sizeof( Block* ) * size.x * size.y * size.z );
+}
+
+GeneratedStructure::~GeneratedStructure()
+{
+    for( int i = 0; i < size.x * size.y * size.z; i++ )
+    {
+        if( blocks[ i ] )
+            blocks[ i ]->release();
+    }
+    delete[] blockIds;
+    delete[] blocks;
+    t->release();
+}
+
+void GeneratedStructure::setBlockAt( Framework::Either<Block*, int> block, Framework::Vec3<int> localPos )
+{
+    assert( localPos.x >= 0 && localPos.y >= 0 && localPos.z >= 0 && localPos.x < size.x&& localPos.y < size.y&& localPos.z < size.z );
+    int index = ((localPos.x * size.y) + localPos.y) * size.z + localPos.z;
+    if( block.isA() )
+        blocks[ index ] = block;
+    else
+        blockIds[ index ] = block;
+}
+
+bool GeneratedStructure::isBlockAffected( Framework::Vec3<int> location ) const
+{
+    Framework::Vec3<int> localPos = location - originPos;
+    if( location.x >= 0 && location.y >= 0 && location.z >= 0 && location.x < size.x && location.y < size.y && location.z < size.z )
+    {
+        int index = ((localPos.x * size.y) + localPos.y) * size.z + localPos.z;
+        return blocks[ index ] || blockIds[ index ];
+    }
+    return 0;
+}
+
+Framework::Either<Block*, int> GeneratedStructure::generateBlockAt( Framework::Vec3<int> location ) const
+{
+    Framework::Vec3<int> localPos = location - originPos;
+    if( location.x >= 0 && location.y >= 0 && location.z >= 0 && location.x < size.x && location.y < size.y && location.z < size.z )
+    {
+        int index = ((localPos.x * size.y) + localPos.y) * size.z + localPos.z;
+        if( blocks[ index ] )
+            return blocks[ index ];
+        return blockIds[ index ];
+    }
+    return 0;
+}
+
+Framework::Vec3<int> GeneratedStructure::getOriginPos() const
+{
+    return originPos;
+}
+
+GenerationTemplate* GeneratedStructure::zTemplate() const
+{
+    return t;
+}

+ 30 - 0
FactoryCraft/GeneratedStructure.h

@@ -0,0 +1,30 @@
+#pragma once
+
+#include <ReferenceCounter.h>
+#include <Vec3.h>
+#include <Either.h>
+
+#include "Block.h"
+
+class GenerationTemplate;
+
+class GeneratedStructure : public Framework::ReferenceCounter
+{
+private:
+    int* blockIds;
+    Block** blocks;
+    Framework::Vec3<int> size;
+    Framework::Vec3<int> minAffectedPos;
+    Framework::Vec3<int> originPos;
+    GenerationTemplate* t;
+
+public:
+    GeneratedStructure( GenerationTemplate* t, Framework::Vec3<int> originPos, Framework::Vec3<int> size, Framework::Vec3<int> minAffectedPos );
+    ~GeneratedStructure();
+    void setBlockAt( Framework::Either<Block*, int> block, Framework::Vec3<int> localPos );
+    bool isBlockAffected( Framework::Vec3<int> location ) const;
+    Framework::Either<Block*, int> generateBlockAt( Framework::Vec3<int> location ) const;
+
+    Framework::Vec3<int> getOriginPos() const;
+    GenerationTemplate* zTemplate() const;
+};

+ 37 - 0
FactoryCraft/GenerationTemplate.cpp

@@ -0,0 +1,37 @@
+#include "GenerationTemplate.h"
+
+
+GenerationTemplate::GenerationTemplate( float propability, int minSurfaceDist, int maxSurfaceDist, Framework::Vec3<int> minPosOffset, Framework::Vec3<int> maxSize )
+    : ReferenceCounter(),
+    propability( propability ),
+    minSurfaceDist( minSurfaceDist ),
+    maxSurfaceDist( maxSurfaceDist ),
+    minPosOffset( minPosOffset ),
+    maxSize( maxSize )
+{}
+
+bool GenerationTemplate::canEffect( Framework::Vec3<int> location, Framework::Vec3<int> affectedLocation ) const
+{
+    Framework::Vec3<int> localPos = affectedLocation - (location + minPosOffset);
+    return localPos.x >= 0 && localPos.y >= 0 && localPos.z >= 0 && localPos.x < maxSize.x&& localPos.y < maxSize.y&& localPos.z < maxSize.z;
+}
+
+bool GenerationTemplate::isGenerationPossable( Framework::Vec3<int> location, int distToSurface ) const
+{
+    return distToSurface >= minSurfaceDist && distToSurface <= maxSurfaceDist;
+}
+
+float GenerationTemplate::getPropability() const
+{
+    return propability;
+}
+
+Framework::Vec3<int> GenerationTemplate::getMinAffectedOffset() const
+{
+    return minPosOffset;
+}
+
+Framework::Vec3<int> GenerationTemplate::getMaxAffectedOffset() const
+{
+    return minPosOffset + maxSize;
+}

+ 28 - 0
FactoryCraft/GenerationTemplate.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include <ReferenceCounter.h>
+#include <Vec3.h>
+
+#include "GeneratedStructure.h"
+#include "Noise.h"
+
+class GenerationTemplate : public Framework::ReferenceCounter
+{
+private:
+    float propability;
+    int minSurfaceDist;
+    int maxSurfaceDist;
+    Framework::Vec3<int> minPosOffset;
+    Framework::Vec3<int> maxSize;
+
+public:
+    GenerationTemplate( float propability, int minSurfaceDist, int maxSurfaceDist, Framework::Vec3<int> minPosOffset, Framework::Vec3<int> maxSize );
+
+    virtual bool canEffect( Framework::Vec3<int> location, Framework::Vec3<int> affectedLocation ) const;
+    virtual bool isGenerationPossable( Framework::Vec3<int> location, int distToSurface ) const;
+    virtual GeneratedStructure* generateAt( Framework::Vec3<int> location, Noise* zNoise ) = 0;
+
+    float getPropability() const;
+    Framework::Vec3<int> getMinAffectedOffset() const;
+    Framework::Vec3<int> getMaxAffectedOffset() const;
+};

+ 11 - 1
FactoryCraft/GrasslandBiom.cpp

@@ -3,10 +3,15 @@
 #include "BasicBlocks.h"
 #include "FastNoiseLite.h"
 #include "FastNoiseWrapper.h"
+#include "TreeTemplate.h"
+
 
 GrasslandBiom::GrasslandBiom()
     : BiomGenerator()
 {
+    addTemplateGenerator( new TreeTemplate( 0.01f, BirchBlockType::INSTANCE, LeavesBlockType::INSTANCE, 8, 15 ) );
+    addTemplateGenerator( new TreeTemplate( 0.005f, BeechBlockType::INSTANCE, LeavesBlockType::INSTANCE, 8, 13 ) );
+    addTemplateGenerator( new TreeTemplate( 0.0025f, OakBlockType::INSTANCE, LeavesBlockType::INSTANCE, 10, 15 ) );
     heightNoise = 0;
 }
 
@@ -16,11 +21,16 @@ GrasslandBiom::~GrasslandBiom()
         heightNoise->release();
 }
 
-Framework::Either<Block*, int> GrasslandBiom::getBlock( int x, int y, int z )
+Framework::Either<Block*, int> GrasslandBiom::generateSurfaceBlock( int x, int y, int z )
 {
     return DirtBlockType::ID;
 }
 
+Framework::Either<Block*, int> GrasslandBiom::generateBelowSurfaceBlock( int x, int y, int z )
+{
+    return StoneBlockType::ID;
+}
+
 Noise* GrasslandBiom::zHeightMapNoise( int seed )
 {
     if( heightNoise )

+ 2 - 1
FactoryCraft/GrasslandBiom.h

@@ -10,6 +10,7 @@ class GrasslandBiom : public BiomGenerator
 public:
     GrasslandBiom();
     ~GrasslandBiom();
-    Framework::Either<Block*, int> getBlock( int x, int y, int z ) override;
+    Framework::Either<Block*, int> generateSurfaceBlock( int x, int y, int z ) override;
+    Framework::Either<Block*, int> generateBelowSurfaceBlock( int x, int y, int z ) override;
     Noise* zHeightMapNoise( int seed ) override;
 };

+ 16 - 0
FactoryCraft/OverworldDimension.cpp

@@ -8,12 +8,15 @@ OverworldDimension::OverworldDimension()
 {
     registerBiom( new GrasslandBiom(), 1.0 );
     biomNoise = 0;
+    structureNoise = 0;
 }
 
 OverworldDimension::~OverworldDimension()
 {
     if( biomNoise )
         biomNoise->release();
+    if( structureNoise )
+        structureNoise->release();
 }
 
 Noise* OverworldDimension::zBiomNoise( int seed )
@@ -32,4 +35,17 @@ Noise* OverworldDimension::zBiomNoise( int seed )
     noise->SetDomainWarpAmp( 30.f );
     biomNoise = new FastNoiseWrapper( noise, seed );
     return biomNoise;
+}
+
+Noise* OverworldDimension::zStructureNoise( int seed )
+{
+    if( structureNoise )
+        return structureNoise;
+    FastNoiseLite* noise = new FastNoiseLite( seed );
+    noise->SetNoiseType( FastNoiseLite::NoiseType::NoiseType_OpenSimplex2S );
+    noise->SetRotationType3D( FastNoiseLite::RotationType3D::RotationType3D_None );
+    noise->SetFrequency( 0.25f );
+    noise->SetFractalType( FastNoiseLite::FractalType::FractalType_None );
+    structureNoise = new FastNoiseWrapper( noise, seed );
+    return structureNoise;
 }

+ 2 - 0
FactoryCraft/OverworldDimension.h

@@ -10,12 +10,14 @@ class OverworldDimension : public DimensionGenerator
 
 private:
     Noise* biomNoise;
+    Noise* structureNoise;
 
 public:
     OverworldDimension();
     ~OverworldDimension();
 
     Noise* zBiomNoise( int seed ) override;
+    Noise* zStructureNoise( int seed ) override;
 };
 
 #ifdef REGISTER

+ 40 - 0
FactoryCraft/TreeTemplate.cpp

@@ -0,0 +1,40 @@
+#include "TreeTemplate.h"
+
+
+TreeTemplate::TreeTemplate( float propability, const BlockType* zWoodType, const BlockType* zLeaveType, int minHeight, int maxHeight )
+    : GenerationTemplate( propability, 0, 1, Framework::Vec3<int>( -3, -3, 0 ), Framework::Vec3<int>( 5, 5, maxHeight ) ),
+    zWoodType( zWoodType ),
+    zLeaveType( zLeaveType ),
+    minHeight( minHeight ),
+    maxHeight( maxHeight )
+{}
+
+GeneratedStructure* TreeTemplate::generateAt( Framework::Vec3<int> location, Noise* zNoise )
+{
+    double noise = zNoise->getNoise( (double)location.x, (double)location.y, (double)location.z );
+    int height = (int)(minHeight + (noise * (maxHeight - minHeight)));
+    GeneratedStructure* generated = new GeneratedStructure( dynamic_cast<GenerationTemplate*>(getThis()), location, Framework::Vec3<int>( 5, 5, height ), Framework::Vec3<int>( -3, -3, 0 ) + location );
+    for( int x = 1; x < 4; x++ )
+    {
+        for( int y = 1; y < 4; y++ )
+        {
+            generated->setBlockAt( zLeaveType->getId(), Framework::Vec3<int>( x, y, height - 1 ) );
+            generated->setBlockAt( zLeaveType->getId(), Framework::Vec3<int>( x, y, height - 5 ) );
+        }
+    }
+    for( int z = height - 2; z >= height - 4; z-- )
+    {
+        for( int x = 1; x < 4; x++ )
+        {
+            generated->setBlockAt( zLeaveType->getId(), Framework::Vec3<int>( x, 0, z ) );
+            generated->setBlockAt( zLeaveType->getId(), Framework::Vec3<int>( 0, x, z ) );
+            generated->setBlockAt( zLeaveType->getId(), Framework::Vec3<int>( x, 4, z ) );
+            generated->setBlockAt( zLeaveType->getId(), Framework::Vec3<int>( 4, x, z ) );
+            for( int y = 1; y < 4; y++ )
+                generated->setBlockAt( zLeaveType->getId(), Framework::Vec3<int>( x, y, z ) );
+        }
+    }
+    for( int i = 0; i < height - 1; i++ )
+        generated->setBlockAt( zWoodType->getId(), Framework::Vec3<int>( 2, 2, i ) );
+    return generated;
+}

+ 16 - 0
FactoryCraft/TreeTemplate.h

@@ -0,0 +1,16 @@
+#pragma once
+
+#include "GenerationTemplate.h"
+
+class TreeTemplate : public GenerationTemplate
+{
+private:
+    const BlockType* zWoodType;
+    const BlockType* zLeaveType;
+    int minHeight;
+    int maxHeight;
+
+public:
+    TreeTemplate( float propability, const BlockType* zWoodType, const BlockType* zLeaveType, int minHeight, int maxHeight );
+    virtual GeneratedStructure* generateAt( Framework::Vec3<int> location, Noise* zNoise ) override;
+};