Dimension.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. #include "Dimension.h"
  2. #include "Constants.h"
  3. #include "Datei.h"
  4. #include "Game.h"
  5. using namespace Framework;
  6. Dimension::Dimension( int id )
  7. : dimensionId( id ),
  8. gravity( 9.8f ),
  9. chunks( new Trie<Chunk>() ),
  10. entities( new RCArray<Entity>() )
  11. {}
  12. Dimension::~Dimension()
  13. {
  14. entities->release();
  15. chunks->release();
  16. }
  17. void Dimension::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse )
  18. {
  19. // TODO: switch type chunck, block, entity
  20. }
  21. void Dimension::tickEntities()
  22. {
  23. for( auto entity : *entities )
  24. {
  25. if( !entity->isRemoved() && zChunk( Punkt( (int)entity->getPosition().x, (int)entity->getPosition().y ) ) )
  26. entity->prepareTick( this );
  27. }
  28. int index = 0;
  29. for( auto entity : *entities )
  30. {
  31. if( !entity->isRemoved() && zChunk( Punkt( (int)entity->getPosition().x, (int)entity->getPosition().y ) ) )
  32. entity->tick( this );
  33. index++;
  34. }
  35. }
  36. void Dimension::getAddrOf( Punkt cPos, char* addr ) const
  37. {
  38. *(int*)addr = cPos.x;
  39. *((int*)addr + 1) = cPos.y;
  40. }
  41. void Dimension::getAddrOfWorld( Punkt wPos, char* addr ) const
  42. {
  43. if( wPos.x < 0 )
  44. wPos.x -= CHUNK_SIZE;
  45. if( wPos.y < 0 ) // needed because otherwise would (-8, -8) have the same adress as (8, 8)
  46. wPos.y -= CHUNK_SIZE;
  47. wPos /= CHUNK_SIZE;
  48. getAddrOf( wPos, addr );
  49. }
  50. Chunk* Dimension::zChunk( Punkt wPos ) const
  51. {
  52. char addr[ 8 ];
  53. getAddrOfWorld( wPos, addr );
  54. return chunks->z( addr, 8 );
  55. }
  56. Framework::Either<Block*, int> Dimension::zBlock( Vec3<int> location )
  57. {
  58. Chunk* c = zChunk( Game::INSTANCE->getChunkCenter( location.x, location.y ) );
  59. if( c )
  60. {
  61. int x = location.x % CHUNK_SIZE;
  62. int y = location.y % CHUNK_SIZE;
  63. if( x < 0 )
  64. x += CHUNK_SIZE;
  65. if( y < 0 )
  66. y += CHUNK_SIZE;
  67. return c->zBlockAt( Vec3<int>( x, y, location.z ) );
  68. }
  69. return 0;
  70. }
  71. Block* Dimension::zRealBlockInstance( Framework::Vec3<int> location )
  72. {
  73. Chunk* c = zChunk( Game::INSTANCE->getChunkCenter( location.x, location.y ) );
  74. if( c )
  75. {
  76. int x = location.x % CHUNK_SIZE;
  77. int y = location.y % CHUNK_SIZE;
  78. if( x < 0 )
  79. x += CHUNK_SIZE;
  80. if( y < 0 )
  81. y += CHUNK_SIZE;
  82. c->instantiateBlock( Vec3<int>( x, y, location.z ) );
  83. return c->zBlockAt( Vec3<int>( x, y, location.z ) );
  84. }
  85. return 0;
  86. }
  87. void Dimension::placeBlock( Framework::Vec3<int> location, Framework::Either<Block*, int> block )
  88. {
  89. Chunk* c = zChunk( Game::getChunkCenter( location.x, location.y ) );
  90. if( c )
  91. {
  92. int x = location.x % CHUNK_SIZE;
  93. int y = location.y % CHUNK_SIZE;
  94. if( x < 0 )
  95. x += CHUNK_SIZE;
  96. if( y < 0 )
  97. y += CHUNK_SIZE;
  98. if( block.isA() )
  99. c->putBlockAt( Vec3<int>( x, y, location.z ), block );
  100. else
  101. {
  102. c->putBlockAt( Vec3<int>( x, y, location.z ), 0 );
  103. c->putBlockTypeAt( Vec3<int>( x, y, location.z ), block );
  104. }
  105. }
  106. else if( block.isA() )
  107. block.getA()->release();
  108. }
  109. void Dimension::addEntity( Entity* entity )
  110. {
  111. entities->add( entity );
  112. }
  113. void Dimension::setChunk( Chunk* chunk, Punkt center )
  114. {
  115. char addr[ 8 ];
  116. getAddrOfWorld( center, addr );
  117. Chunk* old = chunks->z( addr, 8 );
  118. if( old )
  119. {
  120. for( int i = 0; i < chunkList.getEintragAnzahl(); i++ )
  121. {
  122. if( chunkList.get( i ) == old )
  123. {
  124. chunkList.remove( i );
  125. break;
  126. }
  127. }
  128. }
  129. chunks->set( addr, 8, chunk );
  130. if( chunk )
  131. {
  132. chunkList.add( chunk );
  133. chunk->setAdded();
  134. }
  135. getAddrOfWorld( center + Punkt( CHUNK_SIZE, 0 ), addr );
  136. Chunk* zChunk = chunks->z( addr, 8 );
  137. if( zChunk )
  138. {
  139. zChunk->setNeighbor( WEST, chunk );
  140. if( chunk )
  141. chunk->setNeighbor( EAST, zChunk );
  142. }
  143. getAddrOfWorld( center + Punkt( -CHUNK_SIZE, 0 ), addr );
  144. zChunk = chunks->z( addr, 8 );
  145. if( zChunk )
  146. {
  147. zChunk->setNeighbor( EAST, chunk );
  148. if( chunk )
  149. chunk->setNeighbor( WEST, zChunk );
  150. }
  151. getAddrOfWorld( center + Punkt( 0, CHUNK_SIZE ), addr );
  152. zChunk = chunks->z( addr, 8 );
  153. if( zChunk )
  154. {
  155. zChunk->setNeighbor( NORTH, chunk );
  156. if( chunk )
  157. chunk->setNeighbor( SOUTH, zChunk );
  158. }
  159. getAddrOfWorld( center + Punkt( 0, -CHUNK_SIZE ), addr );
  160. zChunk = chunks->z( addr, 8 );
  161. if( zChunk )
  162. {
  163. zChunk->setNeighbor( SOUTH, chunk );
  164. if( chunk )
  165. chunk->setNeighbor( NORTH, zChunk );
  166. }
  167. }
  168. void Dimension::save( Text worldDir ) const
  169. {
  170. for( auto chunk = chunks->getIterator(); chunk; chunk++ )
  171. {
  172. if( !chunk._ )
  173. continue;
  174. Datei* file = new Datei();
  175. Text filePath = worldDir + "/dim/" + dimensionId + "/";
  176. filePath.appendHex( chunk->getCenter().x );
  177. filePath += "_";
  178. filePath.appendHex( chunk->getCenter().y );
  179. filePath += ".chunk";
  180. file->setDatei( filePath );
  181. if( file->open( Datei::Style::schreiben ) )
  182. chunk->save( file, StreamTarget::FULL );
  183. file->close();
  184. file->release();
  185. }
  186. Text filePath = worldDir + "/dim/" + dimensionId + "/entities";
  187. Datei* file = new Datei();
  188. file->setDatei( filePath );
  189. if( file->open( Datei::Style::schreiben ) )
  190. {
  191. for( Entity* entity : *entities )
  192. {
  193. if( entity->zType()->getId() != PlayerEntityType::ID )
  194. {
  195. if( !entity->isRemoved() )
  196. {
  197. int type = entity->zType()->getId();
  198. file->schreibe( (char*)&type, 4 );
  199. StaticRegistry<EntityType>::INSTANCE.zElement( type )->saveEntity( entity, file );
  200. }
  201. }
  202. else
  203. {
  204. Datei pFile;
  205. pFile.setDatei( worldDir + "/player/" + ((Player*)entity)->getName() );
  206. if( pFile.open( Datei::Style::schreiben ) )
  207. PlayerEntityType::INSTANCE->saveEntity( entity, &pFile );
  208. }
  209. }
  210. file->close();
  211. }
  212. }
  213. int Dimension::getDimensionId() const
  214. {
  215. return dimensionId;
  216. }
  217. bool Dimension::hasChunck( int x, int y ) const
  218. {
  219. return zChunk( Punkt( x, y ) );
  220. }
  221. float Dimension::getGravity() const
  222. {
  223. return gravity;
  224. }
  225. void Dimension::removeOldChunks()
  226. {
  227. Array<int> removed;
  228. int index = 0;
  229. for( Chunk* chunk : chunkList )
  230. {
  231. if( !chunk->hasViews() )
  232. removed.add( index, 0 );
  233. index++;
  234. }
  235. for( int i : removed )
  236. {
  237. Chunk* chunk = chunkList.get( i );
  238. // TODO: save chunk
  239. chunk->prepareRemove();
  240. setChunk( 0, chunk->getCenter() );
  241. }
  242. }
  243. Entity* Dimension::zEntity( int id )
  244. {
  245. for( auto entity : *entities )
  246. {
  247. if( !entity->isRemoved() && entity->getId() == id )
  248. return entity;
  249. }
  250. return 0;
  251. }
  252. Entity* Dimension::zNearestEntity( Framework::Vec3<float> pos, std::function<bool( Entity* )> filter )
  253. {
  254. Entity* result = 0;
  255. float sqDist = 0;
  256. for( auto entity : *entities )
  257. {
  258. if( !entity->isRemoved() && filter( entity ) )
  259. {
  260. float d = pos.abstandSq( entity->getPosition() );
  261. if( !result || d < sqDist )
  262. {
  263. result = entity;
  264. sqDist = d;
  265. }
  266. }
  267. }
  268. return result;
  269. }
  270. void Dimension::removeEntity( int id )
  271. {
  272. int index = 0;
  273. for( auto entity : *entities )
  274. {
  275. if( entity->getId() == id )
  276. {
  277. entities->remove( index );
  278. return;
  279. }
  280. index++;
  281. }
  282. }