#include "World.h" #include #include #include #include #include #include #include "Constants.h" #include "Game.h" #include "Globals.h" using namespace Network; using namespace Framework; World* World::INSTANCE = 0; World::World(Screen3D* zScreen, FactoryClient* client) : Thread(), client(client) { renderedWorld = new World3D(); renderedWorld->addDiffuseLight(DiffuseLight{ Vec3(0.5f, 0.5f, -1.f), Vec3(1.f, 1.f, 1.f)}); currentDimension = new Dimension(); renderedWorld->addCollection( dynamic_cast(currentDimension->getThis())); zScreenPtr = zScreen; kam = new PlayerKam(zScreen); kam->setWorld(renderedWorld); zScreen->addKamera(kam); firstMessage = 1; ownEntityId = -1; currentTarget = 0; dayLightFactor = 1; time = 0; dayLength = 1000; transitionLength = 0; nightLength = 0; selectionModel = new FactoryCraftModel(); selectionModel->setModelData(zScreen->zGraphicsApi()->getModel("cube")); selectionModel->setSize(1.005f); selectionModel->setVisible(0); unsigned char light[3] = {0xff, 0xff, 0xff}; selectionModel->setAverageLight(light); selectionModel->setModelTextur(new Model3DTexture()); for (int i = 0; i < 6; i++) { selectionModel->zTexture()->setPolygonTexture(i, zScreen->zGraphicsApi()->createOrGetTexture( "data/textures/blocks.ltdb/selectedblock.p")); } selectionModel->setAlpha(1); selectionModel->setUseEffectAlpha(1); renderedWorld->addDrawable(selectionModel); start(); } World::~World() { zScreenPtr->removeKamera(kam); currentDimension->release(); if (currentTarget) currentTarget->release(); client->release(); World::INSTANCE = 0; } int World::update(bool background) { if (background && currentDimension->getId() < 0) return 0; NetworkReader* serverMessageReader = 0; unsigned char type = 0; int messageCount = 0; while (background ? serverMessageReader = client->getNextBackgroundMessage() : serverMessageReader = client->getNextForegroundMessage()) { messageCount++; serverMessageReader->read((char*)&type, 1); if (type == 3) // API MESSAGE { int length; serverMessageReader->read((char*)&length, 4); char* data = new char[length]; serverMessageReader->read(data, length); switch (data[0]) { case 1: // dimension message { int dimId = *(int*)(data + 1); if (dimId == currentDimension->getId()) { currentDimension->api(data + 5); } 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); ((Game*)(Menu*)menuRegister->get("game")) ->setTargetUIML(""); break; case 1: { setTarget(zEntity(*(int*)(data + 2))); short len = *(short*)(data + 6); char* uiml = new char[len + 8]; memcpy(uiml, data + 8, len); uiml[len] = 0; ((Game*)(Menu*)menuRegister->get("game")) ->setTargetUIML(uiml); delete[] uiml; break; } case 2: { setTarget(zBlockAt(Vec3(*(int*)(data + 2), *(int*)(data + 6), *(int*)(data + 10)))); Direction side = *(Direction*)(data + 14); short len = *(short*)(data + 15); char* uiml = new char[len + 1]; memcpy(uiml, data + 17, len); uiml[len] = 0; ((Game*)(Menu*)menuRegister->get("game")) ->setTargetUIML(uiml); delete[] uiml; break; } } break; } case 4: // chat message { ((Game*)(Menu*)menuRegister->get("game")) ->zChat() ->addMessage(data + 1); break; } case 5: // chat options { ((Game*)(Menu*)menuRegister->get("game")) ->zChat() ->initOptions(data + 1); break; } case 6: // map data { ByteArrayReader reader(data + 1, length - 1, 0); ChunkMap* map = new ChunkMap(&reader); ((Game*)(Menu*)menuRegister->get("game")) ->zMap() ->addChunk(map); break; } case 7: // map player data { ((Game*)(Menu*)menuRegister->get("game")) ->zMap() ->updatePlayerData(data + 1); break; } case 8: // time sync { nightLength = *(double*)(data + 9); transitionLength = *(double*)(data + 17); dayLength = *(double*)(data + 25); time = *(double*)(data + 1); break; } } delete[] data; } if (type == 4) // POSITION UPDATE { int old = ownEntityId; serverMessageReader->read((char*)&ownEntityId, 4); int dimensionId = 0; serverMessageReader->read((char*)&dimensionId, 4); currentDimension->setId(dimensionId); kam->setEntityId(ownEntityId); Entity* p = zEntity(ownEntityId); if (p) p->setPlayerControlled(); if (old != ownEntityId) client->sendPlayerAction("\5", 1); } client->endMessageReading(background); } client->endMessageReading(background); if (!background) { Entity* player = getCurrentPlayerEntity(); if (player) { currentDimension->removeDistantChunks( {(int)player->getPos().x, (int)player->getPos().y}); Point 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](Point center) { Chunk* zC = currentDimension->zChunk(center); if (!zC) { char msg[1]; msg[0] = 0; // add observer and request chaunk data Point pos = center; subLock.lockRead(); bool found = 0; for (Point p : subscriptions) { if (p == pos) { found = 1; break; } } if (!found) { client->chunkAPIRequest(pos, msg, 1); subLock.lockWrite(); subscriptions.add(pos); subLock.unlockWrite(); } subLock.unlockRead(); } }; requestChunk( currentChunk + Point(x * CHUNK_SIZE, y * CHUNK_SIZE)); if (y > 0) requestChunk(currentChunk + Point(x * CHUNK_SIZE, -y * CHUNK_SIZE)); if (x > 0) { requestChunk(currentChunk + Point(-x * CHUNK_SIZE, y * CHUNK_SIZE)); if (y > 0) requestChunk( currentChunk + Point(-x * CHUNK_SIZE, -y * CHUNK_SIZE)); } } } } } return messageCount; } void World::onTick(double time) { selectionModel->tick(0.1); this->time += time; if (this->time >= dayLength + nightLength + transitionLength * 2) { this->time -= dayLength + nightLength + transitionLength * 2; } if (this->time > dayLength && this->time < dayLength + transitionLength) { dayLightFactor = 1.f - (float)((this->time - dayLength) / transitionLength) * 0.95f; } else if (this->time > dayLength + transitionLength && this->time < dayLength + transitionLength + nightLength) { // night dayLightFactor = 0.05f; if (renderedWorld->getDiffuseLightCount() > 0) { renderedWorld->removeDiffuseLight(0); } } else if (this->time > dayLength + transitionLength + nightLength) { dayLightFactor = (float)((this->time - dayLength - nightLength - transitionLength) / transitionLength) * 0.95f + 0.05f; } else { dayLightFactor = 1.f; } if (this->time < dayLength + transitionLength || this->time > dayLength + transitionLength + nightLength) { float currentDayTime = (float)(this->time < dayLength + transitionLength ? this->time + transitionLength : this->time - dayLength + transitionLength + nightLength); Vec3 sunPos = Vec3(-200.f, 50.f, 0.f); sunPos.rotateY(( float)((currentDayTime / (dayLength + transitionLength * 2)) * PI)); sunPos.normalize(); if (!renderedWorld->getDiffuseLightCount()) { renderedWorld->addDiffuseLight( {-sunPos, Vec3(1.0, 1.0, 1.0)}); } else { renderedWorld->getDiffuseLight(0).direction = -sunPos; } } } void World::setChunk(Chunk* chunk) { currentDimension->setChunk(chunk, chunk->getCenter()); } void World::thread() { new AsynchronCall("World Update", [this]() { Timer tm; tm.measureStart(); double sum = 0; int updates = 0; int messages = 0; double wait = 0; while (client->isConnected()) { if (World::INSTANCE != this) { return; } messages += update(0); updates++; tm.measureEnd(); sum += tm.getSekunden(); wait += 10 - tm.getSekunden(); tm.measureStart(); if ((int)wait > 0) { Sleep((int)wait); } if (sum > 1.0) { std::cout << "updates: " << updates << ", messages: " << (double)messages << ", seconds: " << sum << "\n"; sum = 0; updates = 0; messages = 0; } } std::cout << "foreground connection lost\n"; }); while (client->isConnected()) { if (World::INSTANCE != this) { return; } update(1); Sleep(100); } Sleep(1000); std::cout << "background connection lost\n"; menuRegister->get("game")->hide(); menuRegister->get("serverSelection")->show(); zScreenPtr->postAction([this]() { if (World::INSTANCE == this) { World::INSTANCE = 0; release(); } }); } Block* World::zBlockAt(Framework::Vec3 location) const { return currentDimension->zBlock(location); } Block* World::getBlockAt(Framework::Vec3 location) const { return currentDimension->getBlock(location); } Dimension* World::zDimension() const { return currentDimension; } void World::setVisibility(Entity* zEntity, bool visible) { if (visible) renderedWorld->addDrawable( dynamic_cast(zEntity->getThis())); else renderedWorld->removeDrawable(zEntity); } Framework::Point World::getChunkCenter(int x, int y) const { return Point(((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 (!zTarget) { selectionModel->setVisible(0); } else { selectionModel->setPosition( zTarget->getPos().x, zTarget->getPos().y, zTarget->getPos().z); Block* b = dynamic_cast(zTarget); if (b && b->getPartOfModels()) { selectionModel->setDestroyedState(b->getEffectPercentage()); } else { selectionModel->setDestroyedState(0); } selectionModel->setVisible(1); } 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::onChunkAdded(Point pos) { subLock.lockWrite(); int index = 0; for (Point p : subscriptions) { if (p == pos) { subscriptions.remove(index); break; } index++; } subLock.unlockWrite(); } Framework::Model3D* World::getCurrentTarget() const { while (targetLock.isLocked()) Sleep(1); return currentTarget ? dynamic_cast(currentTarget->getThis()) : 0; } FactoryCraftModel* World::zSelectedEffectModel() const { return selectionModel; } Chunk* World::zChunk(Point center) { return currentDimension->zChunk(center); } Lock& World::getChunkReadLock() { return currentDimension->getReadLock(); } FactoryClient* World::zClient() const { return client; } float World::getDayLightFactor() const { return dayLightFactor; }