Quellcode durchsuchen

add foreground and background connection for each client

Kolja Strohm vor 3 Jahren
Ursprung
Commit
5aaf1718bb

+ 6 - 1
FactoryCraft/AddChunkUpdate.cpp

@@ -5,7 +5,7 @@
 
 
 AddChunkUpdate::AddChunkUpdate( Chunk* chunk )
-    : WorldUpdate( chunk->getDimensionId(), Framework::Vec3<int>( chunk->getCenter().x - CHUNK_SIZE / 2, chunk->getCenter().y - CHUNK_SIZE / 2, 0 ), Framework::Vec3<int>( chunk->getCenter().x + CHUNK_SIZE / 2, chunk->getCenter().y + CHUNK_SIZE / 2, WORLD_HEIGHT - 1 ) ),
+    : WorldUpdate( AddChunkUpdateType::ID, chunk->getDimensionId(), Framework::Vec3<int>( chunk->getCenter().x - CHUNK_SIZE / 2, chunk->getCenter().y - CHUNK_SIZE / 2, 0 ), Framework::Vec3<int>( chunk->getCenter().x + CHUNK_SIZE / 2, chunk->getCenter().y + CHUNK_SIZE / 2, WORLD_HEIGHT - 1 ) ),
     chunk( chunk )
 {}
 
@@ -30,6 +30,11 @@ void AddChunkUpdate::write( Framework::StreamWriter* zWriter )
     chunk->save( zWriter );
 }
 
+Chunk* AddChunkUpdate::zChunk() const
+{
+    return chunk;
+}
+
 
 AddChunkUpdateType::AddChunkUpdateType()
     : WorldUpdateType( ID )

+ 1 - 0
FactoryCraft/AddChunkUpdate.h

@@ -15,6 +15,7 @@ public:
 
     void onUpdate( Dimension* zDimension ) override;
     void write( Framework::StreamWriter* zWriter ) override;
+    Chunk* zChunk() const;
 };
 
 class AddChunkUpdateType : WorldUpdateType

+ 13 - 10
FactoryCraft/Dimension.cpp

@@ -43,7 +43,6 @@ void Dimension::getAddrOf( Punkt cPos, char* addr ) const
 {
     *(int*)addr = cPos.x;
     *((int*)addr + 1) = cPos.y;
-    addr[ 8 ] = 0;
 }
 
 void Dimension::getAddrOfWorld( Punkt wPos, char* addr ) const
@@ -58,9 +57,9 @@ void Dimension::getAddrOfWorld( Punkt wPos, char* addr ) const
 
 Chunk* Dimension::zChunk( Punkt wPos ) const
 {
-    char addr[ 9 ];
+    char addr[ 8 ];
     getAddrOfWorld( wPos, addr );
-    return chunks->z( addr, 9 );
+    return chunks->z( addr, 8 );
 }
 
 Framework::Either<Block*, int> Dimension::zBlock( Vec3<int> location, const Game* zGame )
@@ -86,34 +85,34 @@ void Dimension::addEntity( Entity* entity )
 
 void Dimension::addChunk( Chunk* chunk )
 {
-    char addr[ 9 ];
+    char addr[ 8 ];
     getAddrOfWorld( chunk->getCenter(), addr );
-    if( !chunks->z( addr, 9 ) )
+    if( !chunks->z( addr, 8 ) )
     {
-        chunks->set( addr, 9, chunk );
+        chunks->set( addr, 8, chunk );
         getAddrOfWorld( chunk->getCenter() + Punkt( CHUNK_SIZE, 0 ), addr );
-        Chunk* zChunk = chunks->z( addr, 9 );
+        Chunk* zChunk = chunks->z( addr, 8 );
         if( zChunk )
         {
             zChunk->setNeighbor( WEST, chunk );
             chunk->setNeighbor( EAST, chunk );
         }
         getAddrOfWorld( chunk->getCenter() + Punkt( -CHUNK_SIZE, 0 ), addr );
-        zChunk = chunks->z( addr, 9 );
+        zChunk = chunks->z( addr, 8 );
         if( zChunk )
         {
             zChunk->setNeighbor( EAST, chunk );
             chunk->setNeighbor( WEST, chunk );
         }
         getAddrOfWorld( chunk->getCenter() + Punkt( 0, CHUNK_SIZE ), addr );
-        zChunk = chunks->z( addr, 9 );
+        zChunk = chunks->z( addr, 8 );
         if( zChunk )
         {
             zChunk->setNeighbor( NORTH, chunk );
             chunk->setNeighbor( SOUTH, chunk );
         }
         getAddrOfWorld( chunk->getCenter() + Punkt( 0, -CHUNK_SIZE ), addr );
-        zChunk = chunks->z( addr, 9 );
+        zChunk = chunks->z( addr, 8 );
         if( zChunk )
         {
             zChunk->setNeighbor( SOUTH, chunk );
@@ -121,7 +120,11 @@ void Dimension::addChunk( Chunk* chunk )
         }
     }
     else
+    {
+        std::cout << "WARNING: chunk duplication at dimension " << dimensionId << " at chunk " << chunk->getCenter().x << ", " << chunk->getCenter().y << "\n";
+        assert( false );
         chunk->release();
+    }
 }
 
 void Dimension::save( Text worldDir ) const

