Kaynağa Gözat

clients can now subscribe to mat changes and can request the position of all players

Kolja Strohm 1 yıl önce
ebeveyn
işleme
92162d25c4

+ 6 - 1
FactoryCraft/ChunkMap.cpp

@@ -86,7 +86,7 @@ ChunkMap::~ChunkMap()
     delete[] pixels;
 }
 
-void ChunkMap::update(
+bool ChunkMap::update(
     char x, char y, unsigned char height, int color1, int color2)
 {
     cs.lock();
@@ -95,10 +95,12 @@ void ChunkMap::update(
     int resultColor
         = ((color1 >> 24) & 0xFF) > ((color2 >> 24) & 0xFF) ? color1 : color2;
     bool removed = !((resultColor >> 24) & 0xFF);
+    bool changed = 0;
     for (int i = 0; i < pixels[index].len; i++)
     {
         if (pixels[index].blocks[i].height == height)
         {
+            changed = pixels[index].blocks[i].color != resultColor;
             pixels[index].blocks[i].color = resultColor;
             found = 1;
         }
@@ -113,6 +115,7 @@ void ChunkMap::update(
     }
     if (found && removed)
     {
+        changed = 1;
         pixels[index].len--;
     }
     else if (!found && !removed)
@@ -139,11 +142,13 @@ void ChunkMap::update(
         {
             blocks[pixels[index].len] = {height, resultColor};
         }
+        changed = 1;
         pixels[index].len++;
         delete[] pixels[index].blocks;
         pixels[index].blocks = blocks;
     }
     cs.unlock();
+    return changed;
 }
 
 void ChunkMap::writeTo(Framework::StreamWriter* zWriter) const

+ 1 - 1
FactoryCraft/ChunkMap.h

@@ -49,7 +49,7 @@ public:
     // 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);
+    bool update(char x, char y, unsigned char height, int color1, int color2);
 
     void writeTo(Framework::StreamWriter* zWriter) const;
     Framework::Punkt getChunkCenter() const;

+ 26 - 15
FactoryCraft/Dimension.cpp

@@ -87,18 +87,7 @@ void Dimension::api(Framework::InMemoryBuffer* zRequest,
         }
     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();
+            map->api(zRequest, zResponse, zSource, this);
             break;
         }
     }
@@ -895,6 +884,18 @@ void Dimension::updateMap(int x, int y, int height)
     int color1
         = (b2->isPassable() || b2->isTransparent()) ? b1->getMapColor() : 0;
     int color2 = visible ? b2->getMapColor() : 0;
+    int color1m = 0;
+    int color2m = 0;
+    if (h1 > 0)
+    {
+        const Block* b1m = zBlockOrDefault({x, y, h1 - 2});
+        const Block* b2m = zBlockOrDefault({x, y, h1 - 1});
+        color1m = (b2m->isPassable() || b2m->isTransparent())
+                    ? b1m->getMapColor()
+                    : 0;
+        color2m = (b1->isPassable() || b1->isTransparent()) ? b2m->getMapColor()
+                                                            : 0;
+    }
     char addr[8];
     Punkt center = Game::INSTANCE->getChunkCenter(x, y);
     getAddrOfWorld(center, addr);
@@ -905,12 +906,22 @@ void Dimension::updateMap(int x, int y, int height)
         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);
+        if (cMap->update(
+                (char)x, (char)y, (unsigned char)(height / 2), color1, color2)
+            || (h1 > 0
+                && cMap->update((char)x,
+                    (char)y,
+                    (unsigned char)(height / 2) - 1,
+                    color1m,
+                    color2m)))
+        {
+            map->onMapUpdated(addr, 8);
+        }
     }
     chunkCs.unlock();
 }
 
-int Dimension::getChunkCount() {
+int Dimension::getChunkCount()
+{
     return chunkList.getEintragAnzahl();
 }

+ 2 - 0
FactoryCraft/Dimension.h

@@ -85,4 +85,6 @@ public:
     void requestStopAndWait();
     void updateMap(int x, int y, int height);
     int getChunkCount();
+
+    friend DimensionMap;
 };

+ 115 - 1
FactoryCraft/DimensionMap.cpp

@@ -16,6 +16,73 @@ DimensionMap::~DimensionMap()
     chunks->release();
 }
 
