#include "LocalUniverse.hpp" #include "core/geometry/math.hpp" #include "../contouring/Abstract.hpp" #include "../render/Window.hpp" #include "core/utils/logger.hpp" #include "core/world/Elements.hpp" #include "core/utils/io.hpp" #include #undef LOG_PREFIX #define LOG_PREFIX "Client: " using namespace world::client; LocalUniverse::LocalUniverse(const Universe::login& login, server_handle *const handle, const std::string& contour): Universe(contour), handle(handle) { assert(handle != nullptr); handle->playerName = login.name; for (auto i = 0; i < 500 && !handle->running; i++) { LOG_D("Waiting local server startup"); Window::wait(); } assert(handle->running); } LocalUniverse::~LocalUniverse() { handle->running = false; } void LocalUniverse::update(cell_pos pos, float deltaTime) { if (handle->teleport.has_value() && onTeleport) { const auto &rtf = handle->teleport.value(); const auto abs = getAbsolute(rtf); pos = abs.position; onTeleport(rtf, abs); handle->teleport = std::nullopt; } if (onMessage) { handle->messages.extractor(onMessage); } const auto notifyTick = contouringNotifier.mustNotify(pos, deltaTime); const auto lock = getElements(); const auto &elements = *lock; const auto visibleDist2 = glm::pow2(contouring->getVisibleDist()); { // Update alive areas ZoneScopedN("World"); auto rng = std::mt19937(std::rand()); const auto contouringThreshold = UINT32_MAX / (1 + contouring->getQueueSize()); for (auto& ref: elements.areas) { const area_id id = elements.withFlag(ref).val; const auto node = elements.findArea(id); assert(node); //MAYBE: if in load range const auto area_tf = node->absolute; const auto area = node->get(); const auto& chunks = area->getChunks(); //MAYBE: chunk area change for(const auto& chunk: chunks) { //MAYBE: compute absolute manually from chunk_pos(1) * pivot const cell_pos chunkPos = area_tf.computeChild(glm::multiply(chunk.first)); const auto chunkDist = glm::length2(glm::divide(chunkPos - pos)); if (chunkDist > visibleDist2) // FIXME: World still > 20ms with big contouring.keepDist continue; if(const auto neighbors = chunk.second->setEdits()->update(deltaTime, rng() < contouringThreshold)) { contouring->onUpdate(area_chunk_pos{id, chunk.first}, chunkDist, chunks, neighbors.value()); } else if (notifyTick) { contouring->onNotify(area_chunk_pos{id, chunk.first}, chunkDist, chunks); } } } } if (notifyTick) { for(const auto& ref: elements.parts) { const part_id id = elements.withFlag(ref).val; const auto node = elements.findPart(id); if (node->get()->loaded()) { const auto partDist = glm::length2(glm::divide((cell_pos)node->absolute.position - pos)); contouring->onNotify(id, partDist, node->get()->chunkSize(), node->get()->chunks, false); } } elements.models.iter([&] (const model_id& id, const Model& model) { if (!model.instances.empty()) { io::vec_istream idata(model.dt); std::istream iss(&idata); contouring->onLoad(id, iss); } }); } contouring->update(pos, elements); } void LocalUniverse::emit(const world::action::packet &packet) { handle->emit(packet); }