Browse Source

add map information

Kolja Strohm 2 years ago
parent
commit
b8c2d022c7

+ 8 - 5
FactoryCraft/BasicBlock.cpp

@@ -61,7 +61,7 @@ void AdditionalItemSpawningBlock::onDestroy()
 }
 
 BasicBlockType::BasicBlockType(
-    int typeId, int itemTypeId, ModelInfo model, const char* name)
+    int typeId, int itemTypeId, ModelInfo model, const char* name, int mapColor)
     : BasicBlockType(
         typeId,
         itemTypeId,
@@ -69,15 +69,17 @@ BasicBlockType::BasicBlockType(
         [typeId](Framework::Vec3<int> pos) {
             return new BasicBlock(typeId, 0, pos);
         },
-        name)
+        name,
+        mapColor)
 {}
 
 BasicBlockType::BasicBlockType(int typeId,
     int itemTypeId,
     ModelInfo model,
     std::function<Block*(Framework::Vec3<int>)> creatBlockCustom,
-    const char* name)
-    : BlockType(typeId, 0, model, 1, 100, 0, name, false),
+    const char* name,
+    int mapColor)
+    : BlockType(typeId, 0, model, 1, 100, 0, name, false, mapColor),
       itemType(itemTypeId),
       transparent(0),
       passable(0),
@@ -118,7 +120,8 @@ BasicBlockType* BasicBlockType::setHardness(float hardness)
     return this;
 }
 
-BasicBlockType* BasicBlockType::setTransparent(bool transparent) {
+BasicBlockType* BasicBlockType::setTransparent(bool transparent)
+{
     this->transparent = transparent;
     return this;
 }

+ 3 - 2
FactoryCraft/BasicBlocks.h

@@ -56,12 +56,13 @@ protected:
 
 public:
     BasicBlockType(
-        int typeId, int itemTypeId, ModelInfo model, const char* name);
+        int typeId, int itemTypeId, ModelInfo model, const char* name, int mapColor);
     BasicBlockType(int typeId,
         int itemTypeId,
         ModelInfo model,
         std::function<Block*(Framework::Vec3<int>)> creatBlockCustom,
-        const char* name);
+        const char* name,
+        int mapColor);
     virtual Block* createBlock(Framework::Vec3<int> position) const override;
     virtual Item* createItem() const override;
     BasicBlockType* setHardness(float hardness);

+ 6 - 0
FactoryCraft/Block.cpp

@@ -33,6 +33,7 @@ Block::Block(int typeId,
     deadAndRemoved = 0;
     memset(zNeighbours, 0, sizeof(Block*) * 6);
     memset(lightEmisionColor, 0, 3);
+    mapColor = 0;
 }
 
 Block::~Block() {}
@@ -335,6 +336,11 @@ void Block::updateModel(ModelInfo info) const
     Game::INSTANCE->broadcastMessage(changeMsg);
 }
 
+int Block::getMapColor() const
+{
+    return mapColor;
+}
+
 BasicBlockItem::BasicBlockItem(
     int itemTypeId, int blockTypeId, const char* name)
     : Item(itemTypeId, name),

+ 2 - 0
FactoryCraft/Block.h

@@ -53,6 +53,7 @@ protected:
     bool transmissionRequested;
     bool deadAndRemoved;
     unsigned char lightEmisionColor[3];
+    int mapColor;
 
     Framework::RCArray<MultiblockStructure> structures;
 
@@ -113,6 +114,7 @@ public:
     virtual void filterPassingLight(unsigned char rgb[3]) const;
     Block* zNeighbor(Direction dir) const;
     void updateModel(ModelInfo info) const;
+    int getMapColor() const;
 
     friend BlockType;
 };

+ 6 - 1
FactoryCraft/BlockType.cpp

@@ -15,7 +15,8 @@ BlockType::BlockType(int id,
     int initialMaxHP,
     bool lightSource,
     const char* name,
-    bool needModelSubscription)
+    bool needModelSubscription,
+    int initialMapColor)
     : ReferenceCounter(),
       id(id),
       model(model),
@@ -24,6 +25,7 @@ BlockType::BlockType(int id,
       lightSource(lightSource),
       name(name),
       needModelSubscription(needModelSubscription),
+      initialMapColor(initialMapColor),
       defaultBlock(defaultBlock)
 {
     StaticRegistry<BlockType>::INSTANCE.registerT(this, id);
@@ -44,6 +46,7 @@ void BlockType::loadSuperBlock(
     zReader->lese((char*)&zBlock->maxHP, 4);
     zReader->lese((char*)&zBlock->hardness, 4);
     zReader->lese((char*)&zBlock->speedModifier, 4);
+    zReader->lese((char*)&zBlock->mapColor, 4);
     int effectiveToolId;
     zReader->lese((char*)&effectiveToolId, 4);
     if (effectiveToolId >= 0)
@@ -78,6 +81,7 @@ void BlockType::saveSuperBlock(
     zWriter->schreibe((char*)&zBlock->maxHP, 4);
     zWriter->schreibe((char*)&zBlock->hardness, 4);
     zWriter->schreibe((char*)&zBlock->speedModifier, 4);
+    zWriter->schreibe((char*)&zBlock->mapColor, 4);
     int effectiveToolId = zBlock->zTool ? zBlock->zTool->getId() : -1;
     zWriter->schreibe((char*)&effectiveToolId, 4);
     zWriter->schreibe((char*)&zBlock->interactable, 1);
@@ -110,6 +114,7 @@ void BlockType::createSuperBlock(Block* zBlock, Item* zItem) const
                 : 0;
         zBlock->interactable = item->interactable;
     }
+    zBlock->mapColor = initialMapColor;
 }
 
 void BlockType::createSuperItem(Block* zBlock, Item* zItem) const

+ 3 - 1
FactoryCraft/BlockType.h

@@ -56,6 +56,7 @@ private:
     bool lightSource;
     const char* name;
     const bool needModelSubscription;
+    int initialMapColor;
 
 protected:
     Block* defaultBlock;
@@ -66,7 +67,8 @@ protected:
         int initialMaxHP,
         bool lightSource,
         const char* name,
-        bool needModelSubscription);
+        bool needModelSubscription,
+        int initialMapColor);
     virtual ~BlockType();
 
     virtual void loadSuperBlock(

+ 13 - 4
FactoryCraft/Chunk.cpp

@@ -409,10 +409,8 @@ const Block* Chunk::zBlockConst(Framework::Vec3<int> location) const
 {
     auto b = zBlockAt(location);
     if (b.isA()) return b;
-    if (b.getB())
-        return StaticRegistry<BlockType>::INSTANCE.zElement(b.getB())
-            ->zDefault();
-    return 0;
+    return StaticRegistry<BlockType>::INSTANCE.zElement(b.getB())
+        ->zDefault();
 }
 
 void Chunk::instantiateBlock(Framework::Vec3<int> location)
@@ -532,6 +530,13 @@ void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
             }
         }
     }
