Browse Source

implement basic network api design

Kolja Strohm 3 years ago
parent
commit
172f61f656

+ 11 - 0
FactoryCraft/Block.cpp

@@ -19,6 +19,7 @@ Block::Block( const BlockType *zType, ItemType *zTool, Framework::Vec3<int> pos
     maxTickTimeout = -1;
     tickSource = 0;
     currentTickTimeout = 0;
+    dimansionId = 0;
 }
 
 void Block::tick( TickQueue *zQueue )
@@ -60,6 +61,11 @@ void Block::postTick()
     }
 }
 
+void Block::setDimensionId( int id )
+{
+    dimansionId = id;
+}
+
 bool Block::isTickSource() const
 {
     return tickSource;
@@ -110,6 +116,11 @@ const Framework::Vec3<int> Block::getPos() const
     return location;
 }
 
+int Block::getDimensionId() const
+{
+    return dimansionId;
+}
+
 
 BasicBlockItem::BasicBlockItem( const ItemType *zType, const char *name )
     : Item( zType, name )

+ 6 - 0
FactoryCraft/Block.h

@@ -6,6 +6,7 @@
 #include "EventThrower.h"
 #include "Item.h"
 #include "Inventory.h"
+#include "NetworkResponse.h"
 
 #include <Trie.h>
 #include <Vec3.h>
@@ -24,6 +25,7 @@ private:
     int currentTickTimeout;
     bool wasTicked;
     bool onTickCalled;
+    int dimansionId;
 
 protected:
     bool transparent;
@@ -59,6 +61,9 @@ public:
 
     void tick( TickQueue *zQueue );
     void postTick();
+    void setDimensionId( int id );
+
+    void api( Framework::StreamReader *zRequest, NetworkResponse *zResponse );
 
     bool isTickSource() const;
     const BlockType *zBlockType() const;
@@ -70,6 +75,7 @@ public:
     ItemType *zEffectiveTool() const;
     float getSpeedModifier() const;
     const Framework::Vec3<int> getPos() const;
+    int getDimensionId() const;
 
     friend Chunk;
     friend BlockType;

+ 15 - 0
FactoryCraft/Chunk.cpp

@@ -33,6 +33,11 @@ Chunk::~Chunk()
     delete[] blocks;
 }
 
+void Chunk::api( Framework::StreamReader *zRequest, NetworkResponse *zResponse )
+{
+    // TODO: answer api messages
+}
+
 Block *Chunk::getBlockAt( Framework::Vec3<int> location ) const
 {
     location.x += CHUNK_SIZE / 2;
@@ -178,6 +183,16 @@ Framework::Punkt Chunk::getCenter() const
     return location;
 }
 
+Framework::Vec3<int> Chunk::getMin() const
+{
+    return { location.x - CHUNK_SIZE / 2, location.y - CHUNK_SIZE / 2, 0 };
+}
+
+Framework::Vec3<int> Chunk::getMax() const
+{
+    return { location.x + CHUNK_SIZE / 2, location.y + CHUNK_SIZE / 2, WORLD_HEIGHT };
+}
+
 Game *Chunk::zGameObj() const
 {
     return zGame;

+ 5 - 0
FactoryCraft/Chunk.h

@@ -23,6 +23,9 @@ public:
     Chunk( Framework::Punkt location, Game *zGame, int dimensionId );
     Chunk( Framework::Punkt location, Game *zGame, int dimensionId, Framework::StreamReader *zReader );
     ~Chunk();
+
+    void api( Framework::StreamReader *zRequest, NetworkResponse *zResponse );
+
     Block *getBlockAt( Framework::Vec3<int> cLocation ) const;
     Block *zBlockAt( Framework::Vec3<int> cLocation ) const;
     void putBlockAt( Framework::Vec3<int> location, Block *block );
@@ -31,5 +34,7 @@ public:
     void save( Framework::StreamWriter *zWriter );
     int getDimensionId() const;
     Framework::Punkt getCenter() const;
+    Framework::Vec3<int> getMin() const;
+    Framework::Vec3<int> getMax() const;
     Game *zGameObj() const;
 };

