From 3bf42c6ff3805a0d42bbc661794a95ff31bedc26 Mon Sep 17 00:00:00 2001 From: untodesu Date: Sat, 15 Mar 2025 16:22:09 +0500 Subject: Add whatever I was working on for the last month --- game/client/chunk_visibility.cc | 134 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 game/client/chunk_visibility.cc (limited to 'game/client/chunk_visibility.cc') diff --git a/game/client/chunk_visibility.cc b/game/client/chunk_visibility.cc new file mode 100644 index 0000000..df0148c --- /dev/null +++ b/game/client/chunk_visibility.cc @@ -0,0 +1,134 @@ +#include "client/pch.hh" +#include "client/chunk_visibility.hh" + +#include "core/config.hh" + +#include "shared/chunk.hh" +#include "shared/dimension.hh" +#include "shared/protocol.hh" + +#include "client/camera.hh" +#include "client/globals.hh" +#include "client/session.hh" + +static chunk_pos cached_cpos; +static unsigned int cached_dist; +static std::vector requests; + +static void request_chunk(const chunk_pos &cpos) +{ + protocol::RequestChunk packet; + packet.cpos = cpos; + protocol::send(session::peer, protocol::encode(packet)); +} + +// Go through the list of chunk positions that should +// be visible client-side but seem to not exist yet +static void request_new_chunks(void) +{ + auto cmin = cached_cpos - static_cast(cached_dist); + auto cmax = cached_cpos + static_cast(cached_dist); + + requests.clear(); + + for(auto cx = cmin.x; cx <= cmax.x; ++cx) + for(auto cy = cmin.y; cy <= cmax.y; ++cy) + for(auto cz = cmin.z; cz <= cmax.z; ++cz) { + if(globals::dimension->find_chunk({cx, cy, cz})) { + // The chunk already exists, we don't need + // to request it from the server anymore + continue; + } + + requests.push_back(chunk_pos(cx, cy, cz)); + } + + std::sort(requests.begin(), requests.end(), [](const chunk_pos &ca, const chunk_pos &cb) { + auto dir_a = ca - cached_cpos; + auto dir_b = cb - cached_cpos; + + const auto da = dir_a[0] * dir_a[0] + dir_a[1] * dir_a[1] + dir_a[2] * dir_a[2]; + const auto db = dir_b[0] * dir_b[0] + dir_b[1] * dir_b[1] + dir_b[2] * dir_b[2]; + + return da > db; + }); +} + +static bool is_chunk_visible(const chunk_pos &cpos) +{ + const auto dx = cxpr::abs(cpos.x - cached_cpos.x); + const auto dy = cxpr::abs(cpos.z - cached_cpos.z); + + if((dx <= cached_dist) && (dy <= cached_dist)) + return true; + return false; +} + +void chunk_visibility::update_chunk(entt::entity entity) +{ + if(auto component = globals::dimension->chunks.try_get(entity)) { + if(is_chunk_visible(component->cpos)) + globals::dimension->chunks.emplace_or_replace(entity); + else globals::dimension->chunks.remove(entity); + } +} + +void chunk_visibility::update_chunk(const chunk_pos &cpos) +{ + if(auto chunk = globals::dimension->find_chunk(cpos)) { + const auto &component = globals::dimension->chunks.get(chunk->get_entity()); + if(is_chunk_visible(component.cpos)) + globals::dimension->chunks.emplace_or_replace(chunk->get_entity()); + else globals::dimension->chunks.remove(chunk->get_entity()); + } +} + +void chunk_visibility::update_chunks(void) +{ + const auto view = globals::dimension->chunks.view(); + + for(const auto [entity, chunk] : view.each()) { + if(is_chunk_visible(chunk.cpos)) + globals::dimension->chunks.emplace_or_replace(entity); + else globals::dimension->chunks.remove(entity); + } + + request_new_chunks(); +} + +void chunk_visibility::cleanup(void) +{ + cached_cpos = camera::position_chunk + 1; + cached_dist = camera::view_distance.get_value() + 1; + requests.clear(); +} + +void chunk_visibility::update(void) +{ + if(session::is_ingame()) { + if((cached_cpos != camera::position_chunk) || (cached_dist != camera::view_distance.get_value())) { + cached_cpos = camera::position_chunk; + cached_dist = camera::view_distance.get_value(); + chunk_visibility::update_chunks(); + return; + } + + for(int i = 0; i < 16; ++i) { + if(requests.empty()) { + // Done sending requests + break; + } + + request_chunk(requests.back()); + + requests.pop_back(); + } + + cached_cpos = camera::position_chunk; + cached_dist = camera::view_distance.get_value(); + return; + } + + cached_cpos = camera::position_chunk + 1; + cached_dist = camera::view_distance.get_value() + 1; +} -- cgit