Jelajahi Sumber

use ReadWriteLock instead of Critical

Kolja Strohm 1 bulan lalu
induk
melakukan
2cb1f0ea43

+ 66 - 39
FactoryCraft/Chunk.cpp

@@ -97,6 +97,7 @@ Chunk::~Chunk()
     {
         World::INSTANCE->zClient()->chunkAPIRequest(location, &msg, 1);
     }
+    bLock.lockWrite();
     for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
     {
         if (blocks[i])
@@ -106,33 +107,36 @@ Chunk::~Chunk()
         }
     }
     delete[] blocks;
+    bLock.unlockWrite();
 }
 
 void Chunk::appendAnimation(
     Block* zB, int boneId, double time, Vec3<float> pos, Vec3<float> rot)
 {
     if (!zB->zSkeleton() || !zB->zSkeleton()->zBone(boneId)) return;
-    acs.lock();
+    aLock.lockRead();
     for (BlockAnimation* animation : animations)
     {
         if (animation->zBlock() == zB)
         {
             animation->appendAnimation(boneId, time, pos, rot);
-            acs.unlock();
+            aLock.unlockRead();
             return;
         }
     }
+    aLock.unlockRead();
     SkeletonAnimation* sa = new SkeletonAnimation();
     Bone* bone = zB->zSkeleton()->zBone(boneId);
     sa->addAnimation(boneId, bone->getPosition(), bone->getRotation());
     sa->addKeyFrame(boneId, time, pos, rot);
+    aLock.lockWrite();
     animations.add(new BlockAnimation(dynamic_cast<Block*>(zB->getThis()), sa));
-    acs.unlock();
+    aLock.unlockWrite();
 }
 
 void Chunk::load(Framework::StreamReader* zReader)
 {
-    cs.lock();
+    bLock.lockWrite();
     for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
     {
         if (blocks[i])
@@ -141,7 +145,7 @@ void Chunk::load(Framework::StreamReader* zReader)
             blocks[i] = 0;
         }
     }
-    cs.unlock();
+    bLock.unlockWrite();
     isLoading = 1;
     Framework::Vec3<int> pos = {0, 0, 0};
     unsigned short id;
@@ -177,7 +181,6 @@ void Chunk::load(Framework::StreamReader* zReader)
         }
         if (blockTypes[id]->doesNeedInstance())
         {
-            cs.lock();
             Block* b = blockTypes[id]->createBlock(
                 {pos.x + location.x - CHUNK_SIZE / 2,
                     pos.y + location.y - CHUNK_SIZE / 2,
@@ -186,9 +189,9 @@ void Chunk::load(Framework::StreamReader* zReader)
                 speedModifier,
                 dir);
             b->setFlow(flowOptions, distanceToSource);
+            bLock.lockWrite();
             blocks[index] = b;
-            cs.unlock();
-            vcs.lock();
+            bLock.unlockWrite();
             if (b->isVisible())
             {
                 if (!blockTypes[id]->getModelInfo().getModelName().isEqual(
@@ -197,11 +200,12 @@ void Chunk::load(Framework::StreamReader* zReader)
                         "grass"))
                 {
                     b->tick(0);
+                    vLock.lockWrite();
                     visibleBlocks.add(b);
+                    vLock.unlockWrite();
                 }
             }
             count++;
-            vcs.unlock();
         }
         zReader->read((char*)&id, 2);
     }
@@ -224,40 +228,48 @@ void Chunk::load(Framework::StreamReader* zReader)
             if (x == -1)
             {
                 int cacheIndex = y * WORLD_HEIGHT + z;
+                bLock.lockRead();
                 Block* zB = blocks[cacheIndex];
                 if (zB)
                 {
                     zB->setLightData(WEST, (unsigned char*)lightData, 0);
                 }
+                bLock.unlockRead();
             }
             else if (y == -1)
             {
                 int cacheIndex = (x * CHUNK_SIZE) * WORLD_HEIGHT + z;
+                bLock.lockRead();
                 Block* zB = blocks[cacheIndex];
                 if (zB)
                 {
                     zB->setLightData(NORTH, (unsigned char*)lightData, 0);
                 }
+                bLock.unlockRead();
             }
             else if (x == CHUNK_SIZE)
             {
                 int cacheIndex
                     = ((CHUNK_SIZE - 1) * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
+                bLock.lockRead();
                 Block* zB = blocks[cacheIndex];
                 if (zB)
                 {
                     zB->setLightData(EAST, (unsigned char*)lightData, 0);
                 }
+                bLock.unlockRead();
             }
             else if (y == CHUNK_SIZE)
             {
                 int cacheIndex
                     = (x * CHUNK_SIZE + (CHUNK_SIZE - 1)) * WORLD_HEIGHT + z;
+                bLock.lockRead();
                 Block* zB = blocks[cacheIndex];
                 if (zB)
                 {
                     zB->setLightData(SOUTH, (unsigned char*)lightData, 0);
                 }
+                bLock.unlockRead();
             }
         }
         else
@@ -278,6 +290,7 @@ void Chunk::load(Framework::StreamReader* zReader)
                         int cacheIndex
                             = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT
                             + pos.z;
+                        bLock.lockRead();
                         Block* zB = blocks[cacheIndex];
                         if (zB)
                         {
@@ -288,19 +301,22 @@ void Chunk::load(Framework::StreamReader* zReader)
                                 0);
                             if (zB->isVisible() && !visible)
                             {
-                                vcs.lock();
                                 zB->tick(0);
+                                vLock.lockWrite();
                                 visibleBlocks.add(zB);
-                                vcs.unlock();
+                                vLock.unlockWrite();
                             }
                         }
+                        bLock.unlockRead();
                     }
                     else
                     {
                         pos.x += this->location.x - CHUNK_SIZE / 2;
                         pos.y += this->location.y - CHUNK_SIZE / 2;
+                        World::INSTANCE->getChunkReadLock().lock();
                         Chunk* c = World::INSTANCE->zChunk(
                             World::INSTANCE->getChunkCenter(pos.x, pos.y));
+                        c->getBlockReadLock().lock();
                         Block* zB = c ? c->zBlockAt(pos) : 0;
                         if (zB)
                         {
@@ -311,12 +327,14 @@ void Chunk::load(Framework::StreamReader* zReader)
                                 c);
                             if (zB->isVisible() && !visible)
                             {
-                                c->vcs.lock();
                                 zB->tick(0);
+                                vLock.lockWrite();
                                 c->visibleBlocks.add(zB);
-                                c->vcs.unlock();
+                                vLock.unlockWrite();
                             }
                         }
+                        c->getBlockReadLock().unlock();
+                        World::INSTANCE->getChunkReadLock().unlock();
                     }
                 }
             }
@@ -328,24 +346,19 @@ void Chunk::load(Framework::StreamReader* zReader)
 
 void Chunk::buildModel(ChunkModelBuilder* builder)
 {
-    vcs.lock();
     modelChanged &= ~builder->getType();
     lightChanged &= ~builder->getType();
     builder->buildModel();
-    vcs.unlock();
 }
 
 void Chunk::updateLight(ChunkModelBuilder* builder)
 {
-    vcs.lock();
     lightChanged &= ~builder->getType();
     builder->updateLightning();
-    vcs.unlock();
 }
 
 void Chunk::renderSolid(std::function<void(Model3D*)> f)
 {
-    vcs.lock();
     CustomDX11API* api
         = (CustomDX11API*)uiFactory.initParam.bildschirm->zGraphicsApi();
     api->setCullBack(false);
@@ -358,11 +371,12 @@ void Chunk::renderSolid(std::function<void(Model3D*)> f)
     }
     api->setCullBack(true);
     float dist = 0.f;
+    vLock.lockRead();
     for (Block* b : visibleBlocks)
     {
         f(b);
     }
-    vcs.unlock();
+    vLock.unlockRead();
 }
 
 void Chunk::renderTransparent(std::function<void(Model3D*)> f)
