Game.cpp 16 KB

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