Game.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  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( Game* zGame )
  81. {
  82. other.lock();
  83. for( auto req : requests )
  84. zGame->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 = zGame->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( zGame->getChunkCenter( xP, yP ) );
  127. if( chunk )
  128. sendWorldUpdate( new AddChunkUpdate( dynamic_cast<Chunk*>(chunk->getThis()) ) );
  129. }
  130. }
  131. }
  132. zGame->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 = zGame->getChunkCenter( (int)floor( lastPos.x ) - CHUNK_SIZE * viewDistance, (int)floor( lastPos.y ) - CHUNK_SIZE * viewDistance );
  137. Punkt curMin = zGame->getChunkCenter( x - CHUNK_SIZE * viewDistance, y - CHUNK_SIZE * viewDistance );
  138. Punkt lastMax = zGame->getChunkCenter( (int)floor( lastPos.x ) + CHUNK_SIZE * viewDistance, (int)floor( lastPos.y ) + CHUNK_SIZE * viewDistance );
  139. Punkt curMax = zGame->getChunkCenter( x + CHUNK_SIZE * viewDistance, y + CHUNK_SIZE * viewDistance );
  140. Dimension* dim = zGame->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( zGame->getChunkCenter( xP, yP ) );
  150. if( chunk )
  151. sendWorldUpdate( new AddChunkUpdate( dynamic_cast<Chunk*>(chunk->getThis()) ) );
  152. else
  153. zGame->requestArea( zGame->getChunckArea( zGame->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( zGame->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. int seed = 0;
  243. int index = 0;
  244. for( char* n = name; *n; n++ )
  245. seed += (int)pow( (float)*n * 31, (float)++index );
  246. generator = new WorldGenerator( seed, this );
  247. loader = new WorldLoader( this );
  248. start();
  249. }
  250. Game::~Game()
  251. {
  252. dimensions->release();
  253. updates->release();
  254. clients->release();
  255. generator->release();
  256. loader->release();
  257. }
  258. void Game::thread()
  259. {
  260. ZeitMesser m;
  261. while( !stop )
  262. {
  263. m.messungStart();
  264. ticker->nextTick();
  265. Array<int> removed;
  266. cs.lock();
  267. int index = 0;
  268. for( auto player : *clients )
  269. {
  270. if( !player->isOnline() )
  271. {
  272. Datei pFile;
  273. pFile.setDatei( path + "/player/" + player->zEntity()->getName() );
  274. if( pFile.open( Datei::Style::schreiben ) )
  275. PlayerEntityType::INSTANCE->saveEntity( player->zEntity(), &pFile );
  276. removed.add( index, 0 );
  277. }
  278. index++;
  279. }
  280. for( auto i : removed )
  281. clients->remove( i );
  282. cs.unlock();
  283. for( auto dim : *dimensions )
  284. dim->tickEntities( this );
  285. cs.lock();
  286. while( updates->hat( 0 ) )
  287. {
  288. WorldUpdate* update = updates->z( 0 );
  289. for( auto client : *clients )
  290. client->sendWorldUpdate( dynamic_cast<WorldUpdate*>(update->getThis()) );
  291. if( !zDimension( update->getAffectedDimension() ) )
  292. addDimension( new Dimension( update->getAffectedDimension() ) );
  293. update->onUpdate( zDimension( update->getAffectedDimension() ) );
  294. updates->remove( 0 );
  295. }
  296. cs.unlock();
  297. for( auto client : *clients )
  298. client->reply( this );
  299. cs.lock();
  300. for( auto dim : *dimensions )
  301. dim->removeOldChunks();
  302. cs.unlock();
  303. m.messungEnde();
  304. double sec = m.getSekunden();
  305. if( sec < 0.05 )
  306. Sleep( (int)((0.05 - sec) * 1000) );
  307. else
  308. {
  309. std::cout << "WARNING: tick needed " << sec << " seconds. The game will run sower then normal.\n";
  310. }
  311. }
  312. save();
  313. }
  314. void Game::api( Framework::StreamReader* zRequest, GameClient* zOrigin )
  315. {
  316. char type;
  317. zRequest->lese( &type, 1 );
  318. NetworkResponse response;
  319. switch( type )
  320. {
  321. case 1: // world
  322. {
  323. int dimensionId;
  324. zRequest->lese( (char*)&dimensionId, 4 );
  325. Dimension* dim = zDimension( dimensionId );
  326. if( !dim )
  327. {
  328. dim = new Dimension( dimensionId );
  329. addDimension( dim );
  330. }
  331. dim->api( zRequest, &response );
  332. break;
  333. }
  334. case 2: // player
  335. zOrigin->zEntity()->api( zRequest, &response );
  336. break;
  337. default:
  338. std::cout << "received unknown api request in game with type " << (int)type << "\n";
  339. }
  340. if( !response.isEmpty() )
  341. {
  342. if( response.isBroadcast() )
  343. distributeResponse( &response );
  344. else
  345. zOrigin->sendResponse( &response );
  346. }
  347. }
  348. void Game::distributeResponse( NetworkResponse* zResponse )
  349. {
  350. for( auto client : *clients )
  351. client->sendResponse( zResponse );
  352. }
  353. bool Game::requestWorldUpdate( WorldUpdate* update )
  354. {
  355. cs.lock();
  356. for( WorldUpdate* u : *updates )
  357. {
  358. if( u->getMaxAffectedPoint().x >= update->getMinAffectedPoint().x && u->getMinAffectedPoint().x <= update->getMaxAffectedPoint().x &&
  359. u->getMaxAffectedPoint().y >= update->getMinAffectedPoint().y && u->getMinAffectedPoint().y <= update->getMaxAffectedPoint().y &&
  360. u->getMaxAffectedPoint().z >= update->getMinAffectedPoint().z && u->getMinAffectedPoint().z <= update->getMaxAffectedPoint().z )
  361. {
  362. cs.unlock();
  363. update->release();
  364. return 0;
  365. }
  366. }
  367. updates->add( update );
  368. cs.unlock();
  369. return 1;
  370. }
  371. GameClient* Game::addPlayer( FCKlient* client, Framework::Text name )
  372. {
  373. cs.lock();
  374. Datei pFile;
  375. pFile.setDatei( path + "/player/" + name );
  376. Player* player;
  377. bool isNew = 0;
  378. if( !pFile.existiert() || !pFile.open( Datei::Style::lesen ) )
  379. {
  380. player = (Player*)PlayerEntityType::INSTANCE->createEntityAt( Vec3<float>( 0.5, 0.5, 0 ), OverworldDimension::ID, this );
  381. player->setName( name );
  382. isNew = 1;
  383. }
  384. else
  385. {
  386. player = (Player*)PlayerEntityType::INSTANCE->loadEntity( this, &pFile );
  387. pFile.close();
  388. }
  389. GameClient* gameClient = new GameClient( player, client );
  390. clients->add( gameClient );
  391. requestArea( getChunckArea( getChunkCenter( (int)player->getPosition().x, (int)player->getPosition().y ) ) );
  392. while( !zDimension( player->getCurrentDimensionId() ) || (isNew && !zDimension( player->getCurrentDimensionId() )->zChunk( getChunkCenter( (int)player->getPosition().x, (int)player->getPosition().y ) )) )
  393. {
  394. cs.unlock();
  395. Sleep( 1000 );
  396. cs.lock();
  397. }
  398. zDimension( player->getCurrentDimensionId() )->addEntity( player );
  399. if( isNew )
  400. {
  401. Either<Block*, int> b = AirBlockBlockType::ID;
  402. int h = WORLD_HEIGHT;
  403. while( ((b.isA() && (!(Block*)b || ((Block*)b)->isPassable())) || (b.isB() && StaticRegistry<BlockType>::INSTANCE.zElement( b )->zDefault()->isPassable())) && h > 0 )
  404. b = zBlockAt( { (int)player->getPosition().x, (int)player->getPosition().y, --h }, player->getCurrentDimensionId() );
  405. player->setPosition( { player->getPosition().x, player->getPosition().y, (float)h + 1.f } );
  406. }
  407. cs.unlock();
  408. return dynamic_cast<GameClient*>(gameClient->getThis());
  409. }
  410. bool Game::isChunkLoaded( int x, int y, int dimension ) const
  411. {
  412. Dimension* dim = zDimension( dimension );
  413. return (dim && dim->hasChunck( x, y ));
  414. }
  415. bool Game::doesChunkExist( int x, int y, int dimension )
  416. {
  417. cs.lock();
  418. bool result = isChunkLoaded( x, y, dimension ) || loader->existsChunk( x, y, dimension );
  419. if( !result )
  420. {
  421. for( WorldUpdate* update : *updates )
  422. {
  423. if( update->getType() == AddChunkUpdateType::ID )
  424. result |= ((AddChunkUpdate*)update)->zChunk()->getCenter() == Framework::Punkt( x, y );
  425. }
  426. }
  427. cs.unlock();
  428. return result;
  429. }
  430. Framework::Either<Block*, int> Game::zBlockAt( Framework::Vec3<int> location, int dimension ) const
  431. {
  432. Dimension* dim = zDimension( dimension );
  433. if( dim )
  434. return dim->zBlock( location, this );
  435. return 0;
  436. }
  437. Block* Game::zRealBlockInstance( Framework::Vec3<int> location, int dimension )
  438. {
  439. Dimension* dim = zDimension( dimension );
  440. if( dim )
  441. return dim->zRealBlockInstance( location, this );
  442. return 0;
  443. }
  444. Dimension* Game::zDimension( int id ) const
  445. {
  446. for( auto dim : *dimensions )
  447. {
  448. if( dim->getDimensionId() == id )
  449. return dim;
  450. }
  451. return 0;
  452. }
  453. Framework::Punkt Game::getChunkCenter( int x, int y )
  454. {
  455. 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 );
  456. }
  457. Area Game::getChunckArea( Punkt center ) const
  458. {
  459. return { center.x - CHUNK_SIZE / 2, center.y - CHUNK_SIZE / 2, center.x + CHUNK_SIZE / 2 - 1, center.y + CHUNK_SIZE / 2 - 1, 0 };
  460. }
  461. Framework::Text Game::getWorldDirectory() const
  462. {
  463. return path;
  464. }
  465. void Game::requestArea( Area area )
  466. {
  467. generator->requestGeneration( area );
  468. loader->requestLoading( area );
  469. }
  470. void Game::save() const
  471. {
  472. Datei d;
  473. d.setDatei( path + "/eid" );
  474. d.open( Datei::Style::schreiben );
  475. d.schreibe( (char*)&nextEntityId, 4 );
  476. d.close();
  477. for( auto dim : *dimensions )
  478. dim->save( path );
  479. }
  480. void Game::requestStop()
  481. {
  482. stop = 1;
  483. warteAufThread( 1000000 );
  484. }
  485. void Game::addDimension( Dimension* d )
  486. {
  487. dimensions->add( d );
  488. }
  489. int Game::getNextEntityId()
  490. {
  491. cs.lock();
  492. int result = nextEntityId++;
  493. cs.unlock();
  494. return result;
  495. }
  496. WorldGenerator* Game::zGenerator() const
  497. {
  498. return generator;
  499. }