+ 3 - 0
FactoryCraft/DimensionGenerator.cpp

@@ -3,6 +3,8 @@
 #include "Noise.h"
 #include "NoBlock.h"
 
+#include <iostream>
+
 
 DimensionGenerator::DimensionGenerator( BiomInterpolator* interpolator, int dimensionId )
     : ReferenceCounter(),
@@ -50,6 +52,7 @@ void DimensionGenerator::registerBiom( BiomGenerator* generator )
 
 Chunk* DimensionGenerator::generateChunk( Noise* zNoise, Game* zGame, int centerX, int centerY )
 {
+    std::cout << "generating chunk " << centerX << ", " << centerY << "\n";
     Chunk* chunk = new Chunk( Framework::Punkt( centerX, centerY ), zGame, dimensionId );
     for( int x = -CHUNK_SIZE / 2; x < CHUNK_SIZE / 2; x++ )
     {

+ 74 - 50
FactoryCraft/Game.cpp

@@ -11,7 +11,6 @@ GameClient::GameClient( Player* zPlayer, FCKlient* client )
     : ReferenceCounter(),
     zPlayer( zPlayer ),
     client( client ),
-    writer( client->zClient() ),
     viewDistance( DEFAULT_VIEW_DISTANCE ),
     first( 1 ),
     online( 1 )
@@ -22,60 +21,70 @@ GameClient::~GameClient()
     client->release();
 }
 
-void GameClient::sendWorldUpdate( WorldUpdate* zUpdate )
+void GameClient::sendWorldUpdate( WorldUpdate* update )
 {
-    if( zPlayer->getCurrentDimensionId() == zUpdate->getAffectedDimension() )
+    bool add = 0;
+    if( zPlayer->getCurrentDimensionId() == update->getAffectedDimension() )
     {
         auto pos = (Vec3<int>)zPlayer->getPosition();
-        if( abs( pos.x - zUpdate->getMinAffectedPoint().x ) < viewDistance * CHUNK_SIZE || (abs( pos.x - zUpdate->getMaxAffectedPoint().x ) < viewDistance * CHUNK_SIZE) || abs( pos.y - zUpdate->getMinAffectedPoint().y ) < viewDistance * CHUNK_SIZE || (abs( pos.y - zUpdate->getMaxAffectedPoint().y ) < viewDistance * CHUNK_SIZE) )
+        if( abs( pos.x - update->getMinAffectedPoint().x ) < viewDistance * CHUNK_SIZE || (abs( pos.x - update->getMaxAffectedPoint().x ) < viewDistance * CHUNK_SIZE) || abs( pos.y - update->getMinAffectedPoint().y ) < viewDistance * CHUNK_SIZE || (abs( pos.y - update->getMaxAffectedPoint().y ) < viewDistance * CHUNK_SIZE) )
         {
-            cs.Enter();
-            writer.schreibe( (char*)&Message::INGAME_MESSAGE, 1 );
-            writer.schreibe( (char*)&Message::WORLD_UPDATE, 1 );
-            zUpdate->write( &writer );
-            cs.Leave();
+            other.Enter();
+            updateQueue.add( update );
+            other.Leave();
+            add = 1;
         }
     }
+    if( !add )
+        update->release();
 }
 
 void GameClient::reply( Game* zGame )
 {
-    cs.Enter();
+    other.Enter();
     for( auto req : requests )
         zGame->api( req, this );
     requests.leeren();
-    cs.Leave();
+    other.Leave();
     int x = (int)zPlayer->getPosition().x;
     int y = (int)zPlayer->getPosition().y;
     int d = zPlayer->getCurrentDimensionId();
-    cs.Enter();
-    writer.schreibe( (char*)&Message::INGAME_MESSAGE, 1 );
-    writer.schreibe( (char*)&Message::POSITION_UPDATE, 1 );
+    foreground.Enter();
+    client->zForegroundWriter()->schreibe( (char*)&Message::INGAME_MESSAGE, 1 );
+    client->zForegroundWriter()->schreibe( (char*)&Message::POSITION_UPDATE, 1 );
     float f = zPlayer->getPosition().x;
-    writer.schreibe( (char*)&f, 4 );
+    client->zForegroundWriter()->schreibe( (char*)&f, 4 );
     f = zPlayer->getPosition().y;
-    writer.schreibe( (char*)&f, 4 );
+    client->zForegroundWriter()->schreibe( (char*)&f, 4 );
     f = zPlayer->getPosition().z;
-    writer.schreibe( (char*)&f, 4 );
+    client->zForegroundWriter()->schreibe( (char*)&f, 4 );
     f = zPlayer->getFaceDir().x;
-    writer.schreibe( (char*)&f, 4 );
+    client->zForegroundWriter()->schreibe( (char*)&f, 4 );
     f = zPlayer->getFaceDir().y;
-    writer.schreibe( (char*)&f, 4 );
-    cs.Leave();
+    client->zForegroundWriter()->schreibe( (char*)&f, 4 );
+    foreground.Leave();
+    other.Enter();
+    if( updateQueue.hat( 0 ) )
+    {
+        background.Enter();
+        client->zBackgroundWriter()->schreibe( (char*)&Message::INGAME_MESSAGE, 1 );
+        client->zBackgroundWriter()->schreibe( (char*)&Message::WORLD_UPDATE, 1 );
+        updateQueue.z( 0 )->write( client->zBackgroundWriter() );
+        updateQueue.remove( 0 );
+        background.Leave();
+    }
+    other.Leave();
     // send world to client
     if( first )
     {
         first = 0;
-        for( int xP = x - CHUNK_SIZE * viewDistance; x <= x + CHUNK_SIZE * viewDistance; x += CHUNK_SIZE )
+        for( int xP = x - CHUNK_SIZE * viewDistance; xP <= x + CHUNK_SIZE * viewDistance; xP += CHUNK_SIZE )
         {
-            for( int yP = y - CHUNK_SIZE * viewDistance; y <= y + CHUNK_SIZE * viewDistance; y += CHUNK_SIZE )
+            for( int yP = y - CHUNK_SIZE * viewDistance; yP <= y + CHUNK_SIZE * viewDistance; yP += CHUNK_SIZE )
             {
                 Chunk* chunk = zGame->zDimension( d )->zChunk( zGame->getChunkCenter( xP, yP ) );
                 if( chunk )
-                {
-                    AddChunkUpdate update( dynamic_cast<Chunk*>(chunk->getThis()) );
-                    sendWorldUpdate( &update );
-                }
+                    sendWorldUpdate( new AddChunkUpdate( dynamic_cast<Chunk*>(chunk->getThis()) ) );
             }
         }
         zGame->requestArea( { x - CHUNK_SIZE * viewDistance, y - CHUNK_SIZE * viewDistance, x + CHUNK_SIZE * viewDistance, y + CHUNK_SIZE * viewDistance, d } );
@@ -86,22 +95,17 @@ void GameClient::reply( Game* zGame )
         Punkt curMin = zGame->getChunkCenter( x - CHUNK_SIZE * viewDistance, y - CHUNK_SIZE * viewDistance );
         Punkt lastMax = zGame->getChunkCenter( (int)lastPos.x + CHUNK_SIZE * viewDistance, (int)lastPos.y + CHUNK_SIZE * viewDistance );
         Punkt curMax = zGame->getChunkCenter( x + CHUNK_SIZE * viewDistance, y + CHUNK_SIZE * viewDistance );
-        for( int xP = curMin.x; x <= curMax.x; x += CHUNK_SIZE )
+        for( int xP = curMin.x; xP <= curMax.x; xP += CHUNK_SIZE )
         {
-            for( int yP = curMin.y; y <= curMax.y; y += CHUNK_SIZE )
+            for( int yP = curMin.y; yP <= curMax.y; yP += CHUNK_SIZE )
             {
                 if( xP < lastMin.x || xP > lastMax.x || yP < lastMin.y || yP > lastMax.y )
                 {
-                    Chunk* chunk = zGame->zDimension( d )->zChunk( zGame->getChunkCenter( x, y ) );
+                    Chunk* chunk = zGame->zDimension( d )->zChunk( zGame->getChunkCenter( xP, yP ) );
                     if( chunk )
-                    {
-                        AddChunkUpdate update( dynamic_cast<Chunk*>(chunk->getThis()) );
-                        sendWorldUpdate( &update );
-                    }
+                        sendWorldUpdate( new AddChunkUpdate( dynamic_cast<Chunk*>(chunk->getThis()) ) );
                     else
-                    {
-                        zGame->requestArea( zGame->getChunckArea( Punkt( xP, yP ) ) );
-                    }
+                        zGame->requestArea( zGame->getChunckArea( zGame->getChunkCenter( xP, yP ) ) );
                 }
             }
         }
@@ -123,9 +127,9 @@ void GameClient::addMessage( StreamReader* reader )
     reader->lese( tmp, len );
     buffer->schreibe( tmp, len );
     delete[]tmp;
-    cs.Enter();
+    other.Enter();
     requests.add( buffer );
-    cs.Leave();
+    other.Leave();
 }
 
 bool GameClient::isOnline() const
@@ -137,11 +141,22 @@ void GameClient::sendResponse( NetworkResponse* zResponse )
 {
     if( zResponse->isAreaAffected( { lastPos.x - (float)CHUNK_SIZE * (float)viewDistance, lastPos.y - (float)CHUNK_SIZE * (float)viewDistance, 0.f }, { lastPos.x + (float)CHUNK_SIZE * (float)viewDistance, lastPos.y + (float)CHUNK_SIZE * (float)viewDistance, (float)WORLD_HEIGHT } ) )
     {
-        cs.Leave();
-        writer.schreibe( (char*)&Message::INGAME_MESSAGE, 1 );
-        writer.schreibe( (char*)&Message::API_MESSAGE, 1 );
-        zResponse->writeTo( client->zWriter() );
-        cs.Leave();
+        if( zResponse->isUseBackground() )
+        {
+            background.Leave();
+            client->zBackgroundWriter()->schreibe( (char*)&Message::INGAME_MESSAGE, 1 );
+            client->zBackgroundWriter()->schreibe( (char*)&Message::API_MESSAGE, 1 );
+            zResponse->writeTo( client->zBackgroundWriter() );
+            background.Leave();
+        }
+        else
+        {
+            foreground.Leave();
+            client->zForegroundWriter()->schreibe( (char*)&Message::INGAME_MESSAGE, 1 );
+            client->zForegroundWriter()->schreibe( (char*)&Message::API_MESSAGE, 1 );
+            zResponse->writeTo( client->zForegroundWriter() );
+            foreground.Leave();
+        }
     }
 }
 
@@ -224,13 +239,11 @@ void Game::thread()
         while( updates->hat( 0 ) )
         {
             WorldUpdate* update = updates->z( 0 );
-            cs.Leave();
             for( auto client : *clients )
-                client->sendWorldUpdate( update );
+                client->sendWorldUpdate( dynamic_cast<WorldUpdate*>(update->getThis()) );
             if( !zDimension( update->getAffectedDimension() ) )
                 addDimension( new Dimension( update->getAffectedDimension() ) );
             update->onUpdate( zDimension( update->getAffectedDimension() ) );
-            cs.Enter();
             updates->remove( 0 );
         }
         cs.Leave();
@@ -338,9 +351,20 @@ bool Game::isChunkLoaded( int x, int y, int dimension ) const
     return (dim && dim->hasChunck( x, y ));
 }
 
-bool Game::doesChunkExist( int x, int y, int dimension ) const
+bool Game::doesChunkExist( int x, int y, int dimension )
 {
-    return isChunkLoaded( x, y, dimension ) || loader->existsChunk( x, y, dimension );
+    cs.Enter();
+    bool result = isChunkLoaded( x, y, dimension ) || loader->existsChunk( x, y, dimension );
+    if( !result )
+    {
+        for( WorldUpdate* update : *updates )
+        {
+            if( update->getType() == AddChunkUpdateType::ID )
+                result |= ((AddChunkUpdate*)update)->zChunk()->getCenter() == Framework::Punkt( x, y );
+        }
+    }
+    cs.Leave();
+    return result;
 }
 
 Framework::Either<Block*, int> Game::zBlockAt( Framework::Vec3<int> location, int dimension ) const
@@ -363,12 +387,12 @@ Dimension* Game::zDimension( int id ) const
 
 Framework::Punkt Game::getChunkCenter( int x, int y ) const
 {
-    return Punkt( (x / CHUNK_SIZE) * CHUNK_SIZE + (x < 0 ? -CHUNK_SIZE : CHUNK_SIZE) / 2, (y / CHUNK_SIZE) * CHUNK_SIZE + (y < 0 ? -CHUNK_SIZE : CHUNK_SIZE) / 2 );
+    return Punkt( ((x < 0 ? x + 1 : x) / CHUNK_SIZE) * CHUNK_SIZE + (x < 0 ? -CHUNK_SIZE : CHUNK_SIZE) / 2, ((y < 0 ? y + 1 : y) / CHUNK_SIZE) * CHUNK_SIZE + (y < 0 ? -CHUNK_SIZE : CHUNK_SIZE) / 2 );
 }
 
 Area Game::getChunckArea( Punkt center ) const
 {
-    return { center.x - CHUNK_SIZE / 2, center.y - CHUNK_SIZE / 2, center.x + CHUNK_SIZE / 2, center.y + CHUNK_SIZE / 2, 0 };
+    return { center.x - CHUNK_SIZE / 2, center.y - CHUNK_SIZE / 2, center.x + CHUNK_SIZE / 2 - 1, center.y + CHUNK_SIZE / 2 - 1, 0 };
 }
 
 Framework::Text Game::getWorldDirectory() const

+ 6 - 4
FactoryCraft/Game.h

@@ -22,10 +22,12 @@ class GameClient : public virtual Framework::ReferenceCounter
 private:
     Player* zPlayer;
     FCKlient* client;
-    Network::NetworkWriter writer;
-    CriticalSection cs;
+    CriticalSection background;
+    CriticalSection foreground;
+    CriticalSection other;
     RCArray<InMemoryBuffer> requests;
     Vec3<float> lastPos;
+    RCArray<WorldUpdate> updateQueue;
     int viewDistance;
     bool first;
     bool online;
@@ -34,7 +36,7 @@ public:
     GameClient( Player* zPlayer, FCKlient* client );
     ~GameClient();
 
-    void sendWorldUpdate( WorldUpdate* zUpdate );
+    void sendWorldUpdate( WorldUpdate* update );
     void reply( Game* zGame );
     void logout();
     void addMessage( StreamReader* reader );
@@ -78,7 +80,7 @@ public:
     void distributeResponse( NetworkResponse* zResponse );
     void requestWorldUpdate( WorldUpdate* update );
     GameClient* addPlayer( FCKlient* client, Framework::Text name );
-    bool doesChunkExist( int x, int y, int dimension ) const;
+    bool doesChunkExist( int x, int y, int dimension );
     bool isChunkLoaded( int x, int y, int dimension ) const;
     Framework::Either<Block*, int> zBlockAt( Framework::Vec3<int> location, int dimension ) const;
     Dimension* zDimension( int id ) const;

+ 11 - 0
FactoryCraft/NetworkResponse.cpp

@@ -11,6 +11,7 @@ NetworkResponse::NetworkResponse()
     message = 0;
     msgDelete = 0;
     msgLength = 0;
+    useBackground = 0;
 }
 
 NetworkResponse::~NetworkResponse()
