DimensionMap.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. #include "DimensionMap.h"
  2. #include <FileSystem.h>
  3. #include "Constants.h"
  4. #include "Entity.h"
  5. #include "FactoryClient.h"
  6. #include "Globals.h"
  7. #include "World.h"
  8. DimensionMap::DimensionMap(MapOptions* zOptions)
  9. : DrawableBackground(),
  10. zOptions(zOptions),
  11. originChunkCenter(0, 0),
  12. scrollOffset(0, 0),
  13. chunkCount(0),
  14. pixelsPerBlock(16),
  15. requestCount(0),
  16. drag(0),
  17. nextPlayersRequest(-1)
  18. {
  19. setStyle(Style::Visible | Style::Allowed);
  20. chunks = new Framework::RCTrie<ChunkMap>();
  21. setMouseEvent(_ret1ME);
  22. requestNextChunk();
  23. char msg[2];
  24. msg[0] = 2; // subscribe to map changes
  25. msg[1] = 1;
  26. World::INSTANCE->zClient()->dimensionAPIRequest(msg, 2);
  27. LTDBFile iconsDat;
  28. iconsDat.setFile(new Text("data/images/gui_icons.ltdb"));
  29. iconsDat.readData(0);
  30. playerIcon = iconsDat.load(0, new Text("player.png"));
  31. }
  32. DimensionMap::~DimensionMap()
  33. {
  34. char msg[2];
  35. msg[0] = 2; // unsubscribe from map changes
  36. msg[1] = 2;
  37. World::INSTANCE->zClient()->dimensionAPIRequest(msg, 2);
  38. chunks->release();
  39. playerIcon->release();
  40. }
  41. void DimensionMap::getAddrOf(Point cPos, char* addr) const
  42. {
  43. *(int*)addr = cPos.x;
  44. *((int*)addr + 1) = cPos.y;
  45. }
  46. void DimensionMap::getAddrOfWorld(Point wPos, char* addr) const
  47. {
  48. // needed because otherwise would (-8, -8) have the same
  49. // adress as (8, 8)
  50. if (wPos.x < 0) wPos.x -= CHUNK_SIZE;
  51. if (wPos.y < 0) wPos.y -= CHUNK_SIZE;
  52. wPos /= CHUNK_SIZE;
  53. getAddrOf(wPos, addr);
  54. }
  55. Framework::Point DimensionMap::getMinVisibleChunkCenter(
  56. Framework::Point& screenPos) const
  57. {
  58. screenPos = getSize() / 2 - scrollOffset;
  59. Point currentChunkCenter = originChunkCenter;
  60. while (screenPos.x + pixelsPerBlock * (CHUNK_SIZE / 2) >= 0)
  61. {
  62. screenPos.x -= pixelsPerBlock * CHUNK_SIZE;
  63. currentChunkCenter.x -= CHUNK_SIZE;
  64. }
  65. while (screenPos.y + pixelsPerBlock * (CHUNK_SIZE / 2) >= 0)
  66. {
  67. screenPos.y -= pixelsPerBlock * CHUNK_SIZE;
  68. currentChunkCenter.y -= CHUNK_SIZE;
  69. }
  70. while (screenPos.x + pixelsPerBlock * (CHUNK_SIZE / 2) < 0)
  71. {
  72. screenPos.x += pixelsPerBlock * CHUNK_SIZE;
  73. currentChunkCenter.x += CHUNK_SIZE;
  74. }
  75. while (screenPos.y + pixelsPerBlock * (CHUNK_SIZE / 2) < 0)
  76. {
  77. screenPos.y += pixelsPerBlock * CHUNK_SIZE;
  78. currentChunkCenter.y += CHUNK_SIZE;
  79. }
  80. return currentChunkCenter;
  81. }
  82. Framework::Point DimensionMap::getMaxVisibleChunkCenter(
  83. Framework::Point& screenPos) const
  84. {
  85. screenPos = getSize() / 2 - scrollOffset;
  86. Point currentChunkCenter = originChunkCenter;
  87. while (screenPos.x - pixelsPerBlock * (CHUNK_SIZE / 2) < getWidth())
  88. {
  89. screenPos.x += pixelsPerBlock * CHUNK_SIZE;
  90. currentChunkCenter.x += CHUNK_SIZE;
  91. }
  92. while (screenPos.y - pixelsPerBlock * (CHUNK_SIZE / 2) < getHeight())
  93. {
  94. screenPos.y += pixelsPerBlock * CHUNK_SIZE;
  95. currentChunkCenter.y += CHUNK_SIZE;
  96. }
  97. while (screenPos.x - pixelsPerBlock * (CHUNK_SIZE / 2) >= getWidth())
  98. {
  99. screenPos.x -= pixelsPerBlock * CHUNK_SIZE;
  100. currentChunkCenter.x -= CHUNK_SIZE;
  101. }
  102. while (screenPos.y - pixelsPerBlock * (CHUNK_SIZE / 2) >= getHeight())
  103. {
  104. screenPos.y -= pixelsPerBlock * CHUNK_SIZE;
  105. currentChunkCenter.y -= CHUNK_SIZE;
  106. }
  107. return currentChunkCenter;
  108. }
  109. void DimensionMap::removeUnused() const
  110. {
  111. Point tmp;
  112. Framework::Point min
  113. = getMinVisibleChunkCenter(tmp) - Point(CHUNK_SIZE, CHUNK_SIZE) * 5;
  114. Framework::Point max
  115. = getMaxVisibleChunkCenter(tmp) + Point(CHUNK_SIZE, CHUNK_SIZE) * 5;
  116. char addr[8];
  117. for (auto i = chunkList.begin(); i;)
  118. {
  119. if (i->getChunkCenter().x < min.x || i->getChunkCenter().y < min.y
  120. || i->getChunkCenter().x > max.x || i->getChunkCenter().y > max.y)
  121. {
  122. getAddrOfWorld(i->getChunkCenter(), addr);
  123. chunks->remove(addr, 8);
  124. i.remove();
  125. }
  126. else
  127. {
  128. ++i;
  129. }
  130. }
  131. }
  132. void DimensionMap::updatePlayers(char* data)
  133. {
  134. int count = *(int*)data;
  135. data += 4;
  136. writeLock().lock();
  137. players.clear();
  138. // read player information from data buffer
  139. for (int i = 0; i < count; i++)
  140. {
  141. unsigned char nameLen = (unsigned char)*data;
  142. data++;
  143. char* name = new char[nameLen + 1];
  144. memcpy(name, data, nameLen);
  145. name[nameLen] = 0;
  146. data += nameLen;
  147. MapPlayer player;
  148. player.name = name;
  149. delete[] name;
  150. player.position.x = *(float*)data;
  151. player.position.y = *(float*)(data + 4);
  152. player.position.z = *(float*)(data + 8);
  153. data += 12;
  154. players.add(player);
  155. }
  156. writeLock().unlock();
  157. }
  158. void DimensionMap::requestNextChunk()
  159. {
  160. readLock().lock();
  161. if (requestCount >= 20)
  162. {
  163. readLock().unlock();
  164. return;
  165. }
  166. if (chunkCount == 0)
  167. {
  168. writeLock().lock();
  169. requestCount++;
  170. writeLock().unlock();
  171. Vec3<float> playerPos
  172. = World::INSTANCE->getCurrentPlayerEntity()->getPos();
  173. char msg[10];
  174. msg[0] = 2;
  175. msg[1] = 0;
  176. *(int*)(msg + 2) = (int)playerPos.x;
  177. *(int*)(msg + 6) = (int)playerPos.y;
  178. World::INSTANCE->zClient()->dimensionAPIRequest(msg, 10);
  179. }
  180. else
  181. {
  182. while (requestCount < 20)
  183. {
  184. Point minScreenPos;
  185. Point minVisibleChunk = getMinVisibleChunkCenter(minScreenPos);
  186. Point maxScreenPos;
  187. Point maxVisibleChunk = getMaxVisibleChunkCenter(maxScreenPos);
  188. Point screenPos = minScreenPos;
  189. Point screenCenter = getSize() / 2;
  190. double minDist = -1;
  191. Point resultChunk(0, 0);
  192. char addr[8];
  193. for (int x = minVisibleChunk.x; x <= maxVisibleChunk.x;
  194. x += CHUNK_SIZE)
  195. {
  196. for (int y = minVisibleChunk.y; y <= maxVisibleChunk.y;
  197. y += CHUNK_SIZE)
  198. {
  199. getAddrOfWorld({x, y}, addr);
  200. if (!chunks->z(addr, 8))
  201. {
  202. if (minDist < 0
  203. || (screenCenter - screenPos).getLengthSq()
  204. < minDist)
  205. {
  206. minDist = (screenCenter - screenPos).getLengthSq();
  207. resultChunk = {x, y};
  208. }
  209. }
  210. screenPos.y += pixelsPerBlock * CHUNK_SIZE;
  211. }
  212. screenPos.x += pixelsPerBlock * CHUNK_SIZE;
  213. screenPos.y = minScreenPos.y;
  214. }
  215. if (minDist >= 0)
  216. {
  217. requestCount++;
  218. char msg[10];
  219. msg[0] = 2;
  220. msg[1] = 0;
  221. *(int*)(msg + 2) = (int)resultChunk.x;
  222. *(int*)(msg + 6) = (int)resultChunk.y;
  223. World::INSTANCE->zClient()->dimensionAPIRequest(msg, 10);
  224. getAddrOfWorld({resultChunk.x, resultChunk.y}, addr);
  225. writeLock().lock();
  226. chunks->set(addr, 8, new ChunkMap(resultChunk));
  227. writeLock().unlock();
  228. }
  229. else
  230. {
  231. break;
  232. }
  233. }
  234. }
  235. readLock().unlock();
  236. }
  237. void DimensionMap::addChunk(ChunkMap* chunk)
  238. {
  239. writeLock().lock();
  240. if (chunkCount == 0) originChunkCenter = chunk->getChunkCenter();
  241. char addr[8];
  242. getAddrOfWorld(chunk->getChunkCenter(), addr);
  243. ChunkMap* old = chunks->z(addr, 8);
  244. if (old) chunkList.removeValue(old);
  245. chunks->set(addr, 8, chunk);
  246. chunkList.add(chunk);
  247. chunkCount++;
  248. requestCount--;
  249. removeUnused();
  250. writeLock().unlock();
  251. requestNextChunk();
  252. }
  253. bool DimensionMap::tick(double time)
  254. {
  255. if (nextPlayersRequest < 0 && zOptions->isShowPlayers())
  256. {
  257. nextPlayersRequest = 2;
  258. char msg[2];
  259. msg[0] = 2; // request map players
  260. msg[1] = 3;
  261. if (World::INSTANCE)
  262. {
  263. World::INSTANCE->zClient()->dimensionAPIRequest(msg, 2);
  264. }
  265. }
  266. nextPlayersRequest -= time;
  267. if (lastSize != getSize())
  268. {
  269. lastSize = getSize();
  270. requestNextChunk();
  271. }
  272. return DrawableBackground::tick(time);
  273. }
  274. void DimensionMap::render(Framework::Image& rObj)
  275. {
  276. DrawableBackground::render(rObj);
  277. if (!rObj.setDrawOptions(innenPosition, innenSize)) return;
  278. readLock().lock();
  279. if (zOptions->isFollowPlayer())
  280. {
  281. Vec3<float> playerPos
  282. = World::INSTANCE->getCurrentPlayerEntity()->getPos();
  283. scrollOffset
  284. = (Point((int)playerPos.x, (int)playerPos.y) - originChunkCenter)
  285. * pixelsPerBlock;
  286. requestNextChunk();
  287. }
  288. Point minScreenPos;
  289. Point minVisibleChunk = getMinVisibleChunkCenter(minScreenPos);
  290. Point maxScreenPos;
  291. Point maxVisibleChunk = getMaxVisibleChunkCenter(maxScreenPos);
  292. char addr[8];
  293. // render chunks
  294. Point screenPos = minScreenPos;
  295. for (int x = minVisibleChunk.x; x <= maxVisibleChunk.x; x += CHUNK_SIZE)
  296. {
  297. for (int y = minVisibleChunk.y; y <= maxVisibleChunk.y; y += CHUNK_SIZE)
  298. {
  299. getAddrOfWorld({x, y}, addr);
  300. ChunkMap* map = chunks->z(addr, 8);
  301. if (map)
  302. {
  303. if (zOptions->isUnderground())
  304. {
  305. map->setMaxHeight(
  306. (int)(World::INSTANCE->getCurrentPlayerEntity()
  307. ->getPos()
  308. .z
  309. / 2));
  310. }
  311. else
  312. {
  313. map->setMaxHeight(255);
  314. }
  315. Point topLeft(screenPos.x - (pixelsPerBlock * CHUNK_SIZE) / 2,
  316. screenPos.y - (pixelsPerBlock * CHUNK_SIZE) / 2);
  317. rObj.drawImageScaled(topLeft.x,
  318. topLeft.y,
  319. pixelsPerBlock * CHUNK_SIZE,
  320. pixelsPerBlock * CHUNK_SIZE,
  321. map->getRenderedImage());
  322. }
  323. screenPos.y += pixelsPerBlock * CHUNK_SIZE;
  324. }
  325. screenPos.x += pixelsPerBlock * CHUNK_SIZE;
  326. screenPos.y = minScreenPos.y;
  327. }
  328. // render shadow and borders
  329. screenPos = minScreenPos;
  330. for (int x = minVisibleChunk.x; x <= maxVisibleChunk.x; x += CHUNK_SIZE)
  331. {
  332. for (int y = minVisibleChunk.y; y <= maxVisibleChunk.y; y += CHUNK_SIZE)
  333. {
  334. getAddrOfWorld({x, y}, addr);
  335. ChunkMap* map = chunks->z(addr, 8);
  336. if (map)
  337. {
  338. Point topLeft(screenPos.x - (pixelsPerBlock * CHUNK_SIZE) / 2,
  339. screenPos.y - (pixelsPerBlock * CHUNK_SIZE) / 2);
  340. getAddrOfWorld({x, y - CHUNK_SIZE}, addr);
  341. ChunkMap* tmp = chunks->z(addr, 8);
  342. unsigned char* heightMapTop = tmp ? tmp->getHeightMap() : 0;
  343. getAddrOfWorld({x + CHUNK_SIZE, y}, addr);
  344. tmp = chunks->z(addr, 8);
  345. unsigned char* heightMapRight = tmp ? tmp->getHeightMap() : 0;
  346. getAddrOfWorld({x, y + CHUNK_SIZE}, addr);
  347. tmp = chunks->z(addr, 8);
  348. unsigned char* heightMapBottom = tmp ? tmp->getHeightMap() : 0;
  349. getAddrOfWorld({x - CHUNK_SIZE, y}, addr);
  350. tmp = chunks->z(addr, 8);
  351. unsigned char* heightMapLeft = tmp ? tmp->getHeightMap() : 0;
  352. unsigned char* heightMap = map->getHeightMap();
  353. for (int xx = 0; xx < CHUNK_SIZE; xx++)
  354. {
  355. for (int yy = 0; yy < CHUNK_SIZE; yy++)
  356. {
  357. bool shadowR = 0;
  358. bool shadowB = 0;
  359. if (xx < CHUNK_SIZE - 1)
  360. {
  361. if (heightMap[yy * CHUNK_SIZE + xx]
  362. > heightMap[yy * CHUNK_SIZE + xx + 1])
  363. {
  364. rObj.drawLineVAlpha((xx * pixelsPerBlock)
  365. + topLeft.x
  366. + pixelsPerBlock,
  367. (yy * pixelsPerBlock) + topLeft.y,
  368. pixelsPerBlock,
  369. 0x40000000);
  370. shadowR = 1;
  371. }
  372. }
  373. else if (heightMapRight)
  374. {
  375. if (heightMap[yy * CHUNK_SIZE + xx]
  376. > heightMapRight[yy * CHUNK_SIZE])
  377. {
  378. rObj.drawLineVAlpha((xx * pixelsPerBlock)
  379. + topLeft.x
  380. + pixelsPerBlock,
  381. (yy * pixelsPerBlock) + topLeft.y,
  382. pixelsPerBlock,
  383. 0x40000000);
  384. shadowR = 1;
  385. }
  386. }
  387. if (yy < CHUNK_SIZE - 1)
  388. {
  389. if (heightMap[yy * CHUNK_SIZE + xx]
  390. > heightMap[(yy + 1) * CHUNK_SIZE + xx])
  391. {
  392. rObj.drawLineHAlpha(
  393. (xx * pixelsPerBlock) + topLeft.x,
  394. (yy * pixelsPerBlock) + topLeft.y
  395. + pixelsPerBlock,
  396. pixelsPerBlock,
  397. 0x30000000);
  398. shadowB = 1;
  399. }
  400. }
  401. else if (heightMapBottom)
  402. {
  403. if (heightMap[yy * CHUNK_SIZE + xx]
  404. > heightMapBottom[xx])
  405. {
  406. rObj.drawLineHAlpha(
  407. (xx * pixelsPerBlock) + topLeft.x,
  408. (yy * pixelsPerBlock) + topLeft.y
  409. + pixelsPerBlock,
  410. pixelsPerBlock,
  411. 0x30000000);
  412. shadowB = 1;
  413. }
  414. }
  415. if (xx > 0)
  416. {
  417. if (heightMap[yy * CHUNK_SIZE + xx]
  418. > heightMap[yy * CHUNK_SIZE + xx - 1])
  419. {
  420. rObj.drawLineVAlpha(
  421. (xx * pixelsPerBlock) + topLeft.x,
  422. (yy * pixelsPerBlock) + topLeft.y,
  423. pixelsPerBlock - shadowB,
  424. 0x20FFFFFF);
  425. }
  426. }
  427. else if (heightMapLeft)
  428. {
  429. if (heightMap[yy * CHUNK_SIZE + xx]
  430. > heightMapLeft[yy * CHUNK_SIZE + CHUNK_SIZE
  431. - 1])
  432. {
  433. rObj.drawLineVAlpha(
  434. (xx * pixelsPerBlock) + topLeft.x,
  435. (yy * pixelsPerBlock) + topLeft.y,
  436. pixelsPerBlock - shadowB,
  437. 0x20FFFFFF);
  438. }
  439. }
  440. if (yy > 0)
  441. {
  442. if (heightMap[yy * CHUNK_SIZE + xx]
  443. > heightMap[(yy - 1) * CHUNK_SIZE + xx])
  444. {
  445. rObj.drawLineHAlpha(
  446. (xx * pixelsPerBlock) + topLeft.x,
  447. (yy * pixelsPerBlock) + topLeft.y,
  448. pixelsPerBlock - shadowR,
  449. 0x10FFFFFF);
  450. }
  451. }
  452. else if (heightMapTop)
  453. {
  454. if (heightMap[yy * CHUNK_SIZE + xx]
  455. > heightMapTop[(CHUNK_SIZE - 1) * CHUNK_SIZE
  456. + xx])
  457. {
  458. rObj.drawLineHAlpha(
  459. (xx * pixelsPerBlock) + topLeft.x,
  460. (yy * pixelsPerBlock) + topLeft.y,
  461. pixelsPerBlock - shadowR,
  462. 0x10FFFFFF);
  463. }
  464. }
  465. }
  466. }
  467. if (zOptions->isShowChunkBorders())
  468. {
  469. rObj.drawLineHAlpha(topLeft.x,
  470. topLeft.y,
  471. pixelsPerBlock * CHUNK_SIZE,
  472. 0x50FFFFFF);
  473. rObj.drawLineVAlpha(topLeft.x,
  474. topLeft.y,
  475. pixelsPerBlock * CHUNK_SIZE,
  476. 0x50FFFFFF);
  477. }
  478. }
  479. screenPos.y += pixelsPerBlock * CHUNK_SIZE;
  480. }
  481. screenPos.x += pixelsPerBlock * CHUNK_SIZE;
  482. screenPos.y = minScreenPos.y;
  483. }
  484. // render players
  485. if (zOptions->isShowPlayers())
  486. {
  487. TextRenderer tm(
  488. dynamic_cast<Font*>(uiFactory.initParam.font->getThis()));
  489. tm.setFontSize(12);
  490. for (const MapPlayer& player : players)
  491. {
  492. Point screenPos
  493. = getSize() / 2 - scrollOffset
  494. + (Point((int)player.position.x, (int)player.position.y)
  495. - originChunkCenter)
  496. * pixelsPerBlock
  497. + Point(pixelsPerBlock, pixelsPerBlock) / 2
  498. - playerIcon->getSize() / 2;
  499. rObj.alphaImage(screenPos.x,
  500. screenPos.y,
  501. playerIcon->getWidth(),
  502. playerIcon->getHeight(),
  503. *playerIcon);
  504. int textWidth = tm.getTextWidth(player.name);
  505. int textheight = tm.getTextHeight(player.name);
  506. screenPos = screenPos + Point(playerIcon->getWidth(), 0) / 2
  507. - Point(textWidth / 2, textheight + 2);
  508. rObj.alphaRegion(
  509. screenPos.x, screenPos.y, textWidth, textheight, 0x70000000);
  510. tm.renderText(
  511. screenPos.x, screenPos.y, player.name, rObj, 0xFFFFFFFF);
  512. }
  513. }
  514. readLock().unlock();
  515. rObj.releaseDrawOptions();
  516. }
  517. void DimensionMap::doMouseEvent(Framework::MouseEvent& me, bool userRet)
  518. {
  519. if (me.id == ME_PLeft)
  520. {
  521. drag = 1;
  522. lastMouse = {me.mx, me.my};
  523. }
  524. if (me.id == ME_RLeft || me.id == ME_Leaves) drag = 0;
  525. if (me.id == ME_Move && drag)
  526. {
  527. scrollOffset -= Point(me.mx, me.my) - lastMouse;
  528. lastMouse = Point(me.mx, me.my);
  529. rend = 1;
  530. requestNextChunk();
  531. }
  532. if (me.id == ME_DScroll && pixelsPerBlock > 1)
  533. {
  534. scrollOffset = (scrollOffset / pixelsPerBlock) * (pixelsPerBlock - 1);
  535. pixelsPerBlock--;
  536. rend = 1;
  537. requestNextChunk();
  538. }
  539. if (me.id == ME_UScroll)
  540. {
  541. scrollOffset = (scrollOffset / pixelsPerBlock) * (pixelsPerBlock + 1);
  542. pixelsPerBlock++;
  543. rend = 1;
  544. requestNextChunk();
  545. }
  546. DrawableBackground::doMouseEvent(me, userRet);
  547. }