DimensionMap.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  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::Trie<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/bilder/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. chunks->set(addr, 8, chunk);
  238. chunkList.add(chunk);
  239. chunkCount++;
  240. requestCount--;
  241. removeUnused();
  242. cs.unlock();
  243. requestNextChunk();
  244. }
  245. bool DimensionMap::tick(double time)
  246. {
  247. if (nextPlayersRequest < 0 && zOptions->isShowPlayers())
  248. {
  249. nextPlayersRequest = 2;
  250. char msg[2];
  251. msg[0] = 2; // request map players
  252. msg[1] = 3;
  253. World::INSTANCE->zClient()->dimensionAPIRequest(msg, 2);
  254. }
  255. nextPlayersRequest -= time;
  256. if (lastSize != getSize())
  257. {
  258. lastSize = getSize();
  259. requestNextChunk();
  260. }
  261. return ZeichnungHintergrund::tick(time);
  262. }
  263. void DimensionMap::render(Framework::Bild& rObj)
  264. {
  265. ZeichnungHintergrund::render(rObj);
  266. if (!rObj.setDrawOptions(innenPosition, innenSize)) return;
  267. cs.lock();
  268. if (zOptions->isFollowPlayer())
  269. {
  270. Vec3<float> playerPos
  271. = World::INSTANCE->getCurrentPlayerEntity()->getPos();
  272. scrollOffset
  273. = (Punkt((int)playerPos.x, (int)playerPos.y) - originChunkCenter)
  274. * pixelsPerBlock;
  275. requestNextChunk();
  276. }
  277. Punkt minScreenPos;
  278. Punkt minVisibleChunk = getMinVisibleChunkCenter(minScreenPos);
  279. Punkt maxScreenPos;
  280. Punkt maxVisibleChunk = getMaxVisibleChunkCenter(maxScreenPos);
  281. char addr[8];
  282. // render chunks
  283. Punkt screenPos = minScreenPos;
  284. for (int x = minVisibleChunk.x; x <= maxVisibleChunk.x; x += CHUNK_SIZE)
  285. {
  286. for (int y = minVisibleChunk.y; y <= maxVisibleChunk.y; y += CHUNK_SIZE)
  287. {
  288. getAddrOfWorld({x, y}, addr);
  289. ChunkMap* map = chunks->z(addr, 8);
  290. if (map)
  291. {
  292. if (zOptions->isUnderground())
  293. {
  294. map->setMaxHeight(
  295. (int)(World::INSTANCE->getCurrentPlayerEntity()
  296. ->getPos()
  297. .z
  298. / 2));
  299. }
  300. else
  301. {
  302. map->setMaxHeight(255);
  303. }
  304. Punkt topLeft(screenPos.x - (pixelsPerBlock * CHUNK_SIZE) / 2,
  305. screenPos.y - (pixelsPerBlock * CHUNK_SIZE) / 2);
  306. rObj.drawBildSkall(topLeft.x,
  307. topLeft.y,
  308. pixelsPerBlock * CHUNK_SIZE,
  309. pixelsPerBlock * CHUNK_SIZE,
  310. map->getRenderedImage());
  311. }
  312. screenPos.y += pixelsPerBlock * CHUNK_SIZE;
  313. }
  314. screenPos.x += pixelsPerBlock * CHUNK_SIZE;
  315. screenPos.y = minScreenPos.y;
  316. }
  317. // render shadow and borders
  318. screenPos = minScreenPos;
  319. for (int x = minVisibleChunk.x; x <= maxVisibleChunk.x; x += CHUNK_SIZE)
  320. {
  321. for (int y = minVisibleChunk.y; y <= maxVisibleChunk.y; y += CHUNK_SIZE)
  322. {
  323. getAddrOfWorld({x, y}, addr);
  324. ChunkMap* map = chunks->z(addr, 8);
  325. if (map)
  326. {
  327. Punkt topLeft(screenPos.x - (pixelsPerBlock * CHUNK_SIZE) / 2,
  328. screenPos.y - (pixelsPerBlock * CHUNK_SIZE) / 2);
  329. getAddrOfWorld({x, y - CHUNK_SIZE}, addr);
  330. ChunkMap* tmp = chunks->z(addr, 8);
  331. unsigned char* heightMapTop = tmp ? tmp->getHeightMap() : 0;
  332. getAddrOfWorld({x + CHUNK_SIZE, y}, addr);
  333. tmp = chunks->z(addr, 8);
  334. unsigned char* heightMapRight = tmp ? tmp->getHeightMap() : 0;
  335. getAddrOfWorld({x, y + CHUNK_SIZE}, addr);
  336. tmp = chunks->z(addr, 8);
  337. unsigned char* heightMapBottom = tmp ? tmp->getHeightMap() : 0;
  338. getAddrOfWorld({x - CHUNK_SIZE, y}, addr);
  339. tmp = chunks->z(addr, 8);
  340. unsigned char* heightMapLeft = tmp ? tmp->getHeightMap() : 0;
  341. unsigned char* heightMap = map->getHeightMap();
  342. for (int xx = 0; xx < CHUNK_SIZE; xx++)
  343. {
  344. for (int yy = 0; yy < CHUNK_SIZE; yy++)
  345. {
  346. bool shadowR = 0;
  347. bool shadowB = 0;
  348. if (xx < CHUNK_SIZE - 1)
  349. {
  350. if (heightMap[yy * CHUNK_SIZE + xx]
  351. > heightMap[yy * CHUNK_SIZE + xx + 1])
  352. {
  353. rObj.drawLinieVAlpha((xx * pixelsPerBlock)
  354. + topLeft.x
  355. + pixelsPerBlock,
  356. (yy * pixelsPerBlock) + topLeft.y,
  357. pixelsPerBlock,
  358. 0x40000000);
  359. shadowR = 1;
  360. }
  361. }
  362. else if (heightMapRight)
  363. {
  364. if (heightMap[yy * CHUNK_SIZE + xx]
  365. > heightMapRight[yy * CHUNK_SIZE])
  366. {
  367. rObj.drawLinieVAlpha((xx * pixelsPerBlock)
  368. + topLeft.x
  369. + pixelsPerBlock,
  370. (yy * pixelsPerBlock) + topLeft.y,
  371. pixelsPerBlock,
  372. 0x40000000);
  373. shadowR = 1;
  374. }
  375. }
  376. if (yy < CHUNK_SIZE - 1)
  377. {
  378. if (heightMap[yy * CHUNK_SIZE + xx]
  379. > heightMap[(yy + 1) * CHUNK_SIZE + xx])
  380. {
  381. rObj.drawLinieHAlpha(
  382. (xx * pixelsPerBlock) + topLeft.x,
  383. (yy * pixelsPerBlock) + topLeft.y
  384. + pixelsPerBlock,
  385. pixelsPerBlock,
  386. 0x30000000);
  387. shadowB = 1;
  388. }
  389. }
  390. else if (heightMapBottom)
  391. {
  392. if (heightMap[yy * CHUNK_SIZE + xx]
  393. > heightMapBottom[xx])
  394. {
  395. rObj.drawLinieHAlpha(
  396. (xx * pixelsPerBlock) + topLeft.x,
  397. (yy * pixelsPerBlock) + topLeft.y
  398. + pixelsPerBlock,
  399. pixelsPerBlock,
  400. 0x30000000);
  401. shadowB = 1;
  402. }
  403. }
  404. if (xx > 0)
  405. {
  406. if (heightMap[yy * CHUNK_SIZE + xx]
  407. > heightMap[yy * CHUNK_SIZE + xx - 1])
  408. {
  409. rObj.drawLinieVAlpha(
  410. (xx * pixelsPerBlock) + topLeft.x,
  411. (yy * pixelsPerBlock) + topLeft.y,
  412. pixelsPerBlock - shadowB,
  413. 0x20FFFFFF);
  414. }
  415. }
  416. else if (heightMapLeft)
  417. {
  418. if (heightMap[yy * CHUNK_SIZE + xx]
  419. > heightMapLeft[yy * CHUNK_SIZE + CHUNK_SIZE
  420. - 1])
  421. {
  422. rObj.drawLinieVAlpha(
  423. (xx * pixelsPerBlock) + topLeft.x,
  424. (yy * pixelsPerBlock) + topLeft.y,
  425. pixelsPerBlock - shadowB,
  426. 0x20FFFFFF);
  427. }
  428. }
  429. if (yy > 0)
  430. {
  431. if (heightMap[yy * CHUNK_SIZE + xx]
  432. > heightMap[(yy - 1) * CHUNK_SIZE + xx])
  433. {
  434. rObj.drawLinieHAlpha(
  435. (xx * pixelsPerBlock) + topLeft.x,
  436. (yy * pixelsPerBlock) + topLeft.y,
  437. pixelsPerBlock - shadowR,
  438. 0x10FFFFFF);
  439. }
  440. }
  441. else if (heightMapTop)
  442. {
  443. if (heightMap[yy * CHUNK_SIZE + xx]
  444. > heightMapTop[(CHUNK_SIZE - 1) * CHUNK_SIZE
  445. + xx])
  446. {
  447. rObj.drawLinieHAlpha(
  448. (xx * pixelsPerBlock) + topLeft.x,
  449. (yy * pixelsPerBlock) + topLeft.y,
  450. pixelsPerBlock - shadowR,
  451. 0x10FFFFFF);
  452. }
  453. }
  454. }
  455. }
  456. if (zOptions->isShowChunkBorders())
  457. {
  458. rObj.drawLinieHAlpha(topLeft.x,
  459. topLeft.y,
  460. pixelsPerBlock * CHUNK_SIZE,
  461. 0x50FFFFFF);
  462. rObj.drawLinieVAlpha(topLeft.x,
  463. topLeft.y,
  464. pixelsPerBlock * CHUNK_SIZE,
  465. 0x50FFFFFF);
  466. }
  467. }
  468. screenPos.y += pixelsPerBlock * CHUNK_SIZE;
  469. }
  470. screenPos.x += pixelsPerBlock * CHUNK_SIZE;
  471. screenPos.y = minScreenPos.y;
  472. }
  473. // render players
  474. if (zOptions->isShowPlayers())
  475. {
  476. TextRenderer tm(dynamic_cast<Schrift*>(uiFactory.initParam.schrift->getThis()));
  477. tm.setSchriftSize(12);
  478. for (MapPlayer& player : players)
  479. {
  480. Punkt screenPos
  481. = getSize() / 2 - scrollOffset
  482. + (Punkt((int)player.position.x, (int)player.position.y)
  483. - originChunkCenter)
  484. * pixelsPerBlock
  485. + Punkt(pixelsPerBlock, pixelsPerBlock) / 2
  486. - playerIcon->getSize() / 2;
  487. rObj.alphaBild(screenPos.x,
  488. screenPos.y,
  489. playerIcon->getBreite(),
  490. playerIcon->getHeight(),
  491. *playerIcon);
  492. int textWidth = tm.getTextBreite(player.name);
  493. int textheight = tm.getTextHeight(player.name);
  494. screenPos = screenPos + Punkt(playerIcon->getBreite(), 0) / 2
  495. - Punkt(textWidth / 2, textheight + 2);
  496. rObj.alphaRegion(
  497. screenPos.x, screenPos.y, textWidth, textheight, 0x70000000);
  498. tm.renderText(
  499. screenPos.x, screenPos.y, player.name, rObj, 0xFFFFFFFF);
  500. }
  501. }
  502. cs.unlock();
  503. rObj.releaseDrawOptions();
  504. }
  505. void DimensionMap::doMausEreignis(Framework::MausEreignis& me, bool userRet)
  506. {
  507. if (me.id == ME_PLinks)
  508. {
  509. drag = 1;
  510. lastMouse = {me.mx, me.my};
  511. }
  512. if (me.id == ME_RLinks || me.id == ME_Leaves) drag = 0;
  513. if (me.id == ME_Bewegung && drag)
  514. {
  515. scrollOffset -= Punkt(me.mx, me.my) - lastMouse;
  516. lastMouse = Punkt(me.mx, me.my);
  517. rend = 1;
  518. requestNextChunk();
  519. }
  520. if (me.id == ME_DScroll && pixelsPerBlock > 1)
  521. {
  522. scrollOffset = (scrollOffset / pixelsPerBlock) * (pixelsPerBlock - 1);
  523. pixelsPerBlock--;
  524. rend = 1;
  525. requestNextChunk();
  526. }
  527. if (me.id == ME_UScroll)
  528. {
  529. scrollOffset = (scrollOffset / pixelsPerBlock) * (pixelsPerBlock + 1);
  530. pixelsPerBlock++;
  531. rend = 1;
  532. requestNextChunk();
  533. }
  534. ZeichnungHintergrund::doMausEreignis(me, userRet);
  535. }