|
@@ -0,0 +1,964 @@
|
|
|
|
+#include "Dimension.h"
|
|
|
|
+
|
|
|
|
+#include "Constants.h"
|
|
|
|
+#include "Datei.h"
|
|
|
|
+#include "Game.h"
|
|
|
|
+#include "NoBlock.h"
|
|
|
|
+
|
|
|
|
+using namespace Framework;
|
|
|
|
+
|
|
|
|
+Dimension::Dimension(int id)
|
|
|
|
+ : Thread(),
|
|
|
|
+ nextStructureId(0),
|
|
|
|
+ dimensionId(id),
|
|
|
|
+ gravity(9.8f),
|
|
|
|
+ chunks(new RCTrie<Chunk>()),
|
|
|
|
+ entities(new RCArray<Entity>()),
|
|
|
|
+ map(new DimensionMap(id)),
|
|
|
|
+ stop(0),
|
|
|
|
+ currentDayTime(0.0),
|
|
|
|
+ nightDuration(0.0),
|
|
|
|
+ nightTransitionDuration(0.0),
|
|
|
|
+ dayDuration(1000.0)
|
|
|
|
+{
|
|
|
|
+ Datei d;
|
|
|
|
+ d.setDatei(
|
|
|
|
+ Game::INSTANCE->getWorldDirectory() + "/dim/" + Text(id) + "/meta.dim");
|
|
|
|
+ if (d.existiert())
|
|
|
|
+ {
|
|
|
|
+ d.open(Datei::Style::lesen);
|
|
|
|
+ d.lese((char*)&nextStructureId, 8);
|
|
|
|
+ d.lese((char*)¤tDayTime, 8);
|
|
|
|
+ d.close();
|
|
|
|
+ }
|
|
|
|
+ start();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+Dimension::~Dimension()
|
|
|
|
+{
|
|
|
|
+ entities->release();
|
|
|
|
+ chunks->release();
|
|
|
|
+ map->release();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Dimension::configureDayNightCyncle(
|
|
|
|
+ double nightDuration, double nightTransitionDuration, double dayDuration)
|
|
|
|
+{
|
|
|
|
+ this->nightDuration = nightDuration;
|
|
|
|
+ this->nightTransitionDuration = nightTransitionDuration;
|
|
|
|
+ this->dayDuration = dayDuration;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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(Game::getChunkCenter(center.x, center.y));
|
|
|
|
+ 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;
|
|
|
|
+ }
|
|
|
|
+ case 1: // block message
|
|
|
|
+ {
|
|
|
|
+ Vec3<int> location;
|
|
|
|
+ zRequest->lese((char*)&location.x, 4);
|
|
|
|
+ zRequest->lese((char*)&location.y, 4);
|
|
|
|
+ zRequest->lese((char*)&location.z, 4);
|
|
|
|
+ Framework::Either<Block*, int> block = zBlock(location);
|
|
|
|
+ if (block.isA())
|
|
|
|
+ {
|
|
|
|
+ block.getA()->api(zRequest, zResponse);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ case 2: // map request
|
|
|
|
+ {
|
|
|
|
+ map->api(zRequest, zResponse, zSource, this);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Dimension::tickEntities()
|
|
|
|
+{
|
|
|
|
+ this->currentDayTime += 1.0 / MAX_TICKS_PER_SECOND;
|
|
|
|
+ if (this->currentDayTime
|
|
|
|
+ > dayDuration + nightDuration + nightTransitionDuration * 2)
|
|
|
|
+ {
|
|
|
|
+ this->currentDayTime
|
|
|
|
+ = dayDuration + nightDuration + nightTransitionDuration * 2;
|
|
|
|
+ }
|
|
|
|
+ for (auto entity : *entities)
|
|
|
|
+ {
|
|
|
|
+ if (!entity->isRemoved()
|
|
|
|
+ && (entity->isMoving()
|
|
|
|
+ || zChunk(Game::getChunkCenter((int)entity->getPosition().x,
|
|
|
|
+ (int)entity->getPosition().y))))
|
|
|
|
+ entity->prepareTick(this);
|
|
|
|
+ }
|
|
|
|
+ int index = 0;
|
|
|
|
+ for (auto entity : *entities)
|
|
|
|
+ {
|
|
|
|
+ if (!entity->isRemoved()
|
|
|
|
+ && (entity->isMoving()
|
|
|
|
+ || zChunk(Game::getChunkCenter((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 (!stop)
|
|
|
|
+ {
|
|
|
|
+ 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);
|
|
|
|
+ char addr[8];
|
|
|
|
+ getAddrOfWorld(removedChunk->getCenter(), addr);
|
|
|
|
+ map->removeMap(addr, 8);
|
|
|
|
+ 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)
|
|
|
|
+ {
|
|
|
|
+ Vec3<int> chunkPos = chunkCoordinates(position);
|
|
|
|
+ unsigned char* light = chunk->getLightData(chunkPos);
|
|
|
|
+ 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));
|
|
|
|
+ if (neighborChunk)
|
|
|
|
+ neighborLeight = neighborChunk->getLightData(
|
|
|
|
+ chunkCoordinates(neighborPos));
|
|
|
|
+ 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);
|
|
|
|
+ // 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(chunkPos, 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;
|
|
|
|
+ messer.messungStart();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ std::cout << Text("Dimension ") + this->getDimensionId()
|
|
|
|
+ + " update Thread exited.\n";
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Dimension::saveStructure(MultiblockStructure* zStructure) const
|
|
|
|
+{
|
|
|
|
+ Datei d;
|
|
|
|
+ Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
|
|
|
|
+ + Text(dimensionId) + "/structures/";
|
|
|
|
+ path.appendHex(zStructure->getStructureId());
|
|
|
|
+ path += ".str";
|
|
|
|
+ d.setDatei(path);
|
|
|
|
+ d.erstellen();
|
|
|
|
+ d.open(Datei::Style::schreiben);
|
|
|
|
+ auto uPos = zStructure->getUniquePosition();
|
|
|
|
+ d.schreibe((char*)&uPos.x, 4);
|
|
|
|
+ d.schreibe((char*)&uPos.y, 4);
|
|
|
|
+ d.schreibe((char*)&uPos.z, 4);
|
|
|
|
+ int typeId = zStructure->getStructureTypeId();
|
|
|
|
+ d.schreibe((char*)&typeId, 4);
|
|
|
|
+ __int64 strId = zStructure->getStructureId();
|
|
|
|
+ d.schreibe((char*)&strId, 8);
|
|
|
|
+ StaticRegistry<MultiblockStructureType>::INSTANCE
|
|
|
|
+ .zElement(zStructure->getStructureTypeId())
|
|
|
|
+ ->saveStructure(zStructure, &d);
|
|
|
|
+ d.close();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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)
|
|
|
|
+ {
|
|
|
|
+ location = chunkCoordinates(location);
|
|
|
|
+ return c->zBlockAt(location);
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+Block* Dimension::zRealBlockInstance(Framework::Vec3<int> location)
|
|
|
|
+{
|
|
|
|
+ Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
|
|
|
|
+ if (c)
|
|
|
|
+ {
|
|
|
|
+ location = chunkCoordinates(location);
|
|
|
|
+ c->instantiateBlock(location);
|
|
|
|
+ auto result = c->zBlockAt(location);
|
|
|
|
+ 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)
|
|
|
|
+ {
|
|
|
|
+ location = chunkCoordinates(location);
|
|
|
|
+ return c->zBlockConst(location);
|
|
|
|
+ }
|
|
|
|
+ return &NoBlock::INSTANCE;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int Dimension::getBlockType(Framework::Vec3<int> location)
|
|
|
|
+{
|
|
|
|
+ Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
|
|
|
|
+ if (c)
|
|
|
|
+ {
|
|
|
|
+ location = chunkCoordinates(location);
|
|
|
|
+ return c->getBlockTypeAt(location);
|
|
|
|
+ }
|
|
|
|
+ return BlockTypeEnum::NO_BLOCK;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Dimension::placeBlock(
|
|
|
|
+ Framework::Vec3<int> location, Framework::Either<Block*, int> block)
|
|
|
|
+{
|
|
|
|
+ Chunk* c = zChunk(Game::getChunkCenter(location.x, location.y));
|
|
|
|
+ if (c)
|
|
|
|
+ {
|
|
|
|
+ location = chunkCoordinates(location);
|
|
|
|
+ if (block.isA())
|
|
|
|
+ c->putBlockAt(location, block);
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ c->putBlockAt(location, 0);
|
|
|
|
+ c->putBlockTypeAt(location, block);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else if (block.isA())
|
|
|
|
+ block.getA()->release();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Dimension::sendBlockInfo(Framework::Vec3<int> location)
|
|
|
|
+{
|
|
|
|
+ Chunk* c = zChunk(Game::getChunkCenter(location.x, location.y));
|
|
|
|
+ if (c)
|
|
|
|
+ {
|
|
|
|
+ location = chunkCoordinates(location);
|
|
|
|
+ c->sendBlockInfo(location);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Dimension::addEntity(Entity* entity)
|
|
|
|
+{
|
|
|
|
+ entities->add(entity);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Dimension::setChunk(Chunk* chunk, Punkt center)
|
|
|
|
+{
|
|
|
|
+ char addr[8];
|
|
|
|
+ getAddrOfWorld(center, addr);
|
|
|
|
+ if (chunk) map->loadMap(addr, 8, chunk);
|
|
|
|
+ chunkCs.lock();
|
|
|
|
+ Chunk* old = chunks->get(addr, 8);
|
|
|
|
+ if (old)
|
|
|
|
+ {
|
|
|
|
+ Game::INSTANCE->zTickOrganizer()->removeTickSource(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();
|
|
|
|
+ Game::INSTANCE->zTickOrganizer()->addTickSource(chunk);
|
|
|
|
+ }
|
|
|
|
+ chunkCs.unlock();
|
|
|
|
+ if (old)
|
|
|
|
+ {
|
|
|
|
+ old->onUnloaded();
|
|
|
|
+ removedChunksCs.lock();
|
|
|
|
+ removedChunks.add(old);
|
|
|
|
+ removedChunksCs.unlock();
|
|
|
|
+ }
|
|
|
|
+ if (chunk) chunk->onLoaded();
|
|
|
|
+ laterHandler.execute();
|
|
|
|
+ if (chunk) updateLightAtChunkBorders(center);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Dimension::save(Text worldDir) const
|
|
|
|
+{
|
|
|
|
+ Datei d;
|
|
|
|
+ d.setDatei(Game::INSTANCE->getWorldDirectory() + "/dim/" + Text(dimensionId)
|
|
|
|
+ + "/meta.dim");
|
|
|
|
+ d.erstellen();
|
|
|
|
+ d.open(Datei::Style::schreiben);
|
|
|
|
+ d.schreibe((char*)&nextStructureId, 8);
|
|
|
|
+ d.schreibe((char*)¤tDayTime, 8);
|
|
|
|
+ d.close();
|
|
|
|
+ for (auto chunk = chunkList.begin(); 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();
|
|
|
|
+ char addr[8];
|
|
|
|
+ getAddrOfWorld(chunk->getCenter(), addr);
|
|
|
|
+ map->saveMap(addr, 8);
|
|
|
|
+ }
|
|
|
|
+ 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() != EntityTypeEnum::PLAYER)
|
|
|
|
+ {
|
|
|
|
+ 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/"
|
|
|
|
+ + Game::INSTANCE->getPlayerId(
|
|
|
|
+ ((Player*)entity)->getName()));
|
|
|
|
+ if (pFile.open(Datei::Style::schreiben))
|
|
|
|
+ StaticRegistry<EntityType>::INSTANCE
|
|
|
|
+ .zElement(EntityTypeEnum::PLAYER)
|
|
|
|
+ ->saveEntity(entity, &pFile);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ file->close();
|
|
|
|
+ }
|
|
|
|
+ for (MultiblockStructure* structure : structures)
|
|
|
|
+ {
|
|
|
|
+ saveStructure(structure);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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();
|
|
|
|
+ structurCs.lock();
|
|
|
|
+ Iterator<MultiblockStructure*> i = structures.begin();
|
|
|
|
+ while (i)
|
|
|
|
+ {
|
|
|
|
+ if (i->isEmpty())
|
|
|
|
+ {
|
|
|
|
+ i.remove();
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ else if (i->isFullyUnloaded())
|
|
|
|
+ {
|
|
|
|
+ saveStructure(i);
|
|
|
|
+ i.remove();
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
|
|
+ structurCs.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\n";
|
|
|
|
+ }
|
|
|
|
+ for (int i = WORLD_HEIGHT - 1; i >= 0; i--)
|
|
|
|
+ {
|
|
|
|
+ for (int j = 0; j < CHUNK_SIZE; j++)
|
|
|
|
+ {
|
|
|
|
+ updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 - 1,
|
|
|
|
+ chunkCenter.y - CHUNK_SIZE / 2 + j,
|
|
|
|
+ i));
|
|
|
|
+ updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2,
|
|
|
|
+ chunkCenter.y - CHUNK_SIZE / 2 + j,
|
|
|
|
+ i));
|
|
|
|
+ updateLightning(Vec3<int>(chunkCenter.x + CHUNK_SIZE / 2 - 1,
|
|
|
|
+ chunkCenter.y - CHUNK_SIZE / 2 + j,
|
|
|
|
+ i));
|
|
|
|
+ updateLightning(Vec3<int>(chunkCenter.x + CHUNK_SIZE / 2,
|
|
|
|
+ chunkCenter.y - CHUNK_SIZE / 2 + j,
|
|
|
|
+ i));
|
|
|
|
+ updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
|
|
|
|
+ chunkCenter.y - CHUNK_SIZE / 2 - 1,
|
|
|
|
+ i));
|
|
|
|
+ updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
|
|
|
|
+ chunkCenter.y - CHUNK_SIZE / 2,
|
|
|
|
+ i));
|
|
|
|
+ updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
|
|
|
|
+ chunkCenter.y + CHUNK_SIZE / 2 - 1,
|
|
|
|
+ i));
|
|
|
|
+ updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
|
|
|
|
+ chunkCenter.y + CHUNK_SIZE / 2,
|
|
|
|
+ i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+__int64 Dimension::getNextStructureId()
|
|
|
|
+{
|
|
|
|
+ return nextStructureId++;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Dimension::addStructure(MultiblockStructure* structure)
|
|
|
|
+{
|
|
|
|
+ structurCs.lock();
|
|
|
|
+ structures.add(structure);
|
|
|
|
+ structurCs.unlock();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+MultiblockStructure* Dimension::zStructureByPosition(
|
|
|
|
+ Framework::Vec3<int> uniquePosition)
|
|
|
|
+{
|
|
|
|
+ structurCs.lock();
|
|
|
|
+ for (MultiblockStructure* str : structures)
|
|
|
|
+ {
|
|
|
|
+ if (str->getUniquePosition() == uniquePosition)
|
|
|
|
+ {
|
|
|
|
+ structurCs.unlock();
|
|
|
|
+ return str;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // search for structure file
|
|
|
|
+ Datei dir(Game::INSTANCE->getWorldDirectory() + "/dim/" + Text(dimensionId)
|
|
|
|
+ + "/structures");
|
|
|
|
+ RCArray<Text>* names = dir.getDateiListe();
|
|
|
|
+ if (names)
|
|
|
|
+ {
|
|
|
|
+ Vec3<int> uPos;
|
|
|
|
+ for (Text* name : *names)
|
|
|
|
+ {
|
|
|
|
+ Datei d(Text(dir.zPfad()->getText()) + "/" + name->getText());
|
|
|
|
+ if (d.open(Datei::Style::lesen))
|
|
|
|
+ {
|
|
|
|
+ d.lese((char*)&uPos.x, 4);
|
|
|
|
+ d.lese((char*)&uPos.y, 4);
|
|
|
|
+ d.lese((char*)&uPos.z, 4);
|
|
|
|
+ if (uPos == uniquePosition)
|
|
|
|
+ {
|
|
|
|
+ int type;
|
|
|
|
+ d.lese((char*)&type, 4);
|
|
|
|
+ __int64 strId;
|
|
|
|
+ d.lese((char*)&strId, 8);
|
|
|
|
+ MultiblockStructure* str
|
|
|
|
+ = StaticRegistry<MultiblockStructureType>::INSTANCE
|
|
|
|
+ .zElement(type)
|
|
|
|
+ ->loadStructure(
|
|
|
|
+ dimensionId, strId, uniquePosition, &d);
|
|
|
|
+ d.close();
|
|
|
|
+ structures.add(str);
|
|
|
|
+ names->release();
|
|
|
|
+ structurCs.unlock();
|
|
|
|
+ return str;
|
|
|
|
+ }
|
|
|
|
+ d.close();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ names->release();
|
|
|
|
+ }
|
|
|
|
+ structurCs.unlock();
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+MultiblockStructure* Dimension::zStructureById(__int64 id)
|
|
|
|
+{
|
|
|
|
+ structurCs.lock();
|
|
|
|
+ for (MultiblockStructure* str : structures)
|
|
|
|
+ {
|
|
|
|
+ if (str->getStructureId() == id)
|
|
|
|
+ {
|
|
|
|
+ structurCs.unlock();
|
|
|
|
+ return str;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // search for structure file
|
|
|
|
+ Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
|
|
|
|
+ + Text(dimensionId) + "/structures/";
|
|
|
|
+ path.appendHex(id);
|
|
|
|
+ path += ".str";
|
|
|
|
+ Datei d(path);
|
|
|
|
+ Vec3<int> uPos;
|
|
|
|
+ if (d.open(Datei::Style::lesen))
|
|
|
|
+ {
|
|
|
|
+ d.lese((char*)&uPos.x, 4);
|
|
|
|
+ d.lese((char*)&uPos.y, 4);
|
|
|
|
+ d.lese((char*)&uPos.z, 4);
|
|
|
|
+ int type;
|
|
|
|
+ d.lese((char*)&type, 4);
|
|
|
|
+ __int64 strId;
|
|
|
|
+ d.lese((char*)&strId, 8);
|
|
|
|
+ MultiblockStructure* str
|
|
|
|
+ = StaticRegistry<MultiblockStructureType>::INSTANCE.zElement(type)
|
|
|
|
+ ->loadStructure(dimensionId, strId, uPos, &d);
|
|
|
|
+ d.close();
|
|
|
|
+ structures.add(str);
|
|
|
|
+ structurCs.unlock();
|
|
|
|
+ return str;
|
|
|
|
+ }
|
|
|
|
+ std::cout << "WARNING: did not find Structure information file '" << path
|
|
|
|
+ << "'.\n";
|
|
|
|
+ structurCs.unlock();
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Dimension::requestStopAndWait()
|
|
|
|
+{
|
|
|
|
+ stop = 1;
|
|
|
|
+ warteAufThread(1000000);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Dimension::updateMap(int x, int y, int height)
|
|
|
|
+{
|
|
|
|
+ chunkCs.lock();
|
|
|
|
+ int h1 = height % 2 == 0 ? height : height - 1;
|
|
|
|
+ int h2 = h1 + 1;
|
|
|
|
+ const Block* b1 = zBlockOrDefault({x, y, h1});
|
|
|
|
+ const Block* b2 = zBlockOrDefault({x, y, h2});
|
|
|
|
+ bool visible = 1;
|
|
|
|
+ if (h2 != WORLD_HEIGHT - 1)
|
|
|
|
+ {
|
|
|
|
+ const Block* b3 = zBlockOrDefault({x, y, h2 + 1});
|
|
|
|
+ visible = b3->isPassable() || b3->isTransparent();
|
|
|
|
+ }
|
|
|
|
+ int color1
|
|
|
|
+ = (b2->isPassable() || b2->isTransparent()) ? b1->getMapColor() : 0;
|
|
|
|
+ int color2 = visible ? b2->getMapColor() : 0;
|
|
|
|
+ int color1m = 0;
|
|
|
|
+ int color2m = 0;
|
|
|
|
+ if (h1 > 0)
|
|
|
|
+ {
|
|
|
|
+ const Block* b1m = zBlockOrDefault({x, y, h1 - 2});
|
|
|
|
+ const Block* b2m = zBlockOrDefault({x, y, h1 - 1});
|
|
|
|
+ color1m = (b2m->isPassable() || b2m->isTransparent())
|
|
|
|
+ ? b1m->getMapColor()
|
|
|
|
+ : 0;
|
|
|
|
+ color2m = (b1->isPassable() || b1->isTransparent()) ? b2m->getMapColor()
|
|
|
|
+ : 0;
|
|
|
|
+ }
|
|
|
|
+ char addr[8];
|
|
|
|
+ Punkt center = Game::INSTANCE->getChunkCenter(x, y);
|
|
|
|
+ getAddrOfWorld(center, addr);
|
|
|
|
+ ChunkMap* cMap = map->getMap(addr, 8, center);
|
|
|
|
+ if (cMap)
|
|
|
|
+ {
|
|
|
|
+ Framework::Vec3<int> chunkLocation = chunkCoordinates({x, y, height});
|
|
|
|
+ if (cMap->update((char)chunkLocation.x,
|
|
|
|
+ (char)chunkLocation.y,
|
|
|
|
+ (unsigned char)(chunkLocation.z / 2),
|
|
|
|
+ color1,
|
|
|
|
+ color2)
|
|
|
|
+ || (h1 > 0
|
|
|
|
+ && cMap->update((char)chunkLocation.x,
|
|
|
|
+ (char)chunkLocation.y,
|
|
|
|
+ (unsigned char)(chunkLocation.z / 2) - 1,
|
|
|
|
+ color1m,
|
|
|
|
+ color2m)))
|
|
|
|
+ {
|
|
|
|
+ map->onMapUpdated(addr, 8);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ chunkCs.unlock();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int Dimension::getChunkCount()
|
|
|
|
+{
|
|
|
|
+ return chunkList.getEintragAnzahl();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+double Dimension::getCurrentDayTime() const
|
|
|
|
+{
|
|
|
|
+ return currentDayTime;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+double Dimension::getNightDuration() const
|
|
|
|
+{
|
|
|
|
+ return nightDuration;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+double Dimension::getNightTransitionDuration() const
|
|
|
|
+{
|
|
|
|
+ return nightTransitionDuration;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+double Dimension::getDayDuration() const
|
|
|
|
+{
|
|
|
|
+ return dayDuration;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+DimensionFactory::DimensionFactory(int dimensionId)
|
|
|
|
+ : ReferenceCounter(),
|
|
|
|
+ dimensionId(dimensionId)
|
|
|
|
+{}
|
|
|
|
+
|
|
|
|
+int DimensionFactory::getDimensionId() const
|
|
|
|
+{
|
|
|
|
+ return dimensionId;
|
|
|
|
+}
|