@@ -68,6 +69,11 @@ void NetworkResponse::setMessage( char* msg, int length, bool deleteMsg )
     msgDelete = deleteMsg;
 }
 
+void NetworkResponse::setUseBackground()
+{
+    useBackground = 1;
+}
+
 void NetworkResponse::sendToAll()
 {
     broadcast = true;
@@ -99,4 +105,9 @@ bool NetworkResponse::isBroadcast() const
 bool NetworkResponse::isEmpty() const
 {
     return msgLength + adressLength <= 0;
+}
+
+bool NetworkResponse::isUseBackground() const
+{
+    return useBackground;
 }

+ 3 - 0
FactoryCraft/NetworkResponse.h

@@ -18,6 +18,7 @@ private:
     char* message;
     bool msgDelete;
     int msgLength;
+    bool useBackground;
 
 public:
     NetworkResponse();
@@ -27,10 +28,12 @@ public:
     void adressEntity( Entity* zEntity );
     void adressBlock( Block* zBlock );
     void setMessage( char* msg, int length, bool deleteMsg );
+    void setUseBackground();
     void sendToAll();
 
     bool isAreaAffected( Framework::Vec3<float> min, Framework::Vec3<float> max ) const;
     void writeTo( Framework::StreamWriter* zWriter ) const;
     bool isBroadcast() const;
     bool isEmpty() const;
+    bool isUseBackground() const;
 };

