Browse Source

the server can now also exit and save the game while clients are still online

Kolja Strohm 2 years ago
parent
commit
d81abce880

+ 12 - 3
FactoryCraft/Dimension.cpp

@@ -13,7 +13,8 @@ Dimension::Dimension(int id)
       dimensionId(id),
       gravity(9.8f),
       chunks(new Trie<Chunk>()),
-      entities(new RCArray<Entity>())
+      entities(new RCArray<Entity>()),
+      stop(0)
 {
     Datei d;
     d.setDatei(
@@ -103,7 +104,7 @@ void Dimension::thread()
     double time = 0;
     bool isForeground = 0;
     Framework::Array<Framework::Vec3<int>> internalLightUpdateQueue;
-    while (true)
+    while (!stop)
     {
         Vec3<int> position;
         if (internalLightUpdateQueue.getEintragAnzahl())
@@ -250,6 +251,8 @@ void Dimension::thread()
             messer.messungStart();
         }
     }
+    std::cout << Text("Dimension ") + this->getDimensionId()
+                     + " update Thread exited.\n";
 }
 
 void Dimension::getAddrOf(Punkt cPos, char* addr) const
@@ -454,7 +457,7 @@ void Dimension::save(Text worldDir) const
     d.open(Datei::Style::schreiben);
     d.schreibe((char*)&nextStructureId, 8);
     d.close();
-    for (auto chunk = chunks->getIterator(); chunk; chunk++)
+    for (auto chunk = chunkList.begin(); chunk; chunk++)
     {
         if (!chunk._) continue;
         Datei* file = new Datei();
@@ -802,4 +805,10 @@ MultiblockStructure* Dimension::zStructureById(__int64 id)
     }
     structurCs.unlock();
     return 0;
+}
+
+void Dimension::requestStopAndWait()
+{
+    stop = 1;
+    warteAufThread(1000000);
 }

+ 2 - 0
FactoryCraft/Dimension.h

@@ -37,6 +37,7 @@ private:
     Framework::RCArray<Chunk> removedChunks;
     Framework::Critical removedChunksCs;
     Framework::RCArray<MultiblockStructure> structures;
+    bool stop;
 
 public:
     Dimension(int id);
@@ -76,4 +77,5 @@ public:
     MultiblockStructure* zStructureByPosition(
         Framework::Vec3<int> uniquePosition);
     MultiblockStructure* zStructureById(__int64 id);
+    void requestStopAndWait();
 };

+ 7 - 0
FactoryCraft/Game.cpp

@@ -168,6 +168,11 @@ void GameClient::reply()
 void GameClient::logout()
 {
     online = 0;
+    updateSync.notify();
+    emptyForegroundQueueSync.notifyAll();
+    emptyBackgroundQueueSync.notifyAll();
+    foregroundQueueSync.notify();
+    backgroundQueueSync.notify();
 }
 
 void GameClient::addMessage(StreamReader* reader)
@@ -454,6 +459,8 @@ void Game::thread()
     generator->exitAndWait();
     loader->exitAndWait();
     ticker->exitAndWait();
+    for (Dimension* dim : *dimensions)
+        dim->requestStopAndWait();
     std::cout << "Game thread exited\n";
 }
 

+ 44 - 5
FactoryCraft/Server.cpp

@@ -217,14 +217,29 @@ void FCKlient::setForegroundClient(SKlient* foreground)
         zGameClient
             = Game::INSTANCE->addPlayer(dynamic_cast<FCKlient*>(getThis()),
                 Framework::Text((int)accountId));
+    foregroundRunning = 1;
     new AsynchronCall([this]() {
         while (this->foreground->waitForNextMessage())
         {
             if (zGameClient) zGameClient->addMessage(foregroundReader);
             if (!zGameClient) Sleep(100);
         }
-        zGameClient->logout();
-        ls->removeKlient(this);
+        cs.lock();
+        foregroundRunning = 0;
+        if (!backgroundRunning)
+        {
+            cs.unlock();
+            if (zGameClient)
+            {
+                zGameClient->logout();
+                zGameClient = (GameClient*)zGameClient->release();
+            }
+            ls->removeKlient(this);
+        }
+        else
+        {
+            cs.unlock();
+        }
     });
 }
 
@@ -237,25 +252,44 @@ void FCKlient::setBackgroundClient(SKlient* background)
         zGameClient
             = Game::INSTANCE->addPlayer(dynamic_cast<FCKlient*>(getThis()),
                 Framework::Text((int)accountId));
