Merge branch 'main' into heightmaps
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
#include "Block.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
#include "core_defs.hpp"
|
||||
#include "data/StructLayout.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
|
||||
std::string to_string(BlockModel model) {
|
||||
@@ -102,6 +104,8 @@ Block::Block(const std::string& name)
|
||||
} {
|
||||
}
|
||||
|
||||
Block::~Block() {}
|
||||
|
||||
Block::Block(std::string name, const std::string& texture)
|
||||
: name(std::move(name)),
|
||||
textureFaces {texture, texture, texture, texture, texture, texture} {
|
||||
@@ -138,3 +142,10 @@ void Block::cloneTo(Block& dst) {
|
||||
dst.inventorySize = inventorySize;
|
||||
dst.tickInterval = tickInterval;
|
||||
}
|
||||
|
||||
static std::set<std::string, std::less<>> RESERVED_BLOCK_FIELDS {
|
||||
};
|
||||
|
||||
bool Block::isReservedBlockField(std::string_view view) {
|
||||
return RESERVED_BLOCK_FIELDS.find(view) != RESERVED_BLOCK_FIELDS.end();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "maths/aabb.hpp"
|
||||
#include "typedefs.hpp"
|
||||
|
||||
namespace data {
|
||||
class StructLayout;
|
||||
}
|
||||
|
||||
inline std::string BLOCK_ITEM_SUFFIX = ".item";
|
||||
|
||||
inline constexpr uint FACE_MX = 0;
|
||||
@@ -22,6 +26,8 @@ inline constexpr uint FACE_PZ = 5;
|
||||
/// complex hitboxes
|
||||
inline constexpr uint BLOCK_AABB_GRID = 16;
|
||||
|
||||
inline constexpr size_t MAX_USER_BLOCK_FIELDS_SIZE = 240;
|
||||
|
||||
inline std::string DEFAULT_MATERIAL = "base:stone";
|
||||
|
||||
struct block_funcs_set {
|
||||
@@ -184,6 +190,8 @@ public:
|
||||
// @brief Block tick interval (1 - 20tps, 2 - 10tps)
|
||||
uint tickInterval = 1;
|
||||
|
||||
std::unique_ptr<data::StructLayout> dataStruct;
|
||||
|
||||
/// @brief Runtime indices (content indexing results)
|
||||
struct {
|
||||
/// @brief block runtime integer id
|
||||
@@ -211,8 +219,11 @@ public:
|
||||
Block(const std::string& name);
|
||||
Block(std::string name, const std::string& texture);
|
||||
Block(const Block&) = delete;
|
||||
~Block();
|
||||
|
||||
void cloneTo(Block& dst);
|
||||
|
||||
static bool isReservedBlockField(std::string_view view);
|
||||
};
|
||||
|
||||
inline glm::ivec3 get_ground_direction(const Block& def, int rotation) {
|
||||
|
||||
+17
-34
@@ -2,9 +2,10 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "content/ContentLUT.hpp"
|
||||
#include "content/ContentReport.hpp"
|
||||
#include "items/Inventory.hpp"
|
||||
#include "lighting/Lightmap.hpp"
|
||||
#include "util/data_io.hpp"
|
||||
#include "voxel.hpp"
|
||||
|
||||
Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos) {
|
||||
@@ -53,7 +54,7 @@ void Chunk::removeBlockInventory(uint x, uint y, uint z) {
|
||||
}
|
||||
}
|
||||
|
||||
void Chunk::setBlockInventories(chunk_inventories_map map) {
|
||||
void Chunk::setBlockInventories(ChunkInventoriesMap map) {
|
||||
inventories = std::move(map);
|
||||
}
|
||||
|
||||
@@ -78,59 +79,41 @@ std::unique_ptr<Chunk> Chunk::clone() const {
|
||||
|
||||
/**
|
||||
Current chunk format:
|
||||
- byte-order: big-endian
|
||||
- [don't panic!] first and second bytes are separated for RLE efficiency
|
||||
- byte-order: little-endian
|
||||
|
||||
```cpp
|
||||
uint8_t voxel_id_first_byte[CHUNK_VOL];
|
||||
uint8_t voxel_id_second_byte[CHUNK_VOL];
|
||||
uint8_t voxel_states_first_byte[CHUNK_VOL];
|
||||
uint8_t voxel_states_second_byte[CHUNK_VOL];
|
||||
uint16_t voxel_id[CHUNK_VOL];
|
||||
uint16_t voxel_states[CHUNK_VOL];
|
||||
```
|
||||
|
||||
Total size: (CHUNK_VOL * 4) bytes
|
||||
*/
|
||||
std::unique_ptr<ubyte[]> Chunk::encode() const {
|
||||
auto buffer = std::make_unique<ubyte[]>(CHUNK_DATA_LEN);
|
||||
auto dst = reinterpret_cast<uint16_t*>(buffer.get());
|
||||
for (uint i = 0; i < CHUNK_VOL; i++) {
|
||||
buffer[i] = voxels[i].id >> 8;
|
||||
buffer[CHUNK_VOL + i] = voxels[i].id & 0xFF;
|
||||
|
||||
blockstate_t state = blockstate2int(voxels[i].state);
|
||||
buffer[CHUNK_VOL * 2 + i] = state >> 8;
|
||||
buffer[CHUNK_VOL * 3 + i] = state & 0xFF;
|
||||
dst[i] = dataio::h2le(voxels[i].id);
|
||||
dst[CHUNK_VOL + i] = dataio::h2le(blockstate2int(voxels[i].state));
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool Chunk::decode(const ubyte* data) {
|
||||
auto src = reinterpret_cast<const uint16_t*>(data);
|
||||
for (uint i = 0; i < CHUNK_VOL; i++) {
|
||||
voxel& vox = voxels[i];
|
||||
|
||||
ubyte bid1 = data[i];
|
||||
ubyte bid2 = data[CHUNK_VOL + i];
|
||||
|
||||
ubyte bst1 = data[CHUNK_VOL * 2 + i];
|
||||
ubyte bst2 = data[CHUNK_VOL * 3 + i];
|
||||
|
||||
vox.id =
|
||||
(static_cast<blockid_t>(bid1) << 8) | static_cast<blockid_t>(bid2);
|
||||
vox.state = int2blockstate(
|
||||
(static_cast<blockstate_t>(bst1) << 8) |
|
||||
static_cast<blockstate_t>(bst2)
|
||||
);
|
||||
vox.id = dataio::le2h(src[i]);
|
||||
vox.state = int2blockstate(dataio::le2h(src[CHUNK_VOL + i]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Chunk::convert(ubyte* data, const ContentLUT* lut) {
|
||||
void Chunk::convert(ubyte* data, const ContentReport* report) {
|
||||
auto buffer = reinterpret_cast<uint16_t*>(data);
|
||||
for (uint i = 0; i < CHUNK_VOL; i++) {
|
||||
// see encode method to understand what the hell is going on here
|
||||
blockid_t id =
|
||||
((static_cast<blockid_t>(data[i]) << 8) |
|
||||
static_cast<blockid_t>(data[CHUNK_VOL + i]));
|
||||
blockid_t replacement = lut->blocks.getId(id);
|
||||
data[i] = replacement >> 8;
|
||||
data[CHUNK_VOL + i] = replacement & 0xFF;
|
||||
blockid_t id = dataio::le2h(buffer[i]);
|
||||
blockid_t replacement = report->blocks.getId(id);
|
||||
buffer[i] = dataio::h2le(replacement);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-6
@@ -7,17 +7,19 @@
|
||||
|
||||
#include "constants.hpp"
|
||||
#include "lighting/Lightmap.hpp"
|
||||
#include "util/SmallHeap.hpp"
|
||||
#include "voxel.hpp"
|
||||
|
||||
inline constexpr int CHUNK_DATA_LEN = CHUNK_VOL * 4;
|
||||
|
||||
class Lightmap;
|
||||
class ContentLUT;
|
||||
class ContentReport;
|
||||
class Inventory;
|
||||
|
||||
using chunk_inventories_map =
|
||||
using ChunkInventoriesMap =
|
||||
std::unordered_map<uint, std::shared_ptr<Inventory>>;
|
||||
|
||||
using BlocksMetadata = util::SmallHeap<uint16_t, uint8_t>;
|
||||
|
||||
class Chunk {
|
||||
public:
|
||||
int x, z;
|
||||
@@ -32,10 +34,13 @@ public:
|
||||
bool unsaved : 1;
|
||||
bool loadedLights : 1;
|
||||
bool entities : 1;
|
||||
bool blocksData : 1;
|
||||
} flags {};
|
||||
|
||||
/// @brief Block inventories map where key is index of block in voxels array
|
||||
chunk_inventories_map inventories;
|
||||
ChunkInventoriesMap inventories;
|
||||
/// @brief Blocks metadata heap
|
||||
BlocksMetadata blocksMetadata;
|
||||
|
||||
Chunk(int x, int z);
|
||||
|
||||
@@ -52,7 +57,7 @@ public:
|
||||
std::shared_ptr<Inventory> inventory, uint x, uint y, uint z
|
||||
);
|
||||
void removeBlockInventory(uint x, uint y, uint z);
|
||||
void setBlockInventories(chunk_inventories_map map);
|
||||
void setBlockInventories(ChunkInventoriesMap map);
|
||||
|
||||
/// @return inventory bound to the given block or nullptr
|
||||
std::shared_ptr<Inventory> getBlockInventory(uint x, uint y, uint z) const;
|
||||
@@ -62,10 +67,12 @@ public:
|
||||
flags.unsaved = true;
|
||||
}
|
||||
|
||||
/// @brief Encode chunk to bytes array of size CHUNK_DATA_LEN
|
||||
/// @see /doc/specs/region_voxels_chunk_spec.md
|
||||
std::unique_ptr<ubyte[]> encode() const;
|
||||
|
||||
/// @return true if all is fine
|
||||
bool decode(const ubyte* data);
|
||||
|
||||
static void convert(ubyte* data, const ContentLUT* lut);
|
||||
static void convert(ubyte* data, const ContentReport* report);
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "data/StructLayout.hpp"
|
||||
#include "coders/byte_utils.hpp"
|
||||
#include "coders/json.hpp"
|
||||
#include "content/Content.hpp"
|
||||
@@ -363,6 +364,7 @@ void Chunks::set(
|
||||
}
|
||||
int lx = x - cx * CHUNK_W;
|
||||
int lz = z - cz * CHUNK_D;
|
||||
size_t index = vox_index(lx, y, lz);
|
||||
|
||||
// block finalization
|
||||
voxel& vox = chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx];
|
||||
@@ -373,6 +375,13 @@ void Chunks::set(
|
||||
if (prevdef.rt.extended && !vox.state.segment) {
|
||||
eraseSegments(prevdef, vox.state, x, y, z);
|
||||
}
|
||||
if (prevdef.dataStruct) {
|
||||
if (auto found = chunk->blocksMetadata.find(index)) {
|
||||
chunk->blocksMetadata.free(found);
|
||||
chunk->flags.unsaved = true;
|
||||
chunk->flags.blocksData = true;
|
||||
}
|
||||
}
|
||||
|
||||
// block initialization
|
||||
const auto& newdef = indices->blocks.require(id);
|
||||
|
||||
@@ -59,8 +59,7 @@ std::shared_ptr<Chunk> ChunksStorage::create(int x, int z) {
|
||||
|
||||
auto chunk = std::make_shared<Chunk>(x, z);
|
||||
store(chunk);
|
||||
auto data = regions.getChunk(chunk->x, chunk->z);
|
||||
if (data) {
|
||||
if (auto data = regions.getVoxels(chunk->x, chunk->z)) {
|
||||
chunk->decode(data.get());
|
||||
|
||||
auto invs = regions.fetchInventories(chunk->x, chunk->z);
|
||||
@@ -78,17 +77,17 @@ std::shared_ptr<Chunk> ChunksStorage::create(int x, int z) {
|
||||
}
|
||||
verifyLoadedChunk(level->content->getIndices(), chunk.get());
|
||||
}
|
||||
|
||||
auto lights = regions.getLights(chunk->x, chunk->z);
|
||||
if (lights) {
|
||||
if (auto lights = regions.getLights(chunk->x, chunk->z)) {
|
||||
chunk->lightmap.set(lights.get());
|
||||
chunk->flags.loadedLights = true;
|
||||
}
|
||||
chunk->blocksMetadata = regions.getBlocksData(chunk->x, chunk->z);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
// reduce nesting on next modification
|
||||
// 25.06.2024: not now
|
||||
// TODO: move to Chunks for performance improvement
|
||||
void ChunksStorage::getVoxels(VoxelsVolume* volume, bool backlight) const {
|
||||
const Content* content = level->content;
|
||||
auto indices = content->getIndices();
|
||||
|
||||
Reference in New Issue
Block a user