+ 139 - 39
FactoryCraft/Server.cpp

@@ -4,6 +4,7 @@
 #include <Globals.h>
 #include <HttpRequest.h>
 #include <JSON.h>
+#include <AsynchronCall.h>
 
 // Inhalt der LoginServer Klasse aus LoginServer.h
 // Konstruktor 
@@ -11,25 +12,76 @@ FactoryCraftServer::FactoryCraftServer( InitDatei* zIni )
     : ReferenceCounter()
 {
     Network::Start( 100 );
+    runningThreads = 0;
     klients = new RCArray< FCKlient >();
-    empfangen = 0;
-    gesendet = 0;
     ini = dynamic_cast<InitDatei*>(zIni->getThis());
     id = *zIni->zWert( "ServerId" );
-    server = new SSLServer();
-    server->setPrivateKeyPassword( zIni->zWert( "SSLPasswort" )->getText() );
-    server->setCertificateFile( zIni->zWert( "SSLCert" )->getText() );
+    sslServer = new SSLServer();
+    sslServer->setPrivateKeyPassword( zIni->zWert( "SSLPasswort" )->getText() );
+    sslServer->setCertificateFile( zIni->zWert( "SSLCert" )->getText() );
     std::cout << "using cert file " << zIni->zWert( "SSLCert" )->getText() << "\n";
-    server->setPrivateKeyFile( zIni->zWert( "SSLKey" )->getText() );
+    sslServer->setPrivateKeyFile( zIni->zWert( "SSLKey" )->getText() );
     std::cout << "using private key " << zIni->zWert( "SSLKey" )->getText() << "\n";
+    server = new Server();
+    std::cout << "Server Port: " << ini->zWert( "Port" )->getText() << "\n";
+    if( !server->verbinde( (unsigned short)TextZuInt( ini->zWert( "Port" )->getText(), 10 ), 10 ) )
+    {
+        std::cout << "Der Server konnte nicht gestartet werden.\n";
+        exit( 1 );
+    }
+    std::cout << "SSL Server Port: " << ini->zWert( "SSLPort" )->getText() << "\n";
+    if( !sslServer->verbinde( (unsigned short)TextZuInt( ini->zWert( "SSLPort" )->getText(), 10 ), 10 ) )
+    {
+        std::cout << "Der SSL Server konnte nicht gestartet werden.\n";
+        exit( 2 );
+    }
     game = new Game( zIni->zWert( "World" )->getText(), zIni->zWert( "SaveDir" )->getText() );
+    new Framework::AsynchronCall( [this]() {
+        runningThreads++;
+        while( server->isConnected() )
+        {
+            SKlient* klient = server->getKlient();
+            if( !klient )
+                continue;
+            unsigned short len;
+            klient->setEmpfangTimeout( 2000 );
+            klient->getNachricht( (char*)&len, 2 );
+            char* key = new char[ len ];
+            klient->getNachricht( (char*)&key, len );
+            bool bg;
+            klient->getNachricht( (char*)&bg, 1 );
+            klient->setEmpfangTimeout( 0 );
+            bool found = 0;
+            EnterCriticalSection( &cs );
+            for( FCKlient* client : *klients )
+            {
+                if( client->matchAuthKey( key, len ) )
+                {
+                    if( bg )
+                        client->setBackgroundClient( klient );
+                    else
+                        client->setForegroundClient( klient );
+                    found = 1;
+                    break;
+                }
+            }
+            LeaveCriticalSection( &cs );
+            if( !found )
+                klient->release();
+        }
+        runningThreads--;
+    } );
     InitializeCriticalSection( &cs );
 }
 
 // Destruktor 
 FactoryCraftServer::~FactoryCraftServer()
 {
+    sslServer->trenne();
     server->trenne();
+    while( runningThreads > 0 )
+        Sleep( 100 );
+    sslServer->release();
     server->release();
     if( klients )
         klients->release();
@@ -42,13 +94,10 @@ FactoryCraftServer::~FactoryCraftServer()
 // nicht constant 
 void FactoryCraftServer::run()
 {
-    if( !server->verbinde( (unsigned short)TextZuInt( ini->zWert( "SSLPort" )->getText(), 10 ), 10 ) )
-        std::cout << "Der Server konnte nicht gestartet werden.\n";
-    else
-        std::cout << "Server Port: " << ini->zWert( "SSLPort" )->getText() << "\n";
-    while( server->isConnected() )
+    runningThreads++;
+    while( sslServer->isConnected() )
     {
-        SSLSKlient* klient = server->getKlient();
+        SSLSKlient* klient = sslServer->getKlient();
         if( !klient )
             continue;
         Framework::getThreadRegister()->cleanUpClosedThreads();
@@ -58,11 +107,12 @@ void FactoryCraftServer::run()
         LeaveCriticalSection( &cs );
         clHandle->start();
     }
+    runningThreads--;
 }
 
 void FactoryCraftServer::close()
 {
-    server->trenne();
+    sslServer->trenne();
     EnterCriticalSection( &cs );
     for( int i = 0; i < klients->getEintragAnzahl(); i++ )
         klients->z( i )->absturz();
@@ -106,16 +156,6 @@ bool FactoryCraftServer::removeKlient( FCKlient* zKlient )
     return gefunden;
 }
 
-void FactoryCraftServer::addGesendet( int bytes )
-{
-    gesendet += bytes;
-}
-
-void FactoryCraftServer::addEmpfangen( int bytes )
-{
-    empfangen += bytes;
-}
-
 bool FactoryCraftServer::hatClients() const
 {
     return klients->hat( 0 );
@@ -126,6 +166,14 @@ Game* FactoryCraftServer::zGame() const
     return game;
 }
 
+char* randomKey( int& len )
+{
+    len = 1024 + (int)(((double)rand() / RAND_MAX - 0.5) * 512);
+    char* key = new char[ len ];
+    for( int i = 0; i < len; i++ )
+        key[ i ] = (char)(((double)rand() / RAND_MAX) * 256);
+    return key;
+}
 
 // Inhalt der LSKlient aus LoginServer.h
 // Konstruktor
@@ -133,10 +181,16 @@ FCKlient::FCKlient( SSLSKlient* klient, FactoryCraftServer* ls )
     : Thread()
 {
     this->klient = klient;
+    background = 0;
+    foreground = 0;
     accountId = 0;
     this->ls = ls;
-    reader = new NetworkReader( klient );
-    writer = new NetworkWriter( klient );
+    zGameClient = 0;
+    backgroundReader = 0;
+    foregroundReader = 0;
+    backgroundWriter = 0;
+    foregroundWriter = 0;
+    authKey = randomKey( authKeyLen );
 }
 
 // Destruktor 
@@ -147,13 +201,52 @@ FCKlient::~FCKlient()
         zGameClient->logout();
         zGameClient = (GameClient*)zGameClient->release();
     }