+    if (added)
+    {
+        Game::INSTANCE->zDimension(dimensionId)
+            ->updateMap(location.x + this->location.x - CHUNK_SIZE / 2,
+                location.y + this->location.y - CHUNK_SIZE / 2,
+                location.z);
+    }
 }
 
 void Chunk::putBlockTypeAt(Framework::Vec3<int> location, int type)
@@ -570,6 +575,10 @@ void Chunk::putBlockTypeAt(Framework::Vec3<int> location, int type)
                 Vec3<int>(location.x + this->location.x - CHUNK_SIZE / 2,
                     location.y + this->location.y - CHUNK_SIZE / 2,
                     location.z));
+            Game::INSTANCE->zDimension(dimensionId)
+                ->updateMap(location.x + this->location.x - CHUNK_SIZE / 2,
+                    location.y + this->location.y - CHUNK_SIZE / 2,
+                    location.z);
         }
     }
 }

+ 7 - 2
FactoryCraft/Chunk.h

@@ -10,7 +10,10 @@
 #include "DoLaterHandler.h"
 #include "Tickable.h"
 
-class Chunk : public virtual Framework::ReferenceCounter, public Tickable
+class ChunkMap;
+
+class Chunk : public virtual Framework::ReferenceCounter,
+              public Tickable
 {
 private:
     int dimensionId;
@@ -45,7 +48,7 @@ public:
 
     void tick(TickQueue* zQueue) override;
     void postTick() override;
-	
+
     void notifyObservers(NetworkMessage* msg);
     void addObserver(Entity* zEntity, DoLaterHandler& laterHandler);
     void removeObserver(Entity* zEntity);
@@ -79,4 +82,6 @@ public:
     unsigned char* getLightData(Framework::Vec3<int> location) const;
     void setLightData(
         Framework::Vec3<int> location, unsigned char* data, bool foreground);
+
+    friend ChunkMap;
 };

+ 155 - 0
FactoryCraft/ChunkMap.cpp

@@ -0,0 +1,155 @@
+#include "ChunkMap.h"
+
+#include "Chunk.h"
+#include "Constants.h"
+
+ChunkMap::ChunkMap(Chunk* zChunk)
+    : ReferenceCounter(),
+      chunkCenter(zChunk->location)
+{
+    pixels = new MapPixel[CHUNK_SIZE * CHUNK_SIZE];
+    memset(pixels, 0, sizeof(MapPixel) * CHUNK_SIZE * CHUNK_SIZE);
+    MapBlock blocksBuffer[256];
+    for (int x = 0; x < CHUNK_SIZE; x++)
+    {
+        for (int y = 0; y < CHUNK_SIZE; y++)
+        {
+            int count = 0;
+            bool visible = 1;
+            for (int height = WORLD_HEIGHT / 2 - 1; height >= 0; height--)
+            {
+                int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT;
+                const Block* block1
+                    = CONST_BLOCK(zChunk->blocks[index + height * 2],
+                        zChunk->blockIds[index + height * 2]);
+                const Block* block2
+                    = CONST_BLOCK(zChunk->blocks[index + height * 2 + 1],
+                        zChunk->blockIds[index + height * 2 + 1]);
+                int color1 = 0;
+                int color2 = 0;
+                if (visible) color2 = block2->getMapColor();
+                visible = block2->isVisible();
+                if (visible) color1 = block1->getMapColor();
+                visible = block1->isVisible();
+                if (color1 || color2)
+                {
+                    blocksBuffer[256 - ++count] = {(unsigned char)height,
+                        (color1 >> 24) > (color2 >> 24) ? color1 : color2};
+                }
+            }
+            int i = x * CHUNK_SIZE + y;
+            pixels[i].blocks = new MapBlock[count];
+            memcpy(pixels[i].blocks,
+                blocksBuffer + 256 - count,
+                sizeof(MapBlock) * count);
+            pixels[i].len = (unsigned char)count;
+        }
+    }
+}
+
+ChunkMap::ChunkMap(Framework::StreamReader* zReader)
+    : ReferenceCounter()
+{
+    zReader->lese((char*)&chunkCenter.x, 4);
+    zReader->lese((char*)&chunkCenter.y, 4);
+    pixels = new MapPixel[CHUNK_SIZE * CHUNK_SIZE];
+    memset(pixels, 0, sizeof(MapPixel) * CHUNK_SIZE * CHUNK_SIZE);
+    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE; i++)
+    {
+        zReader->lese((char*)&pixels[i].len, 1);
+        if (pixels[i].len > 0)
+        {
+            pixels[i].blocks = new MapBlock[pixels[i].len];
+            zReader->lese(
+                (char*)pixels[i].blocks, (int)sizeof(MapBlock) * pixels[i].len);
+        }
+    }
+}
+
+ChunkMap::~ChunkMap()
+{
+    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE; i++)
+    {
+        delete[] pixels[i].blocks;
+    }
+    delete[] pixels;
+}
+
+void ChunkMap::update(
+    char x, char y, unsigned char height, int color1, int color2)
+{
+    cs.lock();
+    int index = x * CHUNK_SIZE + y;
+    bool found = 0;
+    int resultColor = (color1 >> 24) > (color2 >> 24) ? color1 : color2;
+    bool removed = !(resultColor >> 24);
+    for (int i = 0; i < pixels[index].len; i++)
+    {
+        if (pixels[index].blocks[i].height == height)
+        {
+            pixels[index].blocks[i].color = resultColor;
+            found = 1;
+        }
+        else if (!found && pixels[index].blocks[i].height > height)
+        {
+            break;
+        }
+        if (found && removed && i < pixels[index].len - 1)
+        {
+            pixels[index].blocks[i] = pixels[index].blocks[i + 1];
+        }
+    }
+    if (found && removed)
+    {
+        pixels[index].len--;
+    }
+    else if (!found && !removed)
+    {
+        MapBlock* blocks = new MapBlock[pixels[index].len + 1];
+        bool added = 0;
+        for (int i = 0; i < pixels[index].len; i++)
+        {
+            if (pixels[index].blocks[i].height < height)
+            {
+                blocks[i] = pixels[index].blocks[i];
+            }
+            else
+            {
+                if (!added)
+                {
+                    blocks[i] = {height, resultColor};
+                    added = 1;
+                }
+                blocks[i + 1] = pixels[index].blocks[i];
+            }
+        }
+        if (!added)
+        {
+            blocks[pixels[index].len] = {height, resultColor};
+        }
+        pixels[index].len++;
+        delete[] pixels[index].blocks;
+        pixels[index].blocks = blocks;
+    }
+    cs.unlock();
+}
+
+void ChunkMap::writeTo(Framework::StreamWriter* zWriter) const
+{
+    zWriter->schreibe((char*)&chunkCenter.x, 4);
+    zWriter->schreibe((char*)&chunkCenter.y, 4);
+    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE; i++)
+    {
+        zWriter->schreibe((char*)&pixels[i].len, 1);
+        if (pixels[i].len > 0)
+        {
+            zWriter->schreibe(
+                (char*)pixels[i].blocks, (int)sizeof(MapBlock) * pixels[i].len);
+        }
+    }
+}
+
+Framework::Punkt ChunkMap::getChunkCenter() const
+{
+    return chunkCenter;
+}