+void DimensionMap::api(Framework::InMemoryBuffer* zRequest,
+    NetworkMessage* zResponse,
+    Entity* zSource,
+    Dimension* zDimension)
+{
+    char type;
+    zRequest->lese(&type, 1);
+    switch (type)
+    {
+    case 0: // request chunk
+        {
+            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];
+            zDimension->getAddrOfWorld(location, addr);
+            ChunkMap* res = 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;
+        }
+    case 1: // subscribe to changes
+        {
+            cs.lock();
+            observers.add(zSource->getId());
+            cs.unlock();
+            break;
+        }
+    case 2: // unsubscribe from changes
+        {
+            cs.lock();
+            observers.removeValue(zSource->getId());
+            cs.unlock();
+            break;
+        }
+    case 3: // player list request
+        {
+            InMemoryBuffer buff;
+            int count = 0;
+            for (Entity* entity : *zDimension->entities)
+            {
+                if (entity->zType()->getId() == EntityTypeEnum::PLAYER)
+                {
+                    Player* p = dynamic_cast<Player*>(entity);
+                    char len = (char)textLength(p->getName());
+                    buff.schreibe(&len, 1);
+                    buff.schreibe(p->getName(), len);
+                    Vec3<float> pos = p->getPosition();
+                    buff.schreibe((char*)&pos.x, 4);
+                    buff.schreibe((char*)&pos.y, 4);
+                    buff.schreibe((char*)&pos.z, 4);
+                    count++;
+                }
+            }
+            char* msg = new char[4 + buff.getSize()];
+            *(int*)msg = count;
+            buff.lese(msg + 4, (int)buff.getSize());
+            zResponse->sendPlayerPositions(msg, 4 + (int)buff.getSize());
+            break;
+        }
+    }
+}
+
 ChunkMap* DimensionMap::load(Framework::Punkt chunkCenter)
 {
     Framework::Datei file;
@@ -44,11 +111,58 @@ void DimensionMap::loadMap(char* addr, int addrLen, Chunk* zChunk)
         return;
     }
     ChunkMap* map = load(zChunk->getCenter());
-    if (!map) map = new ChunkMap(zChunk);
+    if (!map)
+    {
+        map = new ChunkMap(zChunk);
+        for (auto iterator = observers.begin(); iterator;)
+        {
+            Entity* e = Game::INSTANCE->zEntity(iterator.val());
+            if (!e)
+            {
+                iterator.remove();
+                continue;
+            }
+            else
+            {
+                NetworkMessage* msg = new NetworkMessage();
+                msg->sendMap(map);
+                msg->setUseBackground();
+                Game::INSTANCE->sendMessage(msg, e);
+            }
+            iterator++;
+        }
+    }
     chunks->set(addr, addrLen, map);
     cs.unlock();
 }
 
+void DimensionMap::onMapUpdated(char* addr, int addrLen)
+{
+    cs.lock();
+    ChunkMap* map = chunks->z(addr, addrLen);
+    if (map)
+    {
+        for (auto iterator = observers.begin(); iterator;)
+        {
+            Entity* e = Game::INSTANCE->zEntity(iterator.val());
+            if (!e)
+            {
+                iterator.remove();
+                continue;
+            }
+            else
+            {
+                NetworkMessage* msg = new NetworkMessage();
+                msg->sendMap(map);
+                msg->setUseBackground();
+                Game::INSTANCE->sendMessage(msg, e);
+            }
+            iterator++;
+        }
+    }
+    cs.unlock();
+}
+
 void DimensionMap::saveMap(char* addr, int addrLen)
 {
     cs.lock();

+ 13 - 0
FactoryCraft/DimensionMap.h

@@ -1,15 +1,22 @@
 #pragma once
 
+#include <Array.h>
+#include <InMemoryBuffer.h>
 #include <ReferenceCounter.h>
 #include <Trie.h>
 
 #include "ChunkMap.h"
 
+class Dimension;
+class NetworkMessage;
+class Entity;
+
 class DimensionMap : public Framework::ReferenceCounter
 {
 private:
     Framework::Trie<ChunkMap>* chunks;
     Framework::Critical cs;
+    Framework::Array<int> observers;
     int dimensionId;
 
     ChunkMap* load(Framework::Punkt chunkCenter);
@@ -18,7 +25,13 @@ public:
     DimensionMap(int dimensionId);
     ~DimensionMap();
 
+    void api(Framework::InMemoryBuffer* zRequest,
+        NetworkMessage* zResponse,
+        Entity* zSource,
+        Dimension* zDimension);
+
     void loadMap(char* addr, int addrLen, Chunk* zChunk);
+    void onMapUpdated(char* addr, int addrLen);
     void saveMap(char* addr, int addrLen);
     void removeMap(char* addr, int addrLen);
     ChunkMap* getMap(char* addr, int addrLen, Framework::Punkt chunkCenter);

+ 0 - 1
FactoryCraft/Game.cpp

@@ -475,7 +475,6 @@ void Game::thread()
     for (Dimension* dim : *dimensions)
         dim->requestStopAndWait();
     std::cout << "Game thread exited\n";
-    getThis();
 }
 
 void Game::api(Framework::InMemoryBuffer* zRequest, GameClient* zOrigin)

+ 1 - 1
FactoryCraft/ItemType.cpp

@@ -59,7 +59,7 @@ void ItemType::saveSuperItem(
     unsigned char flags
         = (unsigned char)((zItem->usable << 4) | (zItem->solid << 3)
                           | (zItem->equippable << 2) | (zItem->placeable << 1)
-                          | zItem->eatable);
+                          | (int)zItem->eatable);
     zWriter->schreibe((char*)&flags, 1);
     zWriter->schreibe((char*)&zItem->maxStackSize, 1);
     unsigned char len = (unsigned char)zItem->name.getLength();

+ 8 - 0
FactoryCraft/NetworkMessage.cpp

@@ -136,6 +136,14 @@ void NetworkMessage::sendMap(ChunkMap* zMap)
     setMessage(msg, (int)buffer.getSize());
 }
 