-    delete reader;
-    delete writer;
+    if( background )
+        background->release();
+    if( foreground )
+        foreground->release();
+    delete backgroundReader;
+    delete foregroundReader;
+    delete backgroundWriter;
+    delete foregroundWriter;
     klient->release();
     ls->release();
+    delete[] authKey;
 }
 
 // nicht constant 
+void FCKlient::setForegroundClient( SKlient* foreground )
+{
+    this->foreground = foreground;
+    if( foreground && background )
+        zGameClient = ls->zGame()->addPlayer( dynamic_cast<FCKlient*>(getThis()), Framework::Text( (int)accountId ) );
+    new AsynchronCall( [this]() {
+        while( this->foreground->waitForNextMessage() )
+        {
+            if( zGameClient )
+                zGameClient->addMessage( foregroundReader );
+            if( !zGameClient )
+                Sleep( 100 );
+        }
+    } );
+}
+
+void FCKlient::setBackgroundClient( SKlient* background )
+{
+    this->background = background;
+    if( foreground && background )
+        zGameClient = ls->zGame()->addPlayer( dynamic_cast<FCKlient*>(getThis()), Framework::Text( (int)accountId ) );
+    new AsynchronCall( [this]() {
+        while( this->background->waitForNextMessage() )
+        {
+            if( zGameClient )
+                zGameClient->addMessage( backgroundReader );
+            if( !zGameClient )
+                Sleep( 100 );
+        }
+    } );
+}
+
 void FCKlient::absturz()
 {
     ende();
@@ -205,7 +298,6 @@ void FCKlient::thread()
                                     zGameClient = (GameClient*)zGameClient->release();
                                 }
                                 klient->sende( "\1", 1 );
