#include "World.h" #include #include #include #include #include #include #include "Constants.h" #include "Dimension.h" #include "FactoryClient.h" #include "Game.h" #include "Globals.h" #include "PlayerKam.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 = Vec3(1.f, 1.f, 1.f); dayLightDirection = Vec3(0.f, 0.f, -1.f); 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}); Framework::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](Framework::Point center) { Chunk* zC = currentDimension->zChunk(center); if (!zC) { char msg[1]; msg[0] = 0; // add observer and request chaunk data Framework::Point pos = center; subLock.lockRead(); bool found = 0; for (Framework::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); Vec3 dayColor = Vec3(1.f, 1.f, 1.f); Vec3 dawnColor = Vec3(1.f, 0.8f, 0.f); Vec3 nightColor = Vec3(0.05f, 0.05f, 0.05f); Vec3 beginDayLightDirection = Vec3(-1.f, -0.2f, 0.2f); this->time += time; if (this->time >= dayLength + nightLength + transitionLength * 2) { this->time -= dayLength + nightLength + transitionLength * 2; } double startTime = dayLength + transitionLength + nightLength; float dayDirectionRotation = (float)(this->time - startTime); if (dayDirectionRotation < 0) { dayDirectionRotation += (float)(dayLength + nightLength + transitionLength * 2); } dayDirectionRotation = max(0.f, (float)(dayDirectionRotation / (dayLength + transitionLength + 2 * transitionLength + nightLength))); dayLightDirection = beginDayLightDirection.rotateY(dayDirectionRotation * (float)PI); if (this->time > dayLength && this->time < dayLength + transitionLength) { // transition from day to night; float transformation = (float)min( (this->time - dayLength) / (transitionLength / 2), 1.0); float transformation2 = (float)min(max((this->time - dayLength - transitionLength / 2) / (transitionLength / 2), 0.0), 1.0); dayLightFactor = dawnColor * transformation + dayColor * (1.f - transformation); dayLightFactor = dayLightFactor * (1.f - transformation2) + nightColor * transformation2; } else if (this->time > dayLength + transitionLength && this->time < dayLength + transitionLength + nightLength) { // night dayLightFactor = nightColor; if (renderedWorld->getDiffuseLightCount() > 0) { renderedWorld->removeDiffuseLight(0); } } else if (this->time > dayLength + transitionLength + nightLength) { // transition from night to day float transformation = (float)min( (this->time - dayLength - transitionLength - nightLength) / (transitionLength / 2), 1.0); float transformation2 = (float)min(max((this->time - dayLength - transitionLength - nightLength - transitionLength / 2) / (transitionLength / 2), 0.0), 1.0); dayLightFactor = nightColor * (1.f - transformation) + dawnColor * transformation; dayLightFactor = dayLightFactor * (1.f - transformation2) + dayColor * transformation2; } else { dayLightFactor = dayColor; } 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) { 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(Framework::Point pos) { subLock.lockWrite(); int index = 0; for (Framework::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(Framework::Point center) { return currentDimension->zChunk(center); } Framework::Lock& World::getChunkReadLock() { return currentDimension->getReadLock(); } FactoryClient* World::zClient() const { return client; } Vec3 World::getDayLightFactor() const { return dayLightFactor; } Vec3 World::getDayLightDirection() const { return dayLightDirection; }