+ 55 - 0
FactoryCraft/ChunkMap.h

@@ -0,0 +1,55 @@
+#pragma once
+
+#include <Punkt.h>
+#include <Reader.h>
+#include <Writer.h>
+#include <ReferenceCounter.h>
+#include <Critical.h>
+
+#pragma pack(1)
+
+// stores the color aof the map at a specific height
+struct MapBlock
+{
+    unsigned char height;
+    int color;
+};
+
+// stores the colors at all heights of a specific x and y position on the map.
+// there can by only 256 colors stored per position
+struct MapPixel
+{
+    unsigned char len;
+    MapBlock* blocks;
+};
+
+#pragma pack(0)
+
+class Chunk;
+
+// stores the map colors of a complete chunk
+class ChunkMap : public Framework::ReferenceCounter
+{
+private:
+    Framework::Punkt chunkCenter;
+    MapPixel* pixels;
+    Framework::Critical cs;
+
+public:
+    ChunkMap(Chunk *zChunk);
+    ChunkMap(Framework::StreamReader* zReader);
+    ~ChunkMap();
+
+    // updates the color in the chunk map at a specific position.
+    // the color stored will be the color that is less transparent from color1
+    // and color2. if both colors are completle transparent then the color at
+    // this height will be removed.
+    // \param x the x coordinate in chunk space \param y the y
+    // coordinate in chunk space \param heigth the height to update (at each
+    // height are two blocks stored) \param color1 the color of the first block
+    // at this height \param color2 the color of the second block at this height
+    void update(char x, char y, unsigned char height, int color1, int color2);
+
+    void writeTo(Framework::StreamWriter* zWriter) const;
+    Framework::Punkt getChunkCenter() const;
+};

+ 73 - 19
FactoryCraft/Dimension.cpp

@@ -14,6 +14,7 @@ Dimension::Dimension(int id)
       gravity(9.8f),
       chunks(new Trie<Chunk>()),
       entities(new RCArray<Entity>()),
