#include #include #include #include #include "World.h" #include "Globals.h" #include "WorldUpdate.h" #include "Constants.h" #include "Registries.h" #include "Game.h" #include using namespace Network; using namespace Framework; World* World::INSTANCE = 0; World::World(Bildschirm3D* zScreen, FactoryClient* client) : Thread(), client(client) { renderedWorld = new Welt3D(); renderedWorld->addDiffuseLight(DiffuseLight{ Vec3(0.5f, 0.5f, -1.f), Vec3(1.f, 1.f, 1.f) }); currentDimension = new Dimension(); zScreenPtr = zScreen; kam = new PlayerKam(zScreen); kam->setWelt(renderedWorld); zScreen->addKamera(kam); firstMessage = 1; ownEntityId = -1; currentTarget = 0; start(); } World::~World() { zScreenPtr->removeKamera(kam); currentDimension->release(); if (currentTarget) currentTarget->release(); client->release(); } void World::update(bool background) { NetworkReader* serverMessageReader = 0; unsigned char type = 0; while (background ? serverMessageReader = client->getNextBackgroundMessage() : serverMessageReader = client->getNextForegroundMessage()) { serverMessageReader->lese((char*)&type, 1); if (type == 2) // WORLD UPDATE { int id = 0; serverMessageReader->lese((char*)&id, 4); STATIC_REGISTRY(WorldUpdateType).zElement(id)->applyUpdateAndCheck(serverMessageReader); } if (type == 3) // API MESSAGE { int length; serverMessageReader->lese((char*)&length, 4); char* data = new char[length]; serverMessageReader->lese(data, length); switch (data[0]) { case 1: // dimension message { currentDimension->api(data + 1); break; } case 2: // gui message ((Game*)(Menu*)menuRegister->get("game"))->api(data + 1); break; case 3: // set target { switch (data[1]) { case 0: setTarget(0); break; case 1: setTarget(zEntity(*(int*)(data + 2))); break; case 2: setTarget(zBlockAt(Vec3(*(int*)(data + 2), *(int*)(data + 6), *(int*)(data + 10)))); break; } break; } } delete[] data; // TODO: process messages } if (type == 4) // POSITION UPDATE { int old = ownEntityId; serverMessageReader->lese((char*)&ownEntityId, 4); kam->setEntityId(ownEntityId); Entity* p = zEntity(ownEntityId); if (p) p->setPlayerControlled(); if (old != ownEntityId) client->sendPlayerAction("\5", 1); } client->endMessageReading(background); } client->endMessageReading(background); Entity* player = getCurrentPlayerEntity(); if (player) { renderedWorld->lock(); currentDimension->removeDistantChunks({ (int)player->getPos().x, (int)player->getPos().y }); Punkt currentChunk = getChunkCenter((int)player->getX(), (int)player->getY()); for (int x = 0; x <= CHUNK_VISIBILITY_RANGE; x++) { for (int y = 0; y <= CHUNK_VISIBILITY_RANGE; y++) { std::function requestChunk = [this](Punkt center) { Chunk* zC = currentDimension->zChunk(center); if (!zC) { char msg[1]; msg[0] = 0; // add observer and request chaunk data Punkt pos = center; subLock.lock(); bool found = 0; for (Punkt p : subscriptions) { if (p == pos) { found = 1; break; } } if (!found) { client->chunkAPIRequest(pos, msg, 1); subscriptions.add(pos); } subLock.unlock(); } }; requestChunk(currentChunk + Punkt(x * CHUNK_SIZE, y * CHUNK_SIZE)); if (y > 0) requestChunk(currentChunk + Punkt(x * CHUNK_SIZE, -y * CHUNK_SIZE)); if (x > 0) { requestChunk(currentChunk + Punkt(-x * CHUNK_SIZE, y * CHUNK_SIZE)); if (y > 0) requestChunk(currentChunk + Punkt(-x * CHUNK_SIZE, -y * CHUNK_SIZE)); } } } renderedWorld->unlock(); } } void World::setChunk(Chunk* chunk) { zScreenPtr->lock(); renderedWorld->lock(); currentDimension->setChunk(chunk, chunk->getCenter()); renderedWorld->unlock(); zScreenPtr->unlock(); } void World::thread() { new AsynchronCall("World Update", [this]() { while (true) { zScreenPtr->lock(); if (World::INSTANCE != this) { zScreenPtr->unlock(); return; } zScreenPtr->unlock(); update(0); Sleep(10); } }); while (true) { zScreenPtr->lock(); if (World::INSTANCE != this) { zScreenPtr->unlock(); return; } zScreenPtr->unlock(); update(1); Sleep(10); } } Block* World::zBlockAt(Framework::Vec3 location) const { return currentDimension->zBlock(location); return 0; } Block* World::getBlockAt(Framework::Vec3 location) const { return currentDimension->getBlock(location); return 0; } Dimension* World::zDimension() const { return currentDimension; } void World::setVisibility(Chunk* zChunk, bool visible) { renderedWorld->lock(); if (visible) renderedWorld->addCollection(dynamic_cast(zChunk->getThis())); else renderedWorld->removeCollection(zChunk); renderedWorld->unlock(); } void World::setVisibility(Entity* zEntity, bool visible) { renderedWorld->lock(); if (visible) renderedWorld->addZeichnung(dynamic_cast(zEntity->getThis())); else renderedWorld->removeZeichnung(zEntity); renderedWorld->unlock(); } Framework::Punkt World::getChunkCenter(int x, int y) const { return Punkt(((x < 0 ? x + 1 : x) / CHUNK_SIZE) * CHUNK_SIZE + (x < 0 ? -CHUNK_SIZE : CHUNK_SIZE) / 2, ((y < 0 ? y + 1 : y) / CHUNK_SIZE) * CHUNK_SIZE + (y < 0 ? -CHUNK_SIZE : CHUNK_SIZE) / 2); } Entity* World::zEntity(int id) const { Entity* e = currentDimension->zEntity(id); if (e) return e; return 0; } Entity* World::getEntity(int id) const { Entity* e = currentDimension->getEntity(id); if (e) return e; return 0; } void World::removeEntity(int id) { currentDimension->removeEntity(id); } PlayerKam* World::zKamera() const { return kam; } int World::getCurrentPlayerId() const { return ownEntityId; } Entity* World::getCurrentPlayerEntity() const { return zEntity(ownEntityId); } void World::setTarget(Framework::Model3D* zTarget) { if (zTarget != currentTarget) { targetLock.lock(); if (currentTarget) { currentTarget->setAmbientFactor(currentTarget->getAmbientFactor() - 0.2f); currentTarget->release(); currentTarget = 0; } if (zTarget) { currentTarget = dynamic_cast(zTarget->getThis()); if (currentTarget) currentTarget->setAmbientFactor(currentTarget->getAmbientFactor() + 0.2f); } targetLock.unlock(); } } void World::lockWorld() { renderedWorld->lock(); } void World::unlockWorld() { renderedWorld->unlock(); } void World::onChunkAdded(Punkt pos) { subLock.lock(); int index = 0; for (Punkt p : subscriptions) { if (p == pos) { subscriptions.remove(index); break; } index++; } subLock.unlock(); } Framework::Model3D* World::getCurrentTarget() const { while (targetLock.isLocked()) Sleep(1); return currentTarget ? dynamic_cast(currentTarget->getThis()) : 0; } Chunk* World::zChunk(Punkt center) { return currentDimension->zChunk(center); } FactoryClient* World::zClient() const { return client; }