@@ -382,8 +396,6 @@ void Chunk::renderTransparent(std::function<void(Model3D*)> f)
 
 bool Chunk::tick(std::function<void(Model3D*)> f, double time)
 {
-    acs.lock();
-    vcs.lock(); // TODO: enshure no dead lock occures
     for (ChunkModelBuilder* builder : modelBuilders)
     {
         if ((modelChanged | builder->getType()) == modelChanged)
@@ -399,6 +411,7 @@ bool Chunk::tick(std::function<void(Model3D*)> f, double time)
     {
         res |= builder->zModel()->tick(time);
     }
+    aLock.lockRead();
     auto iterator = animations.begin();
     while (iterator)
     {
@@ -407,19 +420,22 @@ bool Chunk::tick(std::function<void(Model3D*)> f, double time)
             res |= iterator->zBlock()->tick(time);
             if (iterator->isFinished())
             {
+                aLock.lockWrite();
                 iterator.remove();
+                aLock.unlockWrite();
                 continue;
             }
         }
         else
         {
+            aLock.lockWrite();
             iterator.remove();
+            aLock.unlockWrite();
             continue;
         }
         ++iterator;
     }
-    vcs.unlock();
-    acs.unlock();
+    aLock.unlockRead();
     return 1;
 }
 
@@ -481,8 +497,10 @@ void Chunk::api(char* message)
             }
             else
             {
+                bLock.lockRead();
                 Block* zB = zBlockAt(location);
                 if (zB) removeBlock(zB);
+                bLock.unlockRead();
             }
             break;
         }
@@ -504,8 +522,10 @@ void Chunk::api(char* message)
                 index % WORLD_HEIGHT);
             location.x += this->location.x - CHUNK_SIZE / 2;
             location.y += this->location.y - CHUNK_SIZE / 2;
+            bLock.lockRead();
             Block* zB = zBlockAt(location);
             if (zB) appendAnimation(zB, boneId, time, pos, rot);
+            bLock.unlockRead();
             break;
         }
     }
@@ -525,7 +545,6 @@ Block* Chunk::zBlockAt(Framework::Vec3<int> location)
 
 void Chunk::setBlock(Block* block)
 {
-    cs.lock();
     Framework::Vec3<int> pos = block->getLocation();
     pos.x = pos.x % CHUNK_SIZE;
     pos.y = pos.y % CHUNK_SIZE;
@@ -534,6 +553,7 @@ void Chunk::setBlock(Block* block)
     int index = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z;
     int affectsGround = 0;
     int newAffectsGround = 0;
+    bLock.lockWrite();
     for (ChunkModelBuilder* builder : modelBuilders)
     {
         if (block && builder->isPartOfModel(block))
@@ -547,7 +567,7 @@ void Chunk::setBlock(Block* block)
     }
     if (blocks[index])
     {
-        vcs.lock();
+        vLock.lockWrite();
         for (Framework::ArrayIterator<Block*> vi = visibleBlocks.begin(); vi;
             vi++)
         {
@@ -557,37 +577,36 @@ void Chunk::setBlock(Block* block)
                 break;
             }
         }
-        vcs.unlock();
+        vLock.unlockWrite();
         blocks[index]->copyLightTo(block);
         blocks[index]->release();
         blocks[index] = block;
-        cs.unlock();
-        vcs.lock();
+        bLock.unlockWrite();
         modelChanged |= affectsGround | newAffectsGround;
         if (block && block->isVisible() && !newAffectsGround)
         {
             block->tick(0);
+            vLock.lockWrite();
             visibleBlocks.add(block);
+            vLock.unlockWrite();
         }
-        vcs.unlock();
         return;
     }
     blocks[index] = block;
-    cs.unlock();
-    vcs.lock();
+    bLock.unlockWrite();
     modelChanged |= affectsGround | newAffectsGround;
     if (block && block->isVisible() && !newAffectsGround)
     {
         block->tick(0);
+        vLock.lockWrite();
         visibleBlocks.add(block);
+        vLock.unlockWrite();
     }
-    vcs.unlock();
 }
 
 void Chunk::removeBlock(Block* zBlock)
 {
-    cs.lock();
-    vcs.lock();
+    vLock.lockWrite();
     for (Framework::ArrayIterator<Block*> iterator = visibleBlocks.begin();
         iterator;
         iterator++)
@@ -598,32 +617,35 @@ void Chunk::removeBlock(Block* zBlock)
             break;
         }
     }
-    vcs.unlock();
+    vLock.unlockWrite();
     Vec3<int> pos = zBlock->getLocation();
     pos.x = pos.x % CHUNK_SIZE;
     pos.y = pos.y % CHUNK_SIZE;
     if (pos.x < 0) pos.x += CHUNK_SIZE;
     if (pos.y < 0) pos.y += CHUNK_SIZE;
     int index = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z;
+    bLock.lockWrite();
     if (blocks[index])
     {
         modelChanged |= blocks[index]->getPartOfModels();
         blocks[index]->release();
         blocks[index] = 0;
     }
-    cs.unlock();
+    bLock.unlockWrite();
 }
 
 void Chunk::blockVisibilityChanged(Block* zB)
 {
-    vcs.lock();
     if (zB->isVisible())
     {
         zB->tick(0);
+        vLock.lockWrite();
         visibleBlocks.add(zB);
+        vLock.unlockWrite();
     }
     else
     {
+        vLock.lockWrite();
         for (Framework::ArrayIterator<Block*> iterator = visibleBlocks.begin();
             iterator;
             iterator++)
@@ -634,8 +656,8 @@ void Chunk::blockVisibilityChanged(Block* zB)
                 break;
             }
         }
+        vLock.unlockWrite();
     }
-    vcs.unlock();
 }
 
 Framework::Point Chunk::getCenter() const
@@ -662,4 +684,9 @@ void Chunk::setModelChanged(int type)
 void Chunk::setLightChanged(int type)
 {
     lightChanged |= type;
-}
+}
+
+Lock& Chunk::getBlockReadLock() const
+{
+    return bLock.getReadLock();
+}

+ 14 - 13
FactoryCraft/Chunk.h

@@ -10,20 +10,20 @@
 #include "Area.h"
 #include "Block.h"
 #include "BlockAnimation.h"
+#include "ChunkModelBuilder.h"
 #include "Constants.h"
 #include "FactoryCraftModel.h"