+      map(new DimensionMap(id)),
       stop(0)
 {
     Datei d;
@@ -32,6 +33,7 @@ Dimension::~Dimension()
 {
     entities->release();
     chunks->release();
+    map->release();
 }
 
 void Dimension::api(Framework::InMemoryBuffer* zRequest,
@@ -49,7 +51,7 @@ void Dimension::api(Framework::InMemoryBuffer* zRequest,
             zRequest->lese((char*)&center.x, 4);
             zRequest->lese((char*)&center.y, 4);
             cs.lock();
-            Chunk* cC = zChunk(center);
+            Chunk* cC = zChunk(Game::getChunkCenter(center.x, center.y));
             if (!cC)
             {
                 // TODO: have a max amount of waiting requests per player
@@ -71,18 +73,33 @@ void Dimension::api(Framework::InMemoryBuffer* zRequest,
             break;
         }
     case 1: // block message
-        Vec3<int> location;
-        zRequest->lese((char*)&location.x, 4);
-        zRequest->lese((char*)&location.y, 4);
-        zRequest->lese((char*)&location.z, 4);
-        Framework::Either<Block*, int> block = zBlock(location);
-        if (block.isA())
         {
-            block.getA()->api(zRequest, zResponse);
+            Vec3<int> location;
+            zRequest->lese((char*)&location.x, 4);
+            zRequest->lese((char*)&location.y, 4);
+            zRequest->lese((char*)&location.z, 4);
+            Framework::Either<Block*, int> block = zBlock(location);
+            if (block.isA())
+            {
+                block.getA()->api(zRequest, zResponse);
+            }
+            break;
+        }
+    case 2: // map request
+        {
+            Framework::Punkt location;
+            zRequest->lese((char*)&location.x, 4);
+            zRequest->lese((char*)&location.y, 4);
+            location = Game::getChunkCenter(location.x, location.y);
+            char addr[8];
+            getAddrOfWorld(location, addr);
+            ChunkMap* res = map->getMap(addr, 8, location);
+            zResponse->sendMap(res);
+            zResponse->setUseBackground();
+            res->release();
+            break;
         }
-        break;
     }
-    
 }
 
 void Dimension::tickEntities()
@@ -91,7 +108,7 @@ void Dimension::tickEntities()
     {
         if (!entity->isRemoved()
             && (entity->isMoving()
-                || zChunk(Punkt((int)entity->getPosition().x,
+                || zChunk(Game::getChunkCenter((int)entity->getPosition().x,
                     (int)entity->getPosition().y))))
             entity->prepareTick(this);
     }
@@ -100,7 +117,7 @@ void Dimension::tickEntities()
     {
         if (!entity->isRemoved()
             && (entity->isMoving()
-                || zChunk(Punkt((int)entity->getPosition().x,
+                || zChunk(Game::getChunkCenter((int)entity->getPosition().x,
                     (int)entity->getPosition().y))))
             entity->tick(this);
         index++;
@@ -142,6 +159,9 @@ void Dimension::thread()
                 d.erstellen();
                 d.open(Datei::Style::schreiben);
                 removedChunk->save(&d);
+                char addr[8];
+                getAddrOfWorld(removedChunk->getCenter(), addr);
+                map->removeMap(addr, 8);
                 d.close();
                 removedChunksCs.lock();
                 removedChunks.remove(0);
@@ -227,7 +247,6 @@ void Dimension::thread()
                             (unsigned char)((float)neighborLeight[j] * 0.85f));
                 }
                 const Block* current = zBlockOrDefault(position);
-                if (!current) current = &NoBlock::INSTANCE;
                 // add own light emission
                 for (int j = 3; j < 6; j++)
                     newLight[j] = (unsigned char)MAX(
@@ -331,7 +350,7 @@ const Block* Dimension::zBlockOrDefault(Framework::Vec3<int> location)
         if (y < 0) y += CHUNK_SIZE;
         return c->zBlockConst(Vec3<int>(x, y, location.z));
     }
-    return 0;
+    return &NoBlock::INSTANCE;
 }
 
 void Dimension::placeBlock(
@@ -348,7 +367,6 @@ void Dimension::placeBlock(
             c->putBlockAt(Vec3<int>(x, y, location.z), block);
         else
         {
-            
             c->putBlockAt(Vec3<int>(x, y, location.z), 0);
             c->putBlockTypeAt(Vec3<int>(x, y, location.z), block);
         }
@@ -377,9 +395,10 @@ void Dimension::addEntity(Entity* entity)
 
 void Dimension::setChunk(Chunk* chunk, Punkt center)
 {
-    chunkCs.lock();
     char addr[8];
     getAddrOfWorld(center, addr);
+    if (chunk) map->loadMap(addr, 8, chunk);
+    chunkCs.lock();
     Chunk* old = chunks->get(addr, 8);
     if (old)
     {
@@ -496,6 +515,9 @@ void Dimension::save(Text worldDir) const
         if (file->open(Datei::Style::schreiben)) chunk->save(file);
         file->close();
         file->release();
+        char addr[8];
+        getAddrOfWorld(chunk->getCenter(), addr);
+        map->saveMap(addr, 8);
     }
     Text filePath = worldDir + "/dim/" + dimensionId + "/entities";
     Datei* file = new Datei();
@@ -517,8 +539,9 @@ void Dimension::save(Text worldDir) const
             else
             {
                 Datei pFile;
-                pFile.setDatei(
-                    worldDir + "/player/" + Game::INSTANCE->getPlayerId(((Player*)entity)->getName()));
+                pFile.setDatei(worldDir + "/player/"
+                               + Game::INSTANCE->getPlayerId(
+                                   ((Player*)entity)->getName()));
                 if (pFile.open(Datei::Style::schreiben))
                     StaticRegistry<EntityType>::INSTANCE
                         .zElement(EntityTypeEnum::PLAYER)
@@ -829,7 +852,8 @@ MultiblockStructure* Dimension::zStructureById(__int64 id)
         structurCs.unlock();
         return str;
     }
-    std::cout << "WARNING: did not find Structure information file '" << path << "'.";
+    std::cout << "WARNING: did not find Structure information file '" << path
+              << "'.";
     structurCs.unlock();
     return 0;
 }
@@ -838,4 +862,34 @@ void Dimension::requestStopAndWait()
 {
     stop = 1;
     warteAufThread(1000000);
+}
+
+void Dimension::updateMap(int x, int y, int height)
+{
+    chunkCs.lock();
+    int h1 = height % 2 == 0 ? height : height - 1;
+    int h2 = h1 + 1;
+    const Block* b1 = zBlockOrDefault({x, y, h1});
+    const Block* b2 = zBlockOrDefault({x, y, h2});
+    bool visible = 1;
+    if (h2 != WORLD_HEIGHT - 1)
+    {
+        visible = zBlockOrDefault({x, y, h2 + 1})->isVisible();
+    }
+    int color1 = b2->isVisible() ? b1->getMapColor() : 0;
+    int color2 = visible ? b2->getMapColor() : 0;
+    char addr[8];
+    Punkt center = Game::INSTANCE->getChunkCenter(x, y);
+    getAddrOfWorld(center, addr);
+    ChunkMap* cMap = map->getMap(addr, 8, center);
+    if (cMap)
+    {
+        x = x % CHUNK_SIZE;
+        y = y % CHUNK_SIZE;
+        if (x < 0) x += CHUNK_SIZE;
+        if (y < 0) y += CHUNK_SIZE;
+        cMap->update(
+            (char)x, (char)y, (unsigned char)(height / 2), color1, color2);
+    }
+    chunkCs.unlock();
 }

+ 3 - 0
FactoryCraft/Dimension.h

@@ -7,6 +7,7 @@
 #include "Chunk.h"
 #include "MultiblockStructure.h"
 #include "NetworkMessage.h"
+#include "DimensionMap.h"
 
 struct RequestQueue
 {
@@ -37,6 +38,7 @@ private:
     Framework::RCArray<Chunk> removedChunks;
     Framework::Critical removedChunksCs;
     Framework::RCArray<MultiblockStructure> structures;
+    DimensionMap* map;
     bool stop;
 
 public:
@@ -79,4 +81,5 @@ public:
         Framework::Vec3<int> uniquePosition);
     MultiblockStructure* zStructureById(__int64 id);
     void requestStopAndWait();
+    void updateMap(int x, int y, int height);
 };

+ 101 - 0
FactoryCraft/DimensionMap.cpp

@@ -0,0 +1,101 @@
+#include "DimensionMap.h"
+
+#include <Datei.h>
+
+#include "Game.h"
+
+DimensionMap::DimensionMap(int dimensionId)
+    : ReferenceCounter(),
+      dimensionId(dimensionId)
+{
+    chunks = new Framework::Trie<ChunkMap>();
+}
+
+DimensionMap::~DimensionMap()
+{
+    chunks->release();
+}
+
+ChunkMap* DimensionMap::load(Framework::Punkt chunkCenter)
+{
+    Framework::Datei file;
+    Framework::Text filePath
+        = Game::INSTANCE->getWorldDirectory() + "/dim/" + dimensionId + "/map/";
+    filePath.appendHex(chunkCenter.x);
+    filePath += "_";
+    filePath.appendHex(chunkCenter.y);
+    filePath += ".map";
+    file.setDatei(filePath);
+    if (file.open(Datei::Style::lesen))
+    {
+        ChunkMap* map = new ChunkMap(&file);
+        file.close();
+        return map;
+    }
+    return 0;
+}
+
+void DimensionMap::loadMap(char* addr, int addrLen, Chunk* zChunk)
+{
+    cs.lock();
+    if (chunks->z(addr, addrLen))
+    {
+        cs.unlock();
+        return;
+    }
+    ChunkMap* map = load(zChunk->getCenter());
+    if (!map) map = new ChunkMap(zChunk);
+    chunks->set(addr, addrLen, map);
+    cs.unlock();
+}
+
+void DimensionMap::saveMap(char* addr, int addrLen)
+{
+    cs.lock();
+    ChunkMap* map = chunks->z(addr, addrLen);
+    if (map)
+    {
+        Framework::Datei file;
+        Framework::Text filePath = Game::INSTANCE->getWorldDirectory() + "/dim/"
+                                 + dimensionId + "/map/";
+        filePath.appendHex(map->getChunkCenter().x);
+        filePath += "_";
+        filePath.appendHex(map->getChunkCenter().y);
+        filePath += ".map";
+        file.setDatei(filePath);
+        file.erstellen();
+        if (file.open(Datei::Style::schreiben))
+        {
+            map->writeTo(&file);
+            file.close();
+        }
+        else
+        {
+            Game::INSTANCE->zChat()->broadcastMessage(
+                "Could not save map data. The map has to be recalulated at "
+                "each chunk loading.",
+                Chat::CHANNEL_WARNING);
+            std::cout << "WARNING: could not open file '" << filePath.getText()
+                      << "' for writing.";
+        }
+    }
+    cs.unlock();
+}
+
+void DimensionMap::removeMap(char* addr, int addrLen)
+{
+    cs.lock();
+    saveMap(addr, addrLen);
+    chunks->remove(addr, addrLen);
+    cs.unlock();
+}
+
+ChunkMap* DimensionMap::getMap(
+    char* addr, int addrLen, Framework::Punkt chunkCenter)
+{
+    cs.lock();
+    ChunkMap* map = chunks->get(addr, addrLen);
+    if (!map) map = load(chunkCenter);
+    cs.unlock();
+    return map;
+}

+ 25 - 0
FactoryCraft/DimensionMap.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include <ReferenceCounter.h>
+#include <Trie.h>
+
+#include "ChunkMap.h"
+
+class DimensionMap : public Framework::ReferenceCounter
+{
+private:
+    Framework::Trie<ChunkMap>* chunks;
+    Framework::Critical cs;
+    int dimensionId;
+
+    ChunkMap* load(Framework::Punkt chunkCenter);
+
+public:
+    DimensionMap(int dimensionId);
+    ~DimensionMap();
+
+    void loadMap(char* addr, int addrLen, Chunk* zChunk);
+    void saveMap(char* addr, int addrLen);
+    void removeMap(char* addr, int addrLen);
+    ChunkMap* getMap(char* addr, int addrLen, Framework::Punkt chunkCenter);
+};

+ 4 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -96,6 +96,7 @@
     <RemoteTargetPath>$(RemoteProjectDir)/$(TargetName)$(TargetExt)</RemoteTargetPath>
   </PropertyGroup>
   <ItemGroup>
+    <ClInclude Include="ChunkMap.h" />
     <ClInclude Include="AddEntityUpdate.h" />
     <ClInclude Include="Area.h" />
     <ClInclude Include="Axe.h" />
@@ -141,6 +142,7 @@
     <ClInclude Include="ItemStack.h" />
     <ClInclude Include="ItemType.h" />
     <ClInclude Include="LightSources.h" />
+    <ClInclude Include="DimensionMap.h" />
     <ClInclude Include="ModelInfo.h" />
     <ClInclude Include="MultiblockStructure.h" />
     <ClInclude Include="MultiblockTree.h" />
@@ -190,9 +192,11 @@
     <ClCompile Include="ChatMessage.cpp" />
     <ClCompile Include="ChatObserver.cpp" />
     <ClCompile Include="Chunk.cpp" />
+    <ClCompile Include="ChunkMap.cpp" />
     <ClCompile Include="CraftingStorage.cpp" />
     <ClCompile Include="Dimension.cpp" />
     <ClCompile Include="DimensionGenerator.cpp" />
+    <ClCompile Include="DimensionMap.cpp" />
     <ClCompile Include="DoLaterHandler.cpp" />
     <ClCompile Include="Entity.cpp" />
     <ClCompile Include="EntityRemovedUpdate.cpp" />

+ 15 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -82,6 +82,9 @@
     <Filter Include="chat\commands">
       <UniqueIdentifier>{547d8b22-5902-40ce-9510-e54cabab093d}</UniqueIdentifier>
     </Filter>
+    <Filter Include="world\map">
+      <UniqueIdentifier>{cdafc254-a7ce-4911-8534-20ebcee5bec8}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Chunk.h">
@@ -312,6 +315,12 @@
     <ClInclude Include="PlayerRegister.h">
       <Filter>game</Filter>
     </ClInclude>
+    <ClInclude Include="DimensionMap.h">
+      <Filter>world\map</Filter>
+    </ClInclude>
+    <ClInclude Include="ChunkMap.h">
+      <Filter>world\map</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -530,5 +539,11 @@
     <ClCompile Include="PlayerRegister.cpp">
       <Filter>game</Filter>
     </ClCompile>
+    <ClCompile Include="ChunkMap.cpp">
+      <Filter>world\map</Filter>
+    </ClCompile>
+    <ClCompile Include="DimensionMap.cpp">
+      <Filter>world\map</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 3 - 2
FactoryCraft/FluidBlock.cpp

@@ -244,8 +244,9 @@ void FluidBlock::sortByAmound(FluidBlock** array, int count)
     }
 }
 
-FluidBlockType::FluidBlockType(int id, ModelInfo model, const char* name)
-    : BlockType(id, 0, model, 1, 10, 0, name, true)
+FluidBlockType::FluidBlockType(
+    int id, ModelInfo model, const char* name, int mapColor)
+    : BlockType(id, 0, model, 1, 10, 0, name, true, mapColor)
 {}
 
 void FluidBlockType::loadSuperBlock(

+ 1 - 1
FactoryCraft/FluidBlock.h

@@ -41,5 +41,5 @@ protected:
     virtual Block* createBlock(Framework::Vec3<int> position) const override;
 
 public:
-    FluidBlockType(int id, ModelInfo model, const char* name);
+    FluidBlockType(int id, ModelInfo model, const char* name, int mapColor);
 };

+ 2 - 2
FactoryCraft/Grass.cpp

@@ -65,8 +65,8 @@ void GrassBlock::onDestroy()
 }
 
 GrassBlockType::GrassBlockType(
-    int typeId, int itemTypeId, ModelInfo model, const char* name)
-    : BlockType(typeId, 0, model, 1, 10, 0, name, false),
+    int typeId, int itemTypeId, ModelInfo model, const char* name, int mapColor)
+    : BlockType(typeId, 0, model, 1, 10, 0, name, false, mapColor),
       itemType(itemTypeId),
       transparent(true),
       passable(true),

+ 3 - 4
FactoryCraft/Grass.h

@@ -7,9 +7,7 @@ class GrassBlockType;
 class GrassBlock : public Block
 {
 public:
-    GrassBlock(int typeId,
-        const ItemType* zTool,
-        Framework::Vec3<int> pos);
+    GrassBlock(int typeId, const ItemType* zTool, Framework::Vec3<int> pos);
     virtual bool onTick(
         TickQueue* zQueue, int numTicks, bool& blocked) override;
     virtual void onPostTick() override;
@@ -43,5 +41,6 @@ public:
     GrassBlockType(int typeId,
         int itemTypeId,
         ModelInfo model,
-        const char* name);
+        const char* name,
+        int mapColor);
 };

