#include "Dimension.h" #include "Constants.h" #include "Datei.h" #include "Game.h" using namespace Framework; Dimension::Dimension(int id) : dimensionId(id), gravity(9.8f), chunks(new Trie()), entities(new RCArray()) {} Dimension::~Dimension() { entities->release(); chunks->release(); } void Dimension::api(Framework::StreamReader* zRequest, NetworkResponse* zResponse) { // TODO: switch type chunck, block } void Dimension::tickEntities() { for (auto entity : *entities) { if (!entity->isRemoved() && zChunk(Punkt((int)entity->getPosition().x, (int)entity->getPosition().y))) entity->prepareTick(this); } int index = 0; for (auto entity : *entities) { if (!entity->isRemoved() && zChunk(Punkt((int)entity->getPosition().x, (int)entity->getPosition().y))) entity->tick(this); index++; } } void Dimension::getAddrOf(Punkt cPos, char* addr) const { *(int*)addr = cPos.x; *((int*)addr + 1) = cPos.y; } void Dimension::getAddrOfWorld(Punkt 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); } Chunk* Dimension::zChunk(Punkt wPos) const { char addr[8]; getAddrOfWorld(wPos, addr); return chunks->z(addr, 8); } Framework::Either Dimension::zBlock(Vec3 location) { Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y)); if (c) { int x = location.x % CHUNK_SIZE; int y = location.y % CHUNK_SIZE; if (x < 0) x += CHUNK_SIZE; if (y < 0) y += CHUNK_SIZE; return c->zBlockAt(Vec3(x, y, location.z)); } return 0; } Block* Dimension::zRealBlockInstance(Framework::Vec3 location) { Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y)); if (c) { int x = location.x % CHUNK_SIZE; int y = location.y % CHUNK_SIZE; if (x < 0) x += CHUNK_SIZE; if (y < 0) y += CHUNK_SIZE; c->instantiateBlock(Vec3(x, y, location.z)); return c->zBlockAt(Vec3(x, y, location.z)); } return 0; } void Dimension::placeBlock(Framework::Vec3 location, Framework::Either block) { Chunk* c = zChunk(Game::getChunkCenter(location.x, location.y)); if (c) { int x = location.x % CHUNK_SIZE; int y = location.y % CHUNK_SIZE; if (x < 0) x += CHUNK_SIZE; if (y < 0) y += CHUNK_SIZE; if (block.isA()) c->putBlockAt(Vec3(x, y, location.z), block); else { c->putBlockAt(Vec3(x, y, location.z), 0); c->putBlockTypeAt(Vec3(x, y, location.z), block); } } else if (block.isA()) block.getA()->release(); } void Dimension::addEntity(Entity* entity) { entities->add(entity); } void Dimension::setChunk(Chunk* chunk, Punkt center) { char addr[8]; getAddrOfWorld(center, addr); Chunk* old = chunks->z(addr, 8); if (old) { for (int i = 0; i < chunkList.getEintragAnzahl(); i++) { if (chunkList.get(i) == old) { chunkList.remove(i); break; } } } chunks->set(addr, 8, chunk); if (chunk) { chunkList.add(chunk); chunk->setAdded(); } getAddrOfWorld(center + Punkt(CHUNK_SIZE, 0), addr); Chunk* zChunk = chunks->z(addr, 8); if (zChunk) { zChunk->setNeighbor(WEST, chunk); if (chunk) chunk->setNeighbor(EAST, zChunk); } getAddrOfWorld(center + Punkt(-CHUNK_SIZE, 0), addr); zChunk = chunks->z(addr, 8); if (zChunk) { zChunk->setNeighbor(EAST, chunk); if (chunk) chunk->setNeighbor(WEST, zChunk); } getAddrOfWorld(center + Punkt(0, CHUNK_SIZE), addr); zChunk = chunks->z(addr, 8); if (zChunk) { zChunk->setNeighbor(NORTH, chunk); if (chunk) chunk->setNeighbor(SOUTH, zChunk); } getAddrOfWorld(center + Punkt(0, -CHUNK_SIZE), addr); zChunk = chunks->z(addr, 8); if (zChunk) { zChunk->setNeighbor(SOUTH, chunk); if (chunk) chunk->setNeighbor(NORTH, zChunk); } } void Dimension::save(Text worldDir) const { for (auto chunk = chunks->getIterator(); chunk; chunk++) { if (!chunk._) continue; Datei* file = new Datei(); Text filePath = worldDir + "/dim/" + dimensionId + "/"; filePath.appendHex(chunk->getCenter().x); filePath += "_"; filePath.appendHex(chunk->getCenter().y); filePath += ".chunk"; file->setDatei(filePath); if (file->open(Datei::Style::schreiben)) chunk->save(file); file->close(); file->release(); } Text filePath = worldDir + "/dim/" + dimensionId + "/entities"; Datei* file = new Datei(); file->setDatei(filePath); if (file->open(Datei::Style::schreiben)) { for (Entity* entity : *entities) { if (entity->zType()->getId() != PlayerEntityType::ID) { if (!entity->isRemoved()) { int type = entity->zType()->getId(); file->schreibe((char*)&type, 4); StaticRegistry::INSTANCE.zElement(type)->saveEntity(entity, file); } } else { Datei pFile; pFile.setDatei(worldDir + "/player/" + ((Player*)entity)->getName()); if (pFile.open(Datei::Style::schreiben)) PlayerEntityType::INSTANCE->saveEntity(entity, &pFile); } } file->close(); } } int Dimension::getDimensionId() const { return dimensionId; } bool Dimension::hasChunck(int x, int y) const { return zChunk(Punkt(x, y)); } float Dimension::getGravity() const { return gravity; } void Dimension::removeOldChunks() { Array removed; int index = 0; for (Chunk* chunk : chunkList) { if (!chunk->hasViews()) removed.add(index, 0); index++; } for (int i : removed) { Chunk* chunk = chunkList.get(i); // TODO: save chunk chunk->prepareRemove(); setChunk(0, chunk->getCenter()); } } Entity* Dimension::zEntity(int id) { for (auto entity : *entities) { if (!entity->isRemoved() && entity->getId() == id) return entity; } return 0; } Entity* Dimension::zNearestEntity(Framework::Vec3 pos, std::function filter) { Entity* result = 0; float sqDist = 0; for (auto entity : *entities) { if (!entity->isRemoved() && filter(entity)) { float d = pos.abstandSq(entity->getPosition()); if (!result || d < sqDist) { result = entity; sqDist = d; } } } return result; } void Dimension::removeEntity(int id) { int index = 0; for (auto entity : *entities) { if (entity->getId() == id) { entities->remove(index); return; } index++; } }