#include "DimensionMap.h" #include #include #include "Chat.h" #include "ChunkMap.h" #include "Dimension.h" #include "Entity.h" #include "Game.h" #include "Player.h" DimensionMap::DimensionMap(int dimensionId) : ReferenceCounter(), dimensionId(dimensionId) { chunks = new Framework::RCTrie(); } DimensionMap::~DimensionMap() { chunks->release(); } void DimensionMap::api(Framework::InMemoryBuffer* zRequest, NetworkMessage* zResponse, Entity* zSource, Dimension* zDimension) { char type; zRequest->lese(&type, 1); switch (type) { case 0: // request chunk { Framework::Punkt location; zRequest->lese((char*)&location.x, 4); zRequest->lese((char*)&location.y, 4); location = Game::getChunkCenter(location.x, location.y); char addr[8]; zDimension->getAddrOfWorld(location, addr); ChunkMap* res = getMap(addr, 8, location); // create an empty map for a chunk that does not yet exist if (!res) res = new ChunkMap(location); zResponse->sendMap(res); zResponse->setUseBackground(); res->release(); break; } case 1: // subscribe to changes { cs.lock(); observers.add(zSource->getId()); cs.unlock(); break; } case 2: // unsubscribe from changes { cs.lock(); observers.removeValue(zSource->getId()); cs.unlock(); break; } case 3: // player list request { Framework::InMemoryBuffer buff; int count = 0; for (Entity* entity : *zDimension->entities) { if (entity->zType()->getId() == EntityTypeEnum::PLAYER) { Player* p = dynamic_cast(entity); char len = (char)Framework::textLength(p->getName()); buff.schreibe(&len, 1); buff.schreibe(p->getName(), len); Framework::Vec3 pos = p->getPosition(); buff.schreibe((char*)&pos.x, 4); buff.schreibe((char*)&pos.y, 4); buff.schreibe((char*)&pos.z, 4); count++; } } char* msg = new char[4 + buff.getSize()]; *(int*)msg = count; buff.lese(msg + 4, (int)buff.getSize()); zResponse->sendPlayerPositions(msg, 4 + (int)buff.getSize()); break; } } } ChunkMap* DimensionMap::load(Framework::Punkt chunkCenter) { Framework::Datei file; Framework::Text filePath = Game::INSTANCE->getWorldDirectory() + "/dim/" + dimensionId + "/map/"; filePath.appendHex(chunkCenter.x); filePath += "_"; filePath.appendHex(chunkCenter.y); filePath += ".map"; file.setDatei(filePath); if (file.open(Framework::Datei::Style::lesen)) { ChunkMap* map = new ChunkMap(&file); file.close(); return map; } return 0; } void DimensionMap::loadMap(char* addr, int addrLen, Chunk* zChunk) { cs.lock(); if (chunks->z(addr, addrLen)) { cs.unlock(); return; } ChunkMap* map = load(zChunk->getCenter()); if (!map) { map = new ChunkMap(zChunk); for (auto iterator = observers.begin(); iterator;) { Entity* e = Game::INSTANCE->zEntity(iterator.val()); if (!e) { iterator.remove(); continue; } else { NetworkMessage* msg = new NetworkMessage(); msg->sendMap(map); msg->setUseBackground(); Game::INSTANCE->sendMessage(msg, e); } iterator++; } } chunks->set(addr, addrLen, map); cs.unlock(); } void DimensionMap::onMapUpdated(char* addr, int addrLen) { cs.lock(); ChunkMap* map = chunks->z(addr, addrLen); if (map) { for (auto iterator = observers.begin(); iterator;) { Entity* e = Game::INSTANCE->zEntity(iterator.val()); if (!e) { iterator.remove(); continue; } else { NetworkMessage* msg = new NetworkMessage(); msg->sendMap(map); msg->setUseBackground(); Game::INSTANCE->sendMessage(msg, e); } iterator++; } } cs.unlock(); } void DimensionMap::saveMap(char* addr, int addrLen) { cs.lock(); ChunkMap* map = chunks->z(addr, addrLen); if (map) { Framework::Datei file; Framework::Text filePath = Game::INSTANCE->getWorldDirectory() + "/dim/" + dimensionId + "/map/"; filePath.appendHex(map->getChunkCenter().x); filePath += "_"; filePath.appendHex(map->getChunkCenter().y); filePath += ".map"; file.setDatei(filePath); file.erstellen(); if (file.open(Framework::Datei::Style::schreiben)) { map->writeTo(&file); file.close(); } else { Game::INSTANCE->zChat()->broadcastMessage( "Could not save map data. The map has to be recalulated at " "each chunk loading.", Chat::CHANNEL_WARNING); Framework::Logging::warning() << "could not open file '" << filePath.getText() << "' for writing."; } } cs.unlock(); } void DimensionMap::removeMap(char* addr, int addrLen) { cs.lock(); saveMap(addr, addrLen); chunks->remove(addr, addrLen); cs.unlock(); } ChunkMap* DimensionMap::getMap( char* addr, int addrLen, Framework::Punkt chunkCenter) { cs.lock(); ChunkMap* map = chunks->get(addr, addrLen); if (!map) map = load(chunkCenter); cs.unlock(); return map; }