|
@@ -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;
|
|
|
+}
|