-                                zGameClient = ls->zGame()->addPlayer( dynamic_cast<FCKlient*>(getThis()), Text( accountId ) );
                                 ok = true;
                             }
                         }
@@ -228,19 +320,13 @@ void FCKlient::thread()
                 klient->sende( "\1", 1 );
                 break;
             default:
-                if( zGameClient )
-                    zGameClient->addMessage( reader );
+                br = 1;
                 break;
             }
             if( br )
                 break;
-            ls->addEmpfangen( klient->getDownloadBytes( 1 ) );
-            ls->addGesendet( klient->getUploadBytes( 1 ) );
         }
     }
-    ls->addEmpfangen( klient->getDownloadBytes( 1 ) );
-    ls->addGesendet( klient->getUploadBytes( 1 ) );
-    ls->removeKlient( this ); // delete this
 }
 
 int FCKlient::getAccountId() const // gibt die KlientId zurück
@@ -248,12 +334,26 @@ int FCKlient::getAccountId() const // gibt die KlientId zur
     return accountId;
 }
 
-SSLSKlient* FCKlient::zClient() const
+NetworkWriter* FCKlient::zBackgroundWriter() const
 {
-    return klient;
+    return backgroundWriter;
 }
 
-NetworkWriter* FCKlient::zWriter() const
+NetworkWriter* FCKlient::zForegroundWriter() const
 {
-    return writer;
+    return foregroundWriter;
+}
+
+bool FCKlient::matchAuthKey( char* key, int len ) const
+{
+    if( foreground && background )
+        return 0;
+    if( len != authKeyLen )
+        return 0;
+    for( int i = 0; i < len; i++ )
+    {
+        if( key[ i ] != authKey[ i ] )
+            return 0;
+    }
+    return 1;
 }

