DimensionMap.cpp 20 KB

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