#include "DimensionMap.h" #include #include "Constants.h" #include "Globals.h" #include "World.h" DimensionMap::DimensionMap(MapOptions* zOptions) : ZeichnungHintergrund(), zOptions(zOptions), originChunkCenter(0, 0), scrollOffset(0, 0), chunkCount(0), pixelsPerBlock(16), requestCount(0), drag(0), nextPlayersRequest(-1) { setStyle(Style::Sichtbar | Style::Erlaubt); chunks = new Framework::RCTrie(); setMausEreignis(_ret1ME); requestNextChunk(); char msg[2]; msg[0] = 2; // subscribe to map changes msg[1] = 1; World::INSTANCE->zClient()->dimensionAPIRequest(msg, 2); LTDBDatei iconsDat; iconsDat.setDatei(new Text("data/images/gui_icons.ltdb")); iconsDat.leseDaten(0); playerIcon = iconsDat.laden(0, new Text("player.png")); } DimensionMap::~DimensionMap() { char msg[2]; msg[0] = 2; // unsubscribe from map changes msg[1] = 2; World::INSTANCE->zClient()->dimensionAPIRequest(msg, 2); chunks->release(); playerIcon->release(); } void DimensionMap::getAddrOf(Punkt cPos, char* addr) const { *(int*)addr = cPos.x; *((int*)addr + 1) = cPos.y; } void DimensionMap::getAddrOfWorld(Punkt wPos, char* addr) const { // needed because otherwise would (-8, -8) have the same // adress as (8, 8) if (wPos.x < 0) wPos.x -= CHUNK_SIZE; if (wPos.y < 0) wPos.y -= CHUNK_SIZE; wPos /= CHUNK_SIZE; getAddrOf(wPos, addr); } Framework::Punkt DimensionMap::getMinVisibleChunkCenter( Framework::Punkt& screenPos) const { screenPos = getSize() / 2 - scrollOffset; Punkt currentChunkCenter = originChunkCenter; while (screenPos.x + pixelsPerBlock * (CHUNK_SIZE / 2) >= 0) { screenPos.x -= pixelsPerBlock * CHUNK_SIZE; currentChunkCenter.x -= CHUNK_SIZE; } while (screenPos.y + pixelsPerBlock * (CHUNK_SIZE / 2) >= 0) { screenPos.y -= pixelsPerBlock * CHUNK_SIZE; currentChunkCenter.y -= CHUNK_SIZE; } while (screenPos.x + pixelsPerBlock * (CHUNK_SIZE / 2) < 0) { screenPos.x += pixelsPerBlock * CHUNK_SIZE; currentChunkCenter.x += CHUNK_SIZE; } while (screenPos.y + pixelsPerBlock * (CHUNK_SIZE / 2) < 0) { screenPos.y += pixelsPerBlock * CHUNK_SIZE; currentChunkCenter.y += CHUNK_SIZE; } return currentChunkCenter; } Framework::Punkt DimensionMap::getMaxVisibleChunkCenter( Framework::Punkt& screenPos) const { screenPos = getSize() / 2 - scrollOffset; Punkt currentChunkCenter = originChunkCenter; while (screenPos.x - pixelsPerBlock * (CHUNK_SIZE / 2) < getBreite()) { screenPos.x += pixelsPerBlock * CHUNK_SIZE; currentChunkCenter.x += CHUNK_SIZE; } while (screenPos.y - pixelsPerBlock * (CHUNK_SIZE / 2) < getHeight()) { screenPos.y += pixelsPerBlock * CHUNK_SIZE; currentChunkCenter.y += CHUNK_SIZE; } while (screenPos.x - pixelsPerBlock * (CHUNK_SIZE / 2) >= getBreite()) { screenPos.x -= pixelsPerBlock * CHUNK_SIZE; currentChunkCenter.x -= CHUNK_SIZE; } while (screenPos.y - pixelsPerBlock * (CHUNK_SIZE / 2) >= getHeight()) { screenPos.y -= pixelsPerBlock * CHUNK_SIZE; currentChunkCenter.y -= CHUNK_SIZE; } return currentChunkCenter; } void DimensionMap::removeUnused() const { Punkt tmp; Framework::Punkt min = getMinVisibleChunkCenter(tmp) - Punkt(CHUNK_SIZE, CHUNK_SIZE) * 5; Framework::Punkt max = getMaxVisibleChunkCenter(tmp) + Punkt(CHUNK_SIZE, CHUNK_SIZE) * 5; char addr[8]; for (auto i = chunkList.begin(); i;) { if (i->getChunkCenter().x < min.x || i->getChunkCenter().y < min.y || i->getChunkCenter().x > max.x || i->getChunkCenter().y > max.y) { getAddrOfWorld(i->getChunkCenter(), addr); chunks->remove(addr, 8); i.remove(); } else { ++i; } } } void DimensionMap::updatePlayers(char* data) { int count = *(int*)data; data += 4; cs.lock(); players.leeren(); // read player information from data buffer for (int i = 0; i < count; i++) { unsigned char nameLen = (unsigned char)*data; data++; char* name = new char[nameLen + 1]; memcpy(name, data, nameLen); name[nameLen] = 0; data += nameLen; MapPlayer player; player.name = name; delete[] name; player.position.x = *(float*)data; player.position.y = *(float*)(data + 4); player.position.z = *(float*)(data + 8); data += 12; players.add(player); } cs.unlock(); } void DimensionMap::requestNextChunk() { cs.lock(); if (requestCount >= 20) { cs.unlock(); return; } if (chunkCount == 0) { requestCount++; Vec3 playerPos = World::INSTANCE->getCurrentPlayerEntity()->getPos(); char msg[10]; msg[0] = 2; msg[1] = 0; *(int*)(msg + 2) = (int)playerPos.x; *(int*)(msg + 6) = (int)playerPos.y; World::INSTANCE->zClient()->dimensionAPIRequest(msg, 10); } else { while (requestCount < 20) { Punkt minScreenPos; Punkt minVisibleChunk = getMinVisibleChunkCenter(minScreenPos); Punkt maxScreenPos; Punkt maxVisibleChunk = getMaxVisibleChunkCenter(maxScreenPos); Punkt screenPos = minScreenPos; Punkt screenCenter = getSize() / 2; double minDist = -1; Punkt resultChunk(0, 0); char addr[8]; for (int x = minVisibleChunk.x; x <= maxVisibleChunk.x; x += CHUNK_SIZE) { for (int y = minVisibleChunk.y; y <= maxVisibleChunk.y; y += CHUNK_SIZE) { getAddrOfWorld({x, y}, addr); if (!chunks->z(addr, 8)) { if (minDist < 0 || (screenCenter - screenPos).getLengthSq() < minDist) { minDist = (screenCenter - screenPos).getLengthSq(); resultChunk = {x, y}; } } screenPos.y += pixelsPerBlock * CHUNK_SIZE; } screenPos.x += pixelsPerBlock * CHUNK_SIZE; screenPos.y = minScreenPos.y; } if (minDist >= 0) { requestCount++; char msg[10]; msg[0] = 2; msg[1] = 0; *(int*)(msg + 2) = (int)resultChunk.x; *(int*)(msg + 6) = (int)resultChunk.y; World::INSTANCE->zClient()->dimensionAPIRequest(msg, 10); getAddrOfWorld({resultChunk.x, resultChunk.y}, addr); chunks->set(addr, 8, new ChunkMap(resultChunk)); } else { break; } } } cs.unlock(); } void DimensionMap::addChunk(ChunkMap* chunk) { cs.lock(); if (chunkCount == 0) originChunkCenter = chunk->getChunkCenter(); char addr[8]; getAddrOfWorld(chunk->getChunkCenter(), addr); ChunkMap* old = chunks->z(addr, 8); if (old) chunkList.removeValue(old); chunks->set(addr, 8, chunk); chunkList.add(chunk); chunkCount++; requestCount--; removeUnused(); cs.unlock(); requestNextChunk(); } bool DimensionMap::tick(double time) { if (nextPlayersRequest < 0 && zOptions->isShowPlayers()) { nextPlayersRequest = 2; char msg[2]; msg[0] = 2; // request map players msg[1] = 3; if (World::INSTANCE) { World::INSTANCE->zClient()->dimensionAPIRequest(msg, 2); } } nextPlayersRequest -= time; if (lastSize != getSize()) { lastSize = getSize(); requestNextChunk(); } return ZeichnungHintergrund::tick(time); } void DimensionMap::render(Framework::Bild& rObj) { ZeichnungHintergrund::render(rObj); if (!rObj.setDrawOptions(innenPosition, innenSize)) return; cs.lock(); if (zOptions->isFollowPlayer()) { Vec3 playerPos = World::INSTANCE->getCurrentPlayerEntity()->getPos(); scrollOffset = (Punkt((int)playerPos.x, (int)playerPos.y) - originChunkCenter) * pixelsPerBlock; requestNextChunk(); } Punkt minScreenPos; Punkt minVisibleChunk = getMinVisibleChunkCenter(minScreenPos); Punkt maxScreenPos; Punkt maxVisibleChunk = getMaxVisibleChunkCenter(maxScreenPos); char addr[8]; // render chunks Punkt screenPos = minScreenPos; for (int x = minVisibleChunk.x; x <= maxVisibleChunk.x; x += CHUNK_SIZE) { for (int y = minVisibleChunk.y; y <= maxVisibleChunk.y; y += CHUNK_SIZE) { getAddrOfWorld({x, y}, addr); ChunkMap* map = chunks->z(addr, 8); if (map) { if (zOptions->isUnderground()) { map->setMaxHeight( (int)(World::INSTANCE->getCurrentPlayerEntity() ->getPos() .z / 2)); } else { map->setMaxHeight(255); } Punkt topLeft(screenPos.x - (pixelsPerBlock * CHUNK_SIZE) / 2, screenPos.y - (pixelsPerBlock * CHUNK_SIZE) / 2); rObj.drawBildSkall(topLeft.x, topLeft.y, pixelsPerBlock * CHUNK_SIZE, pixelsPerBlock * CHUNK_SIZE, map->getRenderedImage()); } screenPos.y += pixelsPerBlock * CHUNK_SIZE; } screenPos.x += pixelsPerBlock * CHUNK_SIZE; screenPos.y = minScreenPos.y; } // render shadow and borders screenPos = minScreenPos; for (int x = minVisibleChunk.x; x <= maxVisibleChunk.x; x += CHUNK_SIZE) { for (int y = minVisibleChunk.y; y <= maxVisibleChunk.y; y += CHUNK_SIZE) { getAddrOfWorld({x, y}, addr); ChunkMap* map = chunks->z(addr, 8); if (map) { Punkt topLeft(screenPos.x - (pixelsPerBlock * CHUNK_SIZE) / 2, screenPos.y - (pixelsPerBlock * CHUNK_SIZE) / 2); getAddrOfWorld({x, y - CHUNK_SIZE}, addr); ChunkMap* tmp = chunks->z(addr, 8); unsigned char* heightMapTop = tmp ? tmp->getHeightMap() : 0; getAddrOfWorld({x + CHUNK_SIZE, y}, addr); tmp = chunks->z(addr, 8); unsigned char* heightMapRight = tmp ? tmp->getHeightMap() : 0; getAddrOfWorld({x, y + CHUNK_SIZE}, addr); tmp = chunks->z(addr, 8); unsigned char* heightMapBottom = tmp ? tmp->getHeightMap() : 0; getAddrOfWorld({x - CHUNK_SIZE, y}, addr); tmp = chunks->z(addr, 8); unsigned char* heightMapLeft = tmp ? tmp->getHeightMap() : 0; unsigned char* heightMap = map->getHeightMap(); for (int xx = 0; xx < CHUNK_SIZE; xx++) { for (int yy = 0; yy < CHUNK_SIZE; yy++) { bool shadowR = 0; bool shadowB = 0; if (xx < CHUNK_SIZE - 1) { if (heightMap[yy * CHUNK_SIZE + xx] > heightMap[yy * CHUNK_SIZE + xx + 1]) { rObj.drawLinieVAlpha((xx * pixelsPerBlock) + topLeft.x + pixelsPerBlock, (yy * pixelsPerBlock) + topLeft.y, pixelsPerBlock, 0x40000000); shadowR = 1; } } else if (heightMapRight) { if (heightMap[yy * CHUNK_SIZE + xx] > heightMapRight[yy * CHUNK_SIZE]) { rObj.drawLinieVAlpha((xx * pixelsPerBlock) + topLeft.x + pixelsPerBlock, (yy * pixelsPerBlock) + topLeft.y, pixelsPerBlock, 0x40000000); shadowR = 1; } } if (yy < CHUNK_SIZE - 1) { if (heightMap[yy * CHUNK_SIZE + xx] > heightMap[(yy + 1) * CHUNK_SIZE + xx]) { rObj.drawLinieHAlpha( (xx * pixelsPerBlock) + topLeft.x, (yy * pixelsPerBlock) + topLeft.y + pixelsPerBlock, pixelsPerBlock, 0x30000000); shadowB = 1; } } else if (heightMapBottom) { if (heightMap[yy * CHUNK_SIZE + xx] > heightMapBottom[xx]) { rObj.drawLinieHAlpha( (xx * pixelsPerBlock) + topLeft.x, (yy * pixelsPerBlock) + topLeft.y + pixelsPerBlock, pixelsPerBlock, 0x30000000); shadowB = 1; } } if (xx > 0) { if (heightMap[yy * CHUNK_SIZE + xx] > heightMap[yy * CHUNK_SIZE + xx - 1]) { rObj.drawLinieVAlpha( (xx * pixelsPerBlock) + topLeft.x, (yy * pixelsPerBlock) + topLeft.y, pixelsPerBlock - shadowB, 0x20FFFFFF); } } else if (heightMapLeft) { if (heightMap[yy * CHUNK_SIZE + xx] > heightMapLeft[yy * CHUNK_SIZE + CHUNK_SIZE - 1]) { rObj.drawLinieVAlpha( (xx * pixelsPerBlock) + topLeft.x, (yy * pixelsPerBlock) + topLeft.y, pixelsPerBlock - shadowB, 0x20FFFFFF); } } if (yy > 0) { if (heightMap[yy * CHUNK_SIZE + xx] > heightMap[(yy - 1) * CHUNK_SIZE + xx]) { rObj.drawLinieHAlpha( (xx * pixelsPerBlock) + topLeft.x, (yy * pixelsPerBlock) + topLeft.y, pixelsPerBlock - shadowR, 0x10FFFFFF); } } else if (heightMapTop) { if (heightMap[yy * CHUNK_SIZE + xx] > heightMapTop[(CHUNK_SIZE - 1) * CHUNK_SIZE + xx]) { rObj.drawLinieHAlpha( (xx * pixelsPerBlock) + topLeft.x, (yy * pixelsPerBlock) + topLeft.y, pixelsPerBlock - shadowR, 0x10FFFFFF); } } } } if (zOptions->isShowChunkBorders()) { rObj.drawLinieHAlpha(topLeft.x, topLeft.y, pixelsPerBlock * CHUNK_SIZE, 0x50FFFFFF); rObj.drawLinieVAlpha(topLeft.x, topLeft.y, pixelsPerBlock * CHUNK_SIZE, 0x50FFFFFF); } } screenPos.y += pixelsPerBlock * CHUNK_SIZE; } screenPos.x += pixelsPerBlock * CHUNK_SIZE; screenPos.y = minScreenPos.y; } // render players if (zOptions->isShowPlayers()) { TextRenderer tm( dynamic_cast(uiFactory.initParam.schrift->getThis())); tm.setSchriftSize(12); for (const MapPlayer& player : players) { Punkt screenPos = getSize() / 2 - scrollOffset + (Punkt((int)player.position.x, (int)player.position.y) - originChunkCenter) * pixelsPerBlock + Punkt(pixelsPerBlock, pixelsPerBlock) / 2 - playerIcon->getSize() / 2; rObj.alphaBild(screenPos.x, screenPos.y, playerIcon->getBreite(), playerIcon->getHeight(), *playerIcon); int textWidth = tm.getTextBreite(player.name); int textheight = tm.getTextHeight(player.name); screenPos = screenPos + Punkt(playerIcon->getBreite(), 0) / 2 - Punkt(textWidth / 2, textheight + 2); rObj.alphaRegion( screenPos.x, screenPos.y, textWidth, textheight, 0x70000000); tm.renderText( screenPos.x, screenPos.y, player.name, rObj, 0xFFFFFFFF); } } cs.unlock(); rObj.releaseDrawOptions(); } void DimensionMap::doMausEreignis(Framework::MausEreignis& me, bool userRet) { if (me.id == ME_PLinks) { drag = 1; lastMouse = {me.mx, me.my}; } if (me.id == ME_RLinks || me.id == ME_Leaves) drag = 0; if (me.id == ME_Bewegung && drag) { scrollOffset -= Punkt(me.mx, me.my) - lastMouse; lastMouse = Punkt(me.mx, me.my); rend = 1; requestNextChunk(); } if (me.id == ME_DScroll && pixelsPerBlock > 1) { scrollOffset = (scrollOffset / pixelsPerBlock) * (pixelsPerBlock - 1); pixelsPerBlock--; rend = 1; requestNextChunk(); } if (me.id == ME_UScroll) { scrollOffset = (scrollOffset / pixelsPerBlock) * (pixelsPerBlock + 1); pixelsPerBlock++; rend = 1; requestNextChunk(); } ZeichnungHintergrund::doMausEreignis(me, userRet); }