+ 6 - 1
FactoryCraft/Dimension.cpp

@@ -18,13 +18,18 @@ Dimension::~Dimension()
     chunks->release();
 }
 
+void Dimension::api( Framework::StreamReader *zRequest, NetworkResponse *zResponse )
+{
+    // TODO: switch type chunck, block, entity
+}
+
 void Dimension::tickEntities( Game *zGame )
 {
     int index = 0;
     Array<int> removed;
     for( auto entity = entities->getIterator(); entity; entity++, index++ )
     {
-        if( zChunk( Punkt( entity->getPosition().x, entity->getPosition().y ) ) )
+        if( zChunk( Punkt( (int)entity->getPosition().x, (int)entity->getPosition().y ) ) )
             entity->tick( this, zGame );
         if( entity->isRemoved() )
             removed.add( index, 0 );

+ 4 - 1
FactoryCraft/Dimension.h

@@ -1,8 +1,10 @@
 #pragma once
 
 #include <Punkt.h>
+#include <Reader.h>
 
 #include "Chunk.h"
+#include "NetworkResponse.h"
 
 class Dimension : public virtual Framework::ReferenceCounter
 {
@@ -12,12 +14,12 @@ private:
     Framework::RCArray<Entity> *entities;
     void getAddrOf( Framework::Punkt cPos, char *addr ) const;
     void getAddrOfWorld( Framework::Punkt wPos, char *addr ) const;
-    Chunk *zChunk( Framework::Punkt wPos ) const;
 
 public:
     Dimension( int id );
     ~Dimension();
 
+    void api( Framework::StreamReader *zRequest, NetworkResponse *zResponse );
     void tickEntities( Game *zGame );
 
     Block *zBlock( Framework::Vec3<int> location );
@@ -26,4 +28,5 @@ public:
     void save( Framework::Text worldDir ) const;
     int getDimensionId() const;
     bool hasChunck( int x, int y ) const;
+    Chunk *zChunk( Framework::Punkt wPos ) const;
 };

+ 13 - 2
FactoryCraft/Entity.cpp

@@ -1,10 +1,11 @@
 #include "Entity.h"
 
-Entity::Entity( const EntityType *zType, Framework::Vec3<float> location, int dimensionId )
+Entity::Entity( const EntityType *zType, Framework::Vec3<float> location, int dimensionId, int entityId )
     : Inventory( location ),
     zEntityType( zType ),
     currentDimensionId( dimensionId ),
-    removed( 0 )
+    removed( 0 ),
+    id( entityId )
 {}
 
 void Entity::onDeath()
@@ -15,6 +16,11 @@ void Entity::tick( const Dimension *zDimension, Game *zGame )
     // TODO
 }
 
+void Entity::api( Framework::StreamReader *zRequest, NetworkResponse *zResponse )
+{
+    // TODO: answer api requests
+}
+
 void Entity::setPosition( Framework::Vec3<float> pos )
 {
     location = pos;
@@ -84,3 +90,8 @@ const EntityType *Entity::zType() const
 {
     return zEntityType;
 }
+
+int Entity::getId() const
+{
+    return id;
+}

+ 6 - 1
FactoryCraft/Entity.h

@@ -5,6 +5,7 @@
 
 #include "Effect.h"
 #include "Inventory.h"
+#include "NetworkResponse.h"
 
 class EntityType;
 class Dimension;
@@ -25,13 +26,16 @@ protected:
     const EntityType *zEntityType;
     int currentDimensionId;
     bool removed;
+    int id;
 
     virtual void onDeath();
-    Entity( const EntityType *zType, Framework::Vec3<float> location, int dimensionId );
+    Entity( const EntityType *zType, Framework::Vec3<float> location, int dimensionId, int entityId );
 
 public:
     virtual void tick( const Dimension *zDimension, Game *zGame );
 
+    virtual void api( Framework::StreamReader *zRequest, NetworkResponse *zResponse );
+
     void setPosition( Framework::Vec3<float> pos );
     float getMaxHP() const;
     float getCurrentHP() const;
@@ -47,6 +51,7 @@ public:
     bool isRemoved() const;
 
     const EntityType *zType() const;
+    int getId() const;
 
     friend Effect;
     friend EntityType;

+ 5 - 2
FactoryCraft/EntityType.cpp

@@ -1,5 +1,6 @@
 #include "EntityType.h"
 #include "Entity.h"
+#include "Game.h"
 
 EntityType::EntityType( int id )
     : ReferenceCounter(),
@@ -11,6 +12,7 @@ EntityType::EntityType( int id )
 void EntityType::loadSuperEntity( Entity *zEntity, Framework::StreamReader *zReader ) const
 {
     zEntity->loadInventory( zReader );
+    zReader->lese( (char *)&zEntity->id, 4 );
     zReader->lese( (char *)&zEntity->maxHP, 4 );
     zReader->lese( (char *)&zEntity->currentHP, 4 );
     zReader->lese( (char *)&zEntity->stamina, 4 );
@@ -28,6 +30,7 @@ void EntityType::loadSuperEntity( Entity *zEntity, Framework::StreamReader *zRea
 void EntityType::saveSuperEntity( Entity *zEntity, Framework::StreamWriter *zWriter ) const
 {
     zEntity->saveInventory( zWriter );
+    zWriter->schreibe( (char *)&zEntity->id, 4 );
     zWriter->schreibe( (char *)&zEntity->maxHP, 4 );
     zWriter->schreibe( (char *)&zEntity->currentHP, 4 );
     zWriter->schreibe( (char *)&zEntity->stamina, 4 );
@@ -47,7 +50,7 @@ void EntityType::createSuperEntity( Entity *zEntity ) const
 
 Entity *EntityType::loadEntity( Game *zTarget, Framework::StreamReader *zReader ) const
 {
-    Entity *entity = createEntity( Framework::Vec3<float>( 0, 0, 0 ), 0, zTarget );
+    Entity *entity = createEntity( Framework::Vec3<float>( 0, 0, 0 ), 0, zTarget, 0 );
     loadSuperEntity( entity, zReader );
     return entity;
 }
@@ -59,7 +62,7 @@ void EntityType::saveEntity( Entity *zEntity, Framework::StreamWriter *zWriter )
 
 Entity *EntityType::createEntityAt( Framework::Vec3<float> position, int dimensionId, Game *zTarget ) const
 {
-    Entity *entity = createEntity( position, dimensionId, zTarget );
+    Entity *entity = createEntity( position, dimensionId, zTarget, zTarget->getNextEntityId() );
     createSuperEntity( entity );
     return entity;
 }

+ 1 - 1
FactoryCraft/EntityType.h

@@ -21,7 +21,7 @@ protected:
     virtual void loadSuperEntity( Entity *zEntity, Framework::StreamReader *zReader ) const;
     virtual void saveSuperEntity( Entity *zEntity, Framework::StreamWriter *zWriter ) const;
     virtual void createSuperEntity( Entity *zEntity ) const;
-    virtual Entity *createEntity( Framework::Vec3<float> position, int dimensionId, Game *zTarget ) const = 0;
+    virtual Entity *createEntity( Framework::Vec3<float> position, int dimensionId, Game *zTarget, int entityId ) const = 0;
 
 public:
     virtual Entity *loadEntity( Game *zTarget, Framework::StreamReader *zReader ) const;

+ 6 - 1
FactoryCraft/FactoryCraft.vcxproj

@@ -116,6 +116,7 @@
     <ClInclude Include="ItemSlot.h" />
     <ClInclude Include="ItemStack.h" />
     <ClInclude Include="ItemType.h" />
+    <ClInclude Include="NetworkResponse.h" />
     <ClInclude Include="Noise.h" />
     <ClInclude Include="OverworldDimension.h" />
     <ClInclude Include="PerlinNoise.h" />
@@ -152,6 +153,7 @@
     <ClCompile Include="ItemSlot.cpp" />
     <ClCompile Include="ItemStack.cpp" />
     <ClCompile Include="ItemType.cpp" />
+    <ClCompile Include="NetworkResponse.cpp" />
     <ClCompile Include="Noise.cpp" />
     <ClCompile Include="OverworldDimension.cpp" />
     <ClCompile Include="PerlinNoise.cpp" />
@@ -174,7 +176,7 @@
       <OutputFile>$(RemoteProjectDir)/$(TargetName)$(TargetExt)</OutputFile>
     </Link>
     <ClCompile>
-      <CppLanguageStandard>c++11</CppLanguageStandard>
+      <CppLanguageStandard>c++17</CppLanguageStandard>
     </ClCompile>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -183,6 +185,9 @@
       <LibraryDependencies>Framework;Network;pthread;ssl</LibraryDependencies>
       <AdditionalOptions>-Wl,-rpath,../lib %(AdditionalOptions)</AdditionalOptions>
     </Link>
+    <ClCompile>
+      <CppLanguageStandard>c++17</CppLanguageStandard>
+    </ClCompile>
   </ItemDefinitionGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets" />

+ 9 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -49,6 +49,9 @@
     <Filter Include="inventory">
       <UniqueIdentifier>{4d2e1a89-01ec-4f99-8aed-62d2e9707db9}</UniqueIdentifier>
     </Filter>
+    <Filter Include="server\response">
+      <UniqueIdentifier>{bc887e43-0958-4685-91b8-670eee24b5c0}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Chunk.h">
@@ -162,6 +165,9 @@
     <ClInclude Include="Server.h">
       <Filter>server</Filter>
     </ClInclude>
+    <ClInclude Include="NetworkResponse.h">
+      <Filter>server\response</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -266,5 +272,8 @@
     <ClCompile Include="Game.cpp">
       <Filter>game</Filter>
     </ClCompile>
+    <ClCompile Include="NetworkResponse.cpp">
+      <Filter>server\response</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 139 - 8
FactoryCraft/Game.cpp

@@ -2,6 +2,7 @@
 #include "Zeit.h"
 #include "Player.h"
 #include "OverworldDimension.h"
+#include "AddChunkUpdate.h"
 
 using namespace Framework;
 
@@ -10,6 +11,8 @@ GameClient::GameClient( Player *zPlayer, FCKlient *client )
     zPlayer( zPlayer ),
     client( client ),
     writer( client->zClient() ),
+    viewDistance( 5 ),
+    first( 1 ),
     online( 1 )
 {}
 
@@ -20,21 +23,75 @@ GameClient::~GameClient()
 
 void GameClient::sendWorldUpdate( WorldUpdate *zUpdate )
 {
-    cs.Enter();
-    writer.schreibe( (char *)&Message::WORLD_UPDATE, 1 );
-    zUpdate->write( &writer );
-    cs.Leave();
+    if( zPlayer->getCurrentDimensionId() == zUpdate->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 ) )
+        {
+            cs.Enter();
+            writer.schreibe( (char *)&Message::INGAME_MESSAGE, 1 );
+            writer.schreibe( (char *)&Message::WORLD_UPDATE, 1 );
+            zUpdate->write( &writer );
+            cs.Leave();
+        }
+    }
 }
 
 void GameClient::reply( Game *zGame )
 {
     cs.Enter();
     for( auto req = requests.getIterator(); req; req++ )
-    {
-        // TODO
-    }
+        zGame->api( req, this );
     requests.leeren();
     cs.Leave();
+    int x = (int)zPlayer->getPosition().x;
+    int y = (int)zPlayer->getPosition().y;
+    int d = zPlayer->getCurrentDimensionId();
+    // 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 yP = y - CHUNK_SIZE * viewDistance; y <= y + CHUNK_SIZE * viewDistance; y += CHUNK_SIZE )
+            {
+                Chunk *chunk = zGame->zDimension( d )->zChunk( zGame->getChunkCenter( xP, yP ) );
+                if( chunk )
+                {
+                    AddChunkUpdate update( dynamic_cast<Chunk *>( chunk->getThis() ) );
+                    sendWorldUpdate( &update );
+                }
+            }
+        }
+        zGame->requestArea( { x - CHUNK_SIZE * viewDistance, y - CHUNK_SIZE * viewDistance, x + CHUNK_SIZE * viewDistance, y + CHUNK_SIZE * viewDistance, d } );
+    }
+    else
+    {
+        Punkt lastMin = zGame->getChunkCenter( (int)lastPos.x - CHUNK_SIZE * viewDistance, (int)lastPos.y - CHUNK_SIZE * viewDistance );
+        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 yP = curMin.y; y <= curMax.y; y += 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 ) );
+                    if( chunk )
+                    {
+                        AddChunkUpdate update( dynamic_cast<Chunk *>( chunk->getThis() ) );
+                        sendWorldUpdate( &update );
+                    }
+                    else
+                    {
+                        zGame->requestArea( zGame->getChunckArea( Punkt( xP, yP ) ) );
+                    }
+                }
+            }
+        }
+    }
+    lastPos = zPlayer->getPosition();
 }
 
 void GameClient::logout()
