Prechádzať zdrojové kódy

fix issues with RandNoise on windows

Kolja Strohm 1 rok pred
rodič
commit
cd90b4d8ad

+ 5 - 1
FactoryCraft/Dimension.cpp

@@ -622,7 +622,10 @@ void Dimension::removeOldChunks()
     while (i)
     {
         if (i->isEmpty())
+        {
             i.remove();
+            continue;
+        }
         else if (i->isFullyUnloaded())
         {
             Datei d;
@@ -646,6 +649,7 @@ void Dimension::removeOldChunks()
                 ->saveStructure(i.val(), &d);
             d.close();
             i.remove();
+            continue;
         }
         i++;
     }
@@ -855,7 +859,7 @@ MultiblockStructure* Dimension::zStructureById(__int64 id)
         return str;
     }
     std::cout << "WARNING: did not find Structure information file '" << path
-              << "'.";
+              << "'.\n";
     structurCs.unlock();
     return 0;
 }

+ 9 - 2
FactoryCraft/RandNoise.cpp

@@ -7,6 +7,10 @@
 #include "FastNoiseLite.h"
 #include "FastNoiseWrapper.h"
 
+#ifndef RAND_MAX
+#    define RAND_MAX 0x7FFF
+#endif
+
 RandNoise::RandNoise(int seed)
     : Noise(),
       seed(seed)
@@ -14,7 +18,10 @@ RandNoise::RandNoise(int seed)
     srand(seed);
     table = new unsigned short[RandNoiseTableSize];
     for (int i = 0; i < RandNoiseTableSize; i++)
-        table[i] = (unsigned short)(rand() % 0xFFFF);
+    {
+        int r = rand();
+        table[i] = (unsigned short)(r % RAND_MAX);
+    }
 }
 
 RandNoise::~RandNoise()
@@ -33,5 +40,5 @@ double RandNoise::getNoise(double x, double y, double z)
     index = abs(table[index] + (int)x) % RandNoiseTableSize;
     index = abs(table[index] + (int)y) % RandNoiseTableSize;
     index = abs(table[index] + (int)z) % RandNoiseTableSize;
-    return (double)table[index] / 0xFFFF;
+    return (double)table[index] / RAND_MAX;
 }

+ 1 - 1
FactoryCraft/RandNoise.h

@@ -5,7 +5,7 @@
 
 class FastNoiseWrapper;
 
