Game.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. #include "Game.h"
  2. #include "Zeit.h"
  3. #include "Player.h"
  4. #include "OverworldDimension.h"
  5. #include "AddChunkUpdate.h"
  6. #include "NoBlock.h"
  7. #include "AsynchronCall.h"
  8. #include "Entity.h"
  9. using namespace Framework;
  10. GameClient::GameClient( Player* zPlayer, FCKlient* client )
  11. : ReferenceCounter(),
  12. zPlayer( zPlayer ),
  13. client( client ),
  14. viewDistance( DEFAULT_VIEW_DISTANCE ),
  15. first( 1 ),
  16. online( 1 ),
  17. finished( 0 )
  18. {
  19. new AsynchronCall( [this]() {
  20. while( online )
  21. {
  22. other.lock();
  23. if( updateQueue.hat( 0 ) )
  24. {
  25. WorldUpdate* update = updateQueue.get( 0 );
  26. updateQueue.remove( 0 );
  27. other.unlock();
  28. background.lock();
  29. this->client->zBackgroundWriter()->schreibe( (char*)&Message::WORLD_UPDATE, 1 );
  30. update->write( this->client->zBackgroundWriter() );
  31. background.unlock();
  32. update->release();
  33. }
  34. else
  35. {
  36. other.unlock();
  37. updateSync.wait();
  38. }
  39. }
  40. finished = 1;
  41. } );
  42. }
  43. GameClient::~GameClient()
  44. {
  45. online = 0;
  46. updateSync.notify();
  47. while( !finished )
  48. Sleep( 100 );
  49. client->release();
  50. }
  51. void GameClient::sendWorldUpdate( WorldUpdate* update )
  52. {
  53. bool add = 0;
  54. if( zPlayer->getCurrentDimensionId() == update->getAffectedDimension() )
  55. {
  56. auto pos = (Vec3<int>)zPlayer->getPosition();
  57. int dist = update->distanceTo( pos.x, pos.y );
  58. if( dist < viewDistance * CHUNK_SIZE )
  59. {
  60. other.lock();
  61. int index = 0;
  62. for( auto update2 : updateQueue )
  63. {
  64. int dist2 = update2->distanceTo( pos.x, pos.y );
  65. if( dist2 >= dist )
  66. break;
  67. index++;
  68. }
  69. if( update->getType() == AddChunkUpdateType::ID )
  70. ((AddChunkUpdate*)update)->zChunk()->addView( zPlayer );
  71. updateQueue.add( update, index );
  72. other.unlock();
  73. updateSync.notify();
  74. add = 1;
  75. }
  76. }
  77. if( !add )
  78. update->release();
  79. }
  80. void GameClient::reply()
  81. {
  82. other.lock();
  83. for( auto req : requests )
  84. Game::INSTANCE->api( req, this );
  85. requests.leeren();
  86. other.unlock();
  87. int x = (int)floor( zPlayer->getPosition().x );
  88. int y = (int)floor( zPlayer->getPosition().y );
  89. int d = zPlayer->getCurrentDimensionId();
  90. foreground.lock();
  91. client->zForegroundWriter()->schreibe( (char*)&Message::POSITION_UPDATE, 1 );
  92. float f = zPlayer->getPosition().x;
  93. client->zForegroundWriter()->schreibe( (char*)&f, 4 );
  94. f = zPlayer->getPosition().y;
  95. client->zForegroundWriter()->schreibe( (char*)&f, 4 );
  96. f = zPlayer->getPosition().z;
  97. client->zForegroundWriter()->schreibe( (char*)&f, 4 );
  98. if( first )
  99. {
  100. f = zPlayer->getFaceDir().x;
  101. client->zForegroundWriter()->schreibe( (char*)&f, 4 );
  102. f = zPlayer->getFaceDir().y;
  103. client->zForegroundWriter()->schreibe( (char*)&f, 4 );
  104. f = zPlayer->getFaceDir().z;
  105. client->zForegroundWriter()->schreibe( (char*)&f, 4 );
  106. }
  107. if( zPlayer->zTarget() )
  108. zPlayer->zTarget()->save( client->zForegroundWriter() );
  109. else
  110. {
  111. char b = 0;
  112. client->zForegroundWriter()->schreibe( &b, 1 );
  113. }
  114. foreground.unlock();
  115. // send world to client
  116. if( first )
  117. {
  118. first = 0;
  119. Dimension* dim = Game::INSTANCE->zDimension( d );
  120. if( dim )
  121. {
  122. for( int xP = x - CHUNK_SIZE * viewDistance; xP <= x + CHUNK_SIZE * viewDistance; xP += CHUNK_SIZE )
  123. {
  124. for( int yP = y - CHUNK_SIZE * viewDistance; yP <= y + CHUNK_SIZE * viewDistance; yP += CHUNK_SIZE )
  125. {
  126. Chunk* chunk = dim->zChunk( Game::INSTANCE->getChunkCenter( xP, yP ) );
  127. if( chunk )
  128. sendWorldUpdate( new AddChunkUpdate( dynamic_cast<Chunk*>(chunk->getThis()) ) );
  129. }
  130. }
  131. }
  132. Game::INSTANCE->requestArea( { x - CHUNK_SIZE * viewDistance, y - CHUNK_SIZE * viewDistance, x + CHUNK_SIZE * viewDistance, y + CHUNK_SIZE * viewDistance, d } );
  133. }
  134. else
  135. {
  136. Punkt lastMin = Game::INSTANCE->getChunkCenter( (int)floor( lastPos.x ) - CHUNK_SIZE * viewDistance, (int)floor( lastPos.y ) - CHUNK_SIZE * viewDistance );
  137. Punkt curMin = Game::INSTANCE->getChunkCenter( x - CHUNK_SIZE * viewDistance, y - CHUNK_SIZE * viewDistance );
  138. Punkt lastMax = Game::INSTANCE->getChunkCenter( (int)floor( lastPos.x ) + CHUNK_SIZE * viewDistance, (int)floor( lastPos.y ) + CHUNK_SIZE * viewDistance );
  139. Punkt curMax = Game::INSTANCE->getChunkCenter( x + CHUNK_SIZE * viewDistance, y + CHUNK_SIZE * viewDistance );
  140. Dimension* dim = Game::INSTANCE->zDimension( d );
  141. if( dim )
  142. {
  143. for( int xP = curMin.x; xP <= curMax.x; xP += CHUNK_SIZE )
  144. {
  145. for( int yP = curMin.y; yP <= curMax.y; yP += CHUNK_SIZE )
  146. {
  147. if( xP < lastMin.x || xP > lastMax.x || yP < lastMin.y || yP > lastMax.y )
  148. {
  149. Chunk* chunk = dim->zChunk( Game::INSTANCE->getChunkCenter( xP, yP ) );
  150. if( chunk )
  151. sendWorldUpdate( new AddChunkUpdate( dynamic_cast<Chunk*>(chunk->getThis()) ) );
  152. else
  153. Game::INSTANCE->requestArea( Game::INSTANCE->getChunckArea( Game::INSTANCE->getChunkCenter( xP, yP ) ) );
  154. }
  155. }
  156. }
  157. for( int xP = lastMin.x; xP <= lastMax.x; xP += CHUNK_SIZE )
  158. {
  159. for( int yP = lastMin.y; yP <= lastMax.y; yP += CHUNK_SIZE )
  160. {
  161. if( xP < curMin.x || xP > curMax.x || yP < curMin.y || yP > curMax.y )
  162. {
  163. Chunk* chunk = dim->zChunk( Game::INSTANCE->getChunkCenter( xP, yP ) );
  164. if( chunk )
  165. chunk->removeView( zPlayer );
  166. }
  167. }
  168. }
  169. }
  170. }
  171. lastPos = zPlayer->getPosition();
  172. }
  173. void GameClient::logout()
  174. {
  175. online = 0;
  176. }
  177. void GameClient::addMessage( StreamReader* reader )
  178. {
  179. short len = 0;
  180. reader->lese( (char*)&len, 2 );
  181. InMemoryBuffer* buffer = new InMemoryBuffer();
  182. char* tmp = new char[ len ];
  183. reader->lese( tmp, len );
  184. buffer->schreibe( tmp, len );
  185. delete[]tmp;
  186. other.lock();
  187. requests.add( buffer );
  188. other.unlock();
  189. }
  190. bool GameClient::isOnline() const
  191. {
  192. return online;
  193. }
  194. void GameClient::sendResponse( NetworkResponse* zResponse )
  195. {
  196. 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 } ) )
  197. {
  198. if( zResponse->isUseBackground() )
  199. {
  200. background.unlock();
  201. client->zBackgroundWriter()->schreibe( (char*)&Message::API_MESSAGE, 1 );
  202. zResponse->writeTo( client->zBackgroundWriter() );
  203. background.unlock();
  204. }
  205. else
  206. {
  207. foreground.unlock();
  208. client->zForegroundWriter()->schreibe( (char*)&Message::API_MESSAGE, 1 );
  209. zResponse->writeTo( client->zForegroundWriter() );
  210. foreground.unlock();
  211. }
  212. }
  213. }
  214. Player* GameClient::zEntity() const
  215. {
  216. return zPlayer;
  217. }
  218. Game::Game( Framework::Text name, Framework::Text worldsDir )
  219. : Thread(),
  220. name( name ),
  221. dimensions( new RCArray<Dimension>() ),
  222. updates( new RCArray<WorldUpdate>() ),
  223. clients( new RCArray<GameClient>() ),
  224. ticker( new TickOrganizer() ),
  225. path( (const char*)(worldsDir + "/" + name) ),
  226. stop( 0 ),
  227. tickId( 0 ),
  228. nextEntityId( 0 ),
  229. generator( 0 ),
  230. loader( 0 )
  231. {
  232. if( !DateiExistiert( worldsDir + "/" + name ) )
  233. DateiPfadErstellen( worldsDir + "/" + name + "/" );
  234. Datei d;
  235. d.setDatei( path + "/eid" );
  236. if( d.existiert() )
  237. {
  238. d.open( Datei::Style::lesen );
  239. d.lese( (char*)&nextEntityId, 4 );
  240. d.close();
  241. }
  242. start();
  243. }
  244. Game::~Game()
  245. {
  246. dimensions->release();
  247. updates->release();
  248. clients->release();
  249. generator->release();
  250. loader->release();
  251. }
  252. void Game::initialize()
  253. {
  254. int seed = 0;
  255. int index = 0;
  256. for( char* n = name; *n; n++ )
  257. seed += (int)pow( (float)*n * 31, (float)++index );
  258. generator = new WorldGenerator( seed );
  259. loader = new WorldLoader();
  260. }
  261. void Game::thread()
  262. {
  263. ZeitMesser m;
  264. while( !stop )
  265. {
  266. m.messungStart();
  267. ticker->nextTick();
  268. Array<int> removed;
  269. cs.lock();
  270. int index = 0;
  271. for( auto player : *clients )
  272. {
  273. if( !player->isOnline() )
  274. {
  275. Datei pFile;
  276. pFile.setDatei( path + "/player/" + player->zEntity()->getName() );
  277. if( pFile.open( Datei::Style::schreiben ) )
  278. PlayerEntityType::INSTANCE->saveEntity( player->zEntity(), &pFile );
  279. removed.add( index, 0 );
  280. }
  281. index++;
  282. }
  283. for( auto i : removed )
  284. clients->remove( i );
  285. cs.unlock();
  286. for( auto dim : *dimensions )
  287. dim->tickEntities();
  288. cs.lock();
  289. while( updates->hat( 0 ) )
  290. {
  291. WorldUpdate* update = updates->z( 0 );
  292. for( auto client : *clients )
  293. client->sendWorldUpdate( dynamic_cast<WorldUpdate*>(update->getThis()) );
  294. if( !zDimension( update->getAffectedDimension() ) )
  295. addDimension( new Dimension( update->getAffectedDimension() ) );
  296. update->onUpdate( zDimension( update->getAffectedDimension() ) );
  297. updates->remove( 0 );
  298. }
  299. cs.unlock();
  300. for( auto client : *clients )
  301. client->reply();
  302. cs.lock();
  303. for( auto dim : *dimensions )
  304. dim->removeOldChunks();
  305. cs.unlock();
  306. m.messungEnde();
  307. double sec = m.getSekunden();
  308. if( sec < 0.05 )
  309. Sleep( (int)((0.05 - sec) * 1000) );
  310. else
  311. {
  312. std::cout << "WARNING: tick needed " << sec << " seconds. The game will run sower then normal.\n";
  313. }
  314. }
  315. save();
  316. }
  317. void Game::api( Framework::StreamReader* zRequest, GameClient* zOrigin )
  318. {
  319. char type;
  320. zRequest->lese( &type, 1 );
  321. NetworkResponse response;
  322. switch( type )
  323. {
  324. case 1: // world
  325. {
  326. int dimensionId;
  327. zRequest->lese( (char*)&dimensionId, 4 );
  328. Dimension* dim = zDimension( dimensionId );
  329. if( !dim )
  330. {
  331. dim = new Dimension( dimensionId );
  332. addDimension( dim );
  333. }
  334. dim->api( zRequest, &response );
  335. break;
  336. }
  337. case 2: // player
  338. zOrigin->zEntity()->api( zRequest, &response );
  339. break;
  340. default:
  341. std::cout << "received unknown api request in game with type " << (int)type << "\n";
  342. }
  343. if( !response.isEmpty() )
  344. {
  345. if( response.isBroadcast() )
  346. distributeResponse( &response );
  347. else
  348. zOrigin->sendResponse( &response );
  349. }
  350. }
  351. void Game::distributeResponse( NetworkResponse* zResponse )
  352. {
  353. for( auto client : *clients )
  354. client->sendResponse( zResponse );
  355. }
  356. bool Game::requestWorldUpdate( WorldUpdate* update )
  357. {
  358. cs.lock();
  359. for( WorldUpdate* u : *updates )
  360. {
  361. if( u->getMaxAffectedPoint().x >= update->getMinAffectedPoint().x && u->getMinAffectedPoint().x <= update->getMaxAffectedPoint().x &&
  362. u->getMaxAffectedPoint().y >= update->getMinAffectedPoint().y && u->getMinAffectedPoint().y <= update->getMaxAffectedPoint().y &&
  363. u->getMaxAffectedPoint().z >= update->getMinAffectedPoint().z && u->getMinAffectedPoint().z <= update->getMaxAffectedPoint().z )
  364. {
  365. cs.unlock();
  366. update->release();
  367. return 0;
  368. }
  369. }
  370. updates->add( update );
  371. cs.unlock();
  372. return 1;
  373. }
  374. GameClient* Game::addPlayer( FCKlient* client, Framework::Text name )
  375. {
  376. cs.lock();
  377. Datei pFile;
  378. pFile.setDatei( path + "/player/" + name );
  379. Player* player;
  380. bool isNew = 0;
  381. if( !pFile.existiert() || !pFile.open( Datei::Style::lesen ) )
  382. {
  383. player = (Player*)PlayerEntityType::INSTANCE->createEntityAt( Vec3<float>( 0.5, 0.5, 0 ), OverworldDimension::ID );
  384. player->setName( name );
  385. isNew = 1;
  386. }
  387. else
  388. {
  389. player = (Player*)PlayerEntityType::INSTANCE->loadEntity( &pFile );
  390. pFile.close();
  391. }
  392. GameClient* gameClient = new GameClient( player, client );
  393. clients->add( gameClient );
  394. requestArea( getChunckArea( getChunkCenter( (int)player->getPosition().x, (int)player->getPosition().y ) ) );
  395. while( !zDimension( player->getCurrentDimensionId() ) || (isNew && !zDimension( player->getCurrentDimensionId() )->zChunk( getChunkCenter( (int)player->getPosition().x, (int)player->getPosition().y ) )) )
  396. {
  397. cs.unlock();
  398. Sleep( 1000 );
  399. cs.lock();
  400. }
  401. zDimension( player->getCurrentDimensionId() )->addEntity( player );
  402. if( isNew )
  403. {
  404. Either<Block*, int> b = AirBlockBlockType::ID;
  405. int h = WORLD_HEIGHT;
  406. while( ((b.isA() && (!(Block*)b || ((Block*)b)->isPassable())) || (b.isB() && StaticRegistry<BlockType>::INSTANCE.zElement( b )->zDefault()->isPassable())) && h > 0 )
  407. b = zBlockAt( { (int)player->getPosition().x, (int)player->getPosition().y, --h }, player->getCurrentDimensionId() );
  408. player->setPosition( { player->getPosition().x, player->getPosition().y, (float)h + 1.f } );
  409. }
  410. cs.unlock();
  411. return dynamic_cast<GameClient*>(gameClient->getThis());
  412. }
  413. bool Game::isChunkLoaded( int x, int y, int dimension ) const
  414. {
  415. Dimension* dim = zDimension( dimension );
  416. return (dim && dim->hasChunck( x, y ));
  417. }
  418. bool Game::doesChunkExist( int x, int y, int dimension )
  419. {
  420. cs.lock();
  421. bool result = isChunkLoaded( x, y, dimension ) || loader->existsChunk( x, y, dimension );
  422. if( !result )
  423. {
  424. for( WorldUpdate* update : *updates )
  425. {
  426. if( update->getType() == AddChunkUpdateType::ID )
  427. result |= ((AddChunkUpdate*)update)->zChunk()->getCenter() == Framework::Punkt( x, y );
  428. }
  429. }
  430. cs.unlock();
  431. return result;
  432. }
  433. Framework::Either<Block*, int> Game::zBlockAt( Framework::Vec3<int> location, int dimension ) const
  434. {
  435. Dimension* dim = zDimension( dimension );
  436. if( dim )
  437. return dim->zBlock( location );
  438. return 0;
  439. }
  440. Block* Game::zRealBlockInstance( Framework::Vec3<int> location, int dimension )
  441. {
  442. Dimension* dim = zDimension( dimension );
  443. if( dim )
  444. return dim->zRealBlockInstance( location );
  445. return 0;
  446. }
  447. Dimension* Game::zDimension( int id ) const
  448. {
  449. for( auto dim : *dimensions )
  450. {
  451. if( dim->getDimensionId() == id )
  452. return dim;
  453. }
  454. return 0;
  455. }
  456. Framework::Punkt Game::getChunkCenter( int x, int y )
  457. {
  458. 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 );
  459. }
  460. Area Game::getChunckArea( Punkt center ) const
  461. {
  462. return { center.x - CHUNK_SIZE / 2, center.y - CHUNK_SIZE / 2, center.x + CHUNK_SIZE / 2 - 1, center.y + CHUNK_SIZE / 2 - 1, 0 };
  463. }
  464. Framework::Text Game::getWorldDirectory() const
  465. {
  466. return path;
  467. }
  468. void Game::requestArea( Area area )
  469. {
  470. generator->requestGeneration( area );
  471. loader->requestLoading( area );
  472. }
  473. void Game::save() const
  474. {
  475. Datei d;
  476. d.setDatei( path + "/eid" );
  477. d.open( Datei::Style::schreiben );
  478. d.schreibe( (char*)&nextEntityId, 4 );
  479. d.close();
  480. for( auto dim : *dimensions )
  481. dim->save( path );
  482. }
  483. void Game::requestStop()
  484. {
  485. stop = 1;
  486. warteAufThread( 1000000 );
  487. }
  488. void Game::addDimension( Dimension* d )
  489. {
  490. dimensions->add( d );
  491. }
  492. int Game::getNextEntityId()
  493. {
  494. cs.lock();
  495. int result = nextEntityId++;
  496. cs.unlock();
  497. return result;
  498. }
  499. WorldGenerator* Game::zGenerator() const
  500. {
  501. return generator;
  502. }
  503. Game* Game::INSTANCE = 0;
  504. void Game::initialize( Framework::Text name, Framework::Text worldsDir )
  505. {
  506. if( !Game::INSTANCE )
  507. {
  508. Game::INSTANCE = new Game( name, worldsDir );
  509. Game::INSTANCE->initialize();
  510. }
  511. }