+void NetworkMessage::sendPlayerPositions(char* msg, int length) {
+    delete[] address;
+    addressLength = 1;
+    address = new char[1];
+    address[0] = 7; // map player positions
+    setMessage(msg, length);
+}
+
 void NetworkMessage::setUseBackground()
 {
     useBackground = 1;

+ 1 - 0
FactoryCraft/NetworkMessage.h

@@ -37,6 +37,7 @@ public:
     void sendChatMessage(ChatMessage* zMsg);
     void sendChatOptions(ChatObserver* zOptions);
     void sendMap(ChunkMap* zMap);
+    void sendPlayerPositions(char *msg, int length);
     void setUseBackground();
     void sendToAll();
 

+ 4 - 3
FactoryCraft/Server.cpp

@@ -102,8 +102,6 @@ FactoryCraftServer::~FactoryCraftServer()
     server->release();
     if (klients) klients->release();
     ini->release();
-    Game::INSTANCE->requestStop();
-    Game::INSTANCE->release();
     DeleteCriticalSection(&cs);
 }
 
@@ -128,17 +126,19 @@ void FactoryCraftServer::run()
 
 void FactoryCraftServer::close()
 {
+    Game::INSTANCE->save();
     sslServer->trenne();
+    server->trenne();
     EnterCriticalSection(&cs);
     for (int i = 0; i < klients->getEintragAnzahl(); i++)
         klients->z(i)->absturz();
-    Game::INSTANCE->save();
     LeaveCriticalSection(&cs);
 }
 
 bool FactoryCraftServer::removeKlient(FCKlient* zKlient)
 {
     bool gefunden = 0;
+    getThis();
     EnterCriticalSection(&cs);
     for (int i = 0; i < klients->getEintragAnzahl(); i++)
     {
@@ -150,6 +150,7 @@ bool FactoryCraftServer::removeKlient(FCKlient* zKlient)
         }
     }
     LeaveCriticalSection(&cs);
+    release();
     return gefunden;
 }
 

+ 15 - 6
FactoryCraft/Start.cpp

@@ -27,6 +27,8 @@ void exit()
     }
 }
 
+bool exited = false;
+
 class DuplicatingStreamBuf : public std::stringbuf
 {
 private:
@@ -78,7 +80,7 @@ public:
                 newLines++;
             }
         }
-        if (Game::INSTANCE)
+        if (!exited && Game::INSTANCE)
         {
             int tps = Game::INSTANCE->getTicksPerSecond();
             Framework::Text infoLine = "";
@@ -105,13 +107,17 @@ public:
                 infoLine.append()
                     << /* restore cursor position */ "\033[u"
                     << /* set cursor down by amount of new lines */
-                           (newLines > 0 ? (Text("\033[") + newLines + "B").getText()
-                    : "");
-            //        << "\x1b[0K";
+                    (newLines > 0 ? (Text("\033[") + newLines + "B").getText()
+                                  : "");
+                // << "\x1b[0K";
             }
             infoLength = infoLine.getLength();
             console << infoLine << std::flush;
         }
+        else
+        {
+            infoLength = 0;
+        }
         if (hasFile) file << str() << std::flush;
         str("");
         cs.unlock();
@@ -219,12 +225,15 @@ int main()
 
     std::cout << "The Server is now running.\n";
     mserver->run();
+    exited = 1;
     mserver->release();
     mserver = 0;
     if (Game::INSTANCE)
     {
-        Game::INSTANCE->warteAufThread(100000000);
-        Game::INSTANCE->release();
+        Game* tmp = Game::INSTANCE;
+        tmp->requestStop();
+        tmp->warteAufThread(100000000);
+        tmp->release();
         Game::INSTANCE = 0;
     }
     dat->release();

+ 1 - 1
FactoryCraft/TickWorker.cpp

@@ -36,7 +36,7 @@ void TickWorker::thread()
     tid = (pid_t)syscall(SYS_gettid);
 #endif
     Framework::Text txt = Framework::Text("exiting tick worker ") + tid + "\n";
-    std::cout << txt.getText();
+    std::cout << txt.getText() << std::flush;
 }
 
 bool TickWorker::isWaiting() const