+ 3 - 2
FactoryCraft/GrowingPlant.cpp

@@ -124,8 +124,9 @@ GrowingPlantBlockType::GrowingPlantBlockType(int typeId,
     const char* name,
     int blockTypeAfterGrowth,
     const char* readableName,
-    int ticksNeeded)
-    : BlockType(typeId, 0, model, 1, 10.f, 0, name, true),
+    int ticksNeeded,
+    int mapColor)
+    : BlockType(typeId, 0, model, 1, 10.f, 0, name, true, mapColor),
       transparent(1),
       passable(1),
       hardness(0.1f),

+ 8 - 10
FactoryCraft/GrowingPlant.h

@@ -2,7 +2,6 @@
 
 #include "Block.h"
 
-
 class GrowingPlantBlockType;
 
 struct GrowthState
@@ -28,13 +27,12 @@ private:
     bool plantSpawned;
 
 public:
-    GrowingPlantBlock(
-        int typeId,
+    GrowingPlantBlock(int typeId,
         const ItemType* zTool,
-                      Framework::Vec3<int> pos,
-                      int maxTicks,
-                      const char* name,
-                      int blockTypeAfterGrowth);
+        Framework::Vec3<int> pos,
+        int maxTicks,
+        const char* name,
+        int blockTypeAfterGrowth);
     virtual bool onTick(
         TickQueue* zQueue, int numTicks, bool& blocked) override;
     virtual void onPostTick() override;
