#pragma once #include #include #include #include #include #include "typedefs.hpp" #include "voxel.hpp" #include "util/AreaMap2D.hpp" class VoxelRenderer; struct AABB; class Content; class ContentIndices; class Chunk; class WorldFiles; class LevelEvents; class Block; class VoxelsVolume; /// Player-centred chunks matrix class Chunks { LevelEvents* events; const ContentIndices& indices; void eraseSegments(const Block& def, blockstate state, int x, int y, int z); void repairSegments( const Block& def, blockstate state, int x, int y, int z ); void setRotationExtended( const Block& def, blockstate state, const glm::ivec3& origin, uint8_t rotation ); util::AreaMap2D, int32_t> areaMap; public: Chunks( int32_t w, int32_t d, int32_t ox, int32_t oz, LevelEvents* events, const ContentIndices& indices ); ~Chunks() = default; void configure(int32_t x, int32_t z, uint32_t radius); bool putChunk(const std::shared_ptr& chunk); Chunk* getChunk(int32_t x, int32_t z) const; Chunk* getChunkByVoxel(int32_t x, int32_t y, int32_t z) const; template Chunk* getChunkByVoxel(const glm::vec<3, T>& pos) const { return getChunkByVoxel( glm::floor(pos.x), glm::floor(pos.y), glm::floor(pos.z) ); } voxel* get(int32_t x, int32_t y, int32_t z) const; voxel& require(int32_t x, int32_t y, int32_t z) const; inline voxel* get(const glm::ivec3& pos) { return get(pos.x, pos.y, pos.z); } inline const voxel* get(const glm::ivec3& pos) const { return get(pos.x, pos.y, pos.z); } light_t getLight(int32_t x, int32_t y, int32_t z) const; ubyte getLight(int32_t x, int32_t y, int32_t z, int channel) const; void set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state); /// @brief Seek for the extended block origin position /// @param pos segment block position /// @param def segment block definition /// @param state segment block state /// @return origin block position or `pos` if block is not extended glm::ivec3 seekOrigin( const glm::ivec3& pos, const Block& def, blockstate state ) const; /// @brief Check if required zone is replaceable /// @param def definition of the block that requires a replaceable zone /// @param state the block state /// @param coord position of the zone start /// @param ignore ignored block id (will be counted as replaceable) bool checkReplaceability( const Block& def, blockstate state, const glm::ivec3& coord, blockid_t ignore = 0 ); void setRotation(int32_t x, int32_t y, int32_t z, uint8_t rotation); voxel* rayCast( const glm::vec3& start, const glm::vec3& dir, float maxLength, glm::vec3& end, glm::ivec3& norm, glm::ivec3& iend, std::set filter = {} ) const; glm::vec3 rayCastToObstacle( const glm::vec3& start, const glm::vec3& dir, float maxDist ) const; const AABB* isObstacleAt(float x, float y, float z) const; const AABB* isObstacleAt(const glm::vec3& pos) const { return isObstacleAt(pos.x, pos.y, pos.z); } bool isSolidBlock(int32_t x, int32_t y, int32_t z); bool isReplaceableBlock(int32_t x, int32_t y, int32_t z); bool isObstacleBlock(int32_t x, int32_t y, int32_t z); void getVoxels(VoxelsVolume& volume, bool backlight = false) const; void setCenter(int32_t x, int32_t z); void resize(uint32_t newW, uint32_t newD); void saveAndClear(); const std::vector>& getChunks() const { return areaMap.getBuffer(); } int getWidth() const { return areaMap.getWidth(); } int getHeight() const { return areaMap.getHeight(); } int getOffsetX() const { return areaMap.getOffsetX(); } int getOffsetY() const { return areaMap.getOffsetY(); } size_t getChunksCount() const { return areaMap.count(); } size_t getVolume() const { return areaMap.area(); } const ContentIndices& getContentIndices() const { return indices; } static inline constexpr unsigned matrixSize(int loadDistance, int padding) { return (loadDistance + padding) * 2; } };