-#include "ChunkModelBuilder.h"
 
 class Chunk : public Framework::ReferenceCounter
 {
 public:
-class CombinedModels
-{
-public:
-    static const int GROUND = 1;
-    static const int FLUID = 2;
-    static const int TRANSPARENT_GROUND = 4;
-};
+    class CombinedModels
+    {
+    public:
+        static const int GROUND = 1;
+        static const int FLUID = 2;
+        static const int TRANSPARENT_GROUND = 4;
+    };
 
 private:
     Framework::Point location;
@@ -32,9 +32,9 @@ private:
     Framework::Array<Block*> visibleBlocks;
     Framework::RCArray<ChunkModelBuilder> modelBuilders;
     bool isLoading;
-    Framework::Critical cs;
-    Framework::Critical vcs;
-    Framework::Critical acs;
+    Framework::ReadWriteLock bLock;
+    Framework::ReadWriteLock vLock;
+    Framework::ReadWriteLock aLock;
     Framework::RCArray<BlockAnimation> animations;
     int lightChanged;
     int modelChanged;
@@ -42,8 +42,8 @@ private:
     void appendAnimation(
         Block* zB, int boneId, double time, Vec3<float> pos, Vec3<float> rot);
     void load(Framework::StreamReader* zReader);
-    void buildModel(ChunkModelBuilder *builder);
-    void updateLight(ChunkModelBuilder *builder);
+    void buildModel(ChunkModelBuilder* builder);
+    void updateLight(ChunkModelBuilder* builder);
 
 public:
     Chunk(Framework::Point location);
@@ -65,6 +65,7 @@ public:
     Framework::Vec3<int> getMax() const;
     void setModelChanged(int modelType);
     void setLightChanged(int modelType);
+    Lock& getBlockReadLock() const;
 
     inline static int index(Framework::Vec3<int> localLocation)
     {

+ 36 - 36
FactoryCraft/Dimension.cpp

@@ -77,19 +77,19 @@ void Dimension::api(char* message)
         {
             int cX = *(int*)(message + 1);
             int cY = *(int*)(message + 5);
-            cs.lock();
+            lock.lockRead();
             Chunk* ch = zChunk(Point(cX, cY));
             if (ch) ch->api(message + 9);
-            cs.unlock();
+            lock.unlockRead();
             break;
         }
     case 2: // entity
         {
             int eId = *(int*)(message + 1);
-            cs.lock();
+            lock.lockRead();
             Entity* e = zEntity(eId);
             if (e) e->api(message + 5);
-            cs.unlock();
+            lock.unlockRead();
             break;
         }
     case 3: // block
@@ -97,10 +97,10 @@ void Dimension::api(char* message)
             int px = *(int*)(message + 1);
             int py = *(int*)(message + 5);
             int pz = *(int*)(message + 9);
-            cs.lock();
+            lock.lockRead();
             Block* b = zBlock(Framework::Vec3<int>(px, py, pz));
             if (b) b->api(message + 13);
-            cs.unlock();
+            lock.unlockRead();
             break;
         }
     case 4: // add new chunck
@@ -113,15 +113,11 @@ void Dimension::api(char* message)
                       << "\n";
             Timer zm;
             zm.measureStart();
-            World::INSTANCE->lockWorld();
             Chunk* chunk = new Chunk(center, &reader);
             zm.measureEnd();
             std::cout << "chunk loading took " << zm.getSekunden()
                       << " seconds\n";
-            cs.lock();
             setChunk(chunk, center);
-            cs.unlock();
-            World::INSTANCE->unlockWorld();
             World::INSTANCE->onChunkAdded(center);
             World::INSTANCE->zClient()->chunkAPIRequest(center, "\2", 1);
             break;
@@ -138,7 +134,7 @@ void Dimension::api(char* message)
                     = location + getDirection(getDirectionFromIndex(i));
                 if (pos.z >= 0 && pos.z < WORLD_HEIGHT)
                 {
-                    cs.lock();
+                    lock.lockRead();
                     Chunk* c
                         = zChunk(World::INSTANCE->getChunkCenter(pos.x, pos.y));
                     Block* zB = c ? c->zBlockAt(pos) : 0;
@@ -156,7 +152,7 @@ void Dimension::api(char* message)
                                 ->blockVisibilityChanged(zB);
                         }
                     }
-                    cs.unlock();
+                    lock.unlockRead();
                 }
             }
             break;
@@ -194,16 +190,16 @@ Block* Dimension::zBlock(Vec3<int> location)
 
 Block* Dimension::getBlock(Vec3<int> location)
 {
-    cs.lock();
+    lock.lockRead();
     Chunk* c = zChunk(World::INSTANCE->getChunkCenter(location.x, location.y));
     if (c)
     {
         Block* b = c->zBlockAt(location);
         b = b ? dynamic_cast<Block*>(b->getThis()) : 0;
-        cs.unlock();
+        lock.unlockRead();
         return b;
     }
-    cs.unlock();
+    lock.unlockRead();
     return 0;
 }
 
@@ -217,8 +213,8 @@ void Dimension::setChunk(Chunk* chunk, Point center)
 {
     char addr[8];
     getAddrOfWorld(center, addr);
+    lock.lockWrite();
     Chunk* old = chunks->z(addr, 8);
-    cs.lock();
     if (old)
     {
         int index = 0;
@@ -237,7 +233,7 @@ void Dimension::setChunk(Chunk* chunk, Point center)
     else if (chunk)
         chunkList.add(chunk);
     chunks->set(addr, 8, chunk);
-    cs.unlock();
+    lock.unlockWrite();
 }
 
 bool Dimension::hasChunck(int x, int y) const
@@ -249,6 +245,7 @@ void Dimension::removeDistantChunks(Point wPos)
 {
     Array<int> removed;
     int index = 0;
+    lock.lockRead();
     for (Chunk* chunk : chunkList)
     {
         if (abs(chunk->getCenter().x - wPos.x) > MAX_VIEW_DISTANCE + CHUNK_SIZE
@@ -257,72 +254,72 @@ void Dimension::removeDistantChunks(Point wPos)
             removed.add(index, 0);
         index++;
     }
+    lock.unlockRead();
     for (int i : removed)
     {
-        cs.lock();
+        lock.lockWrite();
         Chunk* chunk = chunkList.get(i);
         chunk->destroy();
         setChunk(0, chunk->getCenter());
-        cs.unlock();
+        lock.unlockWrite();
     }
 }
 
 void Dimension::setBlock(Block* block)
 {
-    cs.lock();
+    lock.lockWrite();
     Chunk* c = zChunk(World::INSTANCE->getChunkCenter(
         (int)floor(block->getPos().x), (int)floor(block->getPos().y)));
     if (c)
         c->setBlock(block);
     else
         block->release();
-    cs.unlock();
+    lock.unlockWrite();
 }
 
 void Dimension::removeBlock(Block* zBlock)
 {
-    cs.lock();
+    lock.lockWrite();
     Chunk* c = zChunk(World::INSTANCE->getChunkCenter(
         (int)floor(zBlock->getPos().x), (int)floor(zBlock->getPos().y)));
     if (c) c->removeBlock(zBlock);
-    cs.unlock();
+    lock.unlockWrite();
 }
 
 Entity* Dimension::zEntity(int id)
 {
-    cs.lock();
+    lock.lockRead();
     for (Entity* e : *entities)
     {
         if (e->getId() == id)
         {
-            cs.unlock();
+            lock.unlockRead();
             return e;
         }
     }
-    cs.unlock();
+    lock.unlockRead();
     return 0;
 }
 
 Entity* Dimension::getEntity(int id)
 {
-    cs.lock();
+    lock.lockRead();
     for (Entity* e : *entities)
     {
         if (e->getId() == id)
         {
             Entity* result = dynamic_cast<Entity*>(e->getThis());
-            cs.unlock();
+            lock.unlockRead();
             return result;
         }
     }
-    cs.unlock();
+    lock.unlockRead();
     return 0;
 }
 
 void Dimension::removeEntity(int id)
 {
-    World::INSTANCE->lockWorld();
-    cs.lock();
+    lock.lockWrite();
     int index = 0;
     for (Entity* e : *entities)
     {
@@ -330,17 +327,20 @@ void Dimension::removeEntity(int id)
         {
             World::INSTANCE->setVisibility(e, 0);
             entities->remove(index);
-            cs.unlock();
-            World::INSTANCE->unlockWorld();
+            lock.unlockWrite();
             return;
         }
         index++;
     }
-    cs.unlock();
-    World::INSTANCE->unlockWorld();
+    lock.unlockWrite();
 }
 
 int Dimension::getId() const
 {
     return id;
-}
+}
+
+Lock& Dimension::getReadLock() const
+{
+    return lock.getReadLock();
+}

+ 2 - 1
FactoryCraft/Dimension.h

@@ -16,7 +16,7 @@ private:
     Framework::RCTrie<Chunk>* chunks;
     Framework::Array<Chunk*> chunkList;
     Framework::RCArray<Entity>* entities;
-    Framework::Critical cs;
+    Framework::ReadWriteLock lock;
     void getAddrOf(Framework::Point cPos, char* addr) const;
     void getAddrOfWorld(Framework::Point wPos, char* addr) const;
 
@@ -43,6 +43,7 @@ public:
     Entity* getEntity(int id);
     void removeEntity(int id);
     int getId() const;
+    Lock& getReadLock() const;
 
     inline static Framework::Vec3<int> chunkCoordinates(
         Framework::Vec3<int> worldLocation)

+ 19 - 15
FactoryCraft/DimensionMap.cpp

@@ -145,7 +145,7 @@ void DimensionMap::updatePlayers(char* data)
 {
     int count = *(int*)data;
     data += 4;
-    cs.lock();
+    writeLock().lock();
     players.clear();
     // read player information from data buffer
     for (int i = 0; i < count; i++)
@@ -165,20 +165,22 @@ void DimensionMap::updatePlayers(char* data)
         data += 12;
         players.add(player);
     }
-    cs.unlock();
+    writeLock().unlock();
 }
 
 void DimensionMap::requestNextChunk()
 {
-    cs.lock();
+    readLock().lock();
     if (requestCount >= 20)
     {
-        cs.unlock();
+        readLock().unlock();
         return;
     }
     if (chunkCount == 0)
     {
+        writeLock().lock();
         requestCount++;
+        writeLock().unlock();
         Vec3<float> playerPos
             = World::INSTANCE->getCurrentPlayerEntity()->getPos();
         char msg[10];
@@ -202,10 +204,10 @@ void DimensionMap::requestNextChunk()
             Point resultChunk(0, 0);
             char addr[8];
             for (int x = minVisibleChunk.x; x <= maxVisibleChunk.x;
-                 x += CHUNK_SIZE)
+                x += CHUNK_SIZE)
             {
                 for (int y = minVisibleChunk.y; y <= maxVisibleChunk.y;
-                     y += CHUNK_SIZE)
+                    y += CHUNK_SIZE)
                 {
                     getAddrOfWorld({x, y}, addr);
                     if (!chunks->z(addr, 8))
@@ -233,7 +235,9 @@ void DimensionMap::requestNextChunk()
                 *(int*)(msg + 6) = (int)resultChunk.y;
                 World::INSTANCE->zClient()->dimensionAPIRequest(msg, 10);
                 getAddrOfWorld({resultChunk.x, resultChunk.y}, addr);
+                writeLock().lock();
                 chunks->set(addr, 8, new ChunkMap(resultChunk));
+                writeLock().unlock();
             }
             else
             {
@@ -241,12 +245,12 @@ void DimensionMap::requestNextChunk()
             }
         }
     }