@@ -61,6 +118,18 @@ bool GameClient::isOnline() const
     return online;
 }
 
+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();
+    }
+}
+
 Player *GameClient::zEntity() const
 {
     return zPlayer;
@@ -78,10 +147,19 @@ Game::Game( Framework::Text name, Framework::Text worldsDir )
     ticker( new TickOrganizer() ),
     path( (const char *)( worldsDir + "/" + name ) ),
     stop( 0 ),
-    tickId( 0 )
+    tickId( 0 ),
+    nextEntityId( 0 )
 {
     if( !DateiExistiert( worldsDir + "/" + name ) )
         DateiPfadErstellen( worldsDir + "/" + name + "/" );
+    Datei d;
+    d.setDatei( path + "/eid" );
+    if( d.existiert() )
+    {
+        d.open( Datei::Style::lesen );
+        d.lese( (char *)&nextEntityId, 4 );
+        d.close();
+    }
     int seed = 0;
     int index = 0;
     for( char *n = name; n; n++ )
@@ -145,6 +223,41 @@ void Game::thread()
     save();
 }
 
+void Game::api( Framework::StreamReader *zRequest, GameClient *zOrigin )
+{
+    char type;
+    zRequest->lese( &type, 1 );
+    NetworkResponse response;
+    switch( type )
+    {
+    case 1: // world
+    {
+        int dimensionId;
+        zRequest->lese( (char *)&dimensionId, 4 );
+        Dimension *dim = zDimension( dimensionId );
+        if( !dim )
+        {
+            dim = new Dimension( dimensionId );
+            addDimension( dim );
+        }
+        dim->api( zRequest, &response );
+        break;
+    }
+    default:
+        std::cout << "received unknown api request in game with type " << (int)type << "\n";
+    }
+    if( response.isBroadcast() )
+        distributeResponse( &response );
+    else
+        zOrigin->sendResponse( &response );
+}
+
+void Game::distributeResponse( NetworkResponse *zResponse )
+{
+    for( auto client = clients->getIterator(); client; client++ )
+        client->sendResponse( zResponse );
+}
+
 void Game::requestWorldUpdate( WorldUpdate *update )
 {
     cs.Enter();
@@ -210,6 +323,11 @@ Framework::Punkt Game::getChunkCenter( int x, int y ) const
     return Punkt( (int)floor( ( (float)x + CHUNK_SIZE / 2 ) / CHUNK_SIZE ), (int)floor( ( (float)y + CHUNK_SIZE / 2 ) / CHUNK_SIZE ) );
 }
 
+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 };
+}
+
 Framework::Text Game::getWorldDirectory() const
 {
     return path;
@@ -223,6 +341,11 @@ void Game::requestArea( Area area )
 
 void Game::save() const
 {
+    Datei d;
+    d.setDatei( path + "/eid" );
+    d.open( Datei::Style::schreiben );
+    d.schreibe( (char *)&nextEntityId, 4 );
+    d.close();
     for( auto dim = dimensions->getIterator(); dim; dim++ )
         dim->save( path );
 }
@@ -237,3 +360,11 @@ void Game::addDimension( Dimension *d )
 {
     dimensions->add( d );
 }
+
+int Game::getNextEntityId()
+{
+    cs.Enter();
+    int result = nextEntityId++;
+    cs.Leave();
+    return result;
+}

+ 14 - 2
FactoryCraft/Game.h

@@ -3,6 +3,7 @@
 #include <Text.h>
 #include <Punkt.h>
 #include <Thread.h>
+#include <Network.h>
 
 #include "Dimension.h"
 #include "Player.h"
@@ -21,9 +22,12 @@ class GameClient : public virtual Framework::ReferenceCounter
 private:
     Player *zPlayer;
     FCKlient *client;
-    NetworkWriter writer;
+    Network::NetworkWriter writer;
     CriticalSection cs;
     RCArray<InMemoryBuffer> requests;
+    Vec3<float> lastPos;
+    int viewDistance;
+    bool first;
     bool online;
 
 public:
@@ -35,13 +39,16 @@ public:
     void logout();
     void addMessage( StreamReader *reader );
     bool isOnline() const;
+    void sendResponse( NetworkResponse *zResponse );
     Player *zEntity() const;
 
 private:
     class Message
     {
     public:
-        static const unsigned char WORLD_UPDATE = 2;
+        inline const static unsigned char INGAME_MESSAGE = 0;
+        inline const static unsigned char WORLD_UPDATE = 2;
+        inline const static unsigned char API_MESSAGE = 3;
     };
 };
 
