123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612 |
- #include "Dimension.h"
- #include "Constants.h"
- #include "Datei.h"
- #include "Game.h"
- #include "NoBlock.h"
- using namespace Framework;
- Dimension::Dimension(int id)
- : Thread(),
- dimensionId(id),
- gravity(9.8f),
- chunks(new Trie<Chunk>()),
- entities(new RCArray<Entity>())
- {
- start();
- }
- Dimension::~Dimension()
- {
- entities->release();
- chunks->release();
- }
- void Dimension::api(Framework::InMemoryBuffer* zRequest, NetworkMessage* zResponse, Entity* zSource)
- {
- DoLaterHandler laterHandler;
- char type;
- zRequest->lese(&type, 1);
- switch (type)
- {
- case 0: // chunk message
- {
- Punkt center;
- zRequest->lese((char*)¢er.x, 4);
- zRequest->lese((char*)¢er.y, 4);
- cs.lock();
- Chunk* cC = zChunk(center);
- if (!cC)
- {
- // TODO: have a max amount of waiting requests per player
- waitingRequests.add({ dynamic_cast<InMemoryBuffer*>(zRequest->getThis()), center, zSource->getId() });
- Game::INSTANCE->requestArea({ center.x - CHUNK_SIZE / 2, center.y - CHUNK_SIZE / 2, center.x + CHUNK_SIZE / 2 - 1, center.y + CHUNK_SIZE / 2 - 1, dimensionId });
- }
- else
- {
- cC->api(zRequest, zSource, laterHandler);
- }
- cs.unlock();
- break;
- }
- }
- }
- 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::thread()
- {
- // light calculation
- int index = 0;
- ZeitMesser messer;
- messer.messungStart();
- double time = 0;
- bool isForeground = 0;
- Framework::Array<Framework::Vec3<int>> internalLightUpdateQueue;
- while (true)
- {
- Vec3<int> position;
- if (internalLightUpdateQueue.getEintragAnzahl())
- {
- position = internalLightUpdateQueue.get(0);
- internalLightUpdateQueue.remove(0);
- }
- else
- {
- removedChunksCs.lock();
- if (removedChunks.getEintragAnzahl() > 0)
- {
- Chunk* removedChunk = removedChunks.z(0);
- removedChunksCs.unlock();
- Text filePath = Game::INSTANCE->getWorldDirectory() + "/dim/" + getDimensionId() + "/";
- filePath.appendHex(removedChunk->getCenter().x);
- filePath += "_";
- filePath.appendHex(removedChunk->getCenter().y);
- filePath += ".chunk";
- Datei d;
- d.setDatei(filePath);
- d.erstellen();
- d.open(Datei::Style::schreiben);
- removedChunk->save(&d);
- d.close();
- removedChunksCs.lock();
- removedChunks.remove(0);
- }
- removedChunksCs.unlock();
- if (priorizedLightUpdateQueue.getEintragAnzahl())
- {
- prioLightCs.lock();
- position = priorizedLightUpdateQueue.get(0);
- priorizedLightUpdateQueue.remove(0);
- prioLightCs.unlock();
- isForeground = 1;
- }
- else
- {
- if (!lightUpdateQueue.getEintragAnzahl())
- {
- messer.messungEnde();
- time += messer.getSekunden();
- Sleep(500);
- messer.messungStart();
- continue;
- }
- lightCs.lock();
- position = lightUpdateQueue.get(0);
- lightUpdateQueue.remove(0);
- lightCs.unlock();
- isForeground = 0;
- }
- }
- Chunk* chunk = zChunk(Game::INSTANCE->getChunkCenter(position.x, position.y));
- if (position.z >= 0 && position.z < WORLD_HEIGHT)
- {
- if (chunk)
- {
- int x = position.x % CHUNK_SIZE;
- int y = position.y % CHUNK_SIZE;
- if (x < 0)
- x += CHUNK_SIZE;
- if (y < 0)
- y += CHUNK_SIZE;
- unsigned char* light = chunk->getLightData(Vec3<int>(x, y, position.z));
- unsigned char dayLight[6] = { 255, 255, 255, 0, 0, 0 };
- unsigned char noLight[6] = { 0, 0, 0, 0, 0, 0 };
- unsigned char newLight[6] = { 0, 0, 0, 0, 0, 0 };
- // add neighbor light emission
- for (int i = 0; i < 6; i++)
- {
- unsigned char* neighborLeight;
- Vec3<int> neighborPos = position + getDirection(getDirectionFromIndex(i));
- if (neighborPos.z < 0)
- {
- neighborLeight = noLight;
- }
- else if (neighborPos.z >= WORLD_HEIGHT)
- {
- neighborLeight = dayLight;
- }
- else
- {
- Chunk* neighborChunk = zChunk(Game::INSTANCE->getChunkCenter(neighborPos.x, neighborPos.y));
- int x = neighborPos.x % CHUNK_SIZE;
- int y = neighborPos.y % CHUNK_SIZE;
- if (x < 0)
- x += CHUNK_SIZE;
- if (y < 0)
- y += CHUNK_SIZE;
- if (neighborChunk)
- neighborLeight = neighborChunk->getLightData(Vec3<int>(x, y, neighborPos.z));
- else
- neighborLeight = noLight;
- }
- for (int j = 0; j < 3; j++)
- newLight[j] = (unsigned char)MAX(newLight[j], i == getDirectionIndex(TOP) ? neighborLeight[j] : (unsigned char)((float)neighborLeight[j] * 0.8f));
- for (int j = 3; j < 6; j++)
- newLight[j] = (unsigned char)MAX(newLight[j], (unsigned char)((float)neighborLeight[j] * 0.85f));
- }
- const Block* current = zBlockOrDefault(position);
- if (!current)
- current = &NoBlock::INSTANCE;
- // add own light emission
- for (int j = 3; j < 6; j++)
- newLight[j] = (unsigned char)MAX(newLight[j], current->getLightEmisionColor()[j - 3]);
- current->filterPassingLight(newLight);
- current->filterPassingLight(newLight + 3);
- for (int i = 0; i < 6; i++)
- {
- if (newLight[i] != light[i])
- {
- chunk->setLightData(Vec3<int>(x, y, position.z), newLight, isForeground);
- for (int j = 0; j < 6; j++)
- internalLightUpdateQueue.add(position + getDirection(getDirectionFromIndex(j)), 0);
- break;
- }
- }
- }
- }
- index++;
- if (index > 100000)
- {
- messer.messungEnde();
- time += messer.getSekunden();
- std::cout << "100000 light updates needed " << time << " seconds\n";
- time = 0;
- index = 0;
- Sleep(250);
- messer.messungStart();
- }
- }
- }
- 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<Block*, int> Dimension::zBlock(Vec3<int> 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<int>(x, y, location.z));
- }
- return 0;
- }
- Block* Dimension::zRealBlockInstance(Framework::Vec3<int> 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<int>(x, y, location.z));
- auto result = c->zBlockAt(Vec3<int>(x, y, location.z));
- return result.isA() ? result.getA() : 0;
- }
- return 0;
- }
- const Block* Dimension::zBlockOrDefault(Framework::Vec3<int> 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->zBlockConst(Vec3<int>(x, y, location.z));
- }
- return 0;
- }
- void Dimension::placeBlock(Framework::Vec3<int> location, Framework::Either<Block*, int> 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<int>(x, y, location.z), block);
- else
- {
- c->putBlockAt(Vec3<int>(x, y, location.z), 0);
- c->putBlockTypeAt(Vec3<int>(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)
- {
- chunkCs.lock();
- char addr[8];
- getAddrOfWorld(center, addr);
- Chunk* old = chunks->get(addr, 8);
- if (old)
- {
- old->prepareRemove();
- 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);
- }
- DoLaterHandler laterHandler;
- if (chunk)
- {
- cs.lock();
- int index = 0;
- for (Iterator<RequestQueue> iterator = waitingRequests.begin(); iterator; )
- {
- Entity* zE = Game::INSTANCE->zEntity(iterator.val().sourceId);
- if (zE)
- {
- if (iterator.val().chunkCenter == chunk->getCenter())
- {
- chunk->api(iterator.val().request, zE, laterHandler);
- iterator.val().request->release();
- iterator.remove();
- continue;
- }
- }
- else
- {
- iterator.val().request->release();
- iterator.remove();
- continue;
- }
- iterator++;
- index++;
- }
- cs.unlock();
- }
- chunkCs.unlock();
- if (old)
- {
- removedChunksCs.lock();
- removedChunks.add(old);
- removedChunksCs.unlock();
- }
- updateLightAtChunkBorders(center);
- }
- 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<EntityType>::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)
- {
- if (zChunk(Punkt(x, y)))
- return 1;
- removedChunksCs.lock();
- for (Chunk* c : removedChunks)
- {
- if (c->getCenter().x == x && c->getCenter().y == y)
- {
- removedChunksCs.unlock();
- return 1;
- }
- }
- removedChunksCs.unlock();
- return 0;
- }
- bool Dimension::reviveChunk(int x, int y)
- {
- chunkCs.lock();
- if (zChunk(Punkt(x, y)))
- {
- chunkCs.unlock();
- return 1;
- }
- removedChunksCs.lock();
- int index = 0;
- for (Iterator<Chunk*> i = removedChunks.begin(); i; i++)
- {
- if (i->getCenter().x == x && i->getCenter().y == y)
- {
- setChunk(dynamic_cast<Chunk*>(i->getThis()), Punkt(x, y));
- if (index > 0)
- i.remove();
- removedChunksCs.unlock();
- chunkCs.unlock();
- return 1;
- }
- index++;
- }
- removedChunksCs.unlock();
- chunkCs.unlock();
- return 0;
- }
- float Dimension::getGravity() const
- {
- return gravity;
- }
- void Dimension::removeOldChunks()
- {
- chunkCs.lock();
- int index = 0;
- for (Chunk* chunk : chunkList)
- {
- if (!chunk->hasObservers())
- setChunk(0, chunk->getCenter());
- index++;
- }
- chunkCs.unlock();
- }
- Entity* Dimension::zEntity(int id)
- {
- for (auto entity : *entities)
- {
- if (!entity->isRemoved() && entity->getId() == id)
- return entity;
- }
- return 0;
- }
- Entity* Dimension::zNearestEntity(Framework::Vec3<float> pos, std::function<bool(Entity*)> 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++;
- }
- }
- void Dimension::removeSubscriptions(Entity* zEntity)
- {
- for (Chunk* chunk : chunkList)
- chunk->removeObserver(zEntity);
- }
- void Dimension::updateLightning(Vec3<int> location)
- {
- lightCs.lock();
- lightUpdateQueue.add(location, 0);
- lightCs.unlock();
- }
- void Dimension::updateLightningWithoutWait(Framework::Vec3<int> location)
- {
- prioLightCs.lock();
- priorizedLightUpdateQueue.add(location, 0);
- prioLightCs.unlock();
- }
- void Dimension::updateLightAtChunkBorders(Punkt chunkCenter)
- {
- if (lightUpdateQueue.getEintragAnzahl() > 300000)
- {
- std::cout << "warning: light calculation queue is over 300000 blocks long";
- }
- for (int i = WORLD_HEIGHT - 1; i >= 0; i--)
- {
- for (int j = 0; j < CHUNK_SIZE; j++)
- {
- updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 8 - 1, chunkCenter.y - CHUNK_SIZE / 8 + j, i));
- updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 8, chunkCenter.y - CHUNK_SIZE / 8 + j, i));
- updateLightning(Vec3<int>(chunkCenter.x + CHUNK_SIZE / 8 - 1, chunkCenter.y - CHUNK_SIZE / 8 + j, i));
- updateLightning(Vec3<int>(chunkCenter.x + CHUNK_SIZE / 8, chunkCenter.y - CHUNK_SIZE / 8 + j, i));
- updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 8 + j, chunkCenter.y - CHUNK_SIZE / 8 - 1, i));
- updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 8 + j, chunkCenter.y - CHUNK_SIZE / 8, i));
- updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 8 + j, chunkCenter.y + CHUNK_SIZE / 8 - 1, i));
- updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 8 + j, chunkCenter.y + CHUNK_SIZE / 8, i));
- }
- }
- }
|