@@ -63,8 +61,7 @@ protected:
     virtual void loadSuperBlock(Block* zBlock,
         Framework::StreamReader* zReader,
         int dimensionId) const override;
-    void createSuperBlock(
-        Block* zBlock, Item* zItem) const override;
+    void createSuperBlock(Block* zBlock, Item* zItem) const override;
     virtual void saveSuperBlock(
         Block* zBlock, Framework::StreamWriter* zWriter) const override;
     virtual Item* createItem() const override;
@@ -76,7 +73,8 @@ public:
         const char* name,
         int blockTypeAfterGrowth,
         const char* readableName,
-        int ticksNeeded);
+        int ticksNeeded,
+        int mapColor);
     GrowingPlantBlockType* setHardness(float hardness);
     GrowingPlantBlockType* addGrowthState(
         float growthPercentage, ModelInfo model);

+ 1 - 1
FactoryCraft/LightSources.cpp

@@ -69,7 +69,7 @@ void BasicLightSource::onPostTick() {}
 
 BasicLightSourceBlockType::BasicLightSourceBlockType(
     int typeId, int itemTypeId, ModelInfo model, const char* name)
-    : BlockType(typeId, 0, model, 1, 1, 1, name, false),
+    : BlockType(typeId, 0, model, 1, 1, 1, name, false, color),
       itemType(itemTypeId),
       transparent(1),
       passable(1),

+ 13 - 0
FactoryCraft/NetworkMessage.cpp

@@ -123,6 +123,19 @@ void NetworkMessage::sendChatOptions(ChatObserver* zOptions)
     setMessage(msg, (int)buffer.getSize());
 }
 