@@ -59,20 +66,25 @@ private:
     bool stop;
     __int64 tickId;
     CriticalSection cs;
+    int nextEntityId;
 
     void thread() override;
 public:
     Game( Framework::Text name, Framework::Text worldsDir );
     ~Game();
+    void api( Framework::StreamReader *zRequest, GameClient *zOrigin );
+    void distributeResponse( NetworkResponse *zResponse );
     void requestWorldUpdate( WorldUpdate *update );
     GameClient *addPlayer( FCKlient *client, Framework::Text name );
     bool doesChunkExist( int x, int y, int dimension ) const;
     Block *zBlockAt( Framework::Vec3<int> location, int dimension ) const;
     Dimension *zDimension( int id ) const;
     Framework::Punkt getChunkCenter( int x, int y ) const;
+    Area getChunckArea( Punkt center ) const;
     Framework::Text getWorldDirectory() const;
     void requestArea( Area area );
     void save() const;
     void requestStop();
     void addDimension( Dimension *d );
+    int getNextEntityId();
 };

+ 97 - 0
FactoryCraft/NetworkResponse.cpp

@@ -0,0 +1,97 @@
+#include "NetworkResponse.h"
+#include "Chunk.h"
+#include "Entity.h"
+#include "Game.h"
+
+NetworkResponse::NetworkResponse()
+{
+    adress = 0;
+    adressLength = 0;
+    broadcast = 0;
+    message = 0;
+    msgDelete = 0;
+    msgLength = 0;
+}
+
+NetworkResponse::~NetworkResponse()
+{
+    if( msgDelete )
+        delete[] message;
+    delete[] adress;
+}
+
+void NetworkResponse::adressChunck( Chunk *zChunk )
+{
+    adressLength = 14;
+    adress = new char[ adressLength ];
+    adress[ 0 ] = 1; // world response
+    *(int *)( adress + 1 ) = zChunk->getDimensionId();
+    adress[ 5 ] = 1; // chunck
+    Framework::Punkt center = zChunk->getCenter();
+    *(int *)( adress + 6 ) = center.x;
+    *(int *)( adress + 10 ) = center.y;
+    minPosition = zChunk->getMin();
+    maxPosition = zChunk->getMax();
+}
+
+void NetworkResponse::adressEntity( Entity *zEntity )
+{
+    adressLength = 10;
+    adress = new char[ adressLength ];
+    adress[ 0 ] = 1; // world response
+    *(int *)( adress + 1 ) = zEntity->getCurrentDimensionId();
+    adress[ 5 ] = 2; // entity
+    *(int *)( adress + 6 ) = zEntity->getId();
+    minPosition = zEntity->getPosition();
+    maxPosition = zEntity->getPosition();
+}
+
+void NetworkResponse::adressBlock( Block *zBlock )
+{
+    adressLength = 18;
+    adress = new char[ adressLength ];
+    adress[ 0 ] = 1; // world response
+    *(int *)( adress + 1 ) = zBlock->getDimensionId();
+    adress[ 5 ] = 3; // block
+    Framework::Vec3<int> pos = zBlock->getPos();
+    *(int *)( adress + 6 ) = pos.x;
+    *(int *)( adress + 10 ) = pos.y;
+    *(int *)( adress + 14 ) = pos.z;
+    minPosition = pos;
+    maxPosition = pos;
+}
+
+void NetworkResponse::setMessage( char *msg, int length, bool deleteMsg )
+{
+    message = msg;
+    msgLength = length;
+    msgDelete = deleteMsg;
+}
+
+void NetworkResponse::sendToAll()
+{
+    broadcast = true;
+}
+
+bool NetworkResponse::isAreaAffected( Framework::Vec3<float> min, Framework::Vec3<float> max ) const
+{
+    return minPosition.x <= max.x && maxPosition.x >= min.x &&
+        minPosition.y <= max.y && maxPosition.y >= min.y &&
+        minPosition.z <= max.z && maxPosition.z >= min.z;
+}
+
+void NetworkResponse::writeTo( Framework::StreamWriter *zWriter ) const
+{
+    int total = msgLength + adressLength;
+    if( total )
+    {
+        zWriter->schreibe( (char *)&total, 4 );
+        zWriter->schreibe( adress, adressLength );
+        zWriter->schreibe( message, msgLength );
+    }
+}
+
+bool NetworkResponse::isBroadcast() const
+{
+    return broadcast;
+}

