Browse Source

improve speed of chunk generation

Kolja Strohm 2 days ago
parent
commit
d4870ffd97

+ 7 - 4
FactoryCraft/Chunk.cpp

@@ -423,6 +423,9 @@ void Chunk::api(Framework::StreamReader* zRequest,
 
 void Chunk::initializeLightning()
 {
+    // TODO: initialize only daylight with a more efficient algorithm here and
+    // add all light sources to the light update thread when the chunk is added
+    // to the map
     unsigned char dayLight[6] = {255, 255, 255, 0, 0, 0};
     unsigned char noLight[6] = {0, 0, 0, 0, 0, 0};
     while (true)
@@ -565,8 +568,8 @@ void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
         {
             for (Framework::ArrayIterator<Block*> obj
                  = tickSourcesEachTick.begin();
-                 obj;
-                 obj++)
+                obj;
+                obj++)
             {
                 if (obj.val() == old)
                 {
@@ -579,8 +582,8 @@ void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
         {
             for (Framework::ArrayIterator<Block*> obj
                  = tickSourcesAfterUpdate.begin();
-                 obj;
-                 obj++)
+                obj;
+                obj++)
             {
                 if (obj.val() == old)
                 {

+ 15 - 89
FactoryCraft/Dimension.cpp

@@ -17,11 +17,12 @@ using namespace Framework;
 
 Dimension::Dimension(int id)
     : Thread(),
-      nextStructureId(0),
+      nextStructureId(1),
       dimensionId(id),
       gravity(9.8f),
       chunks(new RCTrie<Chunk>()),
       entities(new RCArray<Entity>()),
+      structureManager(new MultiblockStructureManager(id)),
       map(new DimensionMap(id)),
       stop(0),
       currentDayTime(0.0),
@@ -47,6 +48,7 @@ Dimension::~Dimension()
     entities->release();
     chunks->release();
     map->release();
+    delete structureManager;
 }
 
 void Dimension::configureDayNightCyncle(
@@ -313,25 +315,7 @@ void Dimension::getAddrOfWorld(Punkt wPos, char* addr) const
 
 void Dimension::saveStructure(MultiblockStructure* zStructure) const
 {
-    Datei d;
-    Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
-              + Text(dimensionId) + "/structures/";
-    path.appendHex(zStructure->getStructureId());
-    path += ".str";
-    d.setDatei(path);
-    d.erstellen();
-    d.open(Datei::Style::schreiben);
-    auto uPos = zStructure->getUniquePosition();
-    d.schreibe((char*)&uPos.x, 4);
-    d.schreibe((char*)&uPos.y, 4);
-    d.schreibe((char*)&uPos.z, 4);
-    int typeId = zStructure->getStructureTypeId();
-    d.schreibe((char*)&typeId, 4);
-    __int64 strId = zStructure->getStructureId();
-    d.schreibe((char*)&strId, 8);
-    Game::INSTANCE->zMultiblockStructureType(zStructure->getStructureTypeId())
-        ->saveStructure(zStructure, &d);
-    d.close();
+    structureManager->saveStructure(zStructure);
 }
 
 Chunk* Dimension::zChunk(Punkt wPos) const
@@ -491,7 +475,7 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
         cs.lock();
         int index = 0;
         for (ArrayIterator<RequestQueue> iterator = waitingRequests.begin();
-             iterator;)
+            iterator;)
         {
             Entity* zE = Game::INSTANCE->zEntity(iterator.val().sourceId);
             if (zE)
@@ -791,52 +775,11 @@ void Dimension::addStructure(MultiblockStructure* structure)
 MultiblockStructure* Dimension::zStructureByPosition(
     Framework::Vec3<int> uniquePosition)
 {
-    structurCs.lock();
-    for (MultiblockStructure* str : structures)
-    {
-        if (str->getUniquePosition() == uniquePosition)
-        {
-            structurCs.unlock();
-            return str;
-        }
-    }
-    // search for structure file
-    Datei dir(Game::INSTANCE->getWorldDirectory() + "/dim/" + Text(dimensionId)
-              + "/structures");
-    RCArray<Text>* names = dir.getDateiListe();
-    if (names)
+    __int64 id = structureManager->getStructureId(uniquePosition);
+    if (id > 0)
     {
-        Vec3<int> uPos;
-        for (Text* name : *names)
-        {
-            Datei d(Text(dir.zPfad()->getText()) + "/" + name->getText());
-            if (d.open(Datei::Style::lesen))
-            {
-                d.lese((char*)&uPos.x, 4);
-                d.lese((char*)&uPos.y, 4);
-                d.lese((char*)&uPos.z, 4);
-                if (uPos == uniquePosition)
-                {
-                    int type;
-                    d.lese((char*)&type, 4);
-                    __int64 strId;
-                    d.lese((char*)&strId, 8);
-                    MultiblockStructure* str
-                        = Game::INSTANCE->zMultiblockStructureType(type)
-                              ->loadStructure(
-                                  dimensionId, strId, uniquePosition, &d);
-                    d.close();
-                    structures.add(str);
-                    names->release();
-                    structurCs.unlock();
-                    return str;
-                }
-                d.close();
-            }
-        }
-        names->release();
+        return zStructureById(id);
     }
-    structurCs.unlock();
     return 0;
 }
 
@@ -851,32 +794,15 @@ MultiblockStructure* Dimension::zStructureById(__int64 id)
             return str;
         }
     }
-    // search for structure file
-    Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
-              + Text(dimensionId) + "/structures/";
-    path.appendHex(id);
-    path += ".str";
-    Datei d(path);
-    Vec3<int> uPos;
-    if (d.open(Datei::Style::lesen))
-    {
-        d.lese((char*)&uPos.x, 4);
-        d.lese((char*)&uPos.y, 4);
-        d.lese((char*)&uPos.z, 4);
-        int type;
-        d.lese((char*)&type, 4);
-        __int64 strId;
-        d.lese((char*)&strId, 8);
-        MultiblockStructure* str
-            = Game::INSTANCE->zMultiblockStructureType(type)->loadStructure(
-                dimensionId, strId, uPos, &d);
-        d.close();
-        structures.add(str);
+    MultiblockStructure* structure = structureManager->loadStructure(id);
+    if (structure)
+    {
+        structures.add(structure);
         structurCs.unlock();
-        return str;
+        return structure;
     }
-    Logging::warning() << "did not find Structure information file '" << path
-                       << "'.";
+    Logging::warning() << "did not find Structure information file '"
+                       << std::hex << id << "'.";
     structurCs.unlock();
     return 0;
 }

+ 2 - 0
FactoryCraft/Dimension.h

@@ -10,6 +10,7 @@
 #include "Chunk.h"
 #include "Constants.h"
 #include "MultiblockStructure.h"
+#include "MultiblockStructureManager.h"
 
 class DimensionMap;
 class NetworkMessage;
@@ -48,6 +49,7 @@ private:
     Framework::RCArray<Chunk> removedChunks;
     Framework::Critical removedChunksCs;
     Framework::RCArray<MultiblockStructure> structures;
+    MultiblockStructureManager* structureManager;
     DimensionMap* map;
     bool stop;
     double currentDayTime;

+ 29 - 49
FactoryCraft/DimensionGenerator.cpp

@@ -191,6 +191,10 @@ void DimensionGenerator::setSeed(JFloatExpression* seed)
     seedExpression = seed;
 }
 
+const Framework::Text DimensionGenerator::X = "x";
+const Framework::Text DimensionGenerator::Y = "y";
+const Framework::Text DimensionGenerator::Z = "z";
+
 JFloatExpression* DimensionGenerator::zSeed() const
 {
     return seedExpression;
@@ -248,13 +252,13 @@ BiomedCavedDimensionGenerator::getGeneratedStructoresForArea(
     {
         for (int y = minSearchY; y <= maxSearchY; y++)
         {
-            zMemory()->setFloatVariable("x", (float)x);
-            zMemory()->setFloatVariable("y", (float)y);
+            zMemory()->setFloatVariable(X, (float)x);
+            zMemory()->setFloatVariable(Y, (float)y);
             calculateHeightLayers();
             BiomGenerator* gen = zBiomGenerator();
             for (int z = minSearchZ; z <= maxSearchZ; z++)
             {
-                zMemory()->setFloatVariable("z", (float)z);
+                zMemory()->setFloatVariable(Z, (float)z);
                 gen->generateStructures(x,
                     y,
                     z,
@@ -275,13 +279,8 @@ Chunk* BiomedCavedDimensionGenerator::generateChunk(int centerX, int centerY)
     Framework::Logging::debug()
         << "generating chunk " << centerX << ", " << centerY;
     double structureTime = 0;
-    double structureTime2 = 0;
-    double structureTime3 = 0;
     double caveTime = 0;
-    double caveTime2 = 0;
     double blockGenTime = 0;
-    double biomTime = 0;
-    double layerTime = 0;
     Framework::ZeitMesser zm;
     Framework::ZeitMesser zmGlobal;
     zm.messungStart();
@@ -307,54 +306,36 @@ Chunk* BiomedCavedDimensionGenerator::generateChunk(int centerX, int centerY)
     {
         for (int y = -CHUNK_SIZE / 2; y < CHUNK_SIZE / 2; y++)
         {
-            zMemory()->setFloatVariable("x", (float)x + (float)centerX);
-            zMemory()->setFloatVariable("y", (float)y + (float)centerY);
+            zMemory()->setFloatVariable(X, (float)x + (float)centerX);
+            zMemory()->setFloatVariable(Y, (float)y + (float)centerY);
             // calculate height layers
-            zm.messungStart();
             calculateHeightLayers();
-            zm.messungEnde();
-            layerTime += zm.getSekunden();
             // calculate biom
-            zm.messungStart();
             BiomGenerator* biom = zBiomGenerator();
-            zm.messungEnde();
-            biomTime += zm.getSekunden();
             // generate blocks
             for (int z = 0; z < WORLD_HEIGHT; z++)
             {
-                zMemory()->setFloatVariable("z", (float)z);
+                zMemory()->setFloatVariable(Z, (float)z);
                 Framework::Either<Block*, int> generated = BlockTypeEnum::AIR;
                 bool structureAffected = 0;
                 // check if the block is inside of a structure
-                zm.messungStart();
                 for (auto structure : *structures)
                 {
                     if (structure->isBlockAffected(
                             Framework::Vec3<int>(x + centerX, y + centerY, z)))
                     {
-                        zm.messungEnde();
-                        structureTime2 += zm.getSekunden();
-                        zm.messungStart();
                         generated = structure->generateBlockAt(
                             Framework::Vec3<int>(x + centerX, y + centerY, z),
                             getDimensionId());
                         structureAffected = 1;
-                        zm.messungEnde();
-                        structureTime3 += zm.getSekunden();
-                        zm.messungStart();
                         break;
                     }
                 }
-                zm.messungEnde();
-                structureTime2 += zm.getSekunden();
                 if (!structureAffected)
                 {
                     // check if block is a cave block
-                    zm.messungStart();
                     bool inCave
                         = caveGen->isInCave(x + centerX, y + centerY, z);
-                    zm.messungEnde();
-                    caveTime2 += zm.getSekunden();
                     if (!inCave)
                     {
                         // generate biom block
@@ -386,15 +367,8 @@ Chunk* BiomedCavedDimensionGenerator::generateChunk(int centerX, int centerY)
     structures->release();
     zmGlobal.messungEnde();
     Framework::Logging::trace() << "structureGenerationTime: " << structureTime;
-    Framework::Logging::trace()
-        << "structure.isBlockAffected: " << structureTime2;
-    Framework::Logging::trace()
-        << "structure.generateBlockAt: " << structureTime3;
     Framework::Logging::trace() << "caveGenerationTime: " << caveTime;
-    Framework::Logging::trace() << "caveEvaluationTime: " << caveTime2;
     Framework::Logging::trace() << "blockGenTime: " << blockGenTime;
-    Framework::Logging::trace() << "biomTime: " << biomTime;
-    Framework::Logging::trace() << "layerTime: " << layerTime;
     Framework::Logging::debug() << "totalTime: " << zmGlobal.getSekunden();
     zMemory()->unlock();
     return chunk;
@@ -405,8 +379,8 @@ void BiomedCavedDimensionGenerator::generateEntities(Chunk* zChunk)
     zMemory()->lock();
     zMemory()->setCurrentChunk(dynamic_cast<Chunk*>(zChunk->getThis()));
 
-    zMemory()->setFloatVariable("x", (float)zChunk->getCenter().x);
-    zMemory()->setFloatVariable("y", (float)zChunk->getCenter().y);
+    zMemory()->setFloatVariable(X, (float)zChunk->getCenter().x);
+    zMemory()->setFloatVariable(Y, (float)zChunk->getCenter().y);
 
     calculateHeightLayers();
     BiomGenerator* biom = zBiomGenerator();
@@ -416,14 +390,20 @@ void BiomedCavedDimensionGenerator::generateEntities(Chunk* zChunk)
         {
             for (int z = 0; z < WORLD_HEIGHT; z++)
             {
-                if (zChunk->getBlockTypeAt(Framework::Vec3<int>(x, y, z))
+                if (zChunk->getBlockTypeAt(Framework::Vec3<int>(
+                        x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z))
                     == BlockTypeEnum::AIR)
                 {
-                    zMemory()->setFloatVariable("x", (float)z);
-                    zMemory()->setFloatVariable("y", (float)z);
-                    zMemory()->setFloatVariable("z", (float)z);
-                    biom->generateEntities(
-                        x, y, z, getDimensionId(), zMemory());
+                    zMemory()->setFloatVariable(
+                        X, (float)x + (float)zChunk->getCenter().x);
+                    zMemory()->setFloatVariable(
+                        Y, (float)y + (float)zChunk->getCenter().y);
+                    zMemory()->setFloatVariable(Z, (float)z);
+                    biom->generateEntities(x + zChunk->getCenter().x,
+                        y + zChunk->getCenter().y,
+                        z,
+                        getDimensionId(),
+                        zMemory());
                 }
             }
         }
@@ -448,13 +428,13 @@ Framework::Either<Block*, int> BiomedCavedDimensionGenerator::generateBlock(
     Framework::RCArray<GeneratedStructure>* structures
         = getGeneratedStructoresForArea(location, location);
 
-    zMemory()->setFloatVariable("x", (float)location.x);
-    zMemory()->setFloatVariable("y", (float)location.y);
+    zMemory()->setFloatVariable(X, (float)location.x);
+    zMemory()->setFloatVariable(Y, (float)location.y);
 
     calculateHeightLayers();
     BiomGenerator* biom = zBiomGenerator();
 
-    zMemory()->setFloatVariable("z", (float)location.z);
+    zMemory()->setFloatVariable(Z, (float)location.z);
 
     for (auto structure : *structures)
     {
@@ -495,8 +475,8 @@ bool BiomedCavedDimensionGenerator::spawnStructure(
     std::function<bool(GeneratorTemplate* tmpl)> filter)
 {
     zMemory()->lock();
-    zMemory()->setFloatVariable("x", (float)location.x);
-    zMemory()->setFloatVariable("y", (float)location.y);
+    zMemory()->setFloatVariable(X, (float)location.x);
+    zMemory()->setFloatVariable(Y, (float)location.y);
 
     BiomGenerator* biom = zBiomGenerator();
     zMemory()->unlock();

+ 5 - 1
FactoryCraft/DimensionGenerator.h

@@ -84,6 +84,10 @@ public:
     int getId() const;
     void setSeed(JFloatExpression* seed);
     JFloatExpression* zSeed() const;
+
+    static const Framework::Text X;
+    static const Framework::Text Y;
+    static const Framework::Text Z;
 };
 
 template<typename S> class DimensionGeneratorFactory
@@ -146,7 +150,7 @@ public:
                     ->getValidator<JFloatExpression>())
             ->withRequiredArray("heightLayers")
             ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
-                                         ->getValidator<WorldHeightLayer>())
+                    ->getValidator<WorldHeightLayer>())
             ->finishArray()
             ->withRequiredString("name")
             ->finishString()

+ 2 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -167,6 +167,7 @@
     <ClInclude Include="DimensionMap.h" />
     <ClInclude Include="ModelInfo.h" />
     <ClInclude Include="MultiblockStructure.h" />
+    <ClInclude Include="MultiblockStructureManager.h" />
     <ClInclude Include="MultiblockTree.h" />
     <ClInclude Include="MultiplyNoise.h" />
     <ClInclude Include="NegateNoise.h" />
@@ -277,6 +278,7 @@
     <ClCompile Include="LightSources.cpp" />
     <ClCompile Include="ModelInfo.cpp" />
     <ClCompile Include="MultiblockStructure.cpp" />
+    <ClCompile Include="MultiblockStructureManager.cpp" />
     <ClCompile Include="MultiblockTree.cpp" />
     <ClCompile Include="MultiplyNoise.cpp" />
     <ClCompile Include="NegateNoise.cpp" />

+ 6 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -453,6 +453,9 @@
     <ClInclude Include="DropConditionOperator.h">
       <Filter>drops\conditions</Filter>
     </ClInclude>
+    <ClInclude Include="MultiblockStructureManager.h">
+      <Filter>world\structures</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -779,5 +782,8 @@
     <ClCompile Include="SpecificItemDrop.cpp">
       <Filter>drops\implementations</Filter>
     </ClCompile>
+    <ClCompile Include="MultiblockStructureManager.cpp">
+      <Filter>world\structures</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 5 - 4
FactoryCraft/JsonExpression.cpp

@@ -44,22 +44,23 @@ void JExpressionMemory::setCurrentChunk(Chunk* chunk)
     currentChunk = chunk;
 }
 
-float JExpressionMemory::getFloatVariable(Framework::Text name) const
+float JExpressionMemory::getFloatVariable(const Framework::Text& name) const
 {
     return floatVariables.get(name, name.getLength());
 }
 
-void JExpressionMemory::setFloatVariable(Framework::Text name, float value)
+void JExpressionMemory::setFloatVariable(
+    const Framework::Text& name, float value)
 {
     floatVariables.set(name, name.getLength(), value);
 }
 
-bool JExpressionMemory::getBoolVariable(Framework::Text name) const
+bool JExpressionMemory::getBoolVariable(const Framework::Text& name) const
 {
     return boolVariables.get(name, name.getLength());
 }
 
-void JExpressionMemory::setBoolVariable(Framework::Text name, bool value)
+void JExpressionMemory::setBoolVariable(const Framework::Text& name, bool value)
 {
     return boolVariables.set(name, name.getLength(), value);
 }

+ 4 - 4
FactoryCraft/JsonExpression.h

@@ -34,10 +34,10 @@ public:
     void setNoise(Framework::Text name, Noise* noise);
     void setCurrentChunk(Chunk* chunk);
 
-    float getFloatVariable(Framework::Text name) const;
-    void setFloatVariable(Framework::Text name, float value);
-    bool getBoolVariable(Framework::Text name) const;
-    void setBoolVariable(Framework::Text name, bool value);
+    float getFloatVariable(const Framework::Text& name) const;
+    void setFloatVariable(const Framework::Text& name, float value);
+    bool getBoolVariable(const Framework::Text& name) const;
+    void setBoolVariable(const Framework::Text& name, bool value);
     Chunk* zCurrentChunk();
 };
 

+ 1 - 1
FactoryCraft/MultiblockStructure.h

@@ -7,9 +7,9 @@
 #include <Writer.h>
 
 class MultiblockStructureType;
-class Block;
 class Entity;
 class Item;
+class Block;
 class ItemSkill;
 
 class MultiblockStructureEnum

+ 107 - 0
FactoryCraft/MultiblockStructureManager.cpp

@@ -0,0 +1,107 @@
+#include "MultiblockStructureManager.h"
+
+#include <Datei.h>
+#include <Logging.h>
+
+#include "Block.h"
+#include "Game.h"
+
+MultiblockStructureManager::MultiblockStructureManager(int dimensionId)
+    : dimensionId(dimensionId)
+{
+    Framework::Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
+                         + Framework::Text(dimensionId) + "/structures";
+    Framework::Datei folder(path);
+    Framework::RCArray<Framework::Text>* files = folder.getDateiListe();
+    if (files)
+    {
+        Framework::Logging::info() << "Loading Multiblock Position Cache";
+        Framework::ConsoleProgressBar* progressBar
+            = new Framework::ConsoleProgressBar();
+        Game::consoleHandler->addContent(
+            progressBar, Framework::ConsoleContentPosition::Top);
+        progressBar->setMaxProgress(files->getEintragAnzahl());
+        progressBar->triggerUpdate();
+        char addr[12];
+        for (Framework::Text* name : *files)
+        {
+            Framework::Datei d(Framework::Text(folder.zPfad()->getText()) + "/"
+                               + name->getText());
+            if (d.open(Framework::Datei::Style::lesen))
+            {
+                d.lese(addr, 4);
+                d.lese(addr + 4, 4);
+                d.lese(addr + 8, 4);
+                __int64 id;
+                d.lese((char*)&id, 8);
+                idCache.set(addr, 12, id);
+                d.close();
+            }
+            progressBar->setProgress(progressBar->getProgress() + 1);
+            progressBar->triggerUpdate();
+        }
+        files->release();
+        Game::consoleHandler->removeContent(progressBar);
+    }
+}
+
+MultiblockStructure* MultiblockStructureManager::loadStructure(__int64 id) const
+{
+    Framework::Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
+                         + Framework::Text(dimensionId) + "/structures/";
+    path.appendHex(id);
+    path += ".str";
+    Framework::Datei d(path);
+    Framework::Vec3<int> uPos;
+    if (d.open(Framework::Datei::Style::lesen))
+    {
+        d.lese((char*)&uPos.x, 4);
+        d.lese((char*)&uPos.y, 4);
+        d.lese((char*)&uPos.z, 4);
+        __int64 strId;
+        d.lese((char*)&strId, 8);
+        int type;
+        d.lese((char*)&type, 4);
+        MultiblockStructure* str
+            = Game::INSTANCE->zMultiblockStructureType(type)->loadStructure(
+                dimensionId, strId, uPos, &d);
+        d.close();
+        return str;
+    }
+    return 0;
+}
+
+__int64 MultiblockStructureManager::getStructureId(
+    Framework::Vec3<int> pos) const
+{
+    char addr[12];
+    *(int*)addr = pos.x;
+    *(int*)(addr + 4) = pos.y;
+    *(int*)(addr + 8) = pos.z;
+    idCache.get(addr, 12);
+    return 0;
+}
+
+void MultiblockStructureManager::saveStructure(
+    MultiblockStructure* zStructure) const
+{
+    Framework::Datei d;
+    Framework::Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
+                         + Framework::Text(dimensionId) + "/structures/";
+    path.appendHex(zStructure->getStructureId());
+    path += ".str";
+    d.setDatei(path);
+    d.erstellen();
+    d.open(Framework::Datei::Style::schreiben);
+    auto uPos = zStructure->getUniquePosition();
+    d.schreibe((char*)&uPos.x, 4);
+    d.schreibe((char*)&uPos.y, 4);
+    d.schreibe((char*)&uPos.z, 4);
+    __int64 strId = zStructure->getStructureId();
+    d.schreibe((char*)&strId, 8);
+    int typeId = zStructure->getStructureTypeId();
+    d.schreibe((char*)&typeId, 4);
+    Game::INSTANCE->zMultiblockStructureType(zStructure->getStructureTypeId())
+        ->saveStructure(zStructure, &d);
+    d.close();
+}

+ 20 - 0
FactoryCraft/MultiblockStructureManager.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include <Text.h>
+#include <Trie.h>
+
+#include "MultiblockStructure.h"
+
+class MultiblockStructureManager
+{
+private:
+    int dimensionId;
+    Framework::Trie<__int64> idCache;
+
+public:
+    MultiblockStructureManager(int dimensionId);
+
+    MultiblockStructure* loadStructure(__int64 id) const;
+    __int64 getStructureId(Framework::Vec3<int> pos) const;
+    void saveStructure(MultiblockStructure* zStructure) const;
+};

+ 20 - 16
FactoryCraft/Start.cpp

@@ -20,6 +20,7 @@
 #include "Chat.h"
 #include "ChunkMap.h"
 #include "Server.h"
+#include "WorldGenerator.h"
 
 FactoryCraftServer* mserver = 0;
 
@@ -78,6 +79,11 @@ public:
             int tps = Game::INSTANCE->getTicksPerSecond();
             std::cout << "Players: " << Game::INSTANCE->getPlayerCount()
                       << "\tChunks: " << Game::INSTANCE->getChunkCount()
+                      << "\tChunks/s: "
+                      << (Game::INSTANCE->zGenerator()
+                                 ? Game::INSTANCE->zGenerator()
+                                       ->getGeneratedChunksPerSecond()
+                                 : 0)
                       << "\ttps: ";
             if (tps < 15)
             { // red
@@ -123,10 +129,10 @@ int main()
     Logging::LoggingChannel* fileLogger
         = new Logging::FileLoggingChannel(logFile);
     fileLogger->setFormat(Logging::LoggingFormatBuilder()
-                              .datetime("h:i:s")
-                              .level(false)
-                              .text(": ")
-                              .build());
+            .datetime("h:i:s")
+            .level(false)
+            .text(": ")
+            .build());
     Logging::zLoggingHandler()->addChannel(fileLogger);
     Logging::zLoggingHandler()->removeLoggingChannel(
         Logging::LogLevel::Error, fileLogger);
@@ -135,14 +141,14 @@ int main()
     Logging::LoggingChannel* errorFileLogger = new Logging::FileLoggingChannel(
         dynamic_cast<Datei*>(logFile->getThis()));
     errorFileLogger->setFormat(Logging::LoggingFormatBuilder()
-                                   .datetime("h:i:s")
-                                   .level()
-                                   .fileName()
-                                   .functionName()
-                                   .text("(")
-                                   .fileLine(false)
-                                   .text("): ")
-                                   .build());
+            .datetime("h:i:s")
+            .level()
+            .fileName()
+            .functionName()
+            .text("(")
+            .fileLine(false)
+            .text("): ")
+            .build());
     Framework::Logging::zLoggingHandler()->addChannel(
         Logging::LogLevel::Warning,
         dynamic_cast<Logging::LoggingChannel*>(errorFileLogger->getThis()));
@@ -151,8 +157,7 @@ int main()
     Logging::LoggingChannel* consoleLogger
         = new Logging::ConsoleHandlerLoggingChannel(
             dynamic_cast<ConsoleHandler*>(Game::consoleHandler->getThis()));
-    consoleLogger->setFormat(
-        Logging::LoggingFormatBuilder()
+    consoleLogger->setFormat(Logging::LoggingFormatBuilder()
             .color(Logging::LogLevel::Debug, Color::LIGHT_BLUE)
             .color(Logging::LogLevel::Trace, Color::LIGHT_CYAN)
             .datetime("h:i:s")
@@ -167,8 +172,7 @@ int main()
     Logging::LoggingChannel* errorConsoleLogger
         = new Logging::ConsoleHandlerLoggingChannel(
             dynamic_cast<ConsoleHandler*>(Game::consoleHandler->getThis()));
-    errorConsoleLogger->setFormat(
-        Logging::LoggingFormatBuilder()
+    errorConsoleLogger->setFormat(Logging::LoggingFormatBuilder()
             .color(Logging::LogLevel::Warning, Color::LIGHT_YELLOW)
             .color(Logging::LogLevel::Error, Color::LIGHT_RED)
             .datetime("h:i:s")

+ 33 - 13
FactoryCraft/WorldGenerator.cpp

@@ -16,7 +16,8 @@ using namespace Framework::Validator;
 WorldGenerator::WorldGenerator(int seed)
     : Thread(),
       exit(0),
-      seed(seed)
+      seed(seed),
+      chunksPerSecond(0.0)
 {
     setName("World Generator");
     Framework::Logging::info()
@@ -26,7 +27,7 @@ WorldGenerator::WorldGenerator(int seed)
         = DataValidator::buildForArray()
               ->removeInvalidEntries()
               ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
-                                           ->getValidator<DimensionGenerator>())
+                      ->getValidator<DimensionGenerator>())
               ->finishArray();
     loadAllJsonsFromDirectory("data/generator",
         [this, configValidator, seed](
@@ -108,39 +109,49 @@ void WorldGenerator::thread()
             Sleep(1000);
             continue;
         }
+        // TODO: prevent that world loader and world generator create the
+        // dimension at the same time
+        Dimension* dim = Game::INSTANCE->zDimension(next.dimensionId);
+        if (!dim)
+        {
+            dim = new Dimension(next.dimensionId);
+            Game::INSTANCE->addDimension(dim);
+        }
         Punkt start = Game::INSTANCE->getChunkCenter(next.startX, next.startY);
         Punkt end = Game::INSTANCE->getChunkCenter(next.endX, next.endY);
         int xDir = start.x > end.x ? -1 : 1;
         int yDir = start.y > end.y ? -1 : 1;
+        double completeTime = 0.0;
+        int generatedChunks = 0;
         for (int x = start.x; xDir < 0 ? x >= end.x : x <= end.x;
-             x += CHUNK_SIZE * xDir)
+            x += CHUNK_SIZE * xDir)
         {
             for (int y = start.y; yDir < 0 ? y >= end.y : y <= end.y;
-                 y += CHUNK_SIZE * yDir)
+                y += CHUNK_SIZE * yDir)
             {
                 if (!Game::INSTANCE->doesChunkExist(x, y, next.dimensionId))
                 {
+                    ZeitMesser zm;
+                    zm.messungStart();
                     Chunk* generatedChunk
                         = zGenerator(next.dimensionId)->generateChunk(x, y);
-                    ZeitMesser zm;
+                    zm.messungEnde();
+                    Framework::Logging::trace()
+                        << "block generation time: " << zm.getSekunden();
+                    completeTime += zm.getSekunden();
                     zm.messungStart();
                     generatedChunk->initializeLightning();
                     zm.messungEnde();
                     Framework::Logging::trace()
                         << "light calculation: " << zm.getSekunden();
+                    completeTime += zm.getSekunden();
                     zm.messungStart();
                     generatedChunk->removeUnusedBlocks();
                     zm.messungEnde();
                     Framework::Logging::trace()
                         << "unused block removal: " << zm.getSekunden();
+                    completeTime += zm.getSekunden();
                     zm.messungStart();
-                    Dimension* dim
-                        = Game::INSTANCE->zDimension(next.dimensionId);
-                    if (!dim)
-                    {
-                        dim = new Dimension(next.dimensionId);
-                        Game::INSTANCE->addDimension(dim);
-                    }
                     generatedChunk->getThis();
                     dim->setChunk(generatedChunk, Punkt(x, y));
                     zGenerator(next.dimensionId)
@@ -149,9 +160,13 @@ void WorldGenerator::thread()
                     zm.messungEnde();
                     Framework::Logging::trace()
                         << "adding chunk to map: " << zm.getSekunden();
+                    completeTime += zm.getSekunden();
+                    generatedChunks++;
+                    chunksPerSecond = generatedChunks / completeTime;
                 }
             }
         }
+        chunksPerSecond = 0.0;
     }
     Framework::Logging::info() << "World Generator thread exited";
 }
@@ -181,4 +196,9 @@ bool WorldGenerator::spawnStructure(Framework::Vec3<int> location,
     std::function<bool(GeneratorTemplate* tmpl)> filter)
 {
     return zGenerator(dimensionId)->spawnStructure(location, filter);
-}
+}
+
+double WorldGenerator::getGeneratedChunksPerSecond()
+{
+    return chunksPerSecond;
+}

+ 3 - 1
FactoryCraft/WorldGenerator.h

@@ -14,13 +14,14 @@ private:
     Framework::RCArray<DimensionGenerator> dimensionGenerators;
     bool exit;
     int seed;
+    double chunksPerSecond;
 
     DimensionGenerator* zGenerator(int dimensionId);
 
 public:
     WorldGenerator(int seed);
     ~WorldGenerator();
-    Dimension *createDimension(int dimensionId);
+    Dimension* createDimension(int dimensionId);
     void thread() override;
     void requestGeneration(Area request);
     void exitAndWait();
@@ -29,4 +30,5 @@ public:
     bool spawnStructure(Framework::Vec3<int> location,
         int dimensionId,
         std::function<bool(GeneratorTemplate* tmpl)> filter);
+    double getGeneratedChunksPerSecond();
 };

+ 2 - 0
Windows Version/Windows Version.vcxproj

@@ -225,6 +225,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\LightSources.cpp" />
     <ClCompile Include="..\FactoryCraft\ModelInfo.cpp" />
     <ClCompile Include="..\FactoryCraft\MultiblockStructure.cpp" />
+    <ClCompile Include="..\FactoryCraft\MultiblockStructureManager.cpp" />
     <ClCompile Include="..\FactoryCraft\MultiblockTree.cpp" />
     <ClCompile Include="..\FactoryCraft\MultiplyNoise.cpp" />
     <ClCompile Include="..\FactoryCraft\NegateNoise.cpp" />
@@ -338,6 +339,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\DimensionMap.h" />
     <ClInclude Include="..\FactoryCraft\ModelInfo.h" />
     <ClInclude Include="..\FactoryCraft\MultiblockStructure.h" />
+    <ClInclude Include="..\FactoryCraft\MultiblockStructureManager.h" />
     <ClInclude Include="..\FactoryCraft\MultiblockTree.h" />
     <ClInclude Include="..\FactoryCraft\MultiplyNoise.h" />
     <ClInclude Include="..\FactoryCraft\NegateNoise.h" />

+ 6 - 0
Windows Version/Windows Version.vcxproj.filters

@@ -438,6 +438,9 @@
     <ClCompile Include="..\FactoryCraft\DropConfig.cpp">
       <Filter>drops</Filter>
     </ClCompile>
+    <ClCompile Include="..\FactoryCraft\MultiblockStructureManager.cpp">
+      <Filter>world\structures</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\FactoryCraft\Chunk.h">
@@ -779,5 +782,8 @@
     <ClInclude Include="..\FactoryCraft\SpecificItemDrop.h">
       <Filter>drops\implementations</Filter>
     </ClInclude>
+    <ClInclude Include="..\FactoryCraft\MultiblockStructureManager.h">
+      <Filter>world\structures</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>

BIN
Windows Version/error_core_memory_dump.dmp