// SPDX-License-Identifier: BSD-2-Clause // Copyright (c) 2025 Kirill Dmitrievich // File: unloader.cc // Description: Handle chunks that are out of view for all players #include "server/pch.hh" #include "server/world/unloader.hh" #include "core/config/number.hh" #include "shared/entity/player.hh" #include "shared/entity/transform.hh" #include "shared/world/chunk.hh" #include "shared/world/chunk_aabb.hh" #include "shared/world/dimension.hh" #include "server/world/inhabited.hh" #include "server/world/universe.hh" #include "server/game.hh" #include "server/globals.hh" static void on_chunk_update(const ChunkUpdateEvent& event) { event.dimension->chunks.emplace_or_replace(event.chunk->get_entity()); } static void on_voxel_set(const VoxelSetEvent& event) { event.dimension->chunks.emplace_or_replace(event.chunk->get_entity()); } void unloader::init(void) { globals::dispatcher.sink().connect<&on_chunk_update>(); globals::dispatcher.sink().connect<&on_voxel_set>(); } void unloader::init_late(void) { } void unloader::fixed_update_late(Dimension* dimension) { auto group = dimension->entities.group(entt::get); auto boxes = std::vector(); for(const auto [entity, transform] : group.each()) { ChunkAABB aabb; aabb.min = transform.chunk - static_cast(server_game::view_distance.get_value()); aabb.max = transform.chunk + static_cast(server_game::view_distance.get_value()); boxes.push_back(aabb); } auto view = dimension->chunks.view(); auto chunk_in_view = false; for(const auto [entity, chunk] : view.each()) { chunk_in_view = false; for(const auto& aabb : boxes) { if(aabb.contains(chunk.cpos)) { chunk_in_view = true; break; } } if(chunk_in_view) { // The chunk is within view box of at least // a single player; we shouldn't unload it now continue; } if(dimension->chunks.any_of(entity)) { // Only store inhabited chunks on disk universe::save_chunk(dimension, chunk.cpos); } dimension->remove_chunk(entity); } }