#pragma once #include #include #include "core/world/Area.hpp" #include "core/world/Voxel.hpp" #include "core/memory.hpp" #include "core/utils/zctx.hpp" namespace world::server { ///Group of chunks saved as a single file in memory class Region { public: Region(const std::string& folderPath, const area_region_ref &id); ~Region(); template void averages(D &out) { std::shared_lock lock(mutex); out.resize(content.size() * (sizeof(region_chunk_pos) + sizeof(Voxel))); memory::write_view in((uint8_t*)out.data(), out.size() * sizeof(D)); for(const auto& r: content) { if (r.second.average.has_value()) { in.write(r.first); in.write(r.second.average.value()); } } out.resize(in.current()); } bool read(const region_chunk_pos &pos, const zstd::read_ctx &ctx, std::vector &out); void write(const region_chunk_pos &pos, const zstd::write_ctx& ctx, const std::string_view &in, const std::optional& average); static void Read(const std::string& folder, const part_ref& id, const zstd::read_ctx &ctx, const std::function&)>& out); static void Write(const std::string& folder, const part_ref& id, const zstd::write_ctx &ctx, size_t size, const std::function()>& next); private: static size_t Read(const std::string &path, const std::function &, std::vector &&)> &out); void save(bool force = true); std::string path; //TODO: use tickets to remove unused regions enum Flags: unsigned char { ZERO = 0, HAS_AVERAGE = 1 << 0, EMPTY = 1 << 1 }; std::shared_mutex mutex; struct node { node(const std::optional& a, std::vector&& d): average(a), data(std::move(d)) { } std::optional average; std::vector data; }; robin_hood::unordered_map content; struct save_throttler { save_throttler(); /// Counter of currently unsaved size_t changes = 0; /// Save when changes > (1 << it) /// MAYBE: decrease with time size_t nextSaveExponent; inline void change() { changes++; } inline constexpr bool isUnsaved() const { return changes > 0; } inline constexpr bool mustSave() const { return changes > (1ull << nextSaveExponent); } inline void save() { changes = 0; nextSaveExponent++; } } saveThrottler; void load(); }; }