+ 35 - 0
FactoryCraft/NetworkResponse.h

@@ -0,0 +1,35 @@
+#pragma once
+
+#include <Writer.h>
+#include <Vec3.h>
+
+class Chunk;
+class Block;
+class Entity;
+
+class NetworkResponse
+{
+private:
+    char *adress;
+    char adressLength;
+    Framework::Vec3<float> minPosition;
+    Framework::Vec3<float> maxPosition;
+    bool broadcast;
+    char *message;
+    bool msgDelete;
+    int msgLength;
+
+public:
+    NetworkResponse();
+    ~NetworkResponse();
+
+    void adressChunck( Chunk *zChunk );
+    void adressEntity( Entity *zEntity );
+    void adressBlock( Block *zBlock );
+    void setMessage( char *msg, int length, bool deleteMsg );
+    void sendToAll();
+
+    bool isAreaAffected( Framework::Vec3<float> min, Framework::Vec3<float> max ) const;
+    void writeTo( Framework::StreamWriter *zWriter ) const;
+    bool isBroadcast() const;
+};

+ 10 - 4
FactoryCraft/Player.cpp

@@ -1,7 +1,8 @@
 #include "Player.h"
+#include "Game.h"
 
-Player::Player( Framework::Vec3<float> location, int dimensionId )
-    : Entity( PlayerEntityType::INSTANCE, location, dimensionId )
+Player::Player( Framework::Vec3<float> location, int dimensionId, int entityId )
+    : Entity( PlayerEntityType::INSTANCE, location, dimensionId, entityId )
 {}
 
 void Player::setName( Framework::Text name )