+    backgroundRunning = 1;
     new AsynchronCall([this]() {
         while (this->background->waitForNextMessage())
         {
             if (zGameClient) zGameClient->addMessage(backgroundReader);
             if (!zGameClient) Sleep(100);
         }
-        zGameClient->logout();
-        ls->removeKlient(this);
+        cs.lock();
+        backgroundRunning = 0;
+        if (!foregroundRunning)
+        {
+            cs.unlock();
+            if (zGameClient)
+            {
+                zGameClient->logout();
+                zGameClient = (GameClient*)zGameClient->release();
+            }
+            ls->removeKlient(this);
+        }
+        else
+        {
+            cs.unlock();
+        }
     });
 }
 
 void FCKlient::absturz()
 {
-    ende();
     klient->trenne();
+    if (background) background->trenne();
+    if (foreground) foreground->trenne();
+    warteAufThread(10000);
+    ende();
 }
 
 void FCKlient::thread()
 {
+    bool identified = 0;
     while (1)
     {
         char c = 0;
@@ -296,6 +330,7 @@ void FCKlient::thread()
                     else
                     {
                         klient->sende("\1", 1);
+                        identified = 1;
                     }
                     klient->sende((char*)&authKeyLen, 4);
                     klient->sende(authKey, authKeyLen);
@@ -342,6 +377,10 @@ void FCKlient::thread()
             if (br) break;
         }
     }
+    if (!identified)
+    {
+        ls->removeKlient(this);
+    }
 }
 
 int FCKlient::getAccountId() const // gibt die KlientId zurück

+ 3 - 0
FactoryCraft/Server.h

@@ -52,6 +52,9 @@ private:
     NetworkReader* foregroundReader;
     NetworkWriter* backgroundWriter;
     NetworkWriter* foregroundWriter;
+    Critical cs;
+    bool backgroundRunning;
+    bool foregroundRunning;
     char* authKey;
     int authKeyLen;
 

+ 12 - 8
FactoryCraft/Start.cpp

@@ -18,7 +18,7 @@ void exit()
 {
     if (mserver)
     {
-        std::cout << "Der Server wurde unerwartet beendet. Es wird versucht den spielfortschritt zu speichern.\n";
+        std::cout << "The server terminated unexpectedly. Trying to save game progress.\n";
         mserver->close();
     }
 }
@@ -47,8 +47,8 @@ int main()
     // std::cout.rdbuf( file.rdbuf() );
     pfad->release();
 
-    std::cout << "Startet...\n";
-    std::cout << "Lese init Datei fcInit.ini ...\n";
+    std::cout << "Starting...\n";
+    std::cout << "Loading config file fcInit.ini ...\n";
 
     InitDatei* dat = new InitDatei("fcInit.ini");
     if (!dat->laden())
@@ -67,8 +67,8 @@ int main()
         if (!dat->wertExistiert(w))
         {
             std::cout
-                << "error: Der Wert '" << w
-                << "' wurde nicht gefunden. Das Programm wird geschlossen.\n";
+                << "error: The value '" << w
+                << "' was not specified. The Server can not start.\n";
             dat->release();
             file.close();
             std::cout.rdbuf(sbuf);
@@ -92,19 +92,23 @@ int main()
             std::getline(std::cin, line);
             if (Text(line.c_str()) == Text("exit"))
             {
-                std::cout << "Der Server wird beended und der Spielfortschritt wird gespeichert.\n";
+                std::cout << "The server will be terminated and the game progress will be saved.\n";
                 mserver->close();
                 return;
             }
         }
     });
 
-    std::cout << "Der Server läuft. Startforgang beendet.\n";
+    std::cout << "The Server is now running.\n";
     mserver->run();
     mserver->release();
     mserver = 0;
+    if (Game::INSTANCE)
+    {
+        Game::INSTANCE->warteAufThread(100000000);
+    }
     dat->release();
-    std::cout << "Der Server ist erfolgreich heruntergefahren.\n";
+    std::cout << "The server was shut down successfully.\n";
     file.close();
     std::cout.rdbuf(sbuf);
     Framework::releaseFramework();

+ 1 - 1
FactoryCraft/TickWorker.cpp

@@ -26,7 +26,7 @@ void TickWorker::thread()
     // do not use multiple << here because they are not printed at once with
     // multiple threads
     pid_t tid;
-    tid = syscall(SYS_gettid);
+    tid = (pid_t)syscall(SYS_gettid);
     Framework::Text txt = Framework::Text("exiting tick worker ") + tid + "\n";
     std::cout << txt.getText();
 }