add block.get_field(...), block.set_field(...)

This commit is contained in:
MihailRis 2024-09-30 18:55:01 +03:00
parent 8d89e06ac5
commit fc99343fb5
5 changed files with 169 additions and 28 deletions

View File

@ -21,6 +21,7 @@
#include "util/stringutil.hpp"
#include "voxels/Block.hpp"
#include "data/dv_util.hpp"
#include "data/StructLayout.hpp"
namespace fs = std::filesystem;
@ -250,6 +251,12 @@ void ContentLoader::loadBlock(
root.at("ui-layout").get(def.uiLayout);
root.at("inventory-size").get(def.inventorySize);
root.at("tick-interval").get(def.tickInterval);
if (root.has("fields")) {
def.dataStruct = std::make_unique<data::StructLayout>();
def.dataStruct->deserialize(root["fields"]);
}
if (def.tickInterval == 0) {
def.tickInterval = 1;
}

View File

@ -183,7 +183,7 @@ std::vector<FieldIncapatibility> StructLayout::checkCompatibility(
return report;
}
const Field& StructLayout::requreField(const std::string& name) const {
const Field& StructLayout::requireField(const std::string& name) const {
auto found = indices.find(name);
if (found == indices.end()) {
throw std::runtime_error("field '"+name+"' does not exist");
@ -200,9 +200,8 @@ static void set_int(ubyte* dst, integer_t value) {
}
void StructLayout::setInteger(
ubyte* dst, integer_t value, const std::string& name, int index
ubyte* dst, integer_t value, const Field& field, int index
) const {
const auto& field = requreField(name);
if (index < 0 || index >= field.elements) {
throw std::out_of_range(
"index out of bounds [0, "+std::to_string(field.elements)+"]");
@ -216,7 +215,7 @@ void StructLayout::setInteger(
case FieldType::CHAR: set_int<int8_t>(ptr, value); break;
case FieldType::F32:
case FieldType::F64:
setNumber(dst, static_cast<number_t>(value), name, index);
setNumber(dst, static_cast<number_t>(value), field, index);
break;
default:
throw std::runtime_error("type error");
@ -224,9 +223,8 @@ void StructLayout::setInteger(
}
void StructLayout::setNumber(
ubyte* dst, number_t value, const std::string& name, int index
ubyte* dst, number_t value, const Field& field, int index
) const {
const auto& field = requreField(name);
if (index < 0 || index >= field.elements) {
throw std::out_of_range(
"index out of bounds [0, "+std::to_string(field.elements)+"]");
@ -255,7 +253,7 @@ void StructLayout::setNumber(
size_t StructLayout::setAscii(
ubyte* dst, std::string_view value, const std::string& name
) const {
const auto& field = requreField(name);
const auto& field = requireField(name);
if (field.type != FieldType::CHAR) {
throw std::runtime_error("'char' field type required");
}
@ -266,9 +264,8 @@ size_t StructLayout::setAscii(
}
size_t StructLayout::setUnicode(
ubyte* dst, std::string_view value, const std::string& name
ubyte* dst, std::string_view value, const Field& field
) const {
const auto& field = requreField(name);
if (field.type != FieldType::CHAR) {
throw std::runtime_error("'char' field type required");
}
@ -285,9 +282,8 @@ static T get_int(const ubyte* src) {
}
integer_t StructLayout::getInteger(
const ubyte* src, const std::string& name, int index
const ubyte* src, const Field& field, int index
) const {
const auto& field = requreField(name);
if (index < 0 || index >= field.elements) {
throw std::out_of_range(
"index out of bounds [0, "+std::to_string(field.elements)+"]");
@ -305,9 +301,8 @@ integer_t StructLayout::getInteger(
}
number_t StructLayout::getNumber(
const ubyte* src, const std::string& name, int index
const ubyte* src, const Field& field, int index
) const {
const auto& field = requreField(name);
if (index < 0 || index >= field.elements) {
throw std::out_of_range(
"index out of bounds [0, "+std::to_string(field.elements)+"]");
@ -331,16 +326,15 @@ number_t StructLayout::getNumber(
case FieldType::I32:
case FieldType::I64:
case FieldType::CHAR:
return getInteger(src, name, index);
return getInteger(src, field, index);
default:
throw std::runtime_error("type error");
}
}
std::string_view StructLayout::getChars(
const ubyte* src, const std::string& name
const ubyte* src, const Field& field
) const {
const auto& field = requreField(name);
if (field.type != FieldType::CHAR) {
throw std::runtime_error("'char' field type required");
}

View File

@ -129,35 +129,54 @@ namespace data {
/// @throws std::runtime_exception - field not found
/// @param name field name
/// @return read-only field reference
const Field& requreField(const std::string& name) const;
const Field& requireField(const std::string& name) const;
[[nodiscard]]
integer_t getInteger(const ubyte* src, const std::string& name, int index=0) const {
return getInteger(src, requireField(name), index);
}
/// @brief Get integer from specified field.
/// Types: (i8, i16, i32, i64, char)
/// @throws std::runtime_exception - field not found
/// @throws std::out_of_range - index is out of range [0, elements-1]
/// @param src source buffer
/// @param name field name
/// @param field target field
/// @param index array index
/// @return field value
[[nodiscard]]
integer_t getInteger(const ubyte* src, const std::string& name, int index=0) const;
integer_t getInteger(const ubyte* src, const Field& field, int index=0) const;
[[nodiscard]]
number_t getNumber(const ubyte* src, const std::string& name, int index=0) const {
return getNumber(src, requireField(name), index);
}
/// @brief Get floating-point number from specified field.
/// Types: (f32, f64, i8, i16, i32, i64, char)
/// @throws std::runtime_exception - field not found
/// @throws std::out_of_range - index is out of range [0, elements-1]
/// @param src source buffer
/// @param name field name
/// @param field target field
/// @param index array index
/// @return field value
[[nodiscard]]
number_t getNumber(const ubyte* src, const std::string& name, int index=0) const;
number_t getNumber(const ubyte* src, const Field& field, int index=0) const;
[[nodiscard]]
std::string_view getChars(const ubyte* src, const std::string& name) const {
return getChars(src, requireField(name));
}
/// @brief Get read-only chars array as string_view.
/// @param src source buffer
/// @param name field name
/// @param field target field
[[nodiscard]]
std::string_view getChars(const ubyte* src, const std::string& name) const;
std::string_view getChars(const ubyte* src, const Field& field) const;
void setInteger(ubyte* dst, integer_t value, const std::string& name, int index=0) const {
setInteger(dst, value, requireField(name), index);
}
/// @brief Set field integer value.
/// Types: (i8, i16, i32, i64, f32, f64, char)
@ -165,9 +184,13 @@ namespace data {
/// @throws std::out_of_range - index is out of range [0, elements-1]
/// @param dst destination buffer
/// @param value value
/// @param name field name
/// @param field target field
/// @param index array index
void setInteger(ubyte* dst, integer_t value, const std::string& name, int index=0) const;
void setInteger(ubyte* dst, integer_t value, const Field& field, int index=0) const;
void setNumber(ubyte* dst, number_t value, const std::string& name, int index=0) const {
setNumber(dst, value, requireField(name), index);
}
/// @brief Set field numeric value.
/// Types: (f32, f64)
@ -175,9 +198,9 @@ namespace data {
/// @throws std::out_of_range - index is out of range [0, elements-1]
/// @param dst destination buffer
/// @param value value
/// @param name field name
/// @param field target field
/// @param index array index
void setNumber(ubyte* dst, number_t value, const std::string& name, int index=0) const;
void setNumber(ubyte* dst, number_t value, const Field& field, int index=0) const;
/// @brief Replace chars array to given ASCII string
/// @throws std::runtime_exception - field not found
@ -187,6 +210,10 @@ namespace data {
/// @param name field name
/// @return number of written string chars
size_t setAscii(ubyte* dst, std::string_view value, const std::string& name) const;
size_t setUnicode(ubyte* dst, std::string_view value, const std::string& name) const {
return setUnicode(dst, value, requireField(name));
}
/// @brief Unicode-safe version of setAscii
/// @throws std::runtime_exception - field not found
@ -194,7 +221,7 @@ namespace data {
/// @param value utf-8 string
/// @param name field name
/// @return number of written string chars
size_t setUnicode(ubyte* dst, std::string_view value, const std::string& name) const;
size_t setUnicode(ubyte* dst, std::string_view value, const Field& field) const;
/// @return total structure size (bytes)
[[nodiscard]] size_t size() const {

View File

@ -7,6 +7,8 @@
#include "voxels/Chunks.hpp"
#include "voxels/voxel.hpp"
#include "world/Level.hpp"
#include "maths/voxmaths.hpp"
#include "data/StructLayout.hpp"
#include "api_lua.hpp"
using namespace scripting;
@ -436,6 +438,107 @@ static int l_decompose_state(lua::State* L) {
return 1;
}
static int l_get_field(lua::State* L) {
auto x = lua::tointeger(L, 1);
auto y = lua::tointeger(L, 2);
auto z = lua::tointeger(L, 3);
auto name = lua::require_string(L, 4);
size_t index = 0;
if (lua::gettop(L) >= 5) {
index = lua::tointeger(L, 5);
}
auto vox = level->chunks->get(x, y, z);
auto cx = floordiv(x, CHUNK_W);
auto cz = floordiv(z, CHUNK_D);
auto chunk = level->chunks->getChunk(cx, cz);
auto lx = x - cx * CHUNK_W;
auto lz = z - cz * CHUNK_W;
size_t voxelIndex = vox_index(lx, y, lz);
const auto& def = content->getIndices()->blocks.require(vox->id);
if (def.dataStruct == nullptr) {
return 0;
}
const auto& dataStruct = *def.dataStruct;
const auto field = dataStruct.getField(name);
if (field == nullptr) {
return 0;
}
const ubyte* src = chunk->blocksMetadata.find(voxelIndex);
if (src == nullptr) {
throw std::runtime_error("block data is not allocated");
}
switch (field->type) {
case data::FieldType::I8:
case data::FieldType::I16:
case data::FieldType::I32:
case data::FieldType::I64:
return lua::pushinteger(L, dataStruct.getInteger(src, *field, index));
case data::FieldType::F32:
case data::FieldType::F64:
return lua::pushnumber(L, dataStruct.getNumber(src, *field, index));
case data::FieldType::CHAR:
return lua::pushstring(L,
std::string(dataStruct.getChars(src, *field)).c_str());
case data::FieldType::COUNT:
return 0;
}
return 0;
}
static int l_set_field(lua::State* L) {
auto x = lua::tointeger(L, 1);
auto y = lua::tointeger(L, 2);
auto z = lua::tointeger(L, 3);
auto name = lua::require_string(L, 4);
auto value = lua::tovalue(L, 5);
size_t index = 0;
if (lua::gettop(L) >= 6) {
index = lua::tointeger(L, 6);
}
auto vox = level->chunks->get(x, y, z);
auto cx = floordiv(x, CHUNK_W);
auto cz = floordiv(z, CHUNK_D);
auto chunk = level->chunks->getChunk(cx, cz);
auto lx = x - cx * CHUNK_W;
auto lz = z - cz * CHUNK_W;
size_t voxelIndex = vox_index(lx, y, lz);
const auto& def = content->getIndices()->blocks.require(vox->id);
if (def.dataStruct == nullptr) {
return 0;
}
const auto& dataStruct = *def.dataStruct;
const auto field = dataStruct.getField(name);
if (field == nullptr) {
return 0;
}
ubyte* dst = chunk->blocksMetadata.find(voxelIndex);
if (dst == nullptr) {
throw std::runtime_error("block data is not allocated");
}
switch (field->type) {
case data::FieldType::CHAR:
if (value.isString()) {
return lua::pushinteger(L,
dataStruct.setUnicode(dst, value.asString(), *field));
}
case data::FieldType::I8:
case data::FieldType::I16:
case data::FieldType::I32:
case data::FieldType::I64:
dataStruct.setInteger(dst, value.asInteger(), *field, index);
break;
case data::FieldType::F32:
case data::FieldType::F64:
dataStruct.setNumber(dst, value.asNumber(), *field, index);
break;
case data::FieldType::COUNT:
break;
}
return 0;
}
const luaL_Reg blocklib[] = {
{"index", lua::wrap<l_index>},
{"name", lua::wrap<l_get_def>},
@ -469,5 +572,7 @@ const luaL_Reg blocklib[] = {
{"raycast", lua::wrap<l_raycast>},
{"compose_state", lua::wrap<l_compose_state>},
{"decompose_state", lua::wrap<l_decompose_state>},
{"get_field", lua::wrap<l_get_field>},
{"set_field", lua::wrap<l_set_field>},
{NULL, NULL}
};

View File

@ -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"
@ -370,6 +371,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];
@ -380,6 +382,9 @@ void Chunks::set(
if (prevdef.rt.extended && !vox.state.segment) {
eraseSegments(prevdef, vox.state, gx, y, gz);
}
if (prevdef.dataStruct) {
chunk->blocksMetadata.free(chunk->blocksMetadata.find(index));
}
// block initialization
const auto& newdef = indices->blocks.require(id);
@ -389,6 +394,9 @@ void Chunks::set(
if (!state.segment && newdef.rt.extended) {
repairSegments(newdef, state, gx, y, gz);
}
if (newdef.dataStruct) {
chunk->blocksMetadata.allocate(index, newdef.dataStruct->size());
}
if (y < chunk->bottom)
chunk->bottom = y;