#pragma once #include "core/world/EdittableChunk.hpp" namespace world::client { /// ChunkEdits with passive rollback class ChunkFutureEdits: public ChunkEdits { public: ChunkFutureEdits(world::EdittableChunk* ptr): ChunkEdits(ptr) { } ~ChunkFutureEdits() { } /// Update voxels /// @return if modified neighbors to update std::optional update(float deltaTime, bool animate) override { for (auto it = futureEdits.begin(); it != futureEdits.end();) { it->second.second -= deltaTime; if (it->second.second <= 0 && animate) { invalidate(it->first); edits.emplace(it->first, it->second.first); it = futureEdits.erase(it); } else { ++it; } } return ChunkEdits::update(deltaTime, animate); } /// Add future edit void addFutureEdit(const ChunkEdits::Edit& edit, float delay) { futureEdits.insert_or_assign(edit.idx, std::make_pair(EditBody(edit), delay)); } private: /// Temporary animated changes robin_hood::unordered_map> futureEdits; }; /// Special chunk with additional flags for client only class Chunk final: public world::EdittableChunk { public: Chunk(std::istream &is): EdittableChunk(new ChunkFutureEdits(this), is) { } /// Create from average Chunk(Voxel val): EdittableChunk(new ChunkFutureEdits(this), Voxel(val.material(), val.density())), isMajorant(val.swap()) { } inline bool isTrusted(bool allowMajorant) const noexcept { return isHeavy() || (allowMajorant && isMajorant); } void unsetMajorant() { assert(isMajorant); isMajorant = false; } ChunkFutureEdits &setEdits() { assert(edits); return *(ChunkFutureEdits*)edits.get(); } private: /// Is temporary full valued bool isMajorant = false; }; /// Chunk full of void static const std::shared_ptr EMPTY_CHUNK = std::make_shared(Voxel()); }