@@ -14,6 +15,11 @@ const char *Player::getName() const
     return name;
 }
 
+void Player::api( Framework::StreamReader *zRequest, NetworkResponse *zResponse )
+{
+    // TODO: answer API calls
+}
+
 PlayerEntityType::PlayerEntityType()
     : EntityType( ID )
 {}
@@ -24,7 +30,7 @@ void PlayerEntityType::loadSuperEntity( Entity *zEntity, Framework::StreamReader
 void PlayerEntityType::saveSuperEntity( Entity *zEntity, Framework::StreamWriter *zWriter ) const
 {}
 
-Entity *PlayerEntityType::createEntity( Framework::Vec3<float> position, int dimensionId, Game *zTarget ) const
+Entity *PlayerEntityType::createEntity( Framework::Vec3<float> position, int dimensionId, Game *zTarget, int entityId ) const
 {
-    return new Player( position, dimensionId );
+    return new Player( position, dimensionId, entityId );
 }

+ 4 - 2
FactoryCraft/Player.h

@@ -11,10 +11,12 @@ private:
     Framework::Text name;
 
 public:
-    Player( Framework::Vec3<float> location, int dimensionId );
+    Player( Framework::Vec3<float> location, int dimensionId, int entityId );
     void setName( Framework::Text name );
     const char *getName() const;
 
+    void api( Framework::StreamReader *zRequest, NetworkResponse *zResponse ) override;
+
     friend PlayerEntityType;
 };
 
