add block.get_field(...), block.set_field(...)
This commit is contained in:
parent
8d89e06ac5
commit
fc99343fb5
@ -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;
|
||||
}
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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}
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user