Dimension.cpp 6.2 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
  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. }