-    cs.unlock();
+    readLock().unlock();
 }
 
 void DimensionMap::addChunk(ChunkMap* chunk)
 {
-    cs.lock();
+    writeLock().lock();
     if (chunkCount == 0) originChunkCenter = chunk->getChunkCenter();
     char addr[8];
     getAddrOfWorld(chunk->getChunkCenter(), addr);
@@ -257,7 +261,7 @@ void DimensionMap::addChunk(ChunkMap* chunk)
     chunkCount++;
     requestCount--;
     removeUnused();
-    cs.unlock();
+    writeLock().unlock();
     requestNextChunk();
 }
 
@@ -287,7 +291,7 @@ void DimensionMap::render(Framework::Image& rObj)
 {
     DrawableBackground::render(rObj);
     if (!rObj.setDrawOptions(innenPosition, innenSize)) return;
-    cs.lock();
+    readLock().lock();
     if (zOptions->isFollowPlayer())
     {
         Vec3<float> playerPos
@@ -374,8 +378,8 @@ void DimensionMap::render(Framework::Image& rObj)
                                 > heightMap[yy * CHUNK_SIZE + xx + 1])
                             {
                                 rObj.drawLineVAlpha((xx * pixelsPerBlock)
-                                                         + topLeft.x
-                                                         + pixelsPerBlock,
+                                                        + topLeft.x
+                                                        + pixelsPerBlock,
                                     (yy * pixelsPerBlock) + topLeft.y,
                                     pixelsPerBlock,
                                     0x40000000);
@@ -388,8 +392,8 @@ void DimensionMap::render(Framework::Image& rObj)
                                 > heightMapRight[yy * CHUNK_SIZE])
                             {
                                 rObj.drawLineVAlpha((xx * pixelsPerBlock)
-                                                         + topLeft.x
-                                                         + pixelsPerBlock,
+                                                        + topLeft.x
+                                                        + pixelsPerBlock,
                                     (yy * pixelsPerBlock) + topLeft.y,
                                     pixelsPerBlock,
                                     0x40000000);
@@ -523,7 +527,7 @@ void DimensionMap::render(Framework::Image& rObj)
                 screenPos.x, screenPos.y, player.name, rObj, 0xFFFFFFFF);
         }
     }
-    cs.unlock();
+    readLock().unlock();
     rObj.releaseDrawOptions();
 }
 

+ 10 - 16
FactoryCraft/Entity.cpp

@@ -40,10 +40,10 @@ void Entity::api(char* message)
             frame.position.z = *(float*)(message += 4);
             frame.rotation = *(float*)(message += 4);
             frame.duration = *(float*)(message += 4);
-            cs.lock();
+            framesLock.lockWrite();
             frameLength += frame.duration;
             frames.add(frame);
-            cs.unlock();
+            framesLock.unlockWrite();
             break;
         }
     }
@@ -56,8 +56,10 @@ bool Entity::tick(double time)
     {
         totalTime *= 1.5f;
     }
-    cs.lock();
+    framesLock.lockWrite();
     frameLength -= totalTime;
+    framesLock.unlockWrite();
+    framesLock.lockRead();
     if (frameLength < 0.f)
     {
         frameLength = 0.f;
@@ -69,7 +71,9 @@ bool Entity::tick(double time)
             if (frames.getEntryCount() > 0)
             {
                 currentFrame = frames.get(0);
+                framesLock.lockWrite();
                 frames.remove(0);
+                framesLock.unlockWrite();
             }
             else
             {
@@ -87,8 +91,8 @@ bool Entity::tick(double time)
             setRotationZ(getZRotation() + 2.f * (float)PI);
         }
         setRotationZ(getZRotation()
-                    + (currentFrame.rotation - getZRotation())
-                          * (t / currentFrame.duration));
+                     + (currentFrame.rotation - getZRotation())
+                           * (t / currentFrame.duration));
         currentFrame.duration -= t;
         totalTime -= t;
         if (currentFrame.duration <= 0)
@@ -98,7 +102,7 @@ bool Entity::tick(double time)
         }
         rend = 1;
     }
-    cs.unlock();
+    framesLock.unlockRead();
     if (playerControlled)
     {
         World::INSTANCE->zKamera()->setPosition(
@@ -123,16 +127,6 @@ const EntityType* Entity::zEntityType() const
     return zType;
 }
 
-void Entity::lock()
-{
-    cs.lock();
-}
-
-void Entity::unlock()
-{
-    cs.unlock();
-}
-
 void Entity::setPlayerControlled()
 {
     playerControlled = 1;

+ 1 - 3
FactoryCraft/Entity.h

@@ -23,7 +23,7 @@ private:
     int id;
     const EntityType* zType;
     bool playerControlled;
-    Framework::Critical cs;
+    Framework::ReadWriteLock framesLock;
     MovementFrame currentFrame;
     Framework::Array<MovementFrame> frames;
     double frameLength;
@@ -42,7 +42,5 @@ public:
 
     int getId() const;
     const EntityType* zEntityType() const;
-    void lock();
-    void unlock();
     void setPlayerControlled();
 };

+ 17 - 2
FactoryCraft/FactoryClient.cpp

@@ -742,7 +742,7 @@ void FactoryClient::loadServerInfo()
         mdl->setSize(itemTypes[i]->getSize());
         w->addDrawable(mdl);
         w->tick(0);
-        window->zScreen()->lock();
+        window->zScreen()->writeLock().lock();
         DX11Texture* t = (DX11Texture*)window->zScreen()
                              ->zGraphicsApi()
                              ->createOrGetTexture(Text("rendered/items/")
@@ -753,7 +753,7 @@ void FactoryClient::loadServerInfo()
         t->copyToImage(result);
         itemTypes[i]->setBild(result);
         t->release();
-        window->zScreen()->unlock();
+        window->zScreen()->writeLock().unlock();
         w->removeDrawable(mdl);
         loadMenu->stageProgress(1);
     }
@@ -1191,6 +1191,21 @@ void FactoryClient::chatAPIRequest(const char* data, unsigned short length)
     cs.unlock();
 }
 