-#define RandNoiseTableSize 1024 * 512
+#define RandNoiseTableSize 1024 * 1024
 
 class RandNoise : public Noise
 {

+ 899 - 0
enc_temp_folder/2f64842f8d60b6c0f0414517e54e7942/Dimension.cpp

@@ -0,0 +1,899 @@
+#include "Dimension.h"
+
+#include "Constants.h"
+#include "Datei.h"
+#include "Game.h"
+#include "NoBlock.h"
+
+using namespace Framework;
+
+Dimension::Dimension(int id)
+    : Thread(),
+      nextStructureId(0),
+      dimensionId(id),
+      gravity(9.8f),
+      chunks(new Trie<Chunk>()),
+      entities(new RCArray<Entity>()),
+      map(new DimensionMap(id)),
+      stop(0)
+{
+    Datei d;
+    d.setDatei(
+        Game::INSTANCE->getWorldDirectory() + "/dim/" + Text(id) + "/nst.id");
+    if (d.existiert())
+    {
+        d.open(Datei::Style::lesen);
+        d.lese((char*)&nextStructureId, 8);
+        d.close();
+    }
+    start();
+}
+
+Dimension::~Dimension()
+{
+    entities->release();
+    chunks->release();
+    map->release();
+}
+
+void Dimension::api(Framework::InMemoryBuffer* zRequest,
+    NetworkMessage* zResponse,
+    Entity* zSource)
+{
+    DoLaterHandler laterHandler;
+    char type;
+    zRequest->lese(&type, 1);
+    switch (type)
+    {
+    case 0: // chunk message
+        {
+            Punkt center;
+            zRequest->lese((char*)&center.x, 4);
+            zRequest->lese((char*)&center.y, 4);
+            cs.lock();
+            Chunk* cC = zChunk(Game::getChunkCenter(center.x, center.y));
+            if (!cC)
+            {
+                // TODO: have a max amount of waiting requests per player
+                waitingRequests.add(
+                    {dynamic_cast<InMemoryBuffer*>(zRequest->getThis()),
+                        center,
+                        zSource->getId()});
+                Game::INSTANCE->requestArea({center.x - CHUNK_SIZE / 2,
+                    center.y - CHUNK_SIZE / 2,
+                    center.x + CHUNK_SIZE / 2 - 1,
+                    center.y + CHUNK_SIZE / 2 - 1,
+                    dimensionId});
+            }
+            else
+            {
+                cC->api(zRequest, zSource, laterHandler);
+            }
+            cs.unlock();
+            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);
+            }
+            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);
+            // create an empty map for a chunk that does not yet exist
+            if (!res) res = new ChunkMap(location);
+            zResponse->sendMap(res);
+            zResponse->setUseBackground();
+            res->release();
+            break;
+        }
+    }
+}
+
+void Dimension::tickEntities()
+{
+    for (auto entity : *entities)
+    {
+        if (!entity->isRemoved()
+            && (entity->isMoving()
+                || zChunk(Game::getChunkCenter((int)entity->getPosition().x,
+                    (int)entity->getPosition().y))))
+            entity->prepareTick(this);
+    }
+    int index = 0;
+    for (auto entity : *entities)
+    {
+        if (!entity->isRemoved()
+            && (entity->isMoving()
+                || zChunk(Game::getChunkCenter((int)entity->getPosition().x,
+                    (int)entity->getPosition().y))))
+            entity->tick(this);
+        index++;
+    }
+}
+
+void Dimension::thread()
+{
+    // light calculation
+    int index = 0;
+    ZeitMesser messer;
+    messer.messungStart();
+    double time = 0;
+    bool isForeground = 0;
+    Framework::Array<Framework::Vec3<int>> internalLightUpdateQueue;
+    while (!stop)
+    {
+        Vec3<int> position;
+        if (internalLightUpdateQueue.getEintragAnzahl())
+        {
+            position = internalLightUpdateQueue.get(0);
+            internalLightUpdateQueue.remove(0);
+        }
+        else
+        {
+            removedChunksCs.lock();
+            if (removedChunks.getEintragAnzahl() > 0)
+            {
+                Chunk* removedChunk = removedChunks.z(0);
+                removedChunksCs.unlock();
+                Text filePath = Game::INSTANCE->getWorldDirectory() + "/dim/"
+                              + getDimensionId() + "/";
+                filePath.appendHex(removedChunk->getCenter().x);
+                filePath += "_";
+                filePath.appendHex(removedChunk->getCenter().y);
+                filePath += ".chunk";
+                Datei d;
+                d.setDatei(filePath);
+                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);
+            }
+            removedChunksCs.unlock();
+            if (priorizedLightUpdateQueue.getEintragAnzahl())
+            {
+                prioLightCs.lock();
+                position = priorizedLightUpdateQueue.get(0);
+                priorizedLightUpdateQueue.remove(0);
+                prioLightCs.unlock();
+                isForeground = 1;
+            }
+            else
+            {
+                if (!lightUpdateQueue.getEintragAnzahl())
+                {
+                    messer.messungEnde();
+                    time += messer.getSekunden();
+                    Sleep(500);
+                    messer.messungStart();
+                    continue;
+                }
+                lightCs.lock();
+                position = lightUpdateQueue.get(0);
+                lightUpdateQueue.remove(0);
+                lightCs.unlock();
+                isForeground = 0;
+            }
+        }
+        Chunk* chunk
+            = zChunk(Game::INSTANCE->getChunkCenter(position.x, position.y));
+        if (position.z >= 0 && position.z < WORLD_HEIGHT)
+        {
+            if (chunk)
+            {
+                int x = position.x % CHUNK_SIZE;
+                int y = position.y % CHUNK_SIZE;
+                if (x < 0) x += CHUNK_SIZE;
+                if (y < 0) y += CHUNK_SIZE;
+                unsigned char* light
+                    = chunk->getLightData(Vec3<int>(x, y, position.z));
+                unsigned char dayLight[6] = {255, 255, 255, 0, 0, 0};
+                unsigned char noLight[6] = {0, 0, 0, 0, 0, 0};
+                unsigned char newLight[6] = {0, 0, 0, 0, 0, 0};
+                // add neighbor light emission
+                for (int i = 0; i < 6; i++)
+                {
+                    unsigned char* neighborLeight;
+                    Vec3<int> neighborPos
+                        = position + getDirection(getDirectionFromIndex(i));
+                    if (neighborPos.z < 0)
+                    {
+                        neighborLeight = noLight;
+                    }
+                    else if (neighborPos.z >= WORLD_HEIGHT)
+                    {
+                        neighborLeight = dayLight;
+                    }
+                    else
+                    {
+                        Chunk* neighborChunk
+                            = zChunk(Game::INSTANCE->getChunkCenter(
+                                neighborPos.x, neighborPos.y));
+                        int x = neighborPos.x % CHUNK_SIZE;
+                        int y = neighborPos.y % CHUNK_SIZE;
+                        if (x < 0) x += CHUNK_SIZE;
+                        if (y < 0) y += CHUNK_SIZE;
+                        if (neighborChunk)
+                            neighborLeight = neighborChunk->getLightData(
+                                Vec3<int>(x, y, neighborPos.z));
+                        else
+                            neighborLeight = noLight;
+                    }
+                    for (int j = 0; j < 3; j++)
+                        newLight[j] = (unsigned char)MAX(newLight[j],
+                            i == getDirectionIndex(TOP)
+                                ? neighborLeight[j]
+                                : (unsigned char)((float)neighborLeight[j]
+                                                  * 0.8f));
+                    for (int j = 3; j < 6; j++)
+                        newLight[j] = (unsigned char)MAX(newLight[j],
+                            (unsigned char)((float)neighborLeight[j] * 0.85f));
+                }
+                const Block* current = zBlockOrDefault(position);
+                // add own light emission
+                for (int j = 3; j < 6; j++)
+                    newLight[j] = (unsigned char)MAX(
+                        newLight[j], current->getLightEmisionColor()[j - 3]);
+                current->filterPassingLight(newLight);
+                current->filterPassingLight(newLight + 3);
+                for (int i = 0; i < 6; i++)
+                {
+                    if (newLight[i] != light[i])
+                    {
+                        chunk->setLightData(Vec3<int>(x, y, position.z),
+                            newLight,
+                            isForeground);
+                        for (int j = 0; j < 6; j++)
+                            internalLightUpdateQueue.add(
+                                position
+                                    + getDirection(getDirectionFromIndex(j)),
+                                0);
+                        break;
+                    }
+                }
+            }
+        }
+        index++;
+        if (index > 100000)
+        {
+            messer.messungEnde();
+            time += messer.getSekunden();
+            std::cout << "100000 light updates needed " << time << " seconds\n";
+            time = 0;
+            index = 0;
+            Sleep(250);
+            messer.messungStart();
+        }
+    }
+    std::cout << Text("Dimension ") + this->getDimensionId()
+                     + " update Thread exited.\n";
+}
+
+void Dimension::getAddrOf(Punkt cPos, char* addr) const
+{
+    *(int*)addr = cPos.x;
+    *((int*)addr + 1) = cPos.y;
+}
+
+void Dimension::getAddrOfWorld(Punkt wPos, char* addr) const
+{
+    if (wPos.x < 0) wPos.x -= CHUNK_SIZE;
+    if (wPos.y < 0) // needed because otherwise would (-8, -8) have the same
+                    // adress as (8, 8)
+        wPos.y -= CHUNK_SIZE;
+    wPos /= CHUNK_SIZE;
+    getAddrOf(wPos, addr);
+}
+
+Chunk* Dimension::zChunk(Punkt wPos) const
+{
+    char addr[8];
+    getAddrOfWorld(wPos, addr);
+    return chunks->z(addr, 8);
+}
+
+Framework::Either<Block*, int> Dimension::zBlock(Vec3<int> location)
+{
+    Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
+    if (c)
+    {
+        int x = location.x % CHUNK_SIZE;
+        int y = location.y % CHUNK_SIZE;
+        if (x < 0) x += CHUNK_SIZE;
+        if (y < 0) y += CHUNK_SIZE;
+        return c->zBlockAt(Vec3<int>(x, y, location.z));
+    }
+    return 0;
+}
+
+Block* Dimension::zRealBlockInstance(Framework::Vec3<int> location)
+{
+    Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
+    if (c)
+    {
+        int x = location.x % CHUNK_SIZE;
+        int y = location.y % CHUNK_SIZE;
+        if (x < 0) x += CHUNK_SIZE;
+        if (y < 0) y += CHUNK_SIZE;
+        c->instantiateBlock(Vec3<int>(x, y, location.z));
+        auto result = c->zBlockAt(Vec3<int>(x, y, location.z));
+        return result.isA() ? result.getA() : 0;
+    }
+    return 0;
+}
+
+const Block* Dimension::zBlockOrDefault(Framework::Vec3<int> location)
+{
+    Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
+    if (c)
+    {
+        int x = location.x % CHUNK_SIZE;
+        int y = location.y % CHUNK_SIZE;
+        if (x < 0) x += CHUNK_SIZE;
+        if (y < 0) y += CHUNK_SIZE;
+        return c->zBlockConst(Vec3<int>(x, y, location.z));
+    }
+    return &NoBlock::INSTANCE;
+}
+
+void Dimension::placeBlock(
+    Framework::Vec3<int> location, Framework::Either<Block*, int> block)
+{
+    Chunk* c = zChunk(Game::getChunkCenter(location.x, location.y));
+    if (c)
+    {
+        int x = location.x % CHUNK_SIZE;
+        int y = location.y % CHUNK_SIZE;
+        if (x < 0) x += CHUNK_SIZE;
+        if (y < 0) y += CHUNK_SIZE;
+        if (block.isA())
+            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);
+        }
+    }
+    else if (block.isA())
+        block.getA()->release();
+}
+
+void Dimension::sendBlockInfo(Framework::Vec3<int> location)
+{
+    Chunk* c = zChunk(Game::getChunkCenter(location.x, location.y));
+    if (c)
+    {
+        int x = location.x % CHUNK_SIZE;
+        int y = location.y % CHUNK_SIZE;
+        if (x < 0) x += CHUNK_SIZE;
+        if (y < 0) y += CHUNK_SIZE;
+        c->sendBlockInfo(Vec3<int>(x, y, location.z));
+    }
+}
+
+void Dimension::addEntity(Entity* entity)
+{
+    entities->add(entity);
+}
+
+void Dimension::setChunk(Chunk* chunk, Punkt center)
+{
+    char addr[8];
+    getAddrOfWorld(center, addr);
+    if (chunk) map->loadMap(addr, 8, chunk);
+    chunkCs.lock();
+    Chunk* old = chunks->get(addr, 8);
+    if (old)
+    {
+        Game::INSTANCE->zTickOrganizer()->removeTickSource(old);
+        old->prepareRemove();
+        for (int i = 0; i < chunkList.getEintragAnzahl(); i++)
+        {
+            if (chunkList.get(i) == old)
+            {
+                chunkList.remove(i);
+                break;
+            }
+        }
+    }
+    chunks->set(addr, 8, chunk);
+    if (chunk)
+    {
+        chunkList.add(chunk);
+        chunk->setAdded();
+    }
+    getAddrOfWorld(center + Punkt(CHUNK_SIZE, 0), addr);
+    Chunk* zChunk = chunks->z(addr, 8);
+    if (zChunk)
+    {
+        zChunk->setNeighbor(WEST, chunk);
+        if (chunk)
+        {
+            chunk->setNeighbor(EAST, zChunk);
+        }
+    }
+    getAddrOfWorld(center + Punkt(-CHUNK_SIZE, 0), addr);
+    zChunk = chunks->z(addr, 8);
+    if (zChunk)
+    {
+        zChunk->setNeighbor(EAST, chunk);
+        if (chunk) chunk->setNeighbor(WEST, zChunk);
+    }
+    getAddrOfWorld(center + Punkt(0, CHUNK_SIZE), addr);
+    zChunk = chunks->z(addr, 8);
+    if (zChunk)
+    {
+        zChunk->setNeighbor(NORTH, chunk);
+        if (chunk) chunk->setNeighbor(SOUTH, zChunk);
+    }
+    getAddrOfWorld(center + Punkt(0, -CHUNK_SIZE), addr);
+    zChunk = chunks->z(addr, 8);
+    if (zChunk)
+    {
+        zChunk->setNeighbor(SOUTH, chunk);
+        if (chunk) chunk->setNeighbor(NORTH, zChunk);
+    }
+    DoLaterHandler laterHandler;
+    if (chunk)
+    {
+        cs.lock();
+        int index = 0;
+        for (Iterator<RequestQueue> iterator = waitingRequests.begin();
+             iterator;)
+        {
+            Entity* zE = Game::INSTANCE->zEntity(iterator.val().sourceId);
+            if (zE)
+            {
+                if (iterator.val().chunkCenter == chunk->getCenter())
+                {
+                    chunk->api(iterator.val().request, zE, laterHandler);
+                    iterator.val().request->release();
+                    iterator.remove();
+                    continue;
+                }
+            }
+            else
+            {
+                iterator.val().request->release();
+                iterator.remove();
+                continue;
+            }
+            iterator++;
+            index++;
+        }
+        cs.unlock();
+        Game::INSTANCE->zTickOrganizer()->addTickSource(chunk);
+    }
+    chunkCs.unlock();
+    if (old)
+    {
+        old->onUnloaded();
+        removedChunksCs.lock();
+        removedChunks.add(old);
+        removedChunksCs.unlock();
+    }
+    if (chunk) chunk->onLoaded();
+    updateLightAtChunkBorders(center);
+}
+
+void Dimension::save(Text worldDir) const
+{
+    Datei d;
+    d.setDatei(Game::INSTANCE->getWorldDirectory() + "/dim/" + Text(dimensionId)
+               + "/nst.id");
+    d.erstellen();
+    d.open(Datei::Style::schreiben);
+    d.schreibe((char*)&nextStructureId, 8);
+    d.close();
+    for (auto chunk = chunkList.begin(); chunk; chunk++)
+    {
+        if (!chunk._) continue;
+        Datei* file = new Datei();
+        Text filePath = worldDir + "/dim/" + dimensionId + "/";
+        filePath.appendHex(chunk->getCenter().x);
+        filePath += "_";
+        filePath.appendHex(chunk->getCenter().y);
+        filePath += ".chunk";
+        file->setDatei(filePath);
+        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();
+    file->setDatei(filePath);
+    if (file->open(Datei::Style::schreiben))
+    {
+        for (Entity* entity : *entities)
+        {
+            if (entity->zType()->getId() != EntityTypeEnum::PLAYER)
+            {
+                if (!entity->isRemoved())
+                {
+                    int type = entity->zType()->getId();
+                    file->schreibe((char*)&type, 4);
+                    StaticRegistry<EntityType>::INSTANCE.zElement(type)
+                        ->saveEntity(entity, file);
+                }
+            }
+            else
+            {
+                Datei pFile;
+                pFile.setDatei(worldDir + "/player/"
+                               + Game::INSTANCE->getPlayerId(
+                                   ((Player*)entity)->getName()));
+                if (pFile.open(Datei::Style::schreiben))
+                    StaticRegistry<EntityType>::INSTANCE
+                        .zElement(EntityTypeEnum::PLAYER)
+                        ->saveEntity(entity, &pFile);
+            }
+        }
+        file->close();
+    }
+}
+
+int Dimension::getDimensionId() const
+{
+    return dimensionId;
+}
+
+bool Dimension::hasChunck(int x, int y)
+{
+    if (zChunk(Punkt(x, y))) return 1;
+    removedChunksCs.lock();
+    for (Chunk* c : removedChunks)
+    {
+        if (c->getCenter().x == x && c->getCenter().y == y)
+        {
+            removedChunksCs.unlock();
+            return 1;
+        }
+    }
+    removedChunksCs.unlock();
+    return 0;
+}
+
+bool Dimension::reviveChunk(int x, int y)
+{
+    chunkCs.lock();
+    if (zChunk(Punkt(x, y)))
+    {
+        chunkCs.unlock();
+        return 1;
+    }
+    removedChunksCs.lock();
+    int index = 0;
+    for (Iterator<Chunk*> i = removedChunks.begin(); i; i++)
+    {
+        if (i->getCenter().x == x && i->getCenter().y == y)
+        {
+            setChunk(dynamic_cast<Chunk*>(i->getThis()), Punkt(x, y));
+            if (index > 0) i.remove();
+            removedChunksCs.unlock();
+            chunkCs.unlock();
+            return 1;
+        }
+        index++;
+    }
+    removedChunksCs.unlock();
+    chunkCs.unlock();
+    return 0;
+}
+
+float Dimension::getGravity() const
+{
+    return gravity;
+}
+
+void Dimension::removeOldChunks()
+{
+    chunkCs.lock();
+    int index = 0;
+    for (Chunk* chunk : chunkList)
+    {
+        if (!chunk->hasObservers()) setChunk(0, chunk->getCenter());
+        index++;
+    }
+    chunkCs.unlock();
+    structurCs.lock();
+    Iterator<MultiblockStructure*> i = structures.begin();
+    while (i)
+    {
+        if (i->isEmpty())
+            i.remove();
+        else if (i->isFullyUnloaded())
+        {
+            Datei d;
+            Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
+                      + Text(dimensionId) + "/structures/";
+            path.appendHex(i->getStructureId());
+            path += ".str";
+            d.setDatei(path);
+            d.erstellen();
+            d.open(Datei::Style::schreiben);
+            auto uPos = i->getUniquePosition();
+            d.schreibe((char*)&uPos.x, 4);
+            d.schreibe((char*)&uPos.y, 4);
+            d.schreibe((char*)&uPos.z, 4);
+            int typeId = i->getStructureTypeId();
+            d.schreibe((char*)&typeId, 4);
+            __int64 strId = i->getStructureId();
+            d.schreibe((char*)&strId, 8);
+            StaticRegistry<MultiblockStructureType>::INSTANCE
+                .zElement(i->getStructureTypeId())
+                ->saveStructure(i.val(), &d);
+            d.close();
+            i.remove();
+        }
+        i++;
+    }
+    structurCs.unlock();
+}
+
+Entity* Dimension::zEntity(int id)
+{
+    for (auto entity : *entities)
+    {
+        if (!entity->isRemoved() && entity->getId() == id) return entity;
+    }
+    return 0;
+}
+
+Entity* Dimension::zNearestEntity(
+    Framework::Vec3<float> pos, std::function<bool(Entity*)> filter)
+{
+    Entity* result = 0;
+    float sqDist = 0;
+    for (auto entity : *entities)
+    {
+        if (!entity->isRemoved() && filter(entity))
+        {
+            float d = pos.abstandSq(entity->getPosition());
+            if (!result || d < sqDist)
+            {
+                result = entity;
+                sqDist = d;
+            }
+        }
+    }
+    return result;
+}
+
+void Dimension::removeEntity(int id)
+{
+    int index = 0;
+    for (auto entity : *entities)
+    {
+        if (entity->getId() == id)
+        {
+            entities->remove(index);
+            return;
+        }
+        index++;
+    }
+}
+
+void Dimension::removeSubscriptions(Entity* zEntity)
+{
+    for (Chunk* chunk : chunkList)
+        chunk->removeObserver(zEntity);
+}
+
+void Dimension::updateLightning(Vec3<int> location)
+{
+    lightCs.lock();
+    lightUpdateQueue.add(location, 0);
+    lightCs.unlock();
+}
+
+void Dimension::updateLightningWithoutWait(Framework::Vec3<int> location)
+{
+    prioLightCs.lock();
+    priorizedLightUpdateQueue.add(location, 0);
+    prioLightCs.unlock();
+}
+
+void Dimension::updateLightAtChunkBorders(Punkt chunkCenter)
+{
+    if (lightUpdateQueue.getEintragAnzahl() > 300000)
+    {
+        std::cout
+            << "warning: light calculation queue is over 300000 blocks long";
+    }
+    for (int i = WORLD_HEIGHT - 1; i >= 0; i--)
+    {
+        for (int j = 0; j < CHUNK_SIZE; j++)
+        {
+            updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 - 1,
+                chunkCenter.y - CHUNK_SIZE / 2 + j,
+                i));
+            updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2,
+                chunkCenter.y - CHUNK_SIZE / 2 + j,
+                i));
+            updateLightning(Vec3<int>(chunkCenter.x + CHUNK_SIZE / 2 - 1,
+                chunkCenter.y - CHUNK_SIZE / 2 + j,
+                i));
+            updateLightning(Vec3<int>(chunkCenter.x + CHUNK_SIZE / 2,
+                chunkCenter.y - CHUNK_SIZE / 2 + j,
+                i));
+            updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
+                chunkCenter.y - CHUNK_SIZE / 2 - 1,
+                i));
+            updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
+                chunkCenter.y - CHUNK_SIZE / 2,
+                i));
+            updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
+                chunkCenter.y + CHUNK_SIZE / 2 - 1,
+                i));
+            updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
+                chunkCenter.y + CHUNK_SIZE / 2,
+                i));
+        }
+    }
+}
+
+__int64 Dimension::getNextStructureId()
+{
+    return nextStructureId++;
+}
+
+void Dimension::addStructure(MultiblockStructure* structure)
+{
+    structurCs.lock();
+    structures.add(structure);
+    structurCs.unlock();
+}
+
+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)
+    {
+        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
+                        = StaticRegistry<MultiblockStructureType>::INSTANCE
+                              .zElement(type)
+                              ->loadStructure(
+                                  dimensionId, strId, uniquePosition, &d);
+                    d.close();
+                    structures.add(str);
+                    names->release();
+                    structurCs.unlock();
+                    return str;
+                }
+                d.close();
+            }
+        }
+        names->release();
+    }
+    structurCs.unlock();
+    return 0;
+}
+
+MultiblockStructure* Dimension::zStructureById(__int64 id)
+{
+    structurCs.lock();
+    for (MultiblockStructure* str : structures)
+    {
+        if (str->getStructureId() == id)
+        {
+            structurCs.unlock();
+            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
+            = StaticRegistry<MultiblockStructureType>::INSTANCE.zElement(type)
+                  ->loadStructure(dimensionId, strId, uPos, &d);
+        d.close();
+        structures.add(str);
+        structurCs.unlock();
+        return str;
+    }
+    std::cout << "WARNING: did not find Structure information file '" << path
+              << "'.";
+    structurCs.unlock();
+    return 0;
+}
+
+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)
+    {
+        const Block* b3 = zBlockOrDefault({x, y, h2 + 1});
+        visible = b3->isPassable() || b3->isTransparent();
+    }
+    int color1
+        = (b2->isPassable() || b2->isTransparent()) ? 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();
+}