diff --git a/TODO.md b/TODO.md index d48a367..f3cdc45 100644 --- a/TODO.md +++ b/TODO.md @@ -8,21 +8,18 @@ ## Hello other + - [ ] Multiplayer - [ ] Chat - [~] Authentication - [x] Compression - [ ] Encryption - [x] Embedded - [x] Standalone - - [ ] VK - - [ ] Pipeline recreate - - [ ] Pipeline cache - - [ ] Reuse descriptors - - [ ] Secondary buffers ## Hello world - [~] Map stream + - Local prediction - [ ] Contouring service - [~] Edit - Local prediction @@ -30,29 +27,49 @@ - [ ] Iterator ray - [ ] Cast from chunk center - [ ] Transparency + - [ ] Entities -## Hello darkness +## Hello universe - - [ ] ECS - - [ ] Area - - [ ] Rotation + - [ ] Universe + - [ ] Galaxy + - [ ] Rotation + - [ ] Orbit system + - [ ] Gravity referential + - [ ] Better generation + - SIMD + - [ ] Dynamic SIMD libs + - [ ] FastNoiseSIMD / HastyNoise double precision + - [ ] https://github.com/Auburn/FastNoise2/releases + - [ ] Surface features + - [ ] Biomes + - https://imgur.com/kM8b5Zq + - https://imgur.com/a/bh2iy + - https://speciesdevblog.files.wordpress.com/2012/11/biomemap.png + - Curvature - [~] CubeSphere - [ ] Area corrected CubeSphere - [ ] Corrected Normals - [ ] Surface curvature - [ ] Curvature avare frustum - [ ] Healpix - - [ ] Surface features - - [ ] Biomes - - https://imgur.com/kM8b5Zq - - https://imgur.com/a/bh2iy - - https://speciesdevblog.files.wordpress.com/2012/11/biomemap.png - - [ ] Galaxy + +## Hello industry + + - [ ] Multiblock + +## Hello darkness + + - [ ] Slash screen + - [ ] QUIC protocal - [ ] Octree - - SIMD - - [ ] Dynamic SIMD libs - - [ ] FastNoiseSIMD / HastyNoise double precision - - [ ] https://github.com/Auburn/FastNoise2/releases + - [ ] Better Lod + - [ ] VK + - [ ] Pipeline recreate + - [ ] Pipeline cache + - [ ] Reuse descriptors + - [ ] Secondary buffers + - [ ] ECS - [ ] Cross plateforme encoding - [ ] Config (yaml) - [ ] HDR diff --git a/src/client/Client.cpp b/src/client/Client.cpp index 396c44f..ddd485a 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -19,7 +19,6 @@ void Client::run(server_handle* const localHandle) { InputMap inputs(window.getPtr()); Controllable player(window.getPtr(), inputs, options.control); Camera camera(&player, options.camera); - state.position = player.position; auto pipeline = render::Renderer::Get(); pipeline->LightInvDir = glm::normalize(glm::vec3(-.5f, 2, -2)); @@ -27,6 +26,9 @@ void Client::run(server_handle* const localHandle) { auto world = world::client::Load(options.connection, localHandle, options.world, options.contouring); state.contouring = world->getContouring(); + world->onTeleport = [&](voxel_pos pos) { + state.position = player.position = pos; + }; do { window.startFrame(); @@ -49,7 +51,7 @@ void Client::run(server_handle* const localHandle) { if(pos != state.position.as_voxel(options.voxel_density)) { world->emit(world::action::Move(pos)); } - state.position = player.position; + state.position = pos; } camera.update(); pipeline->lookFrom(camera); diff --git a/src/client/control/Controllable.cpp b/src/client/control/Controllable.cpp index 61be0e4..4a467de 100644 --- a/src/client/control/Controllable.cpp +++ b/src/client/control/Controllable.cpp @@ -1,6 +1,6 @@ #include "Controllable.hpp" -Controllable::Controllable(GLFWwindow *window, const InputMap& inputs, const Controllable::options& opt): position(voxel_pos(100, 0, 0), 1), window(window), inputs(inputs), o(opt){ } +Controllable::Controllable(GLFWwindow *window, const InputMap& inputs, const Controllable::options& opt): position(), window(window), inputs(inputs), o(opt){ } Controllable::~Controllable() { } Controllable::axis Controllable::getAxis() const { diff --git a/src/client/world/DistantUniverse.cpp b/src/client/world/DistantUniverse.cpp index 2a38be9..5089d56 100644 --- a/src/client/world/DistantUniverse.cpp +++ b/src/client/world/DistantUniverse.cpp @@ -51,9 +51,11 @@ void DistantUniverse::update(voxel_pos pos, float deltaTime) { for (int y = -queryDistance; y <= queryDistance; y++) { for (int z = -queryDistance; z <= queryDistance; z++) { const auto dist2 = x * x + y * y + z * z; - if (dist2 <= queryDistance * queryDistance) { - const auto p = diff + chunk_pos(x, y, z); - if (chunks.inRange(p) && chunks.find(p) == chunks.end()) { + const auto p = diff + chunk_pos(x, y, z); + if (dist2 <= queryDistance * queryDistance && chunks.inRange(p)) { + if (chunks.find(p) != chunks.end()) { + contouring->onNotify(std::make_pair(area.first, p), diff, chunks); + } else { missing.push_back(p); } } @@ -81,8 +83,7 @@ void DistantUniverse::pullNetwork(voxel_pos pos) { const server_packet_type type = static_cast(*packet->data); switch (type) { case server_packet_type::CAPABILITIES: { - PacketReader(packet).read(serverDistance); - emit(world::action::Move(pos)); + PacketReader(packet, true).read(serverDistance); break; } @@ -95,6 +96,12 @@ void DistantUniverse::pullNetwork(voxel_pos pos) { break; } + case server_packet_type::TELEPORT: { + PacketReader(packet).read(pos); + onTeleport(pos); + break; + } + case server_packet_type::AREAS: { auto reader = PacketReader(packet, true); while(!reader.isFull()) { diff --git a/src/client/world/LocalUniverse.cpp b/src/client/world/LocalUniverse.cpp index ed037fa..44df977 100644 --- a/src/client/world/LocalUniverse.cpp +++ b/src/client/world/LocalUniverse.cpp @@ -23,10 +23,14 @@ LocalUniverse::~LocalUniverse() { } void LocalUniverse::update(voxel_pos pos, float) { + if (handle->teleport.has_value() && onTeleport) { + pos = handle->teleport.value(); + onTeleport(pos); + handle->teleport = std::nullopt; + } + const auto cur_chunk = glm::divide(pos); const auto chunkChange = cur_chunk != last_chunk; - if (last_chunk.x == INT_MAX) - emit(world::action::Move(pos)); last_chunk = cur_chunk; if(chunkChange) { diff --git a/src/client/world/Universe.hpp b/src/client/world/Universe.hpp index 2c55ab3..3073bb8 100644 --- a/src/client/world/Universe.hpp +++ b/src/client/world/Universe.hpp @@ -24,6 +24,8 @@ namespace world::client { /// Send action to ServerUniverse virtual void emit(const action::packet &) = 0; + /// When server teleport player + std::function onTeleport; /// Get current contouring worker contouring::Abstract* getContouring() const { diff --git a/src/core/net/data.hpp b/src/core/net/data.hpp index a9a874f..1398d9d 100644 --- a/src/core/net/data.hpp +++ b/src/core/net/data.hpp @@ -26,15 +26,18 @@ using packet_t = ENetPacket; enum class server_packet_type: enet_uint8 { PERSONAL = 0, /// Get server salt - /// realable + /// reliable CHALLENGE = 0, + /// Set client position + /// voxel_pos reliable + TELEPORT = 1, BROADCASTED = 16, /// List all areas - /// {area_id, world::Area::params}[] realable + /// {area_id, world::Area::params}[] reliable AREAS = 16, /// Full chunk update - /// {area_, zstd} realable + /// {area_, zstd} reliable CHUNK = 17, /// Chunk changes /// {area_id, {chunk_pos, ushort(count), Chunk::Edit[]}[]} notify @@ -42,19 +45,19 @@ enum class server_packet_type: enet_uint8 { EDITS = 18, /// World compression dictionary - /// zstd dict realable + /// zstd dict reliable COMPRESSION = 24, /// Server capabilities - /// ushort(loadDistance), MAYBE: more realable + /// ushort(loadDistance), MAYBE: more reliable CAPABILITIES = 25, }; enum class client_packet_type: enet_uint8 { /// Interact with voxels - /// actions::FillCube realable + /// actions::FillCube reliable FILL_CUBE = 0, /// Request missing chunks - /// area_id, chunk_pos[] realable + /// area_id, chunk_pos[] reliable MISSING_CHUNKS = 8, /// Position update diff --git a/src/core/server_handle.hpp b/src/core/server_handle.hpp index 8e7ae0b..f036031 100644 --- a/src/core/server_handle.hpp +++ b/src/core/server_handle.hpp @@ -10,4 +10,5 @@ struct server_handle { std::function &pos, const chunk_pos &offset, const world::ChunkContainer &data, geometry::Faces neighbors)> onUpdate; std::function emit; std::function raycast; + std::optional teleport; }; diff --git a/src/server/world/SharedUniverse.cpp b/src/server/world/SharedUniverse.cpp index d5b0f2a..be9432a 100644 --- a/src/server/world/SharedUniverse.cpp +++ b/src/server/world/SharedUniverse.cpp @@ -6,8 +6,10 @@ using namespace world::server; SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandle): Universe(o), localHandle(localHandle) { // Local player [[maybe_unused]] - const auto id = entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{}); + const auto id = entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{spawnPoint}); assert(id == PLAYER_ENTITY_ID); + localHandle->teleport = spawnPoint; + movedPlayers.push_back(id); localHandle->areas = (world::client::area_map*)(&areas); //WONT FIX: templated area localHandle->emit = std::function([&](const world::action::packet &packet) { @@ -33,7 +35,8 @@ SharedUniverse::~SharedUniverse() { } void SharedUniverse::loadChunk(area_ area, chunk_pos diff, const world::ChunkContainer& chunks) { - localHandle->onUpdate(area, diff, chunks, Faces::All); + if(localHandle->onUpdate) + localHandle->onUpdate(area, diff, chunks, Faces::All); } void SharedUniverse::updateChunk(area_map::iterator &it, world::ChunkContainer::iterator &it_c, chunk_pos diff, float deltaTime) { if (const auto neighbors = std::dynamic_pointer_cast(it_c->second)->update(deltaTime, true)) { diff --git a/src/server/world/Universe.cpp b/src/server/world/Universe.cpp index 25828a5..4f352b7 100644 --- a/src/server/world/Universe.cpp +++ b/src/server/world/Universe.cpp @@ -52,6 +52,7 @@ Universe::Universe(const Universe::options &options): host(options.connection, o generator::params(std::in_place_type, radius * CHUNK_LENGTH * 3 / 4, 42)}); //far_areas.emplace(Area::params{voxel_pos(0), 1 << 20, generator::params(std::in_place_type, 42)}); } + spawnPoint = voxel_pos(100, 0, 0); //TODO: save in index index.close(); } @@ -292,7 +293,10 @@ void Universe::update(float deltaTime) { #if TRACY_ENABLE size_t entity_count = 0; #endif - entities.for_each([&](entity_id, Entity &val) { + entities.for_each([&](entity_id type, Entity &val) { + if (type == PLAYER_ENTITY_ID) //FIXME: update players + return; + val.instances.remove([&](entity_id, Entity::Instance &inst) { #if TRACY_ENABLE entity_count++; @@ -334,7 +338,7 @@ void Universe::pullNetwork() { [&](peer_t *peer, salt_t salt) { ZoneScopedN("Connect"); LOG_I("Client connect from " << peer->address); - net_client* client = new net_client(salt, entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{ })); + net_client* client = new net_client(salt, entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{spawnPoint})); peer->data = client; const salt_t rnd = std::rand(); @@ -343,6 +347,11 @@ void Universe::pullNetwork() { host.send(peer, server_packet_type::CAPABILITIES, loadDistance, channel_type::RELIABLE); host.send(peer, server_packet_type::COMPRESSION, dict_content.data(), dict_content.size(), channel_type::RELIABLE); + { + auto player = findEntity(PLAYER_ENTITY_ID, client->instanceId); + host.sendTo(peer, server_packet_type::TELEPORT, player->pos.as_voxel(), channel_type::RELIABLE); + movedPlayers.push_back(client->instanceId); + } broadcastAreas(); }, [](peer_t *peer, disconnect_reason reason) { @@ -382,25 +391,27 @@ void Universe::pullNetwork() { break; } case client_packet_type::MISSING_CHUNKS: { - const auto pos = entities.at(PLAYER_ENTITY_ID).instances.at(Server::GetPeerData(peer)->instanceId).pos.as_voxel(); + if (auto player = findEntity(PLAYER_ENTITY_ID,Server::GetPeerData(peer)->instanceId )) { + const auto pos = player->pos.as_voxel(); - auto reader = PacketReader(packet); - area_id id = *reader.read(); - if(auto area = areas.find(id); area != areas.end()) { - auto &chunks = area->second->getChunks(); - const chunk_pos diff = glm::divide(pos - area->second->getOffset().as_voxel()); - while(!reader.isFull()) { - chunk_pos cpos = *reader.read(); - if(glm::length2(diff - cpos) <= glm::pow2(loadDistance) && chunks.inRange(cpos)) { - if(auto chunk = chunks.find(cpos); chunk != chunks.end()) { - host.send(peer, serializeChunk({std::make_pair(id, cpos), std::dynamic_pointer_cast(chunk->second)}), net::channel_type::RELIABLE); + auto reader = PacketReader(packet); + area_id id = *reader.read(); + if(auto area = areas.find(id); area != areas.end()) { + auto &chunks = area->second->getChunks(); + const chunk_pos diff = glm::divide(pos - area->second->getOffset().as_voxel()); + while(!reader.isFull()) { + chunk_pos cpos = *reader.read(); + if(glm::length2(diff - cpos) <= glm::pow2(loadDistance) && chunks.inRange(cpos)) { + if(auto chunk = chunks.find(cpos); chunk != chunks.end()) { + host.send(peer, serializeChunk({std::make_pair(id, cpos), std::dynamic_pointer_cast(chunk->second)}), net::channel_type::RELIABLE); + } + } else { + LOG_T("Request out of range chunk"); } - } else { - LOG_T("Request out of range chunk"); } + } else { + LOG_T("Bad chunk request"); } - } else { - LOG_T("Bad chunk request"); } break; } @@ -531,21 +542,27 @@ entity_instance_id Universe::addEntity(entity_id type, const Entity::Instance &i return std::make_pair(type, entities.at(type).instances.push(instance)); } +Universe::Entity::Instance* Universe::findEntity(entity_id type, entity_id id) { + if(!entities.contains(type)) + return nullptr; + + if(!entities.at(type).instances.contains(id)) + return nullptr; + + return &entities.at(type).instances.at(id); +} + bool Universe::movePlayer(data::generational::id id, glm::ifvec3 pos) { - if(!entities.contains(PLAYER_ENTITY_ID)) - return false; + if (auto player = findEntity(PLAYER_ENTITY_ID, id)) { + if(player->pos.as_voxel() == pos.as_voxel()) + return true; - if(!entities.at(PLAYER_ENTITY_ID).instances.contains(id)) - return false; - - auto &player = entities.at(PLAYER_ENTITY_ID).instances.at(id); - if(player.pos.as_voxel() == pos.as_voxel()) + //TODO: check dist + collision from a to b + movedPlayers.push_back(id); + player->pos = pos; return true; - - //TODO: check dist + collision from a to b - movedPlayers.push_back(id); - player.pos = pos; - return true; + } else + return false; } std::shared_ptr Universe::createChunk(const chunk_pos &pos, const std::unique_ptr &rnd) const { diff --git a/src/server/world/Universe.hpp b/src/server/world/Universe.hpp index 151e3b3..93a673f 100644 --- a/src/server/world/Universe.hpp +++ b/src/server/world/Universe.hpp @@ -47,6 +47,7 @@ namespace world::server { /// Instante entity entity_instance_id addEntity(entity_id type, const Entity::Instance &instance); + Entity::Instance* findEntity(entity_id type, entity_id id); /// Move player bool movePlayer(data::generational::id id, glm::ifvec3 pos); @@ -79,6 +80,7 @@ namespace world::server { virtual void loadChunk(area_, chunk_pos, const world::ChunkContainer &); std::vector movedPlayers; + voxel_pos spawnPoint; /// Alive areas containing chunks area_map areas;