+void FactoryClient::giveItemRequest(int itemTypeId, bool fullStack)
+{
+    if (!foreground) return;
+    cs.lock();
+    short length = 7;
+    foreground->send((char*)&length, 2);
+    char msgId = 2; // player message
+    foreground->send(&msgId, 1);
+    msgId = 11;
+    foreground->send(&msgId, 1); // give items
+    foreground->send((char*)&itemTypeId, 4);
+    foreground->send((char*)&fullStack, 1);
+    cs.unlock();
+}
+
 bool FactoryClient::isConnected()
 {
     return foreground && background && foreground->isConnected()

+ 1 - 0
FactoryCraft/FactoryClient.h

@@ -64,6 +64,7 @@ public:
     void craftingUIMLRequest(int itemTypeId);
     void sendChatMessage(Framework::Text message);
     void chatAPIRequest(const char* data, unsigned short length);
+    void giveItemRequest(int itemTypeId, bool fullStack);
     bool isConnected();
     void leaveGame();
 };

+ 3 - 9
FactoryCraft/FactoryCraftModel.cpp

@@ -50,6 +50,7 @@ void FactoryCraftModel::beforeRender(Framework::GraphicsApi* api,
             buffer, cApi->getVertexShaderLightBufferIndex(), 8);
         if (vertexLightBuffer)
         {
+            vertexLightBuffer->copyToGPU();
             cApi->setVertexLightBuffer(vertexLightBuffer);
         }
         else
@@ -100,24 +101,17 @@ void FactoryCraftModel::setVertexLightBuffer(__int64* data, int vertexCount)
     vertexLightBufferCount = vertexCount;
     vertexLightBuffer->setData(data);
     vertexLightBuffer->setLength(vertexCount * 8);
-    vertexLightBuffer->copyToGPU();
+    vertexLightBuffer->setChanged();
 }
 
 __int64* FactoryCraftModel::zLightBuffer()
 {
-    if (vertexLightBuffer)
-    {
-        vertexLightBuffer->setChanged();
-    }
     return lightBuffer;
 }
 
 void FactoryCraftModel::copyLightToGPU()
 {
-    if (vertexLightBuffer)
-    {
-        vertexLightBuffer->copyToGPU();
-    }
+    vertexLightBuffer->setChanged();
 }
 
 void FactoryCraftModel::setVisible(bool visible)

+ 12 - 16
FactoryCraft/Game.cpp

@@ -151,7 +151,7 @@ void Game::api(char* data)
             char* dialogName = new char[len + 1];
             memcpy(dialogName, data + 3, len);
             dialogName[len] = 0;
-            dialogCs.lock();
+            dialogLock.lockRead();
             for (UIMLDialog* dialog : dialogs)
             {
                 if (dialog->getName().isEqual(dialogName))
@@ -160,7 +160,7 @@ void Game::api(char* data)
                     break;
                 }
             }
-            dialogCs.unlock();
+            dialogLock.unlockRead();
             delete[] dialogName;
             if (!exists)
             {
@@ -172,7 +172,7 @@ void Game::api(char* data)
                     = new UIMLDialog(uiml, [this](UIMLDialog* dialog) {
                           window->zScreen()->postAction([this, dialog]() {
                               int index = 0;
-                              dialogCs.lock();
+                              dialogLock.lockWrite();
                               for (UIMLDialog* d : dialogs)
                               {
                                   if (d == dialog)
@@ -187,12 +187,12 @@ void Game::api(char* data)
                                   }
                                   index++;
                               }
-                              dialogCs.unlock();
+                              dialogLock.unlockWrite();
                           });
                       });
-                dialogCs.lock();
+                dialogLock.lockWrite();
                 dialogs.add(dialog);
-                dialogCs.unlock();
+                dialogLock.unlockWrite();
                 updateRecipieVisibility();
                 World::INSTANCE->zKamera()->setControlEnabled(0);
                 window->zScreen()->addMember(dialog);
@@ -202,14 +202,12 @@ void Game::api(char* data)
         }
     case 1:
         { // element message
-            uiFactory.initParam.bildschirm->lock();
-            dialogCs.lock();
+            dialogLock.lockRead();
             for (UIMLDialog* dialog : dialogs)
             {
                 dialog->api(data + 1);
             }
-            dialogCs.unlock();
-            uiFactory.initParam.bildschirm->unlock();
+            dialogLock.unlockRead();
             short idLen = *(short*)(data + 1);
             char* id = new char[idLen + 1];
             memcpy(id, data + 3, idLen);
@@ -241,7 +239,7 @@ void Game::api(char* data)
             char* dialogName = new char[dialogNameLen + 1];
             memcpy(dialogName, data + 3, dialogNameLen);
             dialogName[dialogNameLen] = 0;
-            dialogCs.lock();
+            dialogLock.lockRead();
             for (UIMLDialog* dialog : dialogs)
             {
                 if (dialog->getName().isEqual(dialogName))
@@ -255,20 +253,20 @@ void Game::api(char* data)
                     break;
                 }
             }
-            dialogCs.unlock();
+            dialogLock.unlockRead();
         }
     }
 }
 
 void Game::closeCurrentDialog()
 {
-    dialogCs.lock();
+    dialogLock.lockRead();
     if (dialogs.getEntryCount() > 0)
     {
         UIMLDialog* d = dialogs.get(dialogs.getEntryCount() - 1);
         d->close();
     }
-    dialogCs.unlock();
+    dialogLock.unlockRead();
 }
 
 DragController<InventoryDragSource, int>* Game::zInventoryDragController()
@@ -280,10 +278,8 @@ void Game::setTargetUIML(Framework::Text uiml)
 {
     if (uiml.getLength())
     {
-        window->zScreen()->lock();
         targetUIMLView->setUIML(uiml);
         targetUIMLView->layout();
-        window->zScreen()->unlock();
         targetUIMLView->setSize(targetUIMLView->calculateContentSize());
         targetUIMLView->setPosition(
             window->zScreen()->zGraphicsApi()->getBackBufferSize()

+ 2 - 2
FactoryCraft/Game.h

@@ -1,7 +1,7 @@
 #pragma once
 
-#include <Image.h>
 #include <Button.h>
+#include <Image.h>
 
 #include "Chat.h"
 #include "Dialog.h"
@@ -29,7 +29,7 @@ private:
     MapWindow* mapWindow;
     Chat* chat;
     bool recipieVisible;
-    Critical dialogCs;
+    ReadWriteLock dialogLock;
 
 public:
     // Konstruktor

+ 18 - 0
FactoryCraft/ItemList.cpp

@@ -8,6 +8,7 @@
 #include "Globals.h"
 #include "UIMLToolTip.h"
 #include "World.h"
+#include <Globals.h>
 
 ItemList::ItemList()
     : DrawableBackground(),
@@ -91,6 +92,23 @@ void ItemList::doMouseEvent(Framework::MouseEvent& me, bool userRet)
                 itemTypes[pos]->getId());
         }
     }
+    else if (me.id == ME_RMiddle)
+    {
+        int pos = getSlotByLocalPos(Point(me.mx, me.my));
+        if (pos >= 0)
+        {
+            if (Framework::getKeyState(T_Shift))
+            {
+                World::INSTANCE->zClient()->giveItemRequest(
+                    itemTypes[pos]->getId(), 1);
+            }
+            else
+            {
+                World::INSTANCE->zClient()->giveItemRequest(
+                    itemTypes[pos]->getId(), 0);
+            }
+        }
+    }
     DrawableBackground::doMouseEvent(me, userRet);
 }
 

