#include "Dimension.h" #include #include "Constants.h" #include "Game.h" #include "Globals.h" #include "World.h" using namespace Framework; Dimension::Dimension() : id(-1), chunks(new RCTrie()), entities(new RCArray()) {} Dimension::~Dimension() { entities->release(); chunks->release(); } void Dimension::forAll(std::function f) { // handled by render and tick function } void Dimension::render(std::function f) { for (Chunk* chunk : chunkList) { chunk->renderSolid(f); } for (Chunk* chunk : chunkList) { chunk->renderTransparent(f); } } bool Dimension::tick(std::function f, double time) { bool res = 0; for (Chunk* chunk : chunkList) { res |= chunk->tick(f, time); } return res; } void Dimension::setId(int id) { this->id = id; } void Dimension::getAddrOf(Point cPos, char* addr) const { *(int*)addr = cPos.x; *((int*)addr + 1) = cPos.y; } void Dimension::getAddrOfWorld(Point wPos, char* addr) const { if (wPos.x < 0) wPos.x -= CHUNK_SIZE; if (wPos.y < 0) // needed because otherwise would (-8, -8) have the same // adress as (8, 8) wPos.y -= CHUNK_SIZE; wPos /= CHUNK_SIZE; getAddrOf(wPos, addr); } void Dimension::api(char* message) { switch (message[0]) { case 1: // chunck { int cX = *(int*)(message + 1); int cY = *(int*)(message + 5); lock.lockRead(); Chunk* ch = zChunk(Point(cX, cY)); if (ch) ch->api(message + 9); lock.unlockRead(); break; } case 2: // entity { int eId = *(int*)(message + 1); lock.lockRead(); Entity* e = zEntity(eId); if (e) e->api(message + 5); lock.unlockRead(); break; } case 3: // block { int px = *(int*)(message + 1); int py = *(int*)(message + 5); int pz = *(int*)(message + 9); lock.lockRead(); Block* b = zBlock(Framework::Vec3(px, py, pz)); if (b) b->api(message + 13); lock.unlockRead(); break; } case 4: // add new chunck { Point center; center.x = *(int*)(message + 1); center.y = *(int*)(message + 5); ByteArrayReader reader(message + 9, INT_MAX, 0); std::cout << "downloading chunk " << center.x << ", " << center.y << "\n"; Timer zm; zm.measureStart(); Chunk* chunk = new Chunk(center, &reader); zm.measureEnd(); std::cout << "chunk loading took " << zm.getSekunden() << " seconds\n"; setChunk(chunk, center); World::INSTANCE->onChunkAdded(center); World::INSTANCE->zClient()->chunkAPIRequest(center, "\2", 1); break; } case 5: // light update { int x = *(int*)(message + 1); int y = *(int*)(message + 5); int z = *(int*)(message + 9); Framework::Vec3 location(x, y, z); for (int i = 0; i < 6; i++) { Framework::Vec3 pos = location + getDirection(getDirectionFromIndex(i)); if (pos.z >= 0 && pos.z < WORLD_HEIGHT) { lock.lockRead(); Chunk* c = zChunk(World::INSTANCE->getChunkCenter(pos.x, pos.y)); Block* zB = c ? c->zBlockAt(pos) : 0; if (zB) { bool visible = zB->isVisible(); zB->setLightData( getOppositeDirection(getDirectionFromIndex(i)), (unsigned char*)(message + 13), c); if (zB->isVisible() != visible) { zChunk( World::INSTANCE->getChunkCenter(pos.x, pos.y)) ->blockVisibilityChanged(zB); } } lock.unlockRead(); } } break; } case 7: // add entity { int type = *(int*)(message + 1); ByteArrayReader reader(message + 5, INT_MAX, 0); Entity* entity = entityTypes[type]->loadEntity(&reader); addEntity(entity); break; } case 8: // remove entity { int id = *(int*)(message + 1); removeEntity(id); break; } } } Chunk* Dimension::zChunk(Point wPos) const { char addr[8]; getAddrOfWorld(wPos, addr); return chunks->z(addr, 8); } Block* Dimension::zBlock(Vec3 location) { Chunk* c = zChunk(World::INSTANCE->getChunkCenter(location.x, location.y)); if (c) return c->zBlockAt(location); return 0; } Block* Dimension::getBlock(Vec3 location) { lock.lockRead(); Chunk* c = zChunk(World::INSTANCE->getChunkCenter(location.x, location.y)); if (c) { Block* b = c->zBlockAt(location); b = b ? dynamic_cast(b->getThis()) : 0; lock.unlockRead(); return b; } lock.unlockRead(); return 0; } void Dimension::addEntity(Entity* entity) { entities->add(entity); World::INSTANCE->setVisibility(entity, 1); } void Dimension::setChunk(Chunk* chunk, Point center) { char addr[8]; getAddrOfWorld(center, addr); lock.lockWrite(); Chunk* old = chunks->z(addr, 8); if (old) { int index = 0; for (auto iterator = chunkList.begin(); iterator; ++iterator, ++index) { if ((Chunk*)iterator == old) { if (chunk) iterator.set(chunk); else chunkList.remove(index); break; } } } else if (chunk) chunkList.add(chunk); chunks->set(addr, 8, chunk); lock.unlockWrite(); } bool Dimension::hasChunck(int x, int y) const { return zChunk(Point(x, y)); } void Dimension::removeDistantChunks(Point wPos) { Array removed; int index = 0; lock.lockRead(); for (Chunk* chunk : chunkList) { if (abs(chunk->getCenter().x - wPos.x) > MAX_VIEW_DISTANCE + CHUNK_SIZE || abs(chunk->getCenter().y - wPos.y) > MAX_VIEW_DISTANCE + CHUNK_SIZE) removed.add(index, 0); index++; } lock.unlockRead(); for (int i : removed) { lock.lockWrite(); Chunk* chunk = chunkList.get(i); chunk->destroy(); setChunk(0, chunk->getCenter()); lock.unlockWrite(); } } void Dimension::setBlock(Block* block) { lock.lockWrite(); Chunk* c = zChunk(World::INSTANCE->getChunkCenter( (int)floor(block->getPos().x), (int)floor(block->getPos().y))); if (c) c->setBlock(block); else block->release(); lock.unlockWrite(); } void Dimension::removeBlock(Block* zBlock) { lock.lockWrite(); Chunk* c = zChunk(World::INSTANCE->getChunkCenter( (int)floor(zBlock->getPos().x), (int)floor(zBlock->getPos().y))); if (c) c->removeBlock(zBlock); lock.unlockWrite(); } Entity* Dimension::zEntity(int id) { lock.lockRead(); for (Entity* e : *entities) { if (e->getId() == id) { lock.unlockRead(); return e; } } lock.unlockRead(); return 0; } Entity* Dimension::getEntity(int id) { lock.lockRead(); for (Entity* e : *entities) { if (e->getId() == id) { Entity* result = dynamic_cast(e->getThis()); lock.unlockRead(); return result; } } lock.unlockRead(); return 0; } void Dimension::removeEntity(int id) { lock.lockWrite(); int index = 0; for (Entity* e : *entities) { if (e->getId() == id) { World::INSTANCE->setVisibility(e, 0); entities->remove(index); lock.unlockWrite(); return; } index++; } lock.unlockWrite(); } int Dimension::getId() const { return id; } Lock& Dimension::getReadLock() const { return lock.getReadLock(); }