@@ -29,7 +31,7 @@ protected:
 public:
     PlayerEntityType();
 
-    virtual Entity *createEntity( Framework::Vec3<float> position, int dimensionId, Game *zTarget ) const override;
+    virtual Entity *createEntity( Framework::Vec3<float> position, int dimensionId, Game *zTarget, int entityId ) const override;
 };
 
 REGISTER( PlayerEntityType, EntityType )

+ 12 - 0
FactoryCraft/Server.cpp

@@ -122,6 +122,11 @@ bool FactoryCraftServer::hatClients() const
     return klientAnzahl > 0;
 }
 
+Game *FactoryCraftServer::zGame() const
+{
+    return game;
+}
+
 
 // Inhalt der LSKlient aus LoginServer.h
 // Konstruktor
@@ -132,6 +137,7 @@ FCKlient::FCKlient( SSLSKlient *klient, FactoryCraftServer *ls )
     accountId = 0;
     this->ls = ls;
     reader = new NetworkReader( klient );
+    writer = new NetworkWriter( klient );
 }
 
 // Destruktor 
@@ -143,6 +149,7 @@ FCKlient::~FCKlient()
         zGameClient = (GameClient *)zGameClient->release();
     }
     delete reader;
+    delete writer;
     klient->release();
     ls->release();
 }
@@ -246,3 +253,8 @@ SSLSKlient *FCKlient::zClient() const
 {
     return klient;
 }
+
+NetworkWriter *FCKlient::zWriter() const
+{
+    return writer;
+}

+ 2 - 0
FactoryCraft/Server.h

@@ -51,6 +51,7 @@ private:
     FactoryCraftServer *ls;
     GameClient *zGameClient;
     NetworkReader *reader;
+    NetworkWriter *writer;
 
 public:
     // Konstruktor 
@@ -63,4 +64,5 @@ public:
     // constant
     int getAccountId() const;
     SSLSKlient *zClient() const;
+    NetworkWriter *zWriter() const;
 };