+ 23 - 6
FactoryCraft/Main.cpp

@@ -1,15 +1,15 @@
-#include <Screen.h>
 #include <File.h>
 #include <FileSystem.h>
-#include <Window.h>
+#include <Font.h>
 #include <GraphicsApi.h>
 #include <HttpRequest.h>
 #include <JSON.h>
 #include <main.h>
 #include <Network.h>
 #include <RenderThread.h>
-#include <Font.h>
+#include <Screen.h>
 #include <Texture.h>
+#include <Window.h>
 
 #include "CustomDX11API.h"
 #include "Globals.h"
@@ -133,7 +133,25 @@ int KSGStart Framework::Start(Framework::Startparam p)
     Network::Start(20);
     initVariables();
     setDebugDX(1);
-
+#ifdef _DEBUG
+    Logging::LoggingChannel* outputDebugLoggingChannel
+        = new Framework::Logging::OutputDebugStringLoggingChannel();
+    Framework::Logging::zLoggingHandler()->addChannel(
+        Logging::LogLevel::Error, outputDebugLoggingChannel);
+    Framework::Logging::zLoggingHandler()->addChannel(Logging::LogLevel::Debug,
+        dynamic_cast<Logging::LoggingChannel*>(
+            outputDebugLoggingChannel->getThis()));
+    Framework::Logging::zLoggingHandler()->addChannel(Logging::LogLevel::Info,
+        dynamic_cast<Logging::LoggingChannel*>(
+            outputDebugLoggingChannel->getThis()));
+    Framework::Logging::zLoggingHandler()->addChannel(
+        Logging::LogLevel::Warning,
+        dynamic_cast<Logging::LoggingChannel*>(
+            outputDebugLoggingChannel->getThis()));
+    Framework::Logging::zLoggingHandler()->addChannel(Logging::LogLevel::Trace,
+        dynamic_cast<Logging::LoggingChannel*>(
+            outputDebugLoggingChannel->getThis()));
+#endif
     File d;
     d.setFile("data/schriften");
     auto list = d.getFileList();
@@ -179,9 +197,8 @@ int KSGStart Framework::Start(Framework::Startparam p)
 
     RenderTh rTh;
     rTh.setMaxFps(-1);
-    rTh.setQuiet(1);
+    rTh.setQuiet(0);
     rTh.setScreen(dynamic_cast<Screen*>(screen.getThis()));