+void NetworkMessage::sendMap(ChunkMap* zMap)
+{
+    delete[] address;
+    addressLength = 1;
+    address = new char[1];
+    address[0] = 6; // map data
+    InMemoryBuffer buffer;
+    zMap->writeTo(&buffer);
+    char* msg = new char[buffer.getSize()];
+    buffer.lese(msg, (int)buffer.getSize());
+    setMessage(msg, (int)buffer.getSize());
+}
+
 void NetworkMessage::setUseBackground()
 {
     useBackground = 1;

+ 2 - 0
FactoryCraft/NetworkMessage.h

@@ -11,6 +11,7 @@ class Dimension;
 
 class ChatMessage;
 class ChatObserver;
+class ChunkMap;
 
 class NetworkMessage : public virtual Framework::ReferenceCounter
 {
@@ -35,6 +36,7 @@ public:
     void setMessage(char* msg, int length);
     void sendChatMessage(ChatMessage* zMsg);
     void sendChatOptions(ChatObserver* zOptions);
+    void sendMap(ChunkMap* zMap);
     void setUseBackground();
     void sendToAll();
 

+ 1 - 1
FactoryCraft/NoBlock.cpp

@@ -1,7 +1,7 @@
 #include "NoBlock.h"
 
 NoBlockBlockType::NoBlockBlockType(int id, const Block* defaultB)
-    : BlockType(id, 0, ModelInfo("", "", 0), 0, 1, 0, "", false),
+    : BlockType(id, 0, ModelInfo("", "", 0), 0, 1, 0, "", false, 0),
       defaultB(defaultB)
 {}
 

+ 3 - 1
FactoryCraft/Start.cpp

@@ -12,6 +12,8 @@
 
 #include "Server.h"
 
+#include "ChunkMap.h"
+
 FactoryCraftServer* mserver = 0;
 
 void exit()
@@ -24,7 +26,7 @@ void exit()
 }
 
 int main()
-{
+{    
     initializeBlockTypes();
     initializeItemTypes();
     initializeEntityTypes();

+ 58 - 31
FactoryCraft/StaticInitializerOrder.cpp

@@ -15,9 +15,9 @@
 #include "ItemEntity.h"
 #include "Player.h"
 // item skills
+#include "Axe.h"
 #include "BasicItems.h"
 #include "PlayerHand.h"
-#include "Axe.h"
 // world updates
 #include "AddEntityUpdate.h"
 #include "EntityRemovedUpdate.h"
@@ -43,24 +43,28 @@ void initializeBlockTypes()
                  "blocks.ltdb/dirt.png",
                  "blocks.ltdb/lawn.png",
                  "blocks.ltdb/dirt.png"}),
-         "Dirt"))
+         "Dirt",
+         0xFF3C7C29))
         ->initializeDefault();
     (new BasicBlockType(BlockTypeEnum::STONE,
          ItemTypeEnum::STONE,
          ModelInfo("cube", "blocks.ltdb/stone.png", 6),
-         "Stone"))
+         "Stone",
+         0xFF8E8E8D))
         ->setHardness(2.f)
         ->initializeDefault();
     (new BasicBlockType(BlockTypeEnum::SAND,
          ItemTypeEnum::SAND,
          ModelInfo("cube", "blocks.ltdb/sand.png", 6),
-         "Sand"))
+         "Sand",
+         0xFFAE8558))
         ->setHardness(0.5f)
         ->initializeDefault();
     (new BasicBlockType(BlockTypeEnum::WOOD_OAK,
          ItemTypeEnum::WOOD_OAK,
          ModelInfo("cube", "blocks.ltdb/oak.png", 6),
-         "Oak Wood"))
+         "Oak Wood",
+         0xFF7F7A70))
         ->setHardness(1.5f)
         ->initializeDefault();
     (new BasicBlockType(
@@ -74,32 +78,37 @@ void initializeBlockTypes()
              block->addSpawn({1, 1, 0.015, ItemTypeEnum::SEBLING_WOOD_OAK});
              return (Block*)block;
          },
-         "Oak Wood Leaves"))
+         "Oak Wood Leaves",
+         0xFF6A7C37))
         ->setHardness(0.1f)
         ->initializeDefault();
 
     (new BasicBlockType(BlockTypeEnum::GRAVEL,
          ItemTypeEnum::GRAVEL,
          ModelInfo("cube", "blocks.ltdb/gravel.png", 6),
-         "Gravel"))
+         "Gravel",
+         0xFF928D8C))
         ->setHardness(0.75f)
         ->initializeDefault();
     (new BasicBlockType(BlockTypeEnum::STONE_GRANITE,
          ItemTypeEnum::STONE_GRANITE,
          ModelInfo("cube", "blocks.ltdb/granite.png", 6),
-         "Granite Stone"))
+         "Granite Stone",
+         0xFF3B3A3E))
         ->setHardness(3.f)
         ->initializeDefault();
     (new BasicBlockType(BlockTypeEnum::STONE_COBBLE,
          ItemTypeEnum::STONE_COBBLE,
          ModelInfo("cube", "blocks.ltdb/cobble.png", 6),
-         "Cobble Stone"))
+         "Cobble Stone",
+         0xFF7E7875))
         ->setHardness(1.f)
         ->initializeDefault();
     (new BasicBlockType(BlockTypeEnum::WOOD_BIRCH,
          ItemTypeEnum::WOOD_BIRCH,
          ModelInfo("cube", "blocks.ltdb/birch.png", 6),
-         "Birch Wood"))
+         "Birch Wood",
+         0xFF99999D))
         ->setHardness(1.5f)
         ->initializeDefault();
     (new BasicBlockType(
@@ -113,14 +122,16 @@ void initializeBlockTypes()
              block->addSpawn({1, 1, 0.03, ItemTypeEnum::SEBLING_WOOD_BIRCH});
              return (Block*)block;
          },
-         "Birch Wood Leaves"))
+         "Birch Wood Leaves",
+         0xFF6A7C37))
         ->setHardness(0.1f)
         ->initializeDefault();
 
     (new BasicBlockType(BlockTypeEnum::WOOD_BEECH,
          ItemTypeEnum::WOOD_BEECH,
          ModelInfo("cube", "blocks.ltdb/beech.png", 6),
-         "Beech Wood"))
+         "Beech Wood",
+         0xFF778172))
         ->setHardness(1.5f)
         ->initializeDefault();
     (new BasicBlockType(
@@ -134,20 +145,23 @@ void initializeBlockTypes()
              block->addSpawn({1, 1, 0.02, ItemTypeEnum::SEBLING_WOOD_BEECH});
              return (Block*)block;
          },
-         "Beech Wood Leaves"))
+         "Beech Wood Leaves",
+         0xFF6A7C37))
         ->setHardness(0.1f)
         ->initializeDefault();
 
     (new BasicBlockType(BlockTypeEnum::STONE_BASALT,
          ItemTypeEnum::STONE_BASALT,
          ModelInfo("cube", "blocks.ltdb/basalt.png", 6),
-         "Basalt Stone"))
+         "Basalt Stone",
+         0xFF595552))
         ->setHardness(2.f)
         ->initializeDefault();
     (new BasicBlockType(BlockTypeEnum::WOOD_PINE,
          ItemTypeEnum::WOOD_PINE,
          ModelInfo("cube", "blocks.ltdb/pine.png", 6),
-         "Pine Wood"))
+         "Pine Wood",
+         0xFF786C72))
         ->setHardness(1.4f)
         ->initializeDefault();
     (new BasicBlockType(
@@ -161,7 +175,8 @@ void initializeBlockTypes()
              block->addSpawn({1, 1, 0.025, ItemTypeEnum::SEBLING_WOOD_PINE});
              return (Block*)block;
          },
-         "Pine Wood Leaves"))
+         "Pine Wood Leaves",
+         0xFF6A7C37))
         ->setHardness(0.1f)
         ->initializeDefault();
 