+ 16 - 9
FactoryCraft/Server.h

@@ -17,14 +17,14 @@ class GameClient;
 class FactoryCraftServer : virtual public ReferenceCounter
 {
 private:
-    SSLServer* server;
+    SSLServer* sslServer;
+    Server* server;
     InitDatei* ini;
     CRITICAL_SECTION cs;
     RCArray< FCKlient >* klients;
     Game* game;
+    int runningThreads;
     int id;
-    int empfangen;
-    int gesendet;
 
 public:
     // Konstruktor 
@@ -36,8 +36,6 @@ public:
     void close();
     bool absturzKlient( int accountId );
     bool removeKlient( FCKlient* zKlient );
-    void addGesendet( int bytes );
-    void addEmpfangen( int bytes );
     bool hatClients() const;
     Game* zGame() const;
 };
@@ -46,22 +44,31 @@ class FCKlient : public Thread
 {
 private:
     SSLSKlient* klient;
+    SKlient* background;
+    SKlient* foreground;
     unsigned int accountId;
     FactoryCraftServer* ls;
     GameClient* zGameClient;
-    NetworkReader* reader;
-    NetworkWriter* writer;
+    NetworkReader* backgroundReader;
+    NetworkReader* foregroundReader;
+    NetworkWriter* backgroundWriter;
+    NetworkWriter* foregroundWriter;
+    char* authKey;
+    int authKeyLen;
 
 public:
     // Konstruktor 
     FCKlient( SSLSKlient* klient, FactoryCraftServer* ls );
     // Destruktor 
     virtual ~FCKlient();
+    void setForegroundClient( SKlient* foreground );
+    void setBackgroundClient( SKlient* background );
     // nicht constant 
     void absturz();
     void thread();
     // constant
     int getAccountId() const;
-    SSLSKlient* zClient() const;
-    NetworkWriter* zWriter() const;
+    NetworkWriter* zBackgroundWriter() const;
+    NetworkWriter* zForegroundWriter() const;
+    bool matchAuthKey( char* key, int len ) const;
 };

