DimensionMap.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. #include "DimensionMap.h"
  2. #include <DateiSystem.h>
  3. #include "Constants.h"
  4. #include "Globals.h"
  5. #include "World.h"
  6. DimensionMap::DimensionMap(MapOptions* zOptions)
  7. : ZeichnungHintergrund(),
  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::Sichtbar | Style::Erlaubt);
  18. chunks = new Framework::RCTrie<ChunkMap>();
  19. setMausEreignis(_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. LTDBDatei iconsDat;
  26. iconsDat.setDatei(new Text("data/images/gui_icons.ltdb"));
  27. iconsDat.leseDaten(0);
  28. playerIcon = iconsDat.laden(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(Punkt cPos, char* addr) const
  40. {
  41. *(int*)addr = cPos.x;
  42. *((int*)addr + 1) = cPos.y;
  43. }
  44. void DimensionMap::getAddrOfWorld(Punkt 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::Punkt DimensionMap::getMinVisibleChunkCenter(
  54. Framework::Punkt& screenPos) const
  55. {
  56. screenPos = getSize() / 2 - scrollOffset;
  57. Punkt 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::Punkt DimensionMap::getMaxVisibleChunkCenter(
  81. Framework::Punkt& screenPos) const
  82. {
  83. screenPos = getSize() / 2 - scrollOffset;
  84. Punkt currentChunkCenter = originChunkCenter;
  85. while (screenPos.x - pixelsPerBlock * (CHUNK_SIZE / 2) < getBreite())
  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) >= getBreite())
  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. Punkt tmp;
  110. Framework::Punkt min
  111. = getMinVisibleChunkCenter(tmp) - Punkt(CHUNK_SIZE, CHUNK_SIZE) * 5;
  112. Framework::Punkt max
  113. = getMaxVisibleChunkCenter(tmp) + Punkt(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. cs.lock();
  135. players.leeren();
  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. cs.unlock();
  155. }
  156. void DimensionMap::requestNextChunk()
  157. {
  158. cs.lock();
  159. if (requestCount >= 20)
  160. {
  161. cs.unlock();
  162. return;
  163. }
  164. if (chunkCount == 0)
  165. {
  166. requestCount++;
  167. Vec3<float> playerPos
  168. = World::INSTANCE->getCurrentPlayerEntity()->getPos();
  169. char msg[10];
  170. msg[0] = 2;
  171. msg[1] = 0;
  172. *(int*)(msg + 2) = (int)playerPos.x;
  173. *(int*)(msg + 6) = (int)playerPos.y;
  174. World::INSTANCE->zClient()->dimensionAPIRequest(msg, 10);
  175. }
  176. else
  177. {
  178. while (requestCount < 20)
  179. {
  180. Punkt minScreenPos;
  181. Punkt minVisibleChunk = getMinVisibleChunkCenter(minScreenPos);
  182. Punkt maxScreenPos;
  183. Punkt maxVisibleChunk = getMaxVisibleChunkCenter(maxScreenPos);
  184. Punkt screenPos = minScreenPos;
  185. Punkt screenCenter = getSize() / 2;
  186. double minDist = -1;
  187. Punkt resultChunk(0, 0);
  188. char addr[8];
  189. for (int x = minVisibleChunk.x; x <= maxVisibleChunk.x;
  190. x += CHUNK_SIZE)
  191. {
  192. for (int y = minVisibleChunk.y; y <= maxVisibleChunk.y;
  193. y += CHUNK_SIZE)
  194. {
  195. getAddrOfWorld({x, y}, addr);
  196. if (!chunks->z(addr, 8))
  197. {
  198. if (minDist < 0
  199. || (screenCenter - screenPos).getLengthSq()
  200. < minDist)
  201. {
  202. minDist = (screenCenter - screenPos).getLengthSq();
  203. resultChunk = {x, y};
  204. }
  205. }
  206. screenPos.y += pixelsPerBlock * CHUNK_SIZE;
  207. }
  208. screenPos.x += pixelsPerBlock * CHUNK_SIZE;
  209. screenPos.y = minScreenPos.y;
  210. }
  211. if (minDist >= 0)
  212. {
  213. requestCount++;
  214. char msg[10];
  215. msg[0] = 2;
  216. msg[1] = 0;
  217. *(int*)(msg + 2) = (int)resultChunk.x;
  218. *(int*)(msg + 6) = (int)resultChunk.y;
  219. World::INSTANCE->zClient()->dimensionAPIRequest(msg, 10);
  220. getAddrOfWorld({resultChunk.x, resultChunk.y}, addr);
  221. chunks->set(addr, 8, new ChunkMap(resultChunk));
  222. }
  223. else
  224. {
  225. break;
  226. }
  227. }
  228. }
  229. cs.unlock();
  230. }
  231. void DimensionMap::addChunk(ChunkMap* chunk)
  232. {
  233. cs.lock();
  234. if (chunkCount == 0) originChunkCenter = chunk->getChunkCenter();
  235. char addr[8];
  236. getAddrOfWorld(chunk->getChunkCenter(), addr);
  237. ChunkMap* old = chunks->z(addr, 8);
  238. if (old) chunkList.removeValue(old);
  239. chunks->set(addr, 8, chunk);
  240. chunkList.add(chunk);
  241. chunkCount++;
  242. requestCount--;
  243. removeUnused();
  244. cs.unlock();
  245. requestNextChunk();
  246. }
  247. bool DimensionMap::tick(double time)
  248. {
  249. if (nextPlayersRequest < 0 && zOptions->isShowPlayers())
  250. {
  251. nextPlayersRequest = 2;
  252. char msg[2];
  253. msg[0] = 2; // request map players
  254. msg[1] = 3;
  255. if (World::INSTANCE)
  256. {
  257. World::INSTANCE->zClient()->dimensionAPIRequest(msg, 2);
  258. }
  259. }
  260. nextPlayersRequest -= time;
  261. if (lastSize != getSize())
  262. {
  263. lastSize = getSize();
  264. requestNextChunk();
  265. }
  266. return ZeichnungHintergrund::tick(time);
  267. }
  268. void DimensionMap::render(Framework::Bild& rObj)
  269. {
  270. ZeichnungHintergrund::render(rObj);
  271. if (!rObj.setDrawOptions(innenPosition, innenSize)) return;
  272. cs.lock();
  273. if (zOptions->isFollowPlayer())
  274. {
  275. Vec3<float> playerPos
  276. = World::INSTANCE->getCurrentPlayerEntity()->getPos();
  277. scrollOffset
  278. = (Punkt((int)playerPos.x, (int)playerPos.y) - originChunkCenter)
  279. * pixelsPerBlock;
  280. requestNextChunk();
  281. }
  282. Punkt minScreenPos;
  283. Punkt minVisibleChunk = getMinVisibleChunkCenter(minScreenPos);
  284. Punkt maxScreenPos;
  285. Punkt maxVisibleChunk = getMaxVisibleChunkCenter(maxScreenPos);
  286. char addr[8];
  287. // render chunks
  288. Punkt screenPos = minScreenPos;
  289. for (int x = minVisibleChunk.x; x <= maxVisibleChunk.x; x += CHUNK_SIZE)
  290. {
  291. for (int y = minVisibleChunk.y; y <= maxVisibleChunk.y; y += CHUNK_SIZE)
  292. {
  293. getAddrOfWorld({x, y}, addr);
  294. ChunkMap* map = chunks->z(addr, 8);
  295. if (map)
  296. {
  297. if (zOptions->isUnderground())
  298. {
  299. map->setMaxHeight(
  300. (int)(World::INSTANCE->getCurrentPlayerEntity()
  301. ->getPos()
  302. .z
  303. / 2));
  304. }
  305. else
  306. {
  307. map->setMaxHeight(255);
  308. }
  309. Punkt topLeft(screenPos.x - (pixelsPerBlock * CHUNK_SIZE) / 2,
  310. screenPos.y - (pixelsPerBlock * CHUNK_SIZE) / 2);
  311. rObj.drawBildSkall(topLeft.x,
  312. topLeft.y,
  313. pixelsPerBlock * CHUNK_SIZE,
  314. pixelsPerBlock * CHUNK_SIZE,
  315. map->getRenderedImage());
  316. }
  317. screenPos.y += pixelsPerBlock * CHUNK_SIZE;
  318. }
  319. screenPos.x += pixelsPerBlock * CHUNK_SIZE;
  320. screenPos.y = minScreenPos.y;
  321. }
  322. // render shadow and borders
  323. screenPos = minScreenPos;
  324. for (int x = minVisibleChunk.x; x <= maxVisibleChunk.x; x += CHUNK_SIZE)
  325. {
  326. for (int y = minVisibleChunk.y; y <= maxVisibleChunk.y; y += CHUNK_SIZE)
  327. {
  328. getAddrOfWorld({x, y}, addr);
  329. ChunkMap* map = chunks->z(addr, 8);
  330. if (map)
  331. {
  332. Punkt topLeft(screenPos.x - (pixelsPerBlock * CHUNK_SIZE) / 2,
  333. screenPos.y - (pixelsPerBlock * CHUNK_SIZE) / 2);
  334. getAddrOfWorld({x, y - CHUNK_SIZE}, addr);
  335. ChunkMap* tmp = chunks->z(addr, 8);
  336. unsigned char* heightMapTop = tmp ? tmp->getHeightMap() : 0;
  337. getAddrOfWorld({x + CHUNK_SIZE, y}, addr);
  338. tmp = chunks->z(addr, 8);
  339. unsigned char* heightMapRight = tmp ? tmp->getHeightMap() : 0;
  340. getAddrOfWorld({x, y + CHUNK_SIZE}, addr);
  341. tmp = chunks->z(addr, 8);
  342. unsigned char* heightMapBottom = tmp ? tmp->getHeightMap() : 0;
  343. getAddrOfWorld({x - CHUNK_SIZE, y}, addr);
  344. tmp = chunks->z(addr, 8);
  345. unsigned char* heightMapLeft = tmp ? tmp->getHeightMap() : 0;
  346. unsigned char* heightMap = map->getHeightMap();
  347. for (int xx = 0; xx < CHUNK_SIZE; xx++)
  348. {
  349. for (int yy = 0; yy < CHUNK_SIZE; yy++)
  350. {
  351. bool shadowR = 0;
  352. bool shadowB = 0;
  353. if (xx < CHUNK_SIZE - 1)
  354. {
  355. if (heightMap[yy * CHUNK_SIZE + xx]
  356. > heightMap[yy * CHUNK_SIZE + xx + 1])
  357. {
  358. rObj.drawLinieVAlpha((xx * pixelsPerBlock)
  359. + topLeft.x
  360. + pixelsPerBlock,
  361. (yy * pixelsPerBlock) + topLeft.y,
  362. pixelsPerBlock,
  363. 0x40000000);
  364. shadowR = 1;
  365. }
  366. }
  367. else if (heightMapRight)
  368. {
  369. if (heightMap[yy * CHUNK_SIZE + xx]
  370. > heightMapRight[yy * CHUNK_SIZE])
  371. {
  372. rObj.drawLinieVAlpha((xx * pixelsPerBlock)
  373. + topLeft.x
  374. + pixelsPerBlock,
  375. (yy * pixelsPerBlock) + topLeft.y,
  376. pixelsPerBlock,
  377. 0x40000000);
  378. shadowR = 1;
  379. }
  380. }
  381. if (yy < CHUNK_SIZE - 1)
  382. {
  383. if (heightMap[yy * CHUNK_SIZE + xx]
  384. > heightMap[(yy + 1) * CHUNK_SIZE + xx])
  385. {
  386. rObj.drawLinieHAlpha(
  387. (xx * pixelsPerBlock) + topLeft.x,
  388. (yy * pixelsPerBlock) + topLeft.y
  389. + pixelsPerBlock,
  390. pixelsPerBlock,
  391. 0x30000000);
  392. shadowB = 1;
  393. }
  394. }
  395. else if (heightMapBottom)
  396. {
  397. if (heightMap[yy * CHUNK_SIZE + xx]
  398. > heightMapBottom[xx])
  399. {
  400. rObj.drawLinieHAlpha(
  401. (xx * pixelsPerBlock) + topLeft.x,
  402. (yy * pixelsPerBlock) + topLeft.y
  403. + pixelsPerBlock,
  404. pixelsPerBlock,
  405. 0x30000000);
  406. shadowB = 1;
  407. }
  408. }
  409. if (xx > 0)
  410. {
  411. if (heightMap[yy * CHUNK_SIZE + xx]
  412. > heightMap[yy * CHUNK_SIZE + xx - 1])
  413. {
  414. rObj.drawLinieVAlpha(
  415. (xx * pixelsPerBlock) + topLeft.x,
  416. (yy * pixelsPerBlock) + topLeft.y,
  417. pixelsPerBlock - shadowB,
  418. 0x20FFFFFF);
  419. }
  420. }
  421. else if (heightMapLeft)
  422. {
  423. if (heightMap[yy * CHUNK_SIZE + xx]
  424. > heightMapLeft[yy * CHUNK_SIZE + CHUNK_SIZE
  425. - 1])
  426. {
  427. rObj.drawLinieVAlpha(
  428. (xx * pixelsPerBlock) + topLeft.x,
  429. (yy * pixelsPerBlock) + topLeft.y,
  430. pixelsPerBlock - shadowB,
  431. 0x20FFFFFF);
  432. }
  433. }
  434. if (yy > 0)
  435. {
  436. if (heightMap[yy * CHUNK_SIZE + xx]
  437. > heightMap[(yy - 1) * CHUNK_SIZE + xx])
  438. {
  439. rObj.drawLinieHAlpha(
  440. (xx * pixelsPerBlock) + topLeft.x,
  441. (yy * pixelsPerBlock) + topLeft.y,
  442. pixelsPerBlock - shadowR,
  443. 0x10FFFFFF);
  444. }
  445. }
  446. else if (heightMapTop)
  447. {
  448. if (heightMap[yy * CHUNK_SIZE + xx]
  449. > heightMapTop[(CHUNK_SIZE - 1) * CHUNK_SIZE
  450. + xx])
  451. {
  452. rObj.drawLinieHAlpha(
  453. (xx * pixelsPerBlock) + topLeft.x,
  454. (yy * pixelsPerBlock) + topLeft.y,
  455. pixelsPerBlock - shadowR,
  456. 0x10FFFFFF);
  457. }
  458. }
  459. }
  460. }
  461. if (zOptions->isShowChunkBorders())
  462. {
  463. rObj.drawLinieHAlpha(topLeft.x,
  464. topLeft.y,
  465. pixelsPerBlock * CHUNK_SIZE,
  466. 0x50FFFFFF);
  467. rObj.drawLinieVAlpha(topLeft.x,
  468. topLeft.y,
  469. pixelsPerBlock * CHUNK_SIZE,
  470. 0x50FFFFFF);
  471. }
  472. }
  473. screenPos.y += pixelsPerBlock * CHUNK_SIZE;
  474. }
  475. screenPos.x += pixelsPerBlock * CHUNK_SIZE;
  476. screenPos.y = minScreenPos.y;
  477. }
  478. // render players
  479. if (zOptions->isShowPlayers())
  480. {
  481. TextRenderer tm(
  482. dynamic_cast<Schrift*>(uiFactory.initParam.schrift->getThis()));
  483. tm.setSchriftSize(12);
  484. for (const MapPlayer& player : players)
  485. {
  486. Punkt screenPos
  487. = getSize() / 2 - scrollOffset
  488. + (Punkt((int)player.position.x, (int)player.position.y)
  489. - originChunkCenter)
  490. * pixelsPerBlock
  491. + Punkt(pixelsPerBlock, pixelsPerBlock) / 2
  492. - playerIcon->getSize() / 2;
  493. rObj.alphaBild(screenPos.x,
  494. screenPos.y,
  495. playerIcon->getBreite(),
  496. playerIcon->getHeight(),
  497. *playerIcon);
  498. int textWidth = tm.getTextBreite(player.name);
  499. int textheight = tm.getTextHeight(player.name);
  500. screenPos = screenPos + Punkt(playerIcon->getBreite(), 0) / 2
  501. - Punkt(textWidth / 2, textheight + 2);
  502. rObj.alphaRegion(
  503. screenPos.x, screenPos.y, textWidth, textheight, 0x70000000);
  504. tm.renderText(
  505. screenPos.x, screenPos.y, player.name, rObj, 0xFFFFFFFF);
  506. }
  507. }
  508. cs.unlock();
  509. rObj.releaseDrawOptions();
  510. }
  511. void DimensionMap::doMausEreignis(Framework::MausEreignis& me, bool userRet)
  512. {
  513. if (me.id == ME_PLinks)
  514. {
  515. drag = 1;
  516. lastMouse = {me.mx, me.my};
  517. }
  518. if (me.id == ME_RLinks || me.id == ME_Leaves) drag = 0;
  519. if (me.id == ME_Bewegung && drag)
  520. {
  521. scrollOffset -= Punkt(me.mx, me.my) - lastMouse;
  522. lastMouse = Punkt(me.mx, me.my);
  523. rend = 1;
  524. requestNextChunk();
  525. }
  526. if (me.id == ME_DScroll && pixelsPerBlock > 1)
  527. {
  528. scrollOffset = (scrollOffset / pixelsPerBlock) * (pixelsPerBlock - 1);
  529. pixelsPerBlock--;
  530. rend = 1;
  531. requestNextChunk();
  532. }
  533. if (me.id == ME_UScroll)
  534. {
  535. scrollOffset = (scrollOffset / pixelsPerBlock) * (pixelsPerBlock + 1);
  536. pixelsPerBlock++;
  537. rend = 1;
  538. requestNextChunk();
  539. }
  540. ZeichnungHintergrund::doMausEreignis(me, userRet);
  541. }