@@ -178,7 +193,8 @@ void initializeBlockTypes()
          ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
          BlockTypeEnum::WOOD_OAK,
          BlockTypeEnum::LEAVES_WOOD_OAK,
-         "Oak Wood Sebling"))
+         "Oak Wood Sebling",
+         0xFD6A7B3A))
         ->setHardness(0.1f)
         ->initializeDefault();
     (new TreeSeblingBlockType(BlockTypeEnum::SEBLING_WOOD_BIRCH,
@@ -186,7 +202,8 @@ void initializeBlockTypes()
          ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
          BlockTypeEnum::WOOD_BIRCH,
          BlockTypeEnum::LEAVES_WOOD_BIRCH,
-         "Birch Wood Sebling"))
+         "Birch Wood Sebling",
+         0xFD6A7B3A))
         ->setHardness(0.1f)
         ->initializeDefault();
     (new TreeSeblingBlockType(BlockTypeEnum::SEBLING_WOOD_BEECH,
@@ -194,7 +211,8 @@ void initializeBlockTypes()
          ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
          BlockTypeEnum::WOOD_BEECH,
          BlockTypeEnum::LEAVES_WOOD_BEECH,
-         "Beech Wood Sebling"))
+         "Beech Wood Sebling",
+         0xFD6A7B3A))
         ->setHardness(0.1f)
         ->initializeDefault();
     (new TreeSeblingBlockType(BlockTypeEnum::SEBLING_WOOD_PINE,
@@ -202,13 +220,15 @@ void initializeBlockTypes()
          ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
          BlockTypeEnum::WOOD_PINE,
          BlockTypeEnum::LEAVES_WOOD_PINE,
-         "Pine Wood Sebling"))
+         "Pine Wood Sebling",
+         0xFD6A7B3A))
         ->setHardness(0.1f)
         ->initializeDefault();
     (new GrassBlockType(BlockTypeEnum::GRASS,
          ItemTypeEnum::GRASS,
          ModelInfo("grass", "blocks.ltdb/grass.png", 16).setTransparent(),
-         "Grass"))
+         "Grass",
+         0x5076C011))
         ->initializeDefault();
     (new BasicBlockType(BlockTypeEnum::FARMLAND,
          ItemTypeEnum::DIRT,
@@ -219,7 +239,8 @@ void initializeBlockTypes()
                  "blocks.ltdb/dirt.png",
                  "blocks.ltdb/farmland.png",
                  "blocks.ltdb/dirt.png"}),
-         "Farmland"))
+         "Farmland",
+         0xFF5E3819))
         ->setTransparent(1)
         ->setHardness(0.1f)
         ->initializeDefault();
@@ -228,7 +249,8 @@ void initializeBlockTypes()
          "WheatSeeds",
          BlockTypeEnum::WHEAT,
          "Growing wheat",
-         18000))
+         18000,
+         0x5076C011))
         ->addGrowthState(0.2f,
             ModelInfo("grass", "plants.ltdb/wheatseedsa.png", 16)
                 .setTransparent())
@@ -253,11 +275,13 @@ void initializeBlockTypes()
              block->addSpawn({0, 4, 1.0, ItemTypeEnum::WHEAT});
              return (Block*)block;
          },
-         "Wheat"))
+         "Wheat",
+         0x90A8C011))
         ->initializeDefault();
     (new FluidBlockType(BlockTypeEnum::WATER,
-        ModelInfo("fluid", "fluids.ltdb/water.png", 6),
-        "Water"))
+         ModelInfo("fluid", "fluids.ltdb/water.png", 6),
+         "Water",
+         0xFF2323BF))
         ->initializeDefault();
     (new BasicBlockType(BlockTypeEnum::CRAFTING_TABLE,
          ItemTypeEnum::CRAFTING_TABLE,
@@ -268,7 +292,8 @@ void initializeBlockTypes()
                  "blocks.ltdb/woodplanks.png",
                  "blocks.ltdb/craftingtable.p",
                  "blocks.ltdb/woodplanks.png"}),
-         "Crafting Table"))
+         "Crafting Table",
+         0xFFC4A783))
         ->initializeDefault(); // TODO: implement crafting table block type
 }
 
@@ -534,7 +559,7 @@ void initializeItemTypes()
                                && below.getA()->zBlockType()->getId()
                                       == BlockTypeEnum::FARMLAND)
                         || (below.isB()
-                               && below.getB() == BlockTypeEnum::FARMLAND);
+                            && below.getB() == BlockTypeEnum::FARMLAND);
                 }
                 return (bool)0;
             },
@@ -545,7 +570,7 @@ void initializeItemTypes()
         0,
         ModelInfo("grass", "plants.ltdb/wheat.png", 16),
         []() {
-            Item *item = ItemType::createBasicItem(ItemTypeEnum::WHEAT,
+            Item* item = ItemType::createBasicItem(ItemTypeEnum::WHEAT,
                 "Wheat",
                 1.f,
                 1.f,
@@ -559,11 +584,13 @@ void initializeItemTypes()
                 50);
             item->setFoodEffect([](Entity* zEntity) {
                 zEntity->setHunger(zEntity->getHunger() + 0.5f);
-                zEntity->setThirst(zEntity->getThirst() + 1.f); // TODO: remove thirst addition when drinkable water exists
+                zEntity->setThirst(
+                    zEntity->getThirst() + 1.f); // TODO: remove thirst addition
+                                                 // when drinkable water exists
             });
             return item;
         }));
-    
+
     (new BasicBlockItemType(ItemTypeEnum::CRAFTING_TABLE,
         "Crafting Table",
         0,

+ 3 - 2
FactoryCraft/TreeSeblingBlock.cpp

@@ -69,8 +69,9 @@ TreeSeblingBlockType::TreeSeblingBlockType(int typeId,
     ModelInfo model,
     int woodType,
     int leavesType,
-    const char* name)
-    : BlockType(typeId, 0, model, 1, 10, 0, name, false),
+    const char* name,
+    int mapColor)
+    : BlockType(typeId, 0, model, 1, 10, 0, name, false, mapColor),
       itemType(itemTypeId),
       transparent(true),
       passable(true),

+ 1 - 1
FactoryCraft/TreeSeblingBlock.h

@@ -55,6 +55,6 @@ public:
         ModelInfo model,
         int woodType,
         int leavesType,
-        const char* name);
+        const char* name, int mapColor);
     TreeSeblingBlockType* setHardness(float hardness);
 };