-
     rTh.setTickFunktion([](void* p, void* o, double time) {
         if (World::INSTANCE)
         {

+ 10 - 8
FactoryCraft/MapWindow.cpp

@@ -40,20 +40,20 @@ void MapWindow::setVisibility(bool visible)
         uiFactory.initParam.bildschirm->postAction([this, visible]() {
             if (visible && !map)
             {
-                lockDrawable();
+                writeLock().lock();
                 map = new DimensionMap(options);
                 map->setSize(getInnerWidth(), getInnerHeight());
                 addMember(map);
-                unlockDrawable();
+                writeLock().unlock();
                 addStyle(Window::Style::Visible);
             }
             if (!visible && map)
             {
                 removeStyle(Window::Style::Visible);
-                lockDrawable();
+                writeLock().lock();
                 removeMember(map);
                 map = 0;
-                unlockDrawable();
+                writeLock().unlock();
             }
         });
     }
@@ -61,7 +61,7 @@ void MapWindow::setVisibility(bool visible)
 
 void MapWindow::addChunk(ChunkMap* chunk)
 {
-    lockDrawable();
+    writeLock().lock();
     if (map)
     {
         map->addChunk(chunk);
@@ -70,18 +70,20 @@ void MapWindow::addChunk(ChunkMap* chunk)
     {
         chunk->release();
     }
-    unlockDrawable();
+    writeLock().unlock();
 }
 
 void MapWindow::updatePlayerData(char* data)
 {
-    lockDrawable();
+    readLock().lock();
     if (map) map->updatePlayers(data);
-    unlockDrawable();
+    readLock().unlock();
 }
 
 bool MapWindow::tick(double time)
 {
+    readLock().lock();
     if (map) map->setSize(getInnerWidth(), getInnerHeight());
+    readLock().unlock();
     return OptionsWindow::tick(time);
 }

+ 14 - 12
FactoryCraft/ServerSelection.cpp

@@ -46,12 +46,12 @@ ServerStatus::ServerStatus(Framework::Text name,
             FactoryClient* client = new FactoryClient();
             if (!client->connect(getIp(), getSSLPort()))
             {
-                lockDrawable();
+                writeLock().lock();
                 status = "The Server is currently not reachable";
                 statusId = 404;
                 ping = -1;
                 rend = 1;
-                unlockDrawable();
+                writeLock().unlock();
                 client->release();
             }
             else
@@ -70,14 +70,14 @@ ServerStatus::ServerStatus(Framework::Text name,
                         getPort(),
                         [this, isNew, client](int result, Text secret) {
                             menuRegister->get("load")->hide();
-                            lockDrawable();
+                            writeLock().lock();
                             statusId = result;
                             if (statusId == 403)
                                 status = "The name is already in use";
                             if (statusId == 500)
                                 status = "Unknown Server message received";
                             if (statusId == 201) status = "Please try again";
-                            unlockDrawable();
+                            writeLock().unlock();
                             if (statusId == 200 || statusId == 201)
                             {
                                 if (isNew)
@@ -150,17 +150,17 @@ ServerStatus::~ServerStatus()
 
 void ServerStatus::updatePlayerName(Framework::Text playerName)
 {
-    lockDrawable();
     status = "";
     this->playerName = playerName;
     ServerStatus* tmp = dynamic_cast<ServerStatus*>(getThis());
+    requestIdLock.lockWrite();
     int id = ++requestId;
-    unlockDrawable();
+    requestIdLock.unlockWrite();
     new AsynchronCall([tmp, id]() {
         FactoryClient* client = new FactoryClient();
         if (!client->connect(tmp->getIp(), tmp->getSSLPort()))
         {
-            tmp->lockDrawable();
+            tmp->requestIdLock.lockRead();
             if (tmp->requestId == id)
             {
                 tmp->status = "The Server is currently not reachable";
@@ -168,17 +168,17 @@ void ServerStatus::updatePlayerName(Framework::Text playerName)
                 tmp->ping = -1;
                 tmp->rend = 1;
             }
-            tmp->unlockDrawable();
+            tmp->requestIdLock.unlockRead();
         }
         else
         {
-            tmp->lockDrawable();
+            tmp->requestIdLock.lockRead();
             if (tmp->requestId == id)
             {
                 Text secret = "";
                 if (tmp->secrets->has(tmp->playerName))
                     secret = tmp->secrets->get(tmp->playerName);
-                tmp->unlockDrawable();
+                tmp->requestIdLock.unlockRead();
                 int ping = client->ping();
                 int statusId = client->status(tmp->playerName, secret);
                 if (statusId == 403)
@@ -190,9 +190,10 @@ void ServerStatus::updatePlayerName(Framework::Text playerName)
                 {
                     statusId = 203;
                 }
-                tmp->lockDrawable();
+                tmp->requestIdLock.lockRead();
                 if (tmp->requestId == id)
                 {
+                    tmp->writeLock().lock();
                     tmp->ping = ping;
                     tmp->statusId = statusId;
                     if (tmp->statusId == 200)
@@ -201,9 +202,10 @@ void ServerStatus::updatePlayerName(Framework::Text playerName)
                     if (tmp->statusId == 403)
                         tmp->status = "The name is already in use";
                     tmp->rend = 1;
+                    tmp->writeLock().unlock();
                 }
             }
-            tmp->unlockDrawable();
+            tmp->requestIdLock.unlockRead();
         }
         client->release();
         tmp->release();

+ 3 - 3
FactoryCraft/ServerSelection.h

@@ -1,7 +1,7 @@
 #pragma once
 
-#include <HashMap.h>
 #include <Button.h>
+#include <HashMap.h>
 #include <List.h>
 #include <TextField.h>
 
@@ -22,6 +22,7 @@ private:
     Framework::HashMap<Framework::Text, Framework::Text>* secrets;
     Framework::Button* removeButton;
     Framework::Button* join;
+    ReadWriteLock requestIdLock;
 
 public:
     ServerStatus(Framework::Text name,
@@ -33,8 +34,7 @@ public:
 
     virtual void updatePlayerName(Framework::Text playerName);
 
-    virtual void doMouseEvent(
-        Framework::MouseEvent& me, bool userRet) override;
+    virtual void doMouseEvent(Framework::MouseEvent& me, bool userRet) override;
     virtual bool tick(double time) override;
     virtual void render(Framework::Image& rObj) override;
 

+ 12 - 12
FactoryCraft/StatusBars.cpp

@@ -114,12 +114,12 @@ void StatusBarsView::api(char* message)
             this->energy = stamina / maxStamina;
             this->hunger = hunger / maxHunger;
             this->thirst = thirst / maxThirst;
-            lockDrawable();
+            writeLock().lock();
             healthText = (int)ceil(health);
             energyText = (int)ceil(stamina);
             hungerText = (int)ceil(hunger);
             thirstText = (int)ceil(thirst);
-            unlockDrawable();
+            writeLock().unlock();
             break;
         }
     case 1: // update health
@@ -127,9 +127,9 @@ void StatusBarsView::api(char* message)
             float maxHealth = *(float*)(message + 1);
             float health = *(float*)(message + 5);
             this->health = health / maxHealth;
-            lockDrawable();
+            writeLock().lock();
             healthText = (int)ceil(health);
-            unlockDrawable();
+            writeLock().unlock();
             break;
         }
     case 2: // update stamina
@@ -137,9 +137,9 @@ void StatusBarsView::api(char* message)
             float maxStamina = *(float*)(message + 1);
             float stamina = *(float*)(message + 5);
             this->energy = stamina / maxStamina;
-            lockDrawable();
+            writeLock().lock();
             energyText = (int)ceil(stamina);
-            unlockDrawable();
+            writeLock().unlock();
             break;
         }
     case 3: // update hunger
@@ -147,9 +147,9 @@ void StatusBarsView::api(char* message)
             float maxHunger = *(float*)(message + 1);
             float hunger = *(float*)(message + 5);
             this->hunger = hunger / maxHunger;
-            lockDrawable();
+            writeLock().lock();
             hungerText = (int)ceil(hunger);
-            unlockDrawable();
+            writeLock().unlock();
             break;
         }
     case 4: // update thirst
@@ -157,9 +157,9 @@ void StatusBarsView::api(char* message)
             float maxThirst = *(float*)(message + 1);
             float thirst = *(float*)(message + 5);
             this->thirst = thirst / maxThirst;
-            lockDrawable();
+            writeLock().lock();
             thirstText = (int)ceil(thirst);
-            unlockDrawable();
+            writeLock().unlock();
             break;
         }
     }
@@ -178,7 +178,7 @@ void StatusBarsView::render(Framework::Image& rObj)
     rObj.alphaImage(gr.x - getBorderWidth() * 2 - 20, 10, 20, 20, *energyIcon);
     rObj.alphaImage(0, 20, 20, 20, *hungerIcon);
     rObj.alphaImage(gr.x - getBorderWidth() * 2 - 20, 30, 20, 20, *thirstIcon);
-    lockDrawable();
+    readLock().lock();
     tr.renderText(25, 4, healthText, rObj, 0xFFFFFFFF);
     tr.renderText(25, 24, hungerText, rObj, 0xFFFFFFFF);
     int leftTxtBr
@@ -195,7 +195,7 @@ void StatusBarsView::render(Framework::Image& rObj)
         thirstText,
         rObj,
         0xFFFFFFFF);
-    unlockDrawable();
+    readLock().unlock();
     int leftWidth = gr.x - 62 - leftTxtBr - getBorderWidth() * 2 - rightTxtBr;
     if (leftWidth > 0)
     {

+ 4 - 8
FactoryCraft/UIMLProgressAndStateView.cpp

@@ -1,7 +1,7 @@
 #include "UIMLProgressAndStateView.h"
 
-#include <Image.h>
 #include <FileSystem.h>
+#include <Image.h>
 #include <TextField.h>
 #include <ToolTip.h>
 
@@ -78,8 +78,6 @@ void UIMLProgressAndStateView::api(char* message)
 {
     max = *(int*)message;
     current = *(int*)(message + 4);
-    uiFactory.initParam.bildschirm->lock();
-    lockDrawable();
     Framework::Text toolTipText;
     toolTipText.append() << toolTipPrefix.getText() << current << " / " << max
                          << toolTipSuffix;
@@ -108,17 +106,15 @@ void UIMLProgressAndStateView::api(char* message)
     }
     toolTip->setRender();
     rend = 1;
-    unlockDrawable();
-    uiFactory.initParam.bildschirm->unlock();
 }
 
 void UIMLProgressAndStateView::render(Framework::Image& rObj)
 {
     if (hasStyleNot(Style::Visible)) return;
-    lockDrawable();
+    readLock().lock();
     if (!rObj.setDrawOptions(pos.x, pos.y, gr.x, gr.y))
     {
-        unlockDrawable();
+        readLock().unlock();
         return;
     }
     Drawable::render(rObj);
@@ -160,5 +156,5 @@ void UIMLProgressAndStateView::render(Framework::Image& rObj)
         }
     }
     rObj.releaseDrawOptions();
-    unlockDrawable();
+    readLock().unlock();
 }

+ 86 - 75
FactoryCraft/World.cpp

@@ -20,7 +20,6 @@ World::World(Screen3D* zScreen, FactoryClient* client)
     : Thread(),
       client(client)
 {
-    zScreen->lock();
     renderedWorld = new World3D();
     renderedWorld->addDiffuseLight(DiffuseLight{
         Vec3<float>(0.5f, 0.5f, -1.f), Vec3<float>(1.f, 1.f, 1.f)});
@@ -63,7 +62,6 @@ World::World(Screen3D* zScreen, FactoryClient* client)
     selectionModel->setAlpha(1);
     selectionModel->setUseEffectAlpha(1);
     renderedWorld->addDrawable(selectionModel);
-    zScreen->unlock();
     start();
 }
 
@@ -76,15 +74,17 @@ World::~World()
     World::INSTANCE = 0;
 }
 
-void World::update(bool background)
+int World::update(bool background)
 {
-    if (background && currentDimension->getId() < 0) return;
+    if (background && currentDimension->getId() < 0) return 0;
     NetworkReader* serverMessageReader = 0;
     unsigned char type = 0;
+    int messageCount = 0;
     while (background
                ? serverMessageReader = client->getNextBackgroundMessage()
                : serverMessageReader = client->getNextForegroundMessage())
     {
+        messageCount++;
         serverMessageReader->read((char*)&type, 1);
         if (type == 3) // API MESSAGE
         {
@@ -201,60 +201,67 @@ void World::update(bool background)
         client->endMessageReading(background);
     }
     client->endMessageReading(background);
-    Entity* player = getCurrentPlayerEntity();
-    if (player)
+    if (!background)
     {
-        renderedWorld->lock();
-        currentDimension->removeDistantChunks(
-            {(int)player->getPos().x, (int)player->getPos().y});
-        Point currentChunk
-            = getChunkCenter((int)player->getX(), (int)player->getY());
-        for (int x = 0; x <= CHUNK_VISIBILITY_RANGE; x++)
+        Entity* player = getCurrentPlayerEntity();
+        if (player)
         {
-            for (int y = 0; y <= CHUNK_VISIBILITY_RANGE; y++)
+            currentDimension->removeDistantChunks(
+                {(int)player->getPos().x, (int)player->getPos().y});
+            Point currentChunk
+                = getChunkCenter((int)player->getX(), (int)player->getY());
+            for (int x = 0; x <= CHUNK_VISIBILITY_RANGE; x++)
             {
-                std::function<void(Point)> requestChunk = [this](Point center) {
-                    Chunk* zC = currentDimension->zChunk(center);
-                    if (!zC)
-                    {
-                        char msg[1];
-                        msg[0] = 0; // add observer and request chaunk data
-                        Point pos = center;
-                        subLock.lock();
-                        bool found = 0;
-                        for (Point p : subscriptions)
-                        {
-                            if (p == pos)
+                for (int y = 0; y <= CHUNK_VISIBILITY_RANGE; y++)
+                {
+                    std::function<void(Point)> requestChunk =
+                        [this](Point center) {
+                            Chunk* zC = currentDimension->zChunk(center);
+                            if (!zC)
                             {
-                                found = 1;
-                                break;
+                                char msg[1];
+                                msg[0]
+                                    = 0; // add observer and request chaunk data
+                                Point pos = center;
+                                subLock.lockRead();
+                                bool found = 0;
+                                for (Point p : subscriptions)
+                                {
+                                    if (p == pos)
+                                    {
+                                        found = 1;
+                                        break;
+                                    }
+                                }
+                                if (!found)
+                                {
+                                    client->chunkAPIRequest(pos, msg, 1);
+                                    subLock.lockWrite();
+                                    subscriptions.add(pos);
+                                    subLock.unlockWrite();
+                                }
+                                subLock.unlockRead();
                             }
-                        }
-                        if (!found)
-                        {
-                            client->chunkAPIRequest(pos, msg, 1);
-                            subscriptions.add(pos);
-                        }
-                        subLock.unlock();
-                    }
-                };
-                requestChunk(
-                    currentChunk + Point(x * CHUNK_SIZE, y * CHUNK_SIZE));
-                if (y > 0)
+                        };
                     requestChunk(
-                        currentChunk + Point(x * CHUNK_SIZE, -y * CHUNK_SIZE));
-                if (x > 0)
-                {
-                    requestChunk(
-                        currentChunk + Point(-x * CHUNK_SIZE, y * CHUNK_SIZE));
+                        currentChunk + Point(x * CHUNK_SIZE, y * CHUNK_SIZE));
                     if (y > 0)
                         requestChunk(currentChunk
-                                     + Point(-x * CHUNK_SIZE, -y * CHUNK_SIZE));
+                                     + Point(x * CHUNK_SIZE, -y * CHUNK_SIZE));
+                    if (x > 0)
+                    {
+                        requestChunk(currentChunk
+                                     + Point(-x * CHUNK_SIZE, y * CHUNK_SIZE));
+                        if (y > 0)
+                            requestChunk(
+                                currentChunk
+                                + Point(-x * CHUNK_SIZE, -y * CHUNK_SIZE));
+                    }
                 }
             }
         }
-        renderedWorld->unlock();
     }
+    return messageCount;
 }
 
 void World::onTick(double time)
@@ -319,48 +326,59 @@ void World::onTick(double time)
 
 void World::setChunk(Chunk* chunk)
 {
-    zScreenPtr->lock();
-    renderedWorld->lock();
     currentDimension->setChunk(chunk, chunk->getCenter());
-    renderedWorld->unlock();
-    zScreenPtr->unlock();
 }
 
 void World::thread()
 {
     new AsynchronCall("World Update", [this]() {
+        Timer tm;
+        tm.measureStart();
+        double sum = 0;
+        int updates = 0;
+        int messages = 0;
+        double wait = 0;
         while (client->isConnected())
         {
-            zScreenPtr->lock();
             if (World::INSTANCE != this)
             {
-                zScreenPtr->unlock();
                 return;
             }
-            zScreenPtr->unlock();
-            update(0);
-            Sleep(10);
+            messages += update(0);
+            updates++;
+            tm.measureEnd();
+            sum += tm.getSekunden();
+            wait += 10 - tm.getSekunden();
+            tm.measureStart();
+            if ((int)wait > 0)
+            {
+                Sleep((int)wait);
+            }
+            if (sum > 1.0)
+            {
+                std::cout << "updates: " << updates
+                          << ", messages: " << (double)messages
+                          << ", seconds: " << sum << "\n";
+                sum = 0;
+                updates = 0;
+                messages = 0;
+            }
         }
         std::cout << "foreground connection lost\n";
     });
     while (client->isConnected())
     {
-        zScreenPtr->lock();
         if (World::INSTANCE != this)
         {
-            zScreenPtr->unlock();
             return;
         }
-        zScreenPtr->unlock();
         update(1);
-        Sleep(10);
+        Sleep(100);
     }
     Sleep(1000);
-    zScreenPtr->lock();
     std::cout << "background connection lost\n";
     menuRegister->get("game")->hide();
     menuRegister->get("serverSelection")->show();
-    zScreenPtr->unlock();
     zScreenPtr->postAction([this]() {
         if (World::INSTANCE == this)
         {
@@ -387,13 +405,11 @@ Dimension* World::zDimension() const
 
 void World::setVisibility(Entity* zEntity, bool visible)
 {
-    renderedWorld->lock();
     if (visible)
         renderedWorld->addDrawable(
             dynamic_cast<Framework::Model3D*>(zEntity->getThis()));
     else
         renderedWorld->removeDrawable(zEntity);
-    renderedWorld->unlock();
 }
 
 Framework::Point World::getChunkCenter(int x, int y) const
@@ -481,19 +497,9 @@ void World::setTarget(Framework::Model3D* zTarget)
     }
 }
 
-void World::lockWorld()
-{
-    renderedWorld->lock();
-}
-
-void World::unlockWorld()
-{
-    renderedWorld->unlock();
-}
-
 void World::onChunkAdded(Point pos)
 {
-    subLock.lock();
+    subLock.lockWrite();
     int index = 0;
     for (Point p : subscriptions)
     {
@@ -504,7 +510,7 @@ void World::onChunkAdded(Point pos)
         }
         index++;
     }
-    subLock.unlock();
+    subLock.unlockWrite();
 }
 
 Framework::Model3D* World::getCurrentTarget() const
@@ -526,6 +532,11 @@ Chunk* World::zChunk(Point center)
     return currentDimension->zChunk(center);
 }
 
+Lock& World::getChunkReadLock()
+{
+    return currentDimension->getReadLock();
+}
+
 FactoryClient* World::zClient() const
 {
     return client;

+ 4 - 5
FactoryCraft/World.h

@@ -1,7 +1,7 @@
 #pragma once
 
-#include <Screen.h>
 #include <Camera3D.h>
+#include <Screen.h>
 #include <Thread.h>
 #include <World3D.h>
 
@@ -25,7 +25,7 @@ private:
     Array<Point> subscriptions;
     FactoryClient* client;
     FactoryCraftModel* selectionModel;
-    Critical subLock;
+    ReadWriteLock subLock;
     Critical targetLock;
     float dayLightFactor;
     double time;
@@ -37,7 +37,7 @@ private:
 public:
     World(Framework::Screen3D* zScreen, FactoryClient* client);
     ~World();
-    void update(bool background);
+    int update(bool background);
     void onTick(double time);
     void setChunk(Chunk* chunk);
     void thread() override;
@@ -54,10 +54,9 @@ public:
     int getCurrentPlayerId() const;
     Entity* getCurrentPlayerEntity() const;
     void setTarget(Framework::Model3D* zTarget);
-    void lockWorld();
-    void unlockWorld();
     void onChunkAdded(Point pos);
     Chunk* zChunk(Point center);
+    Lock& getChunkReadLock();
     Framework::Model3D* getCurrentTarget() const;
     FactoryCraftModel* zSelectedEffectModel() const;
     FactoryClient* zClient() const;