+ 1 - 1
FactoryCraft/Start.cpp

@@ -50,7 +50,7 @@ int main()
         std::cout.rdbuf( sbuf );
         exit( 1 );
     }
-    const char* wichtig[] = { "SSLPort", "SSLCert", "SSLKey", "SSLPasswort" };
+    const char* wichtig[] = { "SSLPort", "SSLCert", "SSLKey", "SSLPasswort", "Port" };
     for( const char* w : wichtig )
     {
         if( !dat->wertExistiert( w ) )

+ 8 - 2
FactoryCraft/WorldUpdate.cpp

@@ -1,10 +1,11 @@
 #include "WorldUpdate.h"
 
-WorldUpdate::WorldUpdate( int dimensionId, Framework::Vec3<int> minAffected, Framework::Vec3<int> maxAffected )
+WorldUpdate::WorldUpdate( int type, int dimensionId, Framework::Vec3<int> minAffected, Framework::Vec3<int> maxAffected )
     : ReferenceCounter(),
     affectedDimensionId( dimensionId ),
     minAffected( minAffected ),
-    maxAffected( maxAffected )
+    maxAffected( maxAffected ),
+    type( type )
 {}
 
 int WorldUpdate::getAffectedDimension() const
@@ -22,6 +23,11 @@ const Framework::Vec3<int>& WorldUpdate::getMaxAffectedPoint() const
     return maxAffected;
 }
 
+int WorldUpdate::getType() const
+{
+    return type;
+}
+
 
 WorldUpdateType::WorldUpdateType( int id )
     : ReferenceCounter()

+ 3 - 1
FactoryCraft/WorldUpdate.h

@@ -14,9 +14,10 @@ private:
     int affectedDimensionId;
     Framework::Vec3<int> minAffected;
     Framework::Vec3<int> maxAffected;
+    int type;
 
 public:
-    WorldUpdate( int dimensionId, Framework::Vec3<int> minAffected, Framework::Vec3<int> maxAffected );
+    WorldUpdate( int type, int dimensionId, Framework::Vec3<int> minAffected, Framework::Vec3<int> maxAffected );
 
     virtual void onUpdate( Dimension* zDimension ) = 0;
     virtual void write( Framework::StreamWriter* zWriter ) = 0;
@@ -24,6 +25,7 @@ public:
     int getAffectedDimension() const;
     const Framework::Vec3<int>& getMinAffectedPoint() const;
     const Framework::Vec3<int>& getMaxAffectedPoint() const;
+    int getType() const;
 };
 
 class WorldUpdateType : public Framework::ReferenceCounter