migrate from dynamic::Value to dv::value & total erase namespace 'dynamic'
This commit is contained in:
parent
d3ba4b2e3e
commit
34d2e6d400
@ -8,7 +8,6 @@
|
||||
#include "constants.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "content/ContentPack.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
#include "files/engine_paths.hpp"
|
||||
#include "files/files.hpp"
|
||||
@ -130,7 +129,7 @@ static std::string assets_def_folder(AssetType tag) {
|
||||
}
|
||||
|
||||
void AssetsLoader::processPreload(
|
||||
AssetType tag, const std::string& name, dynamic::Map* map
|
||||
AssetType tag, const std::string& name, const dv::value& map
|
||||
) {
|
||||
std::string defFolder = assets_def_folder(tag);
|
||||
std::string path = defFolder + "/" + name;
|
||||
@ -138,36 +137,34 @@ void AssetsLoader::processPreload(
|
||||
add(tag, path, name);
|
||||
return;
|
||||
}
|
||||
map->str("path", path);
|
||||
map.at("path").get(path);
|
||||
switch (tag) {
|
||||
case AssetType::SOUND:
|
||||
case AssetType::SOUND: {
|
||||
bool keepPCM = false;
|
||||
add(tag,
|
||||
path,
|
||||
name,
|
||||
std::make_shared<SoundCfg>(map->get("keep-pcm", false)));
|
||||
std::make_shared<SoundCfg>(map.at("keep-pcm").get(keepPCM)));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
add(tag, path, name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AssetsLoader::processPreloadList(AssetType tag, dynamic::List* list) {
|
||||
void AssetsLoader::processPreloadList(AssetType tag, const dv::value& list) {
|
||||
if (list == nullptr) {
|
||||
return;
|
||||
}
|
||||
for (uint i = 0; i < list->size(); i++) {
|
||||
auto value = list->get(i);
|
||||
switch (static_cast<dynamic::Type>(value.index())) {
|
||||
case dynamic::Type::string:
|
||||
processPreload(tag, std::get<std::string>(value), nullptr);
|
||||
for (const auto& value : list) {
|
||||
switch (value.getType()) {
|
||||
case dv::value_type::string:
|
||||
processPreload(tag, value.asString(), nullptr);
|
||||
break;
|
||||
case dynamic::Type::map: {
|
||||
auto map = std::get<dynamic::Map_sptr>(value);
|
||||
auto name = map->get<std::string>("name");
|
||||
processPreload(tag, name, map.get());
|
||||
case dv::value_type::object:
|
||||
processPreload(tag, value["name"].asString(), value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("invalid entry type");
|
||||
}
|
||||
@ -176,12 +173,12 @@ void AssetsLoader::processPreloadList(AssetType tag, dynamic::List* list) {
|
||||
|
||||
void AssetsLoader::processPreloadConfig(const fs::path& file) {
|
||||
auto root = files::read_json(file);
|
||||
processPreloadList(AssetType::ATLAS, root->list("atlases").get());
|
||||
processPreloadList(AssetType::FONT, root->list("fonts").get());
|
||||
processPreloadList(AssetType::SHADER, root->list("shaders").get());
|
||||
processPreloadList(AssetType::TEXTURE, root->list("textures").get());
|
||||
processPreloadList(AssetType::SOUND, root->list("sounds").get());
|
||||
processPreloadList(AssetType::MODEL, root->list("models").get());
|
||||
processPreloadList(AssetType::ATLAS, root["atlases"]);
|
||||
processPreloadList(AssetType::FONT, root["fonts"]);
|
||||
processPreloadList(AssetType::SHADER, root["shaders"]);
|
||||
processPreloadList(AssetType::TEXTURE, root["textures"]);
|
||||
processPreloadList(AssetType::SOUND, root["sounds"]);
|
||||
processPreloadList(AssetType::MODEL, root["models"]);
|
||||
// layouts are loaded automatically
|
||||
}
|
||||
|
||||
|
||||
@ -12,11 +12,7 @@
|
||||
#include "interfaces/Task.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "Assets.hpp"
|
||||
|
||||
namespace dynamic {
|
||||
class Map;
|
||||
class List;
|
||||
}
|
||||
#include "data/dv.hpp"
|
||||
|
||||
class ResPaths;
|
||||
class AssetsLoader;
|
||||
@ -61,9 +57,9 @@ class AssetsLoader {
|
||||
void tryAddSound(const std::string& name);
|
||||
|
||||
void processPreload(
|
||||
AssetType tag, const std::string& name, dynamic::Map* map
|
||||
AssetType tag, const std::string& name, const dv::value& map
|
||||
);
|
||||
void processPreloadList(AssetType tag, dynamic::List* list);
|
||||
void processPreloadList(AssetType tag, const dv::value& list);
|
||||
void processPreloadConfig(const std::filesystem::path& file);
|
||||
void processPreloadConfigs(const Content* content);
|
||||
public:
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#include "coders/json.hpp"
|
||||
#include "coders/obj.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
#include "files/engine_paths.hpp"
|
||||
#include "files/files.hpp"
|
||||
@ -220,17 +219,17 @@ static void read_anim_file(
|
||||
std::vector<std::pair<std::string, int>>& frameList
|
||||
) {
|
||||
auto root = files::read_json(animFile);
|
||||
auto frameArr = root->list("frames");
|
||||
float frameDuration = DEFAULT_FRAME_DURATION;
|
||||
std::string frameName;
|
||||
|
||||
if (frameArr) {
|
||||
for (size_t i = 0; i < frameArr->size(); i++) {
|
||||
auto currentFrame = frameArr->list(i);
|
||||
if (auto found = root.at("frames")) {
|
||||
auto& frameArr = *found;
|
||||
for (size_t i = 0; i < frameArr.size(); i++) {
|
||||
auto currentFrame = frameArr[i];
|
||||
|
||||
frameName = currentFrame->str(0);
|
||||
if (currentFrame->size() > 1) {
|
||||
frameDuration = currentFrame->integer(1);
|
||||
frameName = currentFrame[0].asString();
|
||||
if (currentFrame.size() > 1) {
|
||||
frameDuration = currentFrame[1].asNumber();
|
||||
}
|
||||
frameList.emplace_back(frameName, frameDuration);
|
||||
}
|
||||
|
||||
@ -2,38 +2,38 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "byte_utils.hpp"
|
||||
#include "gzip.hpp"
|
||||
#include "util/Buffer.hpp"
|
||||
|
||||
using namespace json;
|
||||
using namespace dynamic;
|
||||
|
||||
static void to_binary(ByteBuilder& builder, const Value& value) {
|
||||
switch (static_cast<Type>(value.index())) {
|
||||
case Type::none:
|
||||
static void to_binary(ByteBuilder& builder, const dv::value& value) {
|
||||
switch (value.getType()) {
|
||||
case dv::value_type::none:
|
||||
throw std::runtime_error("none value is not implemented");
|
||||
case Type::map: {
|
||||
const auto bytes = to_binary(std::get<Map_sptr>(value).get());
|
||||
case dv::value_type::object: {
|
||||
const auto bytes = json::to_binary(value);
|
||||
builder.put(bytes.data(), bytes.size());
|
||||
break;
|
||||
}
|
||||
case Type::list:
|
||||
case dv::value_type::list:
|
||||
builder.put(BJSON_TYPE_LIST);
|
||||
for (const auto& element : std::get<List_sptr>(value)->values) {
|
||||
for (const auto& element : value) {
|
||||
to_binary(builder, element);
|
||||
}
|
||||
builder.put(BJSON_END);
|
||||
break;
|
||||
case Type::bytes: {
|
||||
const auto& bytes = std::get<ByteBuffer_sptr>(value).get();
|
||||
case dv::value_type::bytes: {
|
||||
const auto& bytes = value.asBytes();
|
||||
builder.put(BJSON_TYPE_BYTES);
|
||||
builder.putInt32(bytes->size());
|
||||
builder.put(bytes->data(), bytes->size());
|
||||
builder.putInt32(bytes.size());
|
||||
builder.put(bytes.data(), bytes.size());
|
||||
break;
|
||||
}
|
||||
case Type::integer: {
|
||||
auto val = std::get<integer_t>(value);
|
||||
case dv::value_type::integer: {
|
||||
auto val = value.asInteger();
|
||||
if (val >= 0 && val <= 255) {
|
||||
builder.put(BJSON_TYPE_BYTE);
|
||||
builder.put(val);
|
||||
@ -49,26 +49,23 @@ static void to_binary(ByteBuilder& builder, const Value& value) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::number:
|
||||
case dv::value_type::number:
|
||||
builder.put(BJSON_TYPE_NUMBER);
|
||||
builder.putFloat64(std::get<number_t>(value));
|
||||
builder.putFloat64(value.asNumber());
|
||||
break;
|
||||
case Type::boolean:
|
||||
builder.put(BJSON_TYPE_FALSE + std::get<bool>(value));
|
||||
case dv::value_type::boolean:
|
||||
builder.put(BJSON_TYPE_FALSE + value.asBoolean());
|
||||
break;
|
||||
case Type::string:
|
||||
case dv::value_type::string:
|
||||
builder.put(BJSON_TYPE_STRING);
|
||||
builder.put(std::get<std::string>(value));
|
||||
builder.put(value.asString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<List> array_from_binary(ByteReader& reader);
|
||||
static std::unique_ptr<Map> object_from_binary(ByteReader& reader);
|
||||
|
||||
std::vector<ubyte> json::to_binary(const Map* obj, bool compress) {
|
||||
std::vector<ubyte> json::to_binary(const dv::value& object, bool compress) {
|
||||
if (compress) {
|
||||
auto bytes = to_binary(obj, false);
|
||||
auto bytes = to_binary(object, false);
|
||||
return gzip::compress(bytes.data(), bytes.size());
|
||||
}
|
||||
ByteBuilder builder;
|
||||
@ -78,9 +75,9 @@ std::vector<ubyte> json::to_binary(const Map* obj, bool compress) {
|
||||
builder.putInt32(0);
|
||||
|
||||
// writing entries
|
||||
for (auto& entry : obj->values) {
|
||||
builder.putCStr(entry.first.c_str());
|
||||
to_binary(builder, entry.second);
|
||||
for (const auto& [key, value] : object.asObject()) {
|
||||
builder.putCStr(key.c_str());
|
||||
to_binary(builder, value);
|
||||
}
|
||||
// terminating byte
|
||||
builder.put(BJSON_END);
|
||||
@ -90,27 +87,23 @@ std::vector<ubyte> json::to_binary(const Map* obj, bool compress) {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
std::vector<ubyte> json::to_binary(const Value& value, bool compress) {
|
||||
if (auto map = std::get_if<Map_sptr>(&value)) {
|
||||
return to_binary(map->get(), compress);
|
||||
}
|
||||
throw std::runtime_error("map is only supported as the root element");
|
||||
}
|
||||
static dv::value list_from_binary(ByteReader& reader);
|
||||
static dv::value object_from_binary(ByteReader& reader);
|
||||
|
||||
static Value value_from_binary(ByteReader& reader) {
|
||||
static dv::value value_from_binary(ByteReader& reader) {
|
||||
ubyte typecode = reader.get();
|
||||
switch (typecode) {
|
||||
case BJSON_TYPE_DOCUMENT:
|
||||
reader.getInt32();
|
||||
return Map_sptr(object_from_binary(reader).release());
|
||||
return object_from_binary(reader);
|
||||
case BJSON_TYPE_LIST:
|
||||
return List_sptr(array_from_binary(reader).release());
|
||||
return list_from_binary(reader);
|
||||
case BJSON_TYPE_BYTE:
|
||||
return static_cast<integer_t>(reader.get());
|
||||
return reader.get();
|
||||
case BJSON_TYPE_INT16:
|
||||
return static_cast<integer_t>(reader.getInt16());
|
||||
return reader.getInt16();
|
||||
case BJSON_TYPE_INT32:
|
||||
return static_cast<integer_t>(reader.getInt32());
|
||||
return reader.getInt32();
|
||||
case BJSON_TYPE_INT64:
|
||||
return reader.getInt64();
|
||||
case BJSON_TYPE_NUMBER:
|
||||
@ -121,7 +114,7 @@ static Value value_from_binary(ByteReader& reader) {
|
||||
case BJSON_TYPE_STRING:
|
||||
return reader.getString();
|
||||
case BJSON_TYPE_NULL:
|
||||
return NONE;
|
||||
return dv::none;
|
||||
case BJSON_TYPE_BYTES: {
|
||||
int32_t size = reader.getInt32();
|
||||
if (size < 0) {
|
||||
@ -132,7 +125,8 @@ static Value value_from_binary(ByteReader& reader) {
|
||||
throw std::runtime_error(
|
||||
"buffer_size > remaining_size "+std::to_string(size));
|
||||
}
|
||||
auto bytes = std::make_shared<ByteBuffer>(reader.pointer(), size);
|
||||
auto bytes = std::make_shared<util::Buffer<ubyte>>(
|
||||
reader.pointer(), size);
|
||||
reader.skip(size);
|
||||
return bytes;
|
||||
}
|
||||
@ -141,26 +135,26 @@ static Value value_from_binary(ByteReader& reader) {
|
||||
"type support not implemented for <"+std::to_string(typecode)+">");
|
||||
}
|
||||
|
||||
static std::unique_ptr<List> array_from_binary(ByteReader& reader) {
|
||||
auto array = std::make_unique<List>();
|
||||
static dv::value list_from_binary(ByteReader& reader) {
|
||||
auto list = dv::list();
|
||||
while (reader.peek() != BJSON_END) {
|
||||
array->put(value_from_binary(reader));
|
||||
list.add(value_from_binary(reader));
|
||||
}
|
||||
reader.get();
|
||||
return array;
|
||||
return list;
|
||||
}
|
||||
|
||||
static std::unique_ptr<Map> object_from_binary(ByteReader& reader) {
|
||||
auto obj = std::make_unique<Map>();
|
||||
static dv::value object_from_binary(ByteReader& reader) {
|
||||
auto obj = dv::object();
|
||||
while (reader.peek() != BJSON_END) {
|
||||
const char* key = reader.getCString();
|
||||
obj->put(key, value_from_binary(reader));
|
||||
obj[key] = value_from_binary(reader);
|
||||
}
|
||||
reader.get();
|
||||
return obj;
|
||||
}
|
||||
|
||||
std::shared_ptr<Map> json::from_binary(const ubyte* src, size_t size) {
|
||||
dv::value json::from_binary(const ubyte* src, size_t size) {
|
||||
if (size < 2) {
|
||||
throw std::runtime_error("bytes length is less than 2");
|
||||
}
|
||||
@ -170,12 +164,6 @@ std::shared_ptr<Map> json::from_binary(const ubyte* src, size_t size) {
|
||||
return from_binary(data.data(), data.size());
|
||||
} else {
|
||||
ByteReader reader(src, size);
|
||||
Value value = value_from_binary(reader);
|
||||
|
||||
if (auto map = std::get_if<Map_sptr>(&value)) {
|
||||
return *map;
|
||||
} else {
|
||||
throw std::runtime_error("root value is not an object");
|
||||
}
|
||||
return value_from_binary(reader);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,11 +4,8 @@
|
||||
#include <vector>
|
||||
|
||||
#include "data/dv.hpp"
|
||||
#include "data/dynamic_fwd.hpp"
|
||||
|
||||
namespace dynamic {
|
||||
class Map;
|
||||
}
|
||||
#include "typedefs.hpp"
|
||||
|
||||
namespace json {
|
||||
inline constexpr int BJSON_END = 0x0;
|
||||
@ -26,15 +23,7 @@ namespace json {
|
||||
inline constexpr int BJSON_TYPE_NULL = 0xC;
|
||||
inline constexpr int BJSON_TYPE_CDOCUMENT = 0x1F;
|
||||
|
||||
std::vector<ubyte> to_binaryDV(const dv::value& obj, bool compress = false);
|
||||
std::vector<ubyte> to_binary(const dv::value& obj, bool compress = false);
|
||||
|
||||
dv::value from_binaryDV(const ubyte* src, size_t size);
|
||||
|
||||
std::vector<ubyte> to_binary(
|
||||
const dynamic::Map* obj, bool compress = false
|
||||
);
|
||||
std::vector<ubyte> to_binary(
|
||||
const dynamic::Value& obj, bool compress = false
|
||||
);
|
||||
std::shared_ptr<dynamic::Map> from_binary(const ubyte* src, size_t size);
|
||||
dv::value from_binary(const ubyte* src, size_t size);
|
||||
}
|
||||
|
||||
@ -1,168 +0,0 @@
|
||||
#include "binary_json.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "data/dv.hpp"
|
||||
#include "byte_utils.hpp"
|
||||
#include "gzip.hpp"
|
||||
|
||||
using namespace json;
|
||||
|
||||
static void to_binary(ByteBuilder& builder, const dv::value& value) {
|
||||
switch (value.getType()) {
|
||||
case dv::value_type::none:
|
||||
throw std::runtime_error("none value is not implemented");
|
||||
case dv::value_type::object: {
|
||||
const auto bytes = json::to_binaryDV(value);
|
||||
builder.put(bytes.data(), bytes.size());
|
||||
break;
|
||||
}
|
||||
case dv::value_type::list:
|
||||
builder.put(BJSON_TYPE_LIST);
|
||||
for (const auto& element : value) {
|
||||
to_binary(builder, element);
|
||||
}
|
||||
builder.put(BJSON_END);
|
||||
break;
|
||||
case dv::value_type::bytes: {
|
||||
const auto& bytes = value.asBytes();
|
||||
builder.put(BJSON_TYPE_BYTES);
|
||||
builder.putInt32(bytes.size());
|
||||
builder.put(bytes.data(), bytes.size());
|
||||
break;
|
||||
}
|
||||
case dv::value_type::integer: {
|
||||
auto val = value.asInteger();
|
||||
if (val >= 0 && val <= 255) {
|
||||
builder.put(BJSON_TYPE_BYTE);
|
||||
builder.put(val);
|
||||
} else if (val >= INT16_MIN && val <= INT16_MAX) {
|
||||
builder.put(BJSON_TYPE_INT16);
|
||||
builder.putInt16(val);
|
||||
} else if (val >= INT32_MIN && val <= INT32_MAX) {
|
||||
builder.put(BJSON_TYPE_INT32);
|
||||
builder.putInt32(val);
|
||||
} else {
|
||||
builder.put(BJSON_TYPE_INT64);
|
||||
builder.putInt64(val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case dv::value_type::number:
|
||||
builder.put(BJSON_TYPE_NUMBER);
|
||||
builder.putFloat64(value.asNumber());
|
||||
break;
|
||||
case dv::value_type::boolean:
|
||||
builder.put(BJSON_TYPE_FALSE + value.asBoolean());
|
||||
break;
|
||||
case dv::value_type::string:
|
||||
builder.put(BJSON_TYPE_STRING);
|
||||
builder.put(value.asString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ubyte> json::to_binaryDV(const dv::value& object, bool compress) {
|
||||
if (compress) {
|
||||
auto bytes = to_binaryDV(object, false);
|
||||
return gzip::compress(bytes.data(), bytes.size());
|
||||
}
|
||||
ByteBuilder builder;
|
||||
// type byte
|
||||
builder.put(BJSON_TYPE_DOCUMENT);
|
||||
// document size
|
||||
builder.putInt32(0);
|
||||
|
||||
// writing entries
|
||||
for (const auto& [key, value] : object.asObject()) {
|
||||
builder.putCStr(key.c_str());
|
||||
to_binary(builder, value);
|
||||
}
|
||||
// terminating byte
|
||||
builder.put(BJSON_END);
|
||||
|
||||
// updating document size
|
||||
builder.setInt32(1, builder.size());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static dv::value list_from_binary(ByteReader& reader);
|
||||
static dv::value object_from_binary(ByteReader& reader);
|
||||
|
||||
static dv::value value_from_binary(ByteReader& reader) {
|
||||
ubyte typecode = reader.get();
|
||||
switch (typecode) {
|
||||
case BJSON_TYPE_DOCUMENT:
|
||||
reader.getInt32();
|
||||
return object_from_binary(reader);
|
||||
case BJSON_TYPE_LIST:
|
||||
return list_from_binary(reader);
|
||||
case BJSON_TYPE_BYTE:
|
||||
return reader.get();
|
||||
case BJSON_TYPE_INT16:
|
||||
return reader.getInt16();
|
||||
case BJSON_TYPE_INT32:
|
||||
return reader.getInt32();
|
||||
case BJSON_TYPE_INT64:
|
||||
return reader.getInt64();
|
||||
case BJSON_TYPE_NUMBER:
|
||||
return reader.getFloat64();
|
||||
case BJSON_TYPE_FALSE:
|
||||
case BJSON_TYPE_TRUE:
|
||||
return (typecode - BJSON_TYPE_FALSE) != 0;
|
||||
case BJSON_TYPE_STRING:
|
||||
return reader.getString();
|
||||
case BJSON_TYPE_NULL:
|
||||
return dv::none;
|
||||
case BJSON_TYPE_BYTES: {
|
||||
int32_t size = reader.getInt32();
|
||||
if (size < 0) {
|
||||
throw std::runtime_error(
|
||||
"invalid byte-buffer size "+std::to_string(size));
|
||||
}
|
||||
if (size > reader.remaining()) {
|
||||
throw std::runtime_error(
|
||||
"buffer_size > remaining_size "+std::to_string(size));
|
||||
}
|
||||
auto bytes = std::make_shared<util::Buffer<ubyte>>(
|
||||
reader.pointer(), size);
|
||||
reader.skip(size);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error(
|
||||
"type support not implemented for <"+std::to_string(typecode)+">");
|
||||
}
|
||||
|
||||
static dv::value list_from_binary(ByteReader& reader) {
|
||||
auto list = dv::list();
|
||||
while (reader.peek() != BJSON_END) {
|
||||
list.add(value_from_binary(reader));
|
||||
}
|
||||
reader.get();
|
||||
return list;
|
||||
}
|
||||
|
||||
static dv::value object_from_binary(ByteReader& reader) {
|
||||
auto obj = dv::object();
|
||||
while (reader.peek() != BJSON_END) {
|
||||
const char* key = reader.getCString();
|
||||
obj[key] = value_from_binary(reader);
|
||||
}
|
||||
reader.get();
|
||||
return obj;
|
||||
}
|
||||
|
||||
dv::value json::from_binaryDV(const ubyte* src, size_t size) {
|
||||
if (size < 2) {
|
||||
throw std::runtime_error("bytes length is less than 2");
|
||||
}
|
||||
if (src[0] == gzip::MAGIC[0] && src[1] == gzip::MAGIC[1]) {
|
||||
// reading compressed document
|
||||
auto data = gzip::decompress(src, size);
|
||||
return from_binaryDV(data.data(), data.size());
|
||||
} else {
|
||||
ByteReader reader(src, size);
|
||||
return value_from_binary(reader);
|
||||
}
|
||||
}
|
||||
@ -258,7 +258,7 @@ int64_t BasicParser::parseSimpleInt(int base) {
|
||||
return value;
|
||||
}
|
||||
|
||||
dynamic::Value BasicParser::parseNumber() {
|
||||
dv::value BasicParser::parseNumber() {
|
||||
switch (peek()) {
|
||||
case '-':
|
||||
skip(1);
|
||||
@ -271,7 +271,7 @@ dynamic::Value BasicParser::parseNumber() {
|
||||
}
|
||||
}
|
||||
|
||||
dynamic::Value BasicParser::parseNumber(int sign) {
|
||||
dv::value BasicParser::parseNumber(int sign) {
|
||||
char c = peek();
|
||||
int base = 10;
|
||||
if (c == '0' && pos + 1 < source.length() &&
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "typedefs.hpp"
|
||||
|
||||
inline int is_box(int c) {
|
||||
@ -90,8 +90,8 @@ protected:
|
||||
void reset();
|
||||
|
||||
int64_t parseSimpleInt(int base);
|
||||
dynamic::Value parseNumber(int sign);
|
||||
dynamic::Value parseNumber();
|
||||
dv::value parseNumber(int sign);
|
||||
dv::value parseNumber();
|
||||
std::string parseString(char chr, bool closeRequired = true);
|
||||
|
||||
parsing_error error(const std::string& message);
|
||||
|
||||
@ -6,29 +6,17 @@
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "commons.hpp"
|
||||
|
||||
using namespace json;
|
||||
using namespace dynamic;
|
||||
|
||||
class Parser : BasicParser {
|
||||
std::unique_ptr<dynamic::List> parseList();
|
||||
std::unique_ptr<dynamic::Map> parseObject();
|
||||
dynamic::Value parseValue();
|
||||
public:
|
||||
Parser(std::string_view filename, std::string_view source);
|
||||
|
||||
std::unique_ptr<dynamic::Map> parse();
|
||||
};
|
||||
|
||||
class ParserDV : BasicParser {
|
||||
dv::value parseList();
|
||||
dv::value parseObject();
|
||||
dv::value parseValue();
|
||||
public:
|
||||
ParserDV(std::string_view filename, std::string_view source);
|
||||
Parser(std::string_view filename, std::string_view source);
|
||||
|
||||
dv::value parse();
|
||||
};
|
||||
@ -46,22 +34,6 @@ inline void newline(
|
||||
}
|
||||
}
|
||||
|
||||
void stringifyObj(
|
||||
const Map* obj,
|
||||
std::stringstream& ss,
|
||||
int indent,
|
||||
const std::string& indentstr,
|
||||
bool nice
|
||||
);
|
||||
|
||||
void stringifyArr(
|
||||
const List* list,
|
||||
std::stringstream& ss,
|
||||
int indent,
|
||||
const std::string& indentstr,
|
||||
bool nice
|
||||
);
|
||||
|
||||
void stringifyObj(
|
||||
const dv::value& obj,
|
||||
std::stringstream& ss,
|
||||
@ -78,34 +50,6 @@ void stringifyList(
|
||||
bool nice
|
||||
);
|
||||
|
||||
void stringifyValue(
|
||||
const Value& value,
|
||||
std::stringstream& ss,
|
||||
int indent,
|
||||
const std::string& indentstr,
|
||||
bool nice
|
||||
) {
|
||||
if (auto map = std::get_if<Map_sptr>(&value)) {
|
||||
stringifyObj(map->get(), ss, indent, indentstr, nice);
|
||||
} else if (auto listptr = std::get_if<List_sptr>(&value)) {
|
||||
stringifyArr(listptr->get(), ss, indent, indentstr, nice);
|
||||
} else if (auto bytesptr = std::get_if<ByteBuffer_sptr>(&value)) {
|
||||
auto bytes = bytesptr->get();
|
||||
ss << "\"" << util::base64_encode(bytes->data(), bytes->size());
|
||||
ss << "\"";
|
||||
} else if (auto flag = std::get_if<bool>(&value)) {
|
||||
ss << (*flag ? "true" : "false");
|
||||
} else if (auto num = std::get_if<number_t>(&value)) {
|
||||
ss << std::setprecision(15) << *num;
|
||||
} else if (auto num = std::get_if<integer_t>(&value)) {
|
||||
ss << *num;
|
||||
} else if (auto str = std::get_if<std::string>(&value)) {
|
||||
ss << util::escape(*str);
|
||||
} else {
|
||||
ss << "null";
|
||||
}
|
||||
}
|
||||
|
||||
void stringifyValue(
|
||||
const dv::value& value,
|
||||
std::stringstream& ss,
|
||||
@ -146,74 +90,6 @@ void stringifyValue(
|
||||
}
|
||||
}
|
||||
|
||||
void stringifyArr(
|
||||
const List* list,
|
||||
std::stringstream& ss,
|
||||
int indent,
|
||||
const std::string& indentstr,
|
||||
bool nice
|
||||
) {
|
||||
if (list == nullptr) {
|
||||
ss << "nullptr";
|
||||
return;
|
||||
}
|
||||
if (list->values.empty()) {
|
||||
ss << "[]";
|
||||
return;
|
||||
}
|
||||
ss << "[";
|
||||
for (size_t i = 0; i < list->size(); i++) {
|
||||
if (i > 0 || nice) {
|
||||
newline(ss, nice, indent, indentstr);
|
||||
}
|
||||
const Value& value = list->values[i];
|
||||
stringifyValue(value, ss, indent + 1, indentstr, nice);
|
||||
if (i + 1 < list->size()) {
|
||||
ss << ',';
|
||||
}
|
||||
}
|
||||
if (nice) {
|
||||
newline(ss, true, indent - 1, indentstr);
|
||||
}
|
||||
ss << ']';
|
||||
}
|
||||
|
||||
void stringifyObj(
|
||||
const Map* obj,
|
||||
std::stringstream& ss,
|
||||
int indent,
|
||||
const std::string& indentstr,
|
||||
bool nice
|
||||
) {
|
||||
if (obj == nullptr) {
|
||||
ss << "nullptr";
|
||||
return;
|
||||
}
|
||||
if (obj->values.empty()) {
|
||||
ss << "{}";
|
||||
return;
|
||||
}
|
||||
ss << "{";
|
||||
size_t index = 0;
|
||||
for (auto& entry : obj->values) {
|
||||
const std::string& key = entry.first;
|
||||
if (index > 0 || nice) {
|
||||
newline(ss, nice, indent, indentstr);
|
||||
}
|
||||
const Value& value = entry.second;
|
||||
ss << util::escape(key) << ": ";
|
||||
stringifyValue(value, ss, indent + 1, indentstr, nice);
|
||||
index++;
|
||||
if (index < obj->values.size()) {
|
||||
ss << ',';
|
||||
}
|
||||
}
|
||||
if (nice) {
|
||||
newline(ss, true, indent - 1, indentstr);
|
||||
}
|
||||
ss << '}';
|
||||
}
|
||||
|
||||
void stringifyList(
|
||||
const dv::value& list,
|
||||
std::stringstream& ss,
|
||||
@ -273,30 +149,6 @@ void stringifyObj(
|
||||
}
|
||||
|
||||
std::string json::stringify(
|
||||
const Map* obj, bool nice, const std::string& indent
|
||||
) {
|
||||
std::stringstream ss;
|
||||
stringifyObj(obj, ss, 1, indent, nice);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string json::stringify(
|
||||
const dynamic::List* arr, bool nice, const std::string& indent
|
||||
) {
|
||||
std::stringstream ss;
|
||||
stringifyArr(arr, ss, 1, indent, nice);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string json::stringify(
|
||||
const dynamic::Value& value, bool nice, const std::string& indent
|
||||
) {
|
||||
std::stringstream ss;
|
||||
stringifyValue(value, ss, 1, indent, nice);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string json::stringifyDV(
|
||||
const dv::value& value, bool nice, const std::string& indent
|
||||
) {
|
||||
std::stringstream ss;
|
||||
@ -308,7 +160,7 @@ Parser::Parser(std::string_view filename, std::string_view source)
|
||||
: BasicParser(filename, source) {
|
||||
}
|
||||
|
||||
std::unique_ptr<Map> Parser::parse() {
|
||||
dv::value Parser::parse() {
|
||||
char next = peek();
|
||||
if (next != '{') {
|
||||
throw error("'{' expected");
|
||||
@ -316,118 +168,7 @@ std::unique_ptr<Map> Parser::parse() {
|
||||
return parseObject();
|
||||
}
|
||||
|
||||
std::unique_ptr<Map> Parser::parseObject() {
|
||||
expect('{');
|
||||
auto obj = std::make_unique<Map>();
|
||||
auto& map = obj->values;
|
||||
while (peek() != '}') {
|
||||
if (peek() == '#') {
|
||||
skipLine();
|
||||
continue;
|
||||
}
|
||||
std::string key = parseName();
|
||||
char next = peek();
|
||||
if (next != ':') {
|
||||
throw error("':' expected");
|
||||
}
|
||||
pos++;
|
||||
map.insert(std::make_pair(key, parseValue()));
|
||||
next = peek();
|
||||
if (next == ',') {
|
||||
pos++;
|
||||
} else if (next == '}') {
|
||||
break;
|
||||
} else {
|
||||
throw error("',' expected");
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
return obj;
|
||||
}
|
||||
|
||||
std::unique_ptr<List> Parser::parseList() {
|
||||
expect('[');
|
||||
auto arr = std::make_unique<List>();
|
||||
auto& values = arr->values;
|
||||
while (peek() != ']') {
|
||||
if (peek() == '#') {
|
||||
skipLine();
|
||||
continue;
|
||||
}
|
||||
values.push_back(parseValue());
|
||||
|
||||
char next = peek();
|
||||
if (next == ',') {
|
||||
pos++;
|
||||
} else if (next == ']') {
|
||||
break;
|
||||
} else {
|
||||
throw error("',' expected");
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
return arr;
|
||||
}
|
||||
|
||||
Value Parser::parseValue() {
|
||||
char next = peek();
|
||||
if (next == '-' || next == '+' || is_digit(next)) {
|
||||
auto numeric = parseNumber();
|
||||
if (std::holds_alternative<integer_t>(numeric)) {
|
||||
return std::get<integer_t>(numeric);
|
||||
}
|
||||
return std::get<number_t>(numeric);
|
||||
}
|
||||
if (is_identifier_start(next)) {
|
||||
std::string literal = parseName();
|
||||
if (literal == "true") {
|
||||
return true;
|
||||
} else if (literal == "false") {
|
||||
return false;
|
||||
} else if (literal == "inf") {
|
||||
return INFINITY;
|
||||
} else if (literal == "nan") {
|
||||
return NAN;
|
||||
}
|
||||
throw error("invalid literal ");
|
||||
}
|
||||
if (next == '{') {
|
||||
return Map_sptr(parseObject().release());
|
||||
}
|
||||
if (next == '[') {
|
||||
return List_sptr(parseList().release());
|
||||
}
|
||||
if (next == '"' || next == '\'') {
|
||||
pos++;
|
||||
return parseString(next);
|
||||
}
|
||||
throw error("unexpected character '" + std::string({next}) + "'");
|
||||
}
|
||||
|
||||
dynamic::Map_sptr json::parse(
|
||||
std::string_view filename, std::string_view source
|
||||
) {
|
||||
Parser parser(filename, source);
|
||||
return parser.parse();
|
||||
}
|
||||
|
||||
dynamic::Map_sptr json::parse(std::string_view source) {
|
||||
return parse("<string>", source);
|
||||
}
|
||||
|
||||
ParserDV::ParserDV(std::string_view filename, std::string_view source)
|
||||
: BasicParser(filename, source) {
|
||||
}
|
||||
|
||||
dv::value ParserDV::parse() {
|
||||
char next = peek();
|
||||
if (next != '{') {
|
||||
throw error("'{' expected");
|
||||
}
|
||||
return parseObject();
|
||||
}
|
||||
|
||||
dv::value ParserDV::parseObject() {
|
||||
dv::value Parser::parseObject() {
|
||||
expect('{');
|
||||
auto object = dv::object();
|
||||
while (peek() != '}') {
|
||||
@ -455,7 +196,7 @@ dv::value ParserDV::parseObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
dv::value ParserDV::parseList() {
|
||||
dv::value Parser::parseList() {
|
||||
expect('[');
|
||||
auto list = dv::list();
|
||||
while (peek() != ']') {
|
||||
@ -478,14 +219,14 @@ dv::value ParserDV::parseList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
dv::value ParserDV::parseValue() {
|
||||
dv::value Parser::parseValue() {
|
||||
char next = peek();
|
||||
if (next == '-' || next == '+' || is_digit(next)) {
|
||||
auto numeric = parseNumber();
|
||||
if (std::holds_alternative<integer_t>(numeric)) {
|
||||
return std::get<integer_t>(numeric);
|
||||
if (numeric.isInteger()) {
|
||||
return numeric.asInteger();
|
||||
}
|
||||
return std::get<number_t>(numeric);
|
||||
return numeric.asNumber();
|
||||
}
|
||||
if (is_identifier_start(next)) {
|
||||
std::string literal = parseName();
|
||||
@ -513,13 +254,13 @@ dv::value ParserDV::parseValue() {
|
||||
throw error("unexpected character '" + std::string({next}) + "'");
|
||||
}
|
||||
|
||||
dv::value json::parseDV(
|
||||
dv::value json::parse(
|
||||
std::string_view filename, std::string_view source
|
||||
) {
|
||||
ParserDV parser(filename, source);
|
||||
Parser parser(filename, source);
|
||||
return parser.parse();
|
||||
}
|
||||
|
||||
dv::value json::parseDV(std::string_view source) {
|
||||
return parseDV("<string>", source);
|
||||
dv::value json::parse(std::string_view source) {
|
||||
return parse("<string>", source);
|
||||
}
|
||||
|
||||
@ -2,31 +2,15 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "binary_json.hpp"
|
||||
|
||||
namespace json {
|
||||
dynamic::Map_sptr parse(std::string_view filename, std::string_view source);
|
||||
dynamic::Map_sptr parse(std::string_view source);
|
||||
|
||||
dv::value parseDV(std::string_view filename, std::string_view source);
|
||||
dv::value parseDV(std::string_view source);
|
||||
dv::value parse(std::string_view filename, std::string_view source);
|
||||
dv::value parse(std::string_view source);
|
||||
|
||||
std::string stringify(
|
||||
const dynamic::Map* obj, bool nice, const std::string& indent
|
||||
);
|
||||
|
||||
std::string stringify(
|
||||
const dynamic::List* arr, bool nice, const std::string& indent
|
||||
);
|
||||
|
||||
std::string stringify(
|
||||
const dynamic::Value& value, bool nice, const std::string& indent
|
||||
);
|
||||
|
||||
std::string stringifyDV(
|
||||
const dv::value& value, bool nice, const std::string& indent=" "
|
||||
);
|
||||
}
|
||||
|
||||
@ -63,18 +63,18 @@ public:
|
||||
}
|
||||
auto cmd = parseName();
|
||||
if (cmd == "v") {
|
||||
float x = dynamic::as_number(parseNumber());
|
||||
float y = dynamic::as_number(parseNumber());
|
||||
float z = dynamic::as_number(parseNumber());
|
||||
float x = parseNumber().asNumber();
|
||||
float y = parseNumber().asNumber();
|
||||
float z = parseNumber().asNumber();
|
||||
coords.emplace_back(x, y, z);
|
||||
} else if (cmd == "vt") {
|
||||
float u = dynamic::as_number(parseNumber());
|
||||
float v = dynamic::as_number(parseNumber());
|
||||
float u = parseNumber().asNumber();
|
||||
float v = parseNumber().asNumber();
|
||||
uvs.emplace_back(u, v);
|
||||
} else if (cmd == "vn") {
|
||||
float x = dynamic::as_number(parseNumber());
|
||||
float y = dynamic::as_number(parseNumber());
|
||||
float z = dynamic::as_number(parseNumber());
|
||||
float x = parseNumber().asNumber();
|
||||
float y = parseNumber().asNumber();
|
||||
float z = parseNumber().asNumber();
|
||||
normals.emplace_back(x, y, z);
|
||||
} else {
|
||||
skipLine();
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/setting.hpp"
|
||||
#include "files/settings_io.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
@ -15,7 +14,7 @@
|
||||
using namespace toml;
|
||||
|
||||
class TomlReader : BasicParser {
|
||||
dynamic::Map_sptr root;
|
||||
dv::value root;
|
||||
|
||||
void skipWhitespace() override {
|
||||
BasicParser::skipWhitespace();
|
||||
@ -27,33 +26,33 @@ class TomlReader : BasicParser {
|
||||
}
|
||||
}
|
||||
|
||||
dynamic::Map& getSection(const std::string& section) {
|
||||
dv::value& getSection(const std::string& section) {
|
||||
if (section.empty()) {
|
||||
return *root;
|
||||
return root;
|
||||
}
|
||||
size_t offset = 0;
|
||||
auto& rootMap = *root;
|
||||
auto rootMap = &root;
|
||||
do {
|
||||
size_t index = section.find('.', offset);
|
||||
if (index == std::string::npos) {
|
||||
auto map = rootMap.map(section);
|
||||
if (map == nullptr) {
|
||||
return rootMap.putMap(section);
|
||||
auto map = rootMap->at(section);
|
||||
if (!map) {
|
||||
return rootMap->object(section);
|
||||
}
|
||||
return *map;
|
||||
}
|
||||
auto subsection = section.substr(offset, index);
|
||||
auto map = rootMap.map(subsection);
|
||||
if (map == nullptr) {
|
||||
rootMap = rootMap.putMap(subsection);
|
||||
auto map = rootMap->at(subsection);
|
||||
if (!map) {
|
||||
rootMap = &rootMap->object(subsection);
|
||||
} else {
|
||||
rootMap = *map;
|
||||
rootMap = &*map;
|
||||
}
|
||||
offset = index + 1;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
void readSection(const std::string& section, dynamic::Map& map) {
|
||||
void readSection(const std::string& section, dv::value& map) {
|
||||
while (hasNext()) {
|
||||
skipWhitespace();
|
||||
if (!hasNext()) {
|
||||
@ -71,23 +70,23 @@ class TomlReader : BasicParser {
|
||||
expect('=');
|
||||
c = peek();
|
||||
if (is_digit(c)) {
|
||||
map.put(name, parseNumber(1));
|
||||
map[name] = parseNumber(1);
|
||||
} else if (c == '-' || c == '+') {
|
||||
int sign = c == '-' ? -1 : 1;
|
||||
pos++;
|
||||
map.put(name, parseNumber(sign));
|
||||
map[name] = parseNumber(sign);
|
||||
} else if (is_identifier_start(c)) {
|
||||
std::string identifier = parseName();
|
||||
if (identifier == "true" || identifier == "false") {
|
||||
map.put(name, identifier == "true");
|
||||
map[name] = identifier == "true";
|
||||
} else if (identifier == "inf") {
|
||||
map.put(name, INFINITY);
|
||||
map[name] = INFINITY;
|
||||
} else if (identifier == "nan") {
|
||||
map.put(name, NAN);
|
||||
map[name] = NAN;
|
||||
}
|
||||
} else if (c == '"' || c == '\'') {
|
||||
pos++;
|
||||
map.put(name, parseString(c));
|
||||
map[name] = parseString(c);
|
||||
} else {
|
||||
throw error("feature is not supported");
|
||||
}
|
||||
@ -97,36 +96,28 @@ class TomlReader : BasicParser {
|
||||
public:
|
||||
TomlReader(std::string_view file, std::string_view source)
|
||||
: BasicParser(file, source) {
|
||||
root = dynamic::create_map();
|
||||
root = dv::object();
|
||||
}
|
||||
|
||||
dynamic::Map_sptr read() {
|
||||
dv::value read() {
|
||||
skipWhitespace();
|
||||
if (!hasNext()) {
|
||||
return root;
|
||||
}
|
||||
readSection("", *root);
|
||||
readSection("", root);
|
||||
return root;
|
||||
}
|
||||
};
|
||||
|
||||
dynamic::Map_sptr toml::parse(std::string_view file, std::string_view source) {
|
||||
return TomlReader(file, source).read();
|
||||
}
|
||||
|
||||
void toml::parse(
|
||||
SettingsHandler& handler, std::string_view file, std::string_view source
|
||||
) {
|
||||
auto map = parse(file, source);
|
||||
for (auto& entry : map->values) {
|
||||
const auto& sectionName = entry.first;
|
||||
auto sectionMap = std::get_if<dynamic::Map_sptr>(&entry.second);
|
||||
if (sectionMap == nullptr) {
|
||||
for (const auto& [sectionName, sectionMap] : map.asObject()) {
|
||||
if (!sectionMap.isObject()) {
|
||||
continue;
|
||||
}
|
||||
for (auto& sectionEntry : (*sectionMap)->values) {
|
||||
const auto& name = sectionEntry.first;
|
||||
auto& value = sectionEntry.second;
|
||||
for (const auto& [name, value] : sectionMap.asObject()) {
|
||||
auto fullname = sectionName + "." + name;
|
||||
if (handler.has(fullname)) {
|
||||
handler.setValue(fullname, value);
|
||||
@ -135,24 +126,24 @@ void toml::parse(
|
||||
}
|
||||
}
|
||||
|
||||
std::string toml::stringify(dynamic::Map& root, const std::string& name) {
|
||||
dv::value toml::parse(std::string_view file, std::string_view source) {
|
||||
return TomlReader(file, source).read();
|
||||
}
|
||||
|
||||
std::string toml::stringify(const dv::value& root, const std::string& name) {
|
||||
std::stringstream ss;
|
||||
if (!name.empty()) {
|
||||
ss << "[" << name << "]\n";
|
||||
}
|
||||
for (auto& entry : root.values) {
|
||||
if (!std::holds_alternative<dynamic::Map_sptr>(entry.second)) {
|
||||
ss << entry.first << " = ";
|
||||
ss << entry.second << "\n";
|
||||
for (const auto& [key, value] : root.asObject()) {
|
||||
if (!value.isObject()) {
|
||||
ss << key << " = " << value << "\n";
|
||||
}
|
||||
}
|
||||
for (auto& entry : root.values) {
|
||||
if (auto submap = std::get_if<dynamic::Map_sptr>(&entry.second)) {
|
||||
ss << "\n"
|
||||
<< toml::stringify(
|
||||
**submap,
|
||||
name.empty() ? entry.first : name + "." + entry.first
|
||||
);
|
||||
for (const auto& [key, value] : root.asObject()) {
|
||||
if (value.isObject()) {
|
||||
ss << "\n" << toml::stringify(value,
|
||||
name.empty() ? key : name + "." + key);
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
|
||||
@ -2,14 +2,15 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
|
||||
class SettingsHandler;
|
||||
|
||||
namespace toml {
|
||||
std::string stringify(SettingsHandler& handler);
|
||||
std::string stringify(dynamic::Map& root, const std::string& name = "");
|
||||
dynamic::Map_sptr parse(std::string_view file, std::string_view source);
|
||||
std::string stringify(const dv::value& root, const std::string& name = "");
|
||||
|
||||
dv::value parse(std::string_view file, std::string_view source);
|
||||
|
||||
void parse(
|
||||
SettingsHandler& handler, std::string_view file, std::string_view source
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "data/dynamic_fwd.hpp"
|
||||
#include "content_fwd.hpp"
|
||||
#include "data/dv.hpp"
|
||||
|
||||
using DrawGroups = std::set<ubyte>;
|
||||
template <class K, class V>
|
||||
@ -122,18 +122,18 @@ public:
|
||||
class ResourceIndices {
|
||||
std::vector<std::string> names;
|
||||
std::unordered_map<std::string, size_t> indices;
|
||||
std::unique_ptr<std::vector<dynamic::Map_sptr>> savedData;
|
||||
std::unique_ptr<std::vector<dv::value>> savedData;
|
||||
public:
|
||||
ResourceIndices()
|
||||
: savedData(std::make_unique<std::vector<dynamic::Map_sptr>>()) {
|
||||
: savedData(std::make_unique<std::vector<dv::value>>()) {
|
||||
}
|
||||
|
||||
static constexpr size_t MISSING = SIZE_MAX;
|
||||
|
||||
void add(std::string name, dynamic::Map_sptr map) {
|
||||
void add(std::string name, dv::value map) {
|
||||
indices[name] = names.size();
|
||||
names.push_back(name);
|
||||
savedData->push_back(map);
|
||||
savedData->push_back(std::move(map));
|
||||
}
|
||||
|
||||
const std::string& getName(size_t index) const {
|
||||
@ -148,12 +148,12 @@ public:
|
||||
return MISSING;
|
||||
}
|
||||
|
||||
dynamic::Map_sptr getSavedData(size_t index) const {
|
||||
dv::value getSavedData(size_t index) const {
|
||||
return savedData->at(index);
|
||||
}
|
||||
|
||||
void saveData(size_t index, dynamic::Map_sptr map) const {
|
||||
savedData->at(index) = map;
|
||||
void saveData(size_t index, dv::value map) const {
|
||||
savedData->at(index) = std::move(map);
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
|
||||
@ -20,9 +20,11 @@ ContentLUT::ContentLUT(
|
||||
|
||||
template <class T>
|
||||
static constexpr size_t get_entries_count(
|
||||
const ContentUnitIndices<T>& indices, const dynamic::List_sptr& list
|
||||
const ContentUnitIndices<T>& indices, const dv::value& list
|
||||
) {
|
||||
return list ? std::max(list->size(), indices.count()) : indices.count();
|
||||
return list != nullptr
|
||||
? std::max(list.size(), indices.count())
|
||||
: indices.count();
|
||||
}
|
||||
|
||||
std::shared_ptr<ContentLUT> ContentLUT::create(
|
||||
@ -36,8 +38,8 @@ std::shared_ptr<ContentLUT> ContentLUT::create(
|
||||
}
|
||||
|
||||
auto root = files::read_json(filename);
|
||||
auto blocklist = root->list("blocks");
|
||||
auto itemlist = root->list("items");
|
||||
auto& blocklist = root["blocks"];
|
||||
auto& itemlist = root["items"];
|
||||
|
||||
auto* indices = content->getIndices();
|
||||
size_t blocks_c = get_entries_count(indices->blocks, blocklist);
|
||||
@ -45,8 +47,8 @@ std::shared_ptr<ContentLUT> ContentLUT::create(
|
||||
|
||||
auto lut = std::make_shared<ContentLUT>(indices, blocks_c, items_c);
|
||||
|
||||
lut->blocks.setup(blocklist.get(), content->blocks);
|
||||
lut->items.setup(itemlist.get(), content->items);
|
||||
lut->blocks.setup(blocklist, content->blocks);
|
||||
lut->items.setup(itemlist, content->items);
|
||||
|
||||
if (lut->hasContentReorder() || lut->hasMissingContent()) {
|
||||
return lut;
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "constants.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "Content.hpp"
|
||||
|
||||
@ -45,10 +45,10 @@ public:
|
||||
names.emplace_back("");
|
||||
}
|
||||
}
|
||||
void setup(dynamic::List* list, const ContentUnitDefs<U>& defs) {
|
||||
if (list) {
|
||||
for (size_t i = 0; i < list->size(); i++) {
|
||||
std::string name = list->str(i);
|
||||
void setup(const dv::value& list, const ContentUnitDefs<U>& defs) {
|
||||
if (list != nullptr) {
|
||||
for (size_t i = 0; i < list.size(); i++) {
|
||||
const std::string& name = list[i].asString();
|
||||
if (auto def = defs.find(name)) {
|
||||
set(i, name, def->rt.id);
|
||||
} else {
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#include "ContentPack.hpp"
|
||||
#include "coders/json.hpp"
|
||||
#include "core_defs.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
#include "files/files.hpp"
|
||||
#include "items/ItemDef.hpp"
|
||||
@ -21,6 +20,7 @@
|
||||
#include "util/listutil.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "data/dv_util.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
@ -60,7 +60,7 @@ static void detect_defs(
|
||||
|
||||
bool ContentLoader::fixPackIndices(
|
||||
const fs::path& folder,
|
||||
dynamic::Map* indicesRoot,
|
||||
dv::value& indicesRoot,
|
||||
const std::string& contentSection
|
||||
) {
|
||||
std::vector<std::string> detected;
|
||||
@ -68,25 +68,23 @@ bool ContentLoader::fixPackIndices(
|
||||
|
||||
std::vector<std::string> indexed;
|
||||
bool modified = false;
|
||||
if (!indicesRoot->has(contentSection)) {
|
||||
indicesRoot->putList(contentSection);
|
||||
if (!indicesRoot.has(contentSection)) {
|
||||
indicesRoot.list(contentSection);
|
||||
}
|
||||
auto arr = indicesRoot->list(contentSection);
|
||||
if (arr) {
|
||||
for (uint i = 0; i < arr->size(); i++) {
|
||||
std::string name = arr->str(i);
|
||||
if (!util::contains(detected, name)) {
|
||||
arr->remove(i);
|
||||
i--;
|
||||
modified = true;
|
||||
continue;
|
||||
}
|
||||
indexed.push_back(name);
|
||||
auto& arr = indicesRoot[contentSection];
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
const std::string& name = arr[i].asString();
|
||||
if (!util::contains(detected, name)) {
|
||||
arr.erase(i);
|
||||
i--;
|
||||
modified = true;
|
||||
continue;
|
||||
}
|
||||
indexed.push_back(name);
|
||||
}
|
||||
for (auto name : detected) {
|
||||
if (!util::contains(indexed, name)) {
|
||||
arr->put(name);
|
||||
arr.add(name);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
@ -100,21 +98,21 @@ void ContentLoader::fixPackIndices() {
|
||||
auto itemsFolder = folder / ContentPack::ITEMS_FOLDER;
|
||||
auto entitiesFolder = folder / ContentPack::ENTITIES_FOLDER;
|
||||
|
||||
dynamic::Map_sptr root;
|
||||
dv::value root;
|
||||
if (fs::is_regular_file(indexFile)) {
|
||||
root = files::read_json(indexFile);
|
||||
} else {
|
||||
root = dynamic::create_map();
|
||||
root = dv::object();
|
||||
}
|
||||
|
||||
bool modified = false;
|
||||
modified |= fixPackIndices(blocksFolder, root.get(), "blocks");
|
||||
modified |= fixPackIndices(itemsFolder, root.get(), "items");
|
||||
modified |= fixPackIndices(entitiesFolder, root.get(), "entities");
|
||||
modified |= fixPackIndices(blocksFolder, root, "blocks");
|
||||
modified |= fixPackIndices(itemsFolder, root, "items");
|
||||
modified |= fixPackIndices(entitiesFolder, root, "entities");
|
||||
|
||||
if (modified) {
|
||||
// rewrite modified json
|
||||
files::write_json(indexFile, root.get());
|
||||
files::write_json(indexFile, root);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,9 +121,8 @@ void ContentLoader::loadBlock(
|
||||
) {
|
||||
auto root = files::read_json(file);
|
||||
|
||||
if (root->has("parent")) {
|
||||
std::string parentName;
|
||||
root->str("parent", parentName);
|
||||
if (root.has("parent")) {
|
||||
const auto& parentName = root["parent"].asString();
|
||||
auto parentDef = this->builder.blocks.get(parentName);
|
||||
if (parentDef == nullptr) {
|
||||
throw std::runtime_error(
|
||||
@ -135,29 +132,28 @@ void ContentLoader::loadBlock(
|
||||
parentDef->cloneTo(def);
|
||||
}
|
||||
|
||||
root->str("caption", def.caption);
|
||||
root.at("caption").get(def.caption);
|
||||
|
||||
// block texturing
|
||||
if (root->has("texture")) {
|
||||
std::string texture;
|
||||
root->str("texture", texture);
|
||||
if (root.has("texture")) {
|
||||
const auto& texture = root["texture"].asString();
|
||||
for (uint i = 0; i < 6; i++) {
|
||||
def.textureFaces[i] = texture;
|
||||
}
|
||||
} else if (root->has("texture-faces")) {
|
||||
auto texarr = root->list("texture-faces");
|
||||
} else if (root.has("texture-faces")) {
|
||||
const auto& texarr = root["texture-faces"];
|
||||
for (uint i = 0; i < 6; i++) {
|
||||
def.textureFaces[i] = texarr->str(i);
|
||||
def.textureFaces[i] = texarr[i].asString();
|
||||
}
|
||||
}
|
||||
|
||||
// block model
|
||||
std::string modelName;
|
||||
root->str("model", modelName);
|
||||
root.at("model").get(modelName);
|
||||
if (auto model = BlockModel_from(modelName)) {
|
||||
if (*model == BlockModel::custom) {
|
||||
if (root->has("model-primitives")) {
|
||||
loadCustomBlockModel(def, root->map("model-primitives").get());
|
||||
if (root.has("model-primitives")) {
|
||||
loadCustomBlockModel(def, root["model-primitives"]);
|
||||
} else {
|
||||
logger.error() << name << ": no 'model-primitives' found";
|
||||
}
|
||||
@ -168,11 +164,12 @@ void ContentLoader::loadBlock(
|
||||
def.model = BlockModel::none;
|
||||
}
|
||||
|
||||
root->str("material", def.material);
|
||||
root.at("material").get(def.material);
|
||||
|
||||
// rotation profile
|
||||
std::string profile = "none";
|
||||
root->str("rotation", profile);
|
||||
root.at("rotation").get(profile);
|
||||
|
||||
def.rotatable = profile != "none";
|
||||
if (profile == BlockRotProfile::PIPE_NAME) {
|
||||
def.rotations = BlockRotProfile::PIPE;
|
||||
@ -184,20 +181,29 @@ void ContentLoader::loadBlock(
|
||||
}
|
||||
|
||||
// block hitbox AABB [x, y, z, width, height, depth]
|
||||
auto boxarr = root->list("hitboxes");
|
||||
if (boxarr) {
|
||||
def.hitboxes.resize(boxarr->size());
|
||||
for (uint i = 0; i < boxarr->size(); i++) {
|
||||
auto box = boxarr->list(i);
|
||||
if (auto found = root.at("hitboxes")) {
|
||||
const auto& boxarr = *found;
|
||||
def.hitboxes.resize(boxarr.size());
|
||||
for (uint i = 0; i < boxarr.size(); i++) {
|
||||
const auto& box = boxarr[i];
|
||||
auto& hitboxesIndex = def.hitboxes[i];
|
||||
hitboxesIndex.a = glm::vec3(box->num(0), box->num(1), box->num(2));
|
||||
hitboxesIndex.b = glm::vec3(box->num(3), box->num(4), box->num(5));
|
||||
hitboxesIndex.a = glm::vec3(
|
||||
box[0].asNumber(), box[1].asNumber(), box[2].asNumber()
|
||||
);
|
||||
hitboxesIndex.b = glm::vec3(
|
||||
box[3].asNumber(), box[4].asNumber(), box[5].asNumber()
|
||||
);
|
||||
hitboxesIndex.b += hitboxesIndex.a;
|
||||
}
|
||||
} else if ((boxarr = root->list("hitbox"))) {
|
||||
} else if (auto found = root.at("hitbox")) {
|
||||
const auto& box = *found;
|
||||
AABB aabb;
|
||||
aabb.a = glm::vec3(boxarr->num(0), boxarr->num(1), boxarr->num(2));
|
||||
aabb.b = glm::vec3(boxarr->num(3), boxarr->num(4), boxarr->num(5));
|
||||
aabb.a = glm::vec3(
|
||||
box[0].asNumber(), box[1].asNumber(), box[2].asNumber()
|
||||
);
|
||||
aabb.b = glm::vec3(
|
||||
box[3].asNumber(), box[4].asNumber(), box[5].asNumber()
|
||||
);
|
||||
aabb.b += aabb.a;
|
||||
def.hitboxes = {aabb};
|
||||
} else if (!def.modelBoxes.empty()) {
|
||||
@ -207,17 +213,19 @@ void ContentLoader::loadBlock(
|
||||
}
|
||||
|
||||
// block light emission [r, g, b] where r,g,b in range [0..15]
|
||||
if (auto emissionarr = root->list("emission")) {
|
||||
def.emission[0] = emissionarr->num(0);
|
||||
def.emission[1] = emissionarr->num(1);
|
||||
def.emission[2] = emissionarr->num(2);
|
||||
if (auto found = root.at("emission")) {
|
||||
const auto& emissionarr = *found;
|
||||
def.emission[0] = emissionarr[0].asNumber();
|
||||
def.emission[1] = emissionarr[1].asNumber();
|
||||
def.emission[2] = emissionarr[2].asNumber();
|
||||
}
|
||||
|
||||
// block size
|
||||
if (auto sizearr = root->list("size")) {
|
||||
def.size.x = sizearr->num(0);
|
||||
def.size.y = sizearr->num(1);
|
||||
def.size.z = sizearr->num(2);
|
||||
if (auto found = root.at("size")) {
|
||||
const auto& sizearr = *found;
|
||||
def.size.x = sizearr[0].asNumber();
|
||||
def.size.y = sizearr[1].asNumber();
|
||||
def.size.z = sizearr[2].asNumber();
|
||||
if (def.model == BlockModel::block &&
|
||||
(def.size.x != 1 || def.size.y != 1 || def.size.z != 1)) {
|
||||
def.model = BlockModel::aabb;
|
||||
@ -226,22 +234,22 @@ void ContentLoader::loadBlock(
|
||||
}
|
||||
|
||||
// primitive properties
|
||||
root->flag("obstacle", def.obstacle);
|
||||
root->flag("replaceable", def.replaceable);
|
||||
root->flag("light-passing", def.lightPassing);
|
||||
root->flag("sky-light-passing", def.skyLightPassing);
|
||||
root->flag("shadeless", def.shadeless);
|
||||
root->flag("ambient-occlusion", def.ambientOcclusion);
|
||||
root->flag("breakable", def.breakable);
|
||||
root->flag("selectable", def.selectable);
|
||||
root->flag("grounded", def.grounded);
|
||||
root->flag("hidden", def.hidden);
|
||||
root->num("draw-group", def.drawGroup);
|
||||
root->str("picking-item", def.pickingItem);
|
||||
root->str("script-name", def.scriptName);
|
||||
root->str("ui-layout", def.uiLayout);
|
||||
root->num("inventory-size", def.inventorySize);
|
||||
root->num("tick-interval", def.tickInterval);
|
||||
root.at("obstacle").get(def.obstacle);
|
||||
root.at("replaceable").get(def.replaceable);
|
||||
root.at("light-passing").get(def.lightPassing);
|
||||
root.at("sky-light-passing").get(def.skyLightPassing);
|
||||
root.at("shadeless").get(def.shadeless);
|
||||
root.at("ambient-occlusion").get(def.ambientOcclusion);
|
||||
root.at("breakable").get(def.breakable);
|
||||
root.at("selectable").get(def.selectable);
|
||||
root.at("grounded").get(def.grounded);
|
||||
root.at("hidden").get(def.hidden);
|
||||
root.at("draw-group").get(def.drawGroup);
|
||||
root.at("picking-item").get(def.pickingItem);
|
||||
root.at("script-name").get(def.scriptName);
|
||||
root.at("ui-layout").get(def.uiLayout);
|
||||
root.at("inventory-size").get(def.inventorySize);
|
||||
root.at("tick-interval").get(def.tickInterval);
|
||||
if (def.tickInterval == 0) {
|
||||
def.tickInterval = 1;
|
||||
}
|
||||
@ -251,48 +259,57 @@ void ContentLoader::loadBlock(
|
||||
}
|
||||
}
|
||||
|
||||
void ContentLoader::loadCustomBlockModel(Block& def, dynamic::Map* primitives) {
|
||||
if (primitives->has("aabbs")) {
|
||||
auto modelboxes = primitives->list("aabbs");
|
||||
for (uint i = 0; i < modelboxes->size(); i++) {
|
||||
/* Parse aabb */
|
||||
auto boxarr = modelboxes->list(i);
|
||||
void ContentLoader::loadCustomBlockModel(Block& def, const dv::value& primitives) {
|
||||
if (primitives.has("aabbs")) {
|
||||
const auto& modelboxes = primitives["aabbs"];
|
||||
for (uint i = 0; i < modelboxes.size(); i++) {
|
||||
// Parse aabb
|
||||
const auto& boxarr = modelboxes[i];
|
||||
AABB modelbox;
|
||||
modelbox.a =
|
||||
glm::vec3(boxarr->num(0), boxarr->num(1), boxarr->num(2));
|
||||
modelbox.b =
|
||||
glm::vec3(boxarr->num(3), boxarr->num(4), boxarr->num(5));
|
||||
modelbox.a = glm::vec3(
|
||||
boxarr[0].asNumber(), boxarr[1].asNumber(), boxarr[2].asNumber()
|
||||
);
|
||||
modelbox.b = glm::vec3(
|
||||
boxarr[3].asNumber(), boxarr[4].asNumber(), boxarr[5].asNumber()
|
||||
);
|
||||
modelbox.b += modelbox.a;
|
||||
def.modelBoxes.push_back(modelbox);
|
||||
|
||||
if (boxarr->size() == 7)
|
||||
if (boxarr.size() == 7) {
|
||||
for (uint j = 6; j < 12; j++) {
|
||||
def.modelTextures.emplace_back(boxarr->str(6));
|
||||
def.modelTextures.emplace_back(boxarr[6].asString());
|
||||
}
|
||||
else if (boxarr->size() == 12)
|
||||
} else if (boxarr.size() == 12) {
|
||||
for (uint j = 6; j < 12; j++) {
|
||||
def.modelTextures.emplace_back(boxarr->str(j));
|
||||
def.modelTextures.emplace_back(boxarr[j].asString());
|
||||
}
|
||||
else
|
||||
} else {
|
||||
for (uint j = 6; j < 12; j++) {
|
||||
def.modelTextures.emplace_back("notfound");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (primitives->has("tetragons")) {
|
||||
auto modeltetragons = primitives->list("tetragons");
|
||||
for (uint i = 0; i < modeltetragons->size(); i++) {
|
||||
/* Parse tetragon to points */
|
||||
auto tgonobj = modeltetragons->list(i);
|
||||
glm::vec3 p1(tgonobj->num(0), tgonobj->num(1), tgonobj->num(2)),
|
||||
xw(tgonobj->num(3), tgonobj->num(4), tgonobj->num(5)),
|
||||
yh(tgonobj->num(6), tgonobj->num(7), tgonobj->num(8));
|
||||
if (primitives.has("tetragons")) {
|
||||
const auto& modeltetragons = primitives["tetragons"];
|
||||
for (uint i = 0; i < modeltetragons.size(); i++) {
|
||||
// Parse tetragon to points
|
||||
const auto& tgonobj = modeltetragons[i];
|
||||
glm::vec3 p1(
|
||||
tgonobj[0].asNumber(), tgonobj[1].asNumber(), tgonobj[2].asNumber()
|
||||
);
|
||||
glm::vec3 xw(
|
||||
tgonobj[3].asNumber(), tgonobj[4].asNumber(), tgonobj[5].asNumber()
|
||||
);
|
||||
glm::vec3 yh(
|
||||
tgonobj[6].asNumber(), tgonobj[7].asNumber(), tgonobj[8].asNumber()
|
||||
);
|
||||
def.modelExtraPoints.push_back(p1);
|
||||
def.modelExtraPoints.push_back(p1 + xw);
|
||||
def.modelExtraPoints.push_back(p1 + xw + yh);
|
||||
def.modelExtraPoints.push_back(p1 + yh);
|
||||
|
||||
def.modelTextures.emplace_back(tgonobj->str(9));
|
||||
def.modelTextures.emplace_back(tgonobj[9].asString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -302,9 +319,8 @@ void ContentLoader::loadItem(
|
||||
) {
|
||||
auto root = files::read_json(file);
|
||||
|
||||
if (root->has("parent")) {
|
||||
std::string parentName;
|
||||
root->str("parent", parentName);
|
||||
if (root.has("parent")) {
|
||||
const auto& parentName = root["parent"].asString();
|
||||
auto parentDef = this->builder.items.get(parentName);
|
||||
if (parentDef == nullptr) {
|
||||
throw std::runtime_error(
|
||||
@ -313,11 +329,10 @@ void ContentLoader::loadItem(
|
||||
}
|
||||
parentDef->cloneTo(def);
|
||||
}
|
||||
|
||||
root->str("caption", def.caption);
|
||||
root.at("caption").get(def.caption);
|
||||
|
||||
std::string iconTypeStr = "";
|
||||
root->str("icon-type", iconTypeStr);
|
||||
root.at("icon-type").get(iconTypeStr);
|
||||
if (iconTypeStr == "none") {
|
||||
def.iconType = item_icon_type::none;
|
||||
} else if (iconTypeStr == "block") {
|
||||
@ -327,16 +342,17 @@ void ContentLoader::loadItem(
|
||||
} else if (iconTypeStr.length()) {
|
||||
logger.error() << name << ": unknown icon type" << iconTypeStr;
|
||||
}
|
||||
root->str("icon", def.icon);
|
||||
root->str("placing-block", def.placingBlock);
|
||||
root->str("script-name", def.scriptName);
|
||||
root->num("stack-size", def.stackSize);
|
||||
root.at("icon").get(def.icon);
|
||||
root.at("placing-block").get(def.placingBlock);
|
||||
root.at("script-name").get(def.scriptName);
|
||||
root.at("stack-size").get(def.stackSize);
|
||||
|
||||
// item light emission [r, g, b] where r,g,b in range [0..15]
|
||||
if (auto emissionarr = root->list("emission")) {
|
||||
def.emission[0] = emissionarr->num(0);
|
||||
def.emission[1] = emissionarr->num(1);
|
||||
def.emission[2] = emissionarr->num(2);
|
||||
if (auto found = root.at("emission")) {
|
||||
const auto& emissionarr = *found;
|
||||
def.emission[0] = emissionarr[0].asNumber();
|
||||
def.emission[1] = emissionarr[1].asNumber();
|
||||
def.emission[2] = emissionarr[2].asNumber();
|
||||
}
|
||||
}
|
||||
|
||||
@ -345,9 +361,8 @@ void ContentLoader::loadEntity(
|
||||
) {
|
||||
auto root = files::read_json(file);
|
||||
|
||||
if (root->has("parent")) {
|
||||
std::string parentName;
|
||||
root->str("parent", parentName);
|
||||
if (root.has("parent")) {
|
||||
const auto& parentName = root["parent"].asString();
|
||||
auto parentDef = this->builder.entities.get(parentName);
|
||||
if (parentDef == nullptr) {
|
||||
throw std::runtime_error(
|
||||
@ -357,54 +372,57 @@ void ContentLoader::loadEntity(
|
||||
parentDef->cloneTo(def);
|
||||
}
|
||||
|
||||
if (auto componentsarr = root->list("components")) {
|
||||
for (size_t i = 0; i < componentsarr->size(); i++) {
|
||||
def.components.emplace_back(componentsarr->str(i));
|
||||
if (auto found = root.at("components")) {
|
||||
for (const auto& elem : *found) {
|
||||
def.components.emplace_back(elem.asString());
|
||||
}
|
||||
}
|
||||
if (auto boxarr = root->list("hitbox")) {
|
||||
def.hitbox = glm::vec3(boxarr->num(0), boxarr->num(1), boxarr->num(2));
|
||||
if (auto found = root.at("hitbox")) {
|
||||
const auto& arr = *found;
|
||||
def.hitbox = glm::vec3(
|
||||
arr[0].asNumber(), arr[1].asNumber(), arr[2].asNumber()
|
||||
);
|
||||
}
|
||||
if (auto sensorsarr = root->list("sensors")) {
|
||||
for (size_t i = 0; i < sensorsarr->size(); i++) {
|
||||
if (auto sensorarr = sensorsarr->list(i)) {
|
||||
auto sensorType = sensorarr->str(0);
|
||||
if (sensorType == "aabb") {
|
||||
def.boxSensors.emplace_back(
|
||||
i,
|
||||
AABB {
|
||||
{sensorarr->num(1),
|
||||
sensorarr->num(2),
|
||||
sensorarr->num(3)},
|
||||
{sensorarr->num(4),
|
||||
sensorarr->num(5),
|
||||
sensorarr->num(6)}
|
||||
}
|
||||
);
|
||||
} else if (sensorType == "radius") {
|
||||
def.radialSensors.emplace_back(i, sensorarr->num(1));
|
||||
} else {
|
||||
logger.error()
|
||||
<< name << ": sensor #" << i << " - unknown type "
|
||||
<< util::quote(sensorType);
|
||||
}
|
||||
if (auto found = root.at("sensors")) {
|
||||
const auto& arr = *found;
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
const auto& sensorarr = arr[i];
|
||||
const auto& sensorType = sensorarr[0].asString();
|
||||
if (sensorType == "aabb") {
|
||||
def.boxSensors.emplace_back(
|
||||
i,
|
||||
AABB {
|
||||
{sensorarr[1].asNumber(),
|
||||
sensorarr[2].asNumber(),
|
||||
sensorarr[3].asNumber()},
|
||||
{sensorarr[4].asNumber(),
|
||||
sensorarr[5].asNumber(),
|
||||
sensorarr[6].asNumber()}
|
||||
}
|
||||
);
|
||||
} else if (sensorType == "radius") {
|
||||
def.radialSensors.emplace_back(i, sensorarr[1].asNumber());
|
||||
} else {
|
||||
logger.error()
|
||||
<< name << ": sensor #" << i << " - unknown type "
|
||||
<< util::quote(sensorType);
|
||||
}
|
||||
}
|
||||
}
|
||||
root->flag("save", def.save.enabled);
|
||||
root->flag("save-skeleton-pose", def.save.skeleton.pose);
|
||||
root->flag("save-skeleton-textures", def.save.skeleton.textures);
|
||||
root->flag("save-body-velocity", def.save.body.velocity);
|
||||
root->flag("save-body-settings", def.save.body.settings);
|
||||
root.at("save").get(def.save.enabled);
|
||||
root.at("save-skeleton-pose").get(def.save.skeleton.pose);
|
||||
root.at("save-skeleton-textures").get(def.save.skeleton.textures);
|
||||
root.at("save-body-velocity").get(def.save.body.velocity);
|
||||
root.at("save-body-settings").get(def.save.body.settings);
|
||||
|
||||
std::string bodyTypeName;
|
||||
root->str("body-type", bodyTypeName);
|
||||
root.at("body-type").get(bodyTypeName);
|
||||
if (auto bodyType = BodyType_from(bodyTypeName)) {
|
||||
def.bodyType = *bodyType;
|
||||
}
|
||||
|
||||
root->str("skeleton-name", def.skeletonName);
|
||||
root->flag("blocking", def.blocking);
|
||||
root.at("skeleton-name").get(def.skeletonName);
|
||||
root.at("blocking").get(def.blocking);
|
||||
}
|
||||
|
||||
void ContentLoader::loadEntity(
|
||||
@ -458,9 +476,9 @@ void ContentLoader::loadBlockMaterial(
|
||||
BlockMaterial& def, const fs::path& file
|
||||
) {
|
||||
auto root = files::read_json(file);
|
||||
root->str("steps-sound", def.stepsSound);
|
||||
root->str("place-sound", def.placeSound);
|
||||
root->str("break-sound", def.breakSound);
|
||||
root.at("steps-sound").get(def.stepsSound);
|
||||
root.at("place-sound").get(def.placeSound);
|
||||
root.at("break-sound").get(def.breakSound);
|
||||
}
|
||||
|
||||
void ContentLoader::load() {
|
||||
@ -486,7 +504,7 @@ void ContentLoader::load() {
|
||||
std::string parent;
|
||||
if (fs::exists(configFile)) {
|
||||
auto root = files::read_json(configFile);
|
||||
if (root->has("parent")) root->str("parent", parent);
|
||||
root.at("parent").get(parent);
|
||||
}
|
||||
return parent;
|
||||
};
|
||||
@ -500,9 +518,10 @@ void ContentLoader::load() {
|
||||
return std::make_pair(full, new_name);
|
||||
};
|
||||
|
||||
if (auto blocksarr = root->list("blocks")) {
|
||||
for (size_t i = 0; i < blocksarr->size(); i++) {
|
||||
auto [full, name] = processName(blocksarr->str(i));
|
||||
if (auto found = root.at("blocks")) {
|
||||
const auto& blocksarr = *found;
|
||||
for (size_t i = 0; i < blocksarr.size(); i++) {
|
||||
auto [full, name] = processName(blocksarr[i].asString());
|
||||
auto parent = getJsonParent("blocks", name);
|
||||
if (parent.empty() || builder.blocks.get(parent)) {
|
||||
// No dependency or dependency already loaded/exists in another
|
||||
@ -544,9 +563,10 @@ void ContentLoader::load() {
|
||||
}
|
||||
}
|
||||
|
||||
if (auto itemsarr = root->list("items")) {
|
||||
for (size_t i = 0; i < itemsarr->size(); i++) {
|
||||
auto [full, name] = processName(itemsarr->str(i));
|
||||
if (auto found = root.at("items")) {
|
||||
const auto& itemsarr = *found;
|
||||
for (size_t i = 0; i < itemsarr.size(); i++) {
|
||||
auto [full, name] = processName(itemsarr[i].asString());
|
||||
auto parent = getJsonParent("items", name);
|
||||
if (parent.empty() || builder.items.get(parent)) {
|
||||
// No dependency or dependency already loaded/exists in another
|
||||
@ -588,9 +608,10 @@ void ContentLoader::load() {
|
||||
}
|
||||
}
|
||||
|
||||
if (auto entitiesarr = root->list("entities")) {
|
||||
for (size_t i = 0; i < entitiesarr->size(); i++) {
|
||||
auto [full, name] = processName(entitiesarr->str(i));
|
||||
if (auto found = root.at("entities")) {
|
||||
const auto& entitiesarr = *found;
|
||||
for (size_t i = 0; i < entitiesarr.size(); i++) {
|
||||
auto [full, name] = processName(entitiesarr[i].asString());
|
||||
auto parent = getJsonParent("entities", name);
|
||||
if (parent.empty() || builder.entities.get(parent)) {
|
||||
// No dependency or dependency already loaded/exists in another
|
||||
@ -669,11 +690,9 @@ void ContentLoader::load() {
|
||||
fs::path resourcesFile = folder / fs::u8path("resources.json");
|
||||
if (fs::exists(resourcesFile)) {
|
||||
auto resRoot = files::read_json(resourcesFile);
|
||||
for (const auto& [key, _] : resRoot->values) {
|
||||
for (const auto& [key, arr] : resRoot.asObject()) {
|
||||
if (auto resType = ResourceType_from(key)) {
|
||||
if (auto arr = resRoot->list(key)) {
|
||||
loadResources(*resType, arr.get());
|
||||
}
|
||||
loadResources(*resType, arr);
|
||||
} else {
|
||||
logger.warning() << "unknown resource type: " << key;
|
||||
}
|
||||
@ -681,10 +700,10 @@ void ContentLoader::load() {
|
||||
}
|
||||
}
|
||||
|
||||
void ContentLoader::loadResources(ResourceType type, dynamic::List* list) {
|
||||
for (size_t i = 0; i < list->size(); i++) {
|
||||
void ContentLoader::loadResources(ResourceType type, const dv::value& list) {
|
||||
for (size_t i = 0; i < list.size(); i++) {
|
||||
builder.resourceIndices[static_cast<size_t>(type)].add(
|
||||
pack->id + ":" + list->str(i), nullptr
|
||||
pack->id + ":" + list[i].asString(), nullptr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "content_fwd.hpp"
|
||||
#include "data/dv.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
@ -18,11 +19,6 @@ class ContentBuilder;
|
||||
class ContentPackRuntime;
|
||||
struct ContentPackStats;
|
||||
|
||||
namespace dynamic {
|
||||
class Map;
|
||||
class List;
|
||||
}
|
||||
|
||||
class ContentLoader {
|
||||
const ContentPack* pack;
|
||||
ContentPackRuntime* runtime;
|
||||
@ -40,7 +36,7 @@ class ContentLoader {
|
||||
EntityDef& def, const std::string& full, const std::string& name
|
||||
);
|
||||
|
||||
static void loadCustomBlockModel(Block& def, dynamic::Map* primitives);
|
||||
static void loadCustomBlockModel(Block& def, const dv::value& primitives);
|
||||
static void loadBlockMaterial(BlockMaterial& def, const fs::path& file);
|
||||
void loadBlock(
|
||||
Block& def, const std::string& name, const fs::path& file
|
||||
@ -51,13 +47,13 @@ class ContentLoader {
|
||||
void loadEntity(
|
||||
EntityDef& def, const std::string& name, const fs::path& file
|
||||
);
|
||||
void loadResources(ResourceType type, dynamic::List* list);
|
||||
void loadResources(ResourceType type, const dv::value& list);
|
||||
public:
|
||||
ContentLoader(ContentPack* pack, ContentBuilder& builder);
|
||||
|
||||
bool fixPackIndices(
|
||||
const fs::path& folder,
|
||||
dynamic::Map* indicesRoot,
|
||||
dv::value& indicesRoot,
|
||||
const std::string& contentSection
|
||||
);
|
||||
void fixPackIndices();
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
#include "constants.hpp"
|
||||
#include "coders/json.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "files/engine_paths.hpp"
|
||||
#include "files/files.hpp"
|
||||
|
||||
@ -72,18 +72,18 @@ static void checkContentPackId(const std::string& id, const fs::path& folder) {
|
||||
ContentPack ContentPack::read(const fs::path& folder) {
|
||||
auto root = files::read_json(folder / fs::path(PACKAGE_FILENAME));
|
||||
ContentPack pack;
|
||||
root->str("id", pack.id);
|
||||
root->str("title", pack.title);
|
||||
root->str("version", pack.version);
|
||||
root->str("creator", pack.creator);
|
||||
root->str("description", pack.description);
|
||||
root.at("id").get(pack.id);
|
||||
root.at("title").get(pack.title);
|
||||
root.at("version").get(pack.version);
|
||||
root.at("creator").get(pack.creator);
|
||||
root.at("description").get(pack.description);
|
||||
pack.folder = folder;
|
||||
|
||||
auto dependencies = root->list("dependencies");
|
||||
if (dependencies) {
|
||||
for (size_t i = 0; i < dependencies->size(); i++) {
|
||||
|
||||
if (auto found = root.at("dependencies")) {
|
||||
const auto& dependencies = *found;
|
||||
for (const auto& elem : dependencies) {
|
||||
pack.dependencies.push_back(
|
||||
{DependencyLevel::required, dependencies->str(i)}
|
||||
{DependencyLevel::required, elem.asString()}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
131
src/data/dv.cpp
131
src/data/dv.cpp
@ -23,16 +23,12 @@ namespace dv {
|
||||
}
|
||||
|
||||
value& value::operator[](const key_t& key) {
|
||||
if (type == value_type::object) {
|
||||
return (*val.object)[key];
|
||||
}
|
||||
throw std::runtime_error("value is not an object");
|
||||
check_type(type, value_type::object);
|
||||
return (*val.object)[key];
|
||||
}
|
||||
const value& value::operator[](const key_t& key) const {
|
||||
if (type == value_type::object) {
|
||||
return (*val.object)[key];
|
||||
}
|
||||
throw std::runtime_error("value is not an object");
|
||||
check_type(type, value_type::object);
|
||||
return (*val.object)[key];
|
||||
}
|
||||
|
||||
value& value::operator=(const objects::Bytes& bytes) {
|
||||
@ -40,23 +36,17 @@ namespace dv {
|
||||
}
|
||||
|
||||
value& value::operator[](size_t index) {
|
||||
if (type == value_type::list) {
|
||||
return (*val.list)[index];
|
||||
}
|
||||
throw std::runtime_error("value is not a list");
|
||||
check_type(type, value_type::list);
|
||||
return (*val.list)[index];
|
||||
}
|
||||
const value& value::operator[](size_t index) const {
|
||||
if (type == value_type::list) {
|
||||
return (*val.list)[index];
|
||||
}
|
||||
throw std::runtime_error("value is not a list");
|
||||
check_type(type, value_type::list);
|
||||
return (*val.list)[index];
|
||||
}
|
||||
|
||||
void value::add(value v) {
|
||||
if (type == value_type::list) {
|
||||
return val.list->push(std::move(v));
|
||||
}
|
||||
throw std::runtime_error("value is not a list");
|
||||
check_type(type, value_type::list);
|
||||
return val.list->push_back(std::move(v));
|
||||
}
|
||||
|
||||
value& value::object(const key_t& key) {
|
||||
@ -72,54 +62,42 @@ namespace dv {
|
||||
}
|
||||
|
||||
value& value::object() {
|
||||
if (type == value_type::list) {
|
||||
return val.list->add(std::make_shared<objects::Object>());
|
||||
}
|
||||
throw std::runtime_error("value is not a list");
|
||||
check_type(type, value_type::list);
|
||||
val.list->push_back(std::make_shared<objects::Object>());
|
||||
return val.list->operator[](val.list->size()-1);
|
||||
}
|
||||
|
||||
value& value::list() {
|
||||
if (type == value_type::list) {
|
||||
return val.list->add(std::make_shared<objects::List>());
|
||||
}
|
||||
throw std::runtime_error("value is not a list");
|
||||
check_type(type, value_type::list);
|
||||
val.list->push_back(std::make_shared<objects::List>());
|
||||
return val.list->operator[](val.list->size()-1);
|
||||
}
|
||||
|
||||
list_t::iterator value::begin() {
|
||||
if (type == value_type::list) {
|
||||
return val.list->begin();
|
||||
}
|
||||
throw std::runtime_error("value is not a list");
|
||||
check_type(type, value_type::list);
|
||||
return val.list->begin();
|
||||
}
|
||||
|
||||
list_t::iterator value::end() {
|
||||
if (type == value_type::list) {
|
||||
return val.list->end();
|
||||
}
|
||||
throw std::runtime_error("value is not a list");
|
||||
check_type(type, value_type::list);
|
||||
return val.list->end();
|
||||
}
|
||||
|
||||
list_t::const_iterator value::begin() const {
|
||||
if (type == value_type::list) {
|
||||
const auto& constlist = *val.list;
|
||||
return constlist.begin();
|
||||
}
|
||||
throw std::runtime_error("value is not a list");
|
||||
check_type(type, value_type::list);
|
||||
const auto& constlist = *val.list;
|
||||
return constlist.begin();
|
||||
}
|
||||
|
||||
list_t::const_iterator value::end() const {
|
||||
if (type == value_type::list) {
|
||||
const auto& constlist = *val.list;
|
||||
return constlist.end();
|
||||
}
|
||||
throw std::runtime_error("value is not a list");
|
||||
check_type(type, value_type::list);
|
||||
const auto& constlist = *val.list;
|
||||
return constlist.end();
|
||||
}
|
||||
|
||||
const std::string& value::asString() const {
|
||||
if (type == value_type::string) {
|
||||
return *val.string;
|
||||
}
|
||||
throw std::runtime_error("type error");
|
||||
check_type(type, value_type::string);
|
||||
return *val.string;
|
||||
}
|
||||
|
||||
integer_t value::asInteger() const {
|
||||
@ -128,7 +106,8 @@ namespace dv {
|
||||
} else if (type == value_type::number) {
|
||||
return static_cast<integer_t>(val.number);
|
||||
}
|
||||
throw std::runtime_error("type error");
|
||||
throw_type_error(type, value_type::integer);
|
||||
return 0; // unreachable
|
||||
}
|
||||
|
||||
number_t value::asNumber() const {
|
||||
@ -137,7 +116,8 @@ namespace dv {
|
||||
} else if (type == value_type::integer) {
|
||||
return static_cast<number_t>(val.integer);
|
||||
}
|
||||
throw std::runtime_error("type error");
|
||||
throw_type_error(type, value_type::integer);
|
||||
return 0; // unreachable
|
||||
}
|
||||
|
||||
boolean_t value::asBoolean() const {
|
||||
@ -146,31 +126,26 @@ namespace dv {
|
||||
} else if (type == value_type::integer) {
|
||||
return val.integer != 0;
|
||||
}
|
||||
throw std::runtime_error("type error");
|
||||
throw_type_error(type, value_type::boolean);
|
||||
return false; // unreachable
|
||||
}
|
||||
|
||||
objects::Bytes& value::asBytes() {
|
||||
if (type == value_type::bytes) {
|
||||
return *val.bytes;
|
||||
}
|
||||
throw std::runtime_error("type error");
|
||||
check_type(type, value_type::bytes);
|
||||
return *val.bytes;
|
||||
}
|
||||
|
||||
const objects::Bytes& value::asBytes() const {
|
||||
if (type == value_type::bytes) {
|
||||
return *val.bytes;
|
||||
}
|
||||
throw std::runtime_error("type error");
|
||||
check_type(type, value_type::bytes);
|
||||
return *val.bytes;
|
||||
}
|
||||
|
||||
const objects::Object& value::asObject() const {
|
||||
if (type == value_type::object) {
|
||||
return *val.object;
|
||||
}
|
||||
throw std::runtime_error("type error");
|
||||
check_type(type, value_type::object);
|
||||
return *val.object;
|
||||
}
|
||||
|
||||
const size_t value::size() const {
|
||||
size_t value::size() const {
|
||||
switch (type) {
|
||||
case value_type::list:
|
||||
return val.list->size();
|
||||
@ -179,8 +154,30 @@ namespace dv {
|
||||
case value_type::string:
|
||||
return val.string->size();
|
||||
default:
|
||||
throw std::runtime_error("type error");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool value::has(const key_t& k) const {
|
||||
if (type == value_type::object) {
|
||||
return val.object->find(k) != val.object->end();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void value::erase(const key_t& key) {
|
||||
check_type(type, value_type::object);
|
||||
val.object->erase(key);
|
||||
}
|
||||
|
||||
void value::erase(size_t index) {
|
||||
check_type(type, value_type::list);
|
||||
val.list->erase(val.list->begin() + index);
|
||||
}
|
||||
}
|
||||
|
||||
#include "coders/json.hpp"
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const dv::value& value) {
|
||||
return stream << json::stringify(value, false);
|
||||
}
|
||||
|
||||
310
src/data/dv.hpp
310
src/data/dv.hpp
@ -6,6 +6,7 @@
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace util {
|
||||
@ -30,10 +31,18 @@ namespace dv {
|
||||
string
|
||||
};
|
||||
|
||||
namespace objects {
|
||||
class Object;
|
||||
class List;
|
||||
using Bytes = util::Buffer<byte_t>;
|
||||
inline const std::string& type_name(value_type type) {
|
||||
static std::string type_names[] = {
|
||||
"none",
|
||||
"number",
|
||||
"boolean",
|
||||
"integer",
|
||||
"object",
|
||||
"list",
|
||||
"bytes",
|
||||
"string"
|
||||
};
|
||||
return type_names[static_cast<int>(type)];
|
||||
}
|
||||
|
||||
class value;
|
||||
@ -45,6 +54,58 @@ namespace dv {
|
||||
using reference = value&;
|
||||
using const_reference = const value&;
|
||||
|
||||
namespace objects {
|
||||
using Object = std::unordered_map<key_t, value>;
|
||||
using List = std::vector<value>;
|
||||
using Bytes = util::Buffer<byte_t>;
|
||||
}
|
||||
|
||||
/// @brief nullable value reference returned by value.at(...)
|
||||
struct elementreference {
|
||||
value* ptr;
|
||||
|
||||
elementreference(value* ptr) : ptr(ptr) {}
|
||||
|
||||
inline operator bool() const {
|
||||
return ptr != nullptr;
|
||||
}
|
||||
|
||||
inline value& operator*() {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline const value& operator*() const {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
bool get(std::string& dst) const;
|
||||
bool get(bool& dst) const;
|
||||
bool get(int8_t& dst) const;
|
||||
bool get(int16_t& dst) const;
|
||||
bool get(int32_t& dst) const;
|
||||
bool get(int64_t& dst) const;
|
||||
bool get(uint8_t& dst) const;
|
||||
bool get(uint16_t& dst) const;
|
||||
bool get(uint32_t& dst) const;
|
||||
bool get(uint64_t& dst) const;
|
||||
bool get(float& dst) const;
|
||||
bool get(double& dst) const;
|
||||
};
|
||||
|
||||
inline void throw_type_error(value_type got, value_type expected) {
|
||||
// place breakpoint here to find cause
|
||||
throw std::runtime_error(
|
||||
"type error: expected " + type_name(expected) + ", got " +
|
||||
type_name(got)
|
||||
);
|
||||
}
|
||||
|
||||
inline void check_type(value_type got, value_type expected) {
|
||||
if (got != expected) {
|
||||
throw_type_error(got, expected);
|
||||
}
|
||||
}
|
||||
|
||||
class value {
|
||||
value_type type = value_type::none;
|
||||
union value_u {
|
||||
@ -149,6 +210,10 @@ namespace dv {
|
||||
}
|
||||
}
|
||||
|
||||
inline value& operator=(std::nullptr_t) {
|
||||
return setNone();
|
||||
}
|
||||
|
||||
inline value& operator=(int8_t v) {
|
||||
return setInteger(v);
|
||||
}
|
||||
@ -302,6 +367,10 @@ namespace dv {
|
||||
return add(value(v));
|
||||
}
|
||||
|
||||
void erase(const key_t& key);
|
||||
|
||||
void erase(size_t index);
|
||||
|
||||
value& operator[](const key_t& key);
|
||||
|
||||
const value& operator[](const key_t& key) const;
|
||||
@ -310,6 +379,14 @@ namespace dv {
|
||||
|
||||
const value& operator[](size_t index) const;
|
||||
|
||||
bool operator!=(std::nullptr_t) const noexcept {
|
||||
return type != value_type::none;
|
||||
}
|
||||
|
||||
bool operator==(std::nullptr_t) const noexcept {
|
||||
return type == value_type::none;
|
||||
}
|
||||
|
||||
value& object(const key_t& key);
|
||||
|
||||
value& list(const key_t& key);
|
||||
@ -342,93 +419,109 @@ namespace dv {
|
||||
return type;
|
||||
}
|
||||
|
||||
const size_t size() const;
|
||||
std::string asString(std::string def) const {
|
||||
if (type != value_type::string) {
|
||||
return def;
|
||||
}
|
||||
return *val.string;
|
||||
}
|
||||
|
||||
const size_t length() const {
|
||||
std::string asString(const char* s) const {
|
||||
return asString(std::string(s));
|
||||
}
|
||||
|
||||
integer_t asBoolean(boolean_t def) const {
|
||||
switch (type) {
|
||||
case value_type::boolean:
|
||||
return val.boolean;
|
||||
default:
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
integer_t asInteger(integer_t def) const {
|
||||
switch (type) {
|
||||
case value_type::integer:
|
||||
return val.integer;
|
||||
case value_type::number:
|
||||
return static_cast<integer_t>(val.number);
|
||||
default:
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
integer_t asNumber(integer_t def) const {
|
||||
switch (type) {
|
||||
case value_type::integer:
|
||||
return static_cast<number_t>(val.integer);
|
||||
case value_type::number:
|
||||
return val.number;
|
||||
default:
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
elementreference at(const key_t& k) const {
|
||||
check_type(type, value_type::object);
|
||||
const auto& found = val.object->find(k);
|
||||
if (found == val.object->end()) {
|
||||
return elementreference(nullptr);
|
||||
}
|
||||
return elementreference(&found->second);
|
||||
}
|
||||
|
||||
elementreference at(size_t index) {
|
||||
check_type(type, value_type::list);
|
||||
return elementreference(&val.list->at(index));
|
||||
}
|
||||
|
||||
const elementreference at(size_t index) const {
|
||||
check_type(type, value_type::list);
|
||||
return elementreference(&val.list->at(index));
|
||||
}
|
||||
|
||||
bool has(const key_t& k) const;
|
||||
|
||||
size_t size() const;
|
||||
|
||||
size_t length() const {
|
||||
return size();
|
||||
}
|
||||
inline bool empty() const {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
inline bool isString() const {
|
||||
return type == value_type::string;
|
||||
}
|
||||
inline bool isObject() const {
|
||||
return type == value_type::object;
|
||||
}
|
||||
inline bool isList() const {
|
||||
return type == value_type::list;
|
||||
}
|
||||
inline bool isInteger() const {
|
||||
return type == value_type::integer;
|
||||
}
|
||||
inline bool isNumber() const {
|
||||
return type == value_type::number;
|
||||
}
|
||||
};
|
||||
|
||||
inline value none = value();
|
||||
}
|
||||
|
||||
namespace dv::objects {
|
||||
class Object {
|
||||
map_t map;
|
||||
public:
|
||||
Object() = default;
|
||||
Object(std::initializer_list<pair> pairs) : map(pairs) {}
|
||||
Object(const Object&) = delete;
|
||||
~Object() = default;
|
||||
inline bool is_numeric(const value& val) {
|
||||
return val.isInteger() && val.isNumber();
|
||||
}
|
||||
|
||||
reference operator[](const key_t& key) {
|
||||
return map[key];
|
||||
}
|
||||
const_reference operator[](const key_t& key) const {
|
||||
return map.at(key);
|
||||
}
|
||||
|
||||
map_t::const_iterator begin() const {
|
||||
return map.begin();
|
||||
}
|
||||
map_t::const_iterator end() const {
|
||||
return map.end();
|
||||
}
|
||||
|
||||
const size_t size() const {
|
||||
return map.size();
|
||||
}
|
||||
};
|
||||
|
||||
class List {
|
||||
list_t list;
|
||||
public:
|
||||
List() = default;
|
||||
List(std::initializer_list<value> values) : list(values) {}
|
||||
List(const List&) = delete;
|
||||
~List() = default;
|
||||
|
||||
reference operator[](std::size_t index) {
|
||||
return list.at(index);
|
||||
}
|
||||
|
||||
const_reference operator[](std::size_t index) const {
|
||||
return list.at(index);
|
||||
}
|
||||
|
||||
void push(value v) {
|
||||
list.push_back(std::move(v));
|
||||
}
|
||||
|
||||
reference add(value v) {
|
||||
list.push_back(std::move(v));
|
||||
return list[list.size()-1];
|
||||
}
|
||||
|
||||
auto begin() {
|
||||
return list.begin();
|
||||
}
|
||||
auto end() {
|
||||
return list.end();
|
||||
}
|
||||
|
||||
list_t::const_iterator begin() const {
|
||||
return list.begin();
|
||||
}
|
||||
list_t::const_iterator end() const {
|
||||
return list.end();
|
||||
}
|
||||
|
||||
const size_t size() const {
|
||||
return list.size();
|
||||
}
|
||||
};
|
||||
using to_string_func = std::function<std::string(const value&)>;
|
||||
}
|
||||
|
||||
namespace dv {
|
||||
inline const std::string& type_name(const value& value) {
|
||||
return type_name(value.getType());
|
||||
}
|
||||
|
||||
inline value object() {
|
||||
return std::make_shared<objects::Object>();
|
||||
}
|
||||
@ -440,4 +533,67 @@ namespace dv {
|
||||
inline value list(std::initializer_list<value> values) {
|
||||
return std::make_shared<objects::List>(values);
|
||||
}
|
||||
|
||||
template<typename T> inline bool get_to_int(value* ptr, T& dst) {
|
||||
if (ptr) {
|
||||
dst = ptr->asInteger();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template<typename T> inline bool get_to_num(value* ptr, T& dst) {
|
||||
if (ptr) {
|
||||
dst = ptr->asNumber();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline bool elementreference::get(std::string& dst) const {
|
||||
if (ptr) {
|
||||
dst = ptr->asString();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool elementreference::get(bool& dst) const {
|
||||
if (ptr) {
|
||||
dst = ptr->asBoolean();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool elementreference::get(int8_t& dst) const {
|
||||
return get_to_int(ptr, dst);
|
||||
}
|
||||
inline bool elementreference::get(int16_t& dst) const {
|
||||
return get_to_int(ptr, dst);
|
||||
}
|
||||
inline bool elementreference::get(int32_t& dst) const {
|
||||
return get_to_int(ptr, dst);
|
||||
}
|
||||
inline bool elementreference::get(int64_t& dst) const {
|
||||
return get_to_int(ptr, dst);
|
||||
}
|
||||
inline bool elementreference::get(uint8_t& dst) const {
|
||||
return get_to_int(ptr, dst);
|
||||
}
|
||||
inline bool elementreference::get(uint16_t& dst) const {
|
||||
return get_to_int(ptr, dst);
|
||||
}
|
||||
inline bool elementreference::get(uint32_t& dst) const {
|
||||
return get_to_int(ptr, dst);
|
||||
}
|
||||
inline bool elementreference::get(uint64_t& dst) const {
|
||||
return get_to_int(ptr, dst);
|
||||
}
|
||||
inline bool elementreference::get(float& dst) const {
|
||||
return get_to_num(ptr, dst);
|
||||
}
|
||||
inline bool elementreference::get(double& dst) const {
|
||||
return get_to_num(ptr, dst);
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const dv::value& value);
|
||||
|
||||
74
src/data/dv_util.hpp
Normal file
74
src/data/dv_util.hpp
Normal file
@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include "dv.hpp"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace dv {
|
||||
template <int n>
|
||||
inline dv::value to_value(glm::vec<n, float> vec) {
|
||||
auto list = dv::list();
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
list.add(vec[i]);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
template <int n, int m>
|
||||
inline dv::value to_value(glm::mat<n, m, float> mat) {
|
||||
auto list = dv::list();
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
for (size_t j = 0; j < m; j++) {
|
||||
list.add(mat[i][j]);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
template <int n>
|
||||
void get_vec(const dv::value& list, glm::vec<n, float>& vec) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
vec[i] = list[i].asNumber();
|
||||
}
|
||||
}
|
||||
|
||||
template <int n>
|
||||
void get_vec(const dv::value& map, const std::string& key, glm::vec<n, float>& vec) {
|
||||
if (!map.has(key)) {
|
||||
return;
|
||||
}
|
||||
auto& list = map[key];
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
vec[i] = list[i].asNumber();
|
||||
}
|
||||
}
|
||||
|
||||
template <int n, int m>
|
||||
void get_mat(
|
||||
const dv::value& list,
|
||||
glm::mat<n, m, float>& mat
|
||||
) {
|
||||
for (size_t y = 0; y < n; y++) {
|
||||
for (size_t x = 0; x < m; x++) {
|
||||
mat[y][x] = list[y * m + x].asNumber();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <int n, int m>
|
||||
void get_mat(
|
||||
const dv::value& map,
|
||||
const std::string& key,
|
||||
glm::mat<n, m, float>& mat
|
||||
) {
|
||||
if (!map.has(key)) {
|
||||
return;
|
||||
}
|
||||
auto& list = map[key];
|
||||
for (size_t y = 0; y < n; y++) {
|
||||
for (size_t x = 0; x < m; x++) {
|
||||
mat[y][x] = list[y * m + x].asNumber();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,345 +0,0 @@
|
||||
#include "dynamic.hpp"
|
||||
|
||||
#include "coders/json.hpp"
|
||||
|
||||
using namespace dynamic;
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const dynamic::Value& value) {
|
||||
stream << json::stringify(value, false, " ");
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const dynamic::Map& value) {
|
||||
stream << json::stringify(&value, false, " ");
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const dynamic::Map_sptr& value) {
|
||||
stream << json::stringify(value, false, " ");
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const dynamic::List& value) {
|
||||
stream << json::stringify(&value, false, " ");
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(
|
||||
std::ostream& stream, const dynamic::List_sptr& value
|
||||
) {
|
||||
stream << json::stringify(value, false, " ");
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::string List::str(size_t index) const {
|
||||
const auto& value = values[index];
|
||||
switch (static_cast<Type>(value.index())) {
|
||||
case Type::string:
|
||||
return std::get<std::string>(value);
|
||||
case Type::boolean:
|
||||
return std::get<bool>(value) ? "true" : "false";
|
||||
case Type::number:
|
||||
return std::to_string(std::get<double>(value));
|
||||
case Type::integer:
|
||||
return std::to_string(std::get<int64_t>(value));
|
||||
default:
|
||||
throw std::runtime_error("type error");
|
||||
}
|
||||
}
|
||||
|
||||
number_t List::num(size_t index) const {
|
||||
const auto& value = values[index];
|
||||
switch (static_cast<Type>(value.index())) {
|
||||
case Type::number:
|
||||
return std::get<number_t>(value);
|
||||
case Type::integer:
|
||||
return std::get<integer_t>(value);
|
||||
case Type::string:
|
||||
return std::stoll(std::get<std::string>(value));
|
||||
case Type::boolean:
|
||||
return std::get<bool>(value);
|
||||
default:
|
||||
throw std::runtime_error("type error");
|
||||
}
|
||||
}
|
||||
|
||||
integer_t List::integer(size_t index) const {
|
||||
const auto& value = values[index];
|
||||
switch (static_cast<Type>(value.index())) {
|
||||
case Type::number:
|
||||
return std::get<number_t>(value);
|
||||
case Type::integer:
|
||||
return std::get<integer_t>(value);
|
||||
case Type::string:
|
||||
return std::stoll(std::get<std::string>(value));
|
||||
case Type::boolean:
|
||||
return std::get<bool>(value);
|
||||
default:
|
||||
throw std::runtime_error("type error");
|
||||
}
|
||||
}
|
||||
|
||||
const Map_sptr& List::map(size_t index) const {
|
||||
if (auto* val = std::get_if<Map_sptr>(&values[index])) {
|
||||
return *val;
|
||||
} else {
|
||||
throw std::runtime_error("type error");
|
||||
}
|
||||
}
|
||||
|
||||
List* List::list(size_t index) const {
|
||||
if (auto* val = std::get_if<List_sptr>(&values[index])) {
|
||||
return val->get();
|
||||
} else {
|
||||
throw std::runtime_error("type error");
|
||||
}
|
||||
}
|
||||
|
||||
bool List::flag(size_t index) const {
|
||||
const auto& value = values[index];
|
||||
switch (static_cast<Type>(value.index())) {
|
||||
case Type::integer:
|
||||
return std::get<integer_t>(value);
|
||||
case Type::boolean:
|
||||
return std::get<bool>(value);
|
||||
default:
|
||||
throw std::runtime_error("type error");
|
||||
}
|
||||
}
|
||||
|
||||
Value* List::getValueWriteable(size_t index) {
|
||||
return &values.at(index);
|
||||
}
|
||||
|
||||
List& List::put(const Value& value) {
|
||||
values.emplace_back(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
List& List::putList() {
|
||||
auto arr = create_list();
|
||||
put(arr);
|
||||
return *arr;
|
||||
}
|
||||
|
||||
Map& List::putMap() {
|
||||
auto map = create_map();
|
||||
put(map);
|
||||
return *map;
|
||||
}
|
||||
|
||||
ByteBuffer& List::putBytes(size_t size) {
|
||||
auto bytes = create_bytes(size);
|
||||
put(bytes);
|
||||
return *bytes;
|
||||
}
|
||||
|
||||
void List::remove(size_t index) {
|
||||
values.erase(values.begin() + index);
|
||||
}
|
||||
|
||||
void Map::str(const std::string& key, std::string& dst) const {
|
||||
dst = get(key, dst);
|
||||
}
|
||||
|
||||
std::string Map::get(const std::string& key, const std::string& def) const {
|
||||
auto found = values.find(key);
|
||||
if (found == values.end()) return def;
|
||||
auto& value = found->second;
|
||||
switch (static_cast<Type>(value.index())) {
|
||||
case Type::string:
|
||||
return std::get<std::string>(value);
|
||||
case Type::boolean:
|
||||
return std::get<bool>(value) ? "true" : "false";
|
||||
case Type::number:
|
||||
return std::to_string(std::get<number_t>(value));
|
||||
case Type::integer:
|
||||
return std::to_string(std::get<integer_t>(value));
|
||||
default:
|
||||
throw std::runtime_error("type error");
|
||||
}
|
||||
}
|
||||
|
||||
number_t Map::get(const std::string& key, double def) const {
|
||||
auto found = values.find(key);
|
||||
if (found == values.end()) return def;
|
||||
auto& value = found->second;
|
||||
switch (static_cast<Type>(value.index())) {
|
||||
case Type::number:
|
||||
return std::get<number_t>(value);
|
||||
case Type::integer:
|
||||
return std::get<integer_t>(value);
|
||||
case Type::string:
|
||||
return std::stoull(std::get<std::string>(value));
|
||||
case Type::boolean:
|
||||
return std::get<bool>(value);
|
||||
default:
|
||||
throw std::runtime_error("type error");
|
||||
}
|
||||
}
|
||||
|
||||
integer_t Map::get(const std::string& key, integer_t def) const {
|
||||
auto found = values.find(key);
|
||||
if (found == values.end()) return def;
|
||||
auto& value = found->second;
|
||||
switch (static_cast<Type>(value.index())) {
|
||||
case Type::number:
|
||||
return std::get<number_t>(value);
|
||||
case Type::integer:
|
||||
return std::get<integer_t>(value);
|
||||
case Type::string:
|
||||
return std::stoull(std::get<std::string>(value));
|
||||
case Type::boolean:
|
||||
return std::get<bool>(value);
|
||||
default:
|
||||
throw std::runtime_error("type error");
|
||||
}
|
||||
}
|
||||
|
||||
bool Map::get(const std::string& key, bool def) const {
|
||||
auto found = values.find(key);
|
||||
if (found == values.end()) return def;
|
||||
auto& value = found->second;
|
||||
switch (static_cast<Type>(value.index())) {
|
||||
case Type::integer:
|
||||
return std::get<integer_t>(value);
|
||||
case Type::boolean:
|
||||
return std::get<bool>(value);
|
||||
default:
|
||||
throw std::runtime_error("type error");
|
||||
}
|
||||
}
|
||||
|
||||
void Map::num(const std::string& key, double& dst) const {
|
||||
dst = get(key, dst);
|
||||
}
|
||||
|
||||
void Map::num(const std::string& key, float& dst) const {
|
||||
dst = get(key, static_cast<number_t>(dst));
|
||||
}
|
||||
|
||||
void Map::num(const std::string& key, ubyte& dst) const {
|
||||
dst = get(key, static_cast<integer_t>(dst));
|
||||
}
|
||||
|
||||
void Map::num(const std::string& key, int& dst) const {
|
||||
dst = get(key, static_cast<integer_t>(dst));
|
||||
}
|
||||
|
||||
void Map::num(const std::string& key, int64_t& dst) const {
|
||||
dst = get(key, dst);
|
||||
}
|
||||
|
||||
void Map::num(const std::string& key, uint64_t& dst) const {
|
||||
dst = get(key, static_cast<integer_t>(dst));
|
||||
}
|
||||
|
||||
void Map::num(const std::string& key, uint& dst) const {
|
||||
dst = get(key, static_cast<integer_t>(dst));
|
||||
}
|
||||
|
||||
Map_sptr Map::map(const std::string& key) const {
|
||||
auto found = values.find(key);
|
||||
if (found != values.end()) {
|
||||
if (auto* val = std::get_if<Map_sptr>(&found->second)) {
|
||||
return *val;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
List_sptr Map::list(const std::string& key) const {
|
||||
auto found = values.find(key);
|
||||
if (found != values.end()) return std::get<List_sptr>(found->second);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ByteBuffer_sptr Map::bytes(const std::string& key) const {
|
||||
auto found = values.find(key);
|
||||
if (found != values.end()) return std::get<ByteBuffer_sptr>(found->second);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Map::flag(const std::string& key, bool& dst) const {
|
||||
dst = get(key, dst);
|
||||
}
|
||||
|
||||
Map& Map::put(const std::string& key, const Value& value) {
|
||||
values[key] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Map::remove(const std::string& key) {
|
||||
values.erase(key);
|
||||
}
|
||||
|
||||
List& Map::putList(const std::string& key) {
|
||||
auto arr = create_list();
|
||||
put(key, arr);
|
||||
return *arr;
|
||||
}
|
||||
|
||||
Map& Map::putMap(const std::string& key) {
|
||||
auto obj = create_map();
|
||||
put(key, obj);
|
||||
return *obj;
|
||||
}
|
||||
|
||||
ByteBuffer& Map::putBytes(const std::string& key, size_t size) {
|
||||
auto bytes = create_bytes(size);
|
||||
put(key, bytes);
|
||||
return *bytes;
|
||||
}
|
||||
|
||||
bool Map::has(const std::string& key) const {
|
||||
return values.find(key) != values.end();
|
||||
}
|
||||
|
||||
size_t Map::size() const {
|
||||
return values.size();
|
||||
}
|
||||
|
||||
static const std::string TYPE_NAMES[] {
|
||||
"none",
|
||||
"map",
|
||||
"list",
|
||||
"string",
|
||||
"number",
|
||||
"bool",
|
||||
"integer",
|
||||
};
|
||||
|
||||
const std::string& dynamic::type_name(const Value& value) {
|
||||
return TYPE_NAMES[value.index()];
|
||||
}
|
||||
|
||||
List_sptr dynamic::create_list(std::initializer_list<Value> values) {
|
||||
return std::make_shared<List>(values);
|
||||
}
|
||||
|
||||
Map_sptr dynamic::create_map(
|
||||
std::initializer_list<std::pair<const std::string, Value>> entries
|
||||
) {
|
||||
return std::make_shared<Map>(entries);
|
||||
}
|
||||
|
||||
ByteBuffer_sptr dynamic::create_bytes(size_t size) {
|
||||
return std::make_shared<ByteBuffer>(size);
|
||||
}
|
||||
|
||||
number_t dynamic::get_number(const Value& value) {
|
||||
if (auto num = std::get_if<number_t>(&value)) {
|
||||
return *num;
|
||||
} else if (auto num = std::get_if<integer_t>(&value)) {
|
||||
return *num;
|
||||
}
|
||||
throw std::runtime_error("cannot cast " + type_name(value) + " to number");
|
||||
}
|
||||
|
||||
integer_t dynamic::get_integer(const Value& value) {
|
||||
if (auto num = std::get_if<integer_t>(&value)) {
|
||||
return *num;
|
||||
}
|
||||
throw std::runtime_error("cannot cast " + type_name(value) + " to integer");
|
||||
}
|
||||
@ -1,190 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "dynamic_fwd.hpp"
|
||||
|
||||
namespace dynamic {
|
||||
enum class Type {
|
||||
none = 0,
|
||||
map,
|
||||
list,
|
||||
bytes,
|
||||
string,
|
||||
number,
|
||||
boolean,
|
||||
integer
|
||||
};
|
||||
|
||||
const std::string& type_name(const Value& value);
|
||||
List_sptr create_list(std::initializer_list<Value> values = {});
|
||||
Map_sptr create_map(
|
||||
std::initializer_list<std::pair<const std::string, Value>> entries = {}
|
||||
);
|
||||
ByteBuffer_sptr create_bytes(size_t size);
|
||||
|
||||
number_t get_number(const Value& value);
|
||||
integer_t get_integer(const Value& value);
|
||||
|
||||
inline bool is_numeric(const Value& value) {
|
||||
return std::holds_alternative<number_t>(value) ||
|
||||
std::holds_alternative<integer_t>(value);
|
||||
}
|
||||
|
||||
inline number_t as_number(const Value& value) {
|
||||
if (auto num = std::get_if<number_t>(&value)) {
|
||||
return *num;
|
||||
} else if (auto num = std::get_if<integer_t>(&value)) {
|
||||
return *num;
|
||||
}
|
||||
return NAN;
|
||||
}
|
||||
|
||||
class List {
|
||||
public:
|
||||
std::vector<Value> values;
|
||||
|
||||
List() = default;
|
||||
List(std::vector<Value> values) : values(std::move(values)) {
|
||||
}
|
||||
|
||||
std::string str(size_t index) const;
|
||||
number_t num(size_t index) const;
|
||||
integer_t integer(size_t index) const;
|
||||
const Map_sptr& map(size_t index) const;
|
||||
List* list(size_t index) const;
|
||||
bool flag(size_t index) const;
|
||||
|
||||
inline size_t size() const {
|
||||
return values.size();
|
||||
}
|
||||
|
||||
inline Value& get(size_t i) {
|
||||
return values.at(i);
|
||||
}
|
||||
|
||||
List& put(std::unique_ptr<Map> value) {
|
||||
return put(Map_sptr(std::move(value)));
|
||||
}
|
||||
List& put(std::unique_ptr<List> value) {
|
||||
return put(List_sptr(std::move(value)));
|
||||
}
|
||||
List& put(std::unique_ptr<ByteBuffer> value) {
|
||||
return put(ByteBuffer_sptr(std::move(value)));
|
||||
}
|
||||
List& put(const Value& value);
|
||||
|
||||
Value* getValueWriteable(size_t index);
|
||||
|
||||
List& putList();
|
||||
Map& putMap();
|
||||
ByteBuffer& putBytes(size_t size);
|
||||
|
||||
void remove(size_t index);
|
||||
};
|
||||
|
||||
class Map {
|
||||
public:
|
||||
std::unordered_map<std::string, Value> values;
|
||||
|
||||
Map() = default;
|
||||
Map(std::unordered_map<std::string, Value> values)
|
||||
: values(std::move(values)) {};
|
||||
|
||||
template <typename T>
|
||||
T get(const std::string& key) const {
|
||||
if (!has(key)) {
|
||||
throw std::runtime_error("missing key '" + key + "'");
|
||||
}
|
||||
return get(key, T());
|
||||
}
|
||||
|
||||
std::string get(const std::string& key, const std::string& def) const;
|
||||
number_t get(const std::string& key, double def) const;
|
||||
integer_t get(const std::string& key, integer_t def) const;
|
||||
bool get(const std::string& key, bool def) const;
|
||||
|
||||
int get(const std::string& key, int def) const {
|
||||
return get(key, static_cast<integer_t>(def));
|
||||
}
|
||||
uint get(const std::string& key, uint def) const {
|
||||
return get(key, static_cast<integer_t>(def));
|
||||
}
|
||||
uint64_t get(const std::string& key, uint64_t def) const {
|
||||
return get(key, static_cast<integer_t>(def));
|
||||
}
|
||||
|
||||
void str(const std::string& key, std::string& dst) const;
|
||||
void num(const std::string& key, int& dst) const;
|
||||
void num(const std::string& key, float& dst) const;
|
||||
void num(const std::string& key, uint& dst) const;
|
||||
void num(const std::string& key, int64_t& dst) const;
|
||||
void num(const std::string& key, uint64_t& dst) const;
|
||||
void num(const std::string& key, ubyte& dst) const;
|
||||
void num(const std::string& key, double& dst) const;
|
||||
Map_sptr map(const std::string& key) const;
|
||||
List_sptr list(const std::string& key) const;
|
||||
ByteBuffer_sptr bytes(const std::string& key) const;
|
||||
void flag(const std::string& key, bool& dst) const;
|
||||
|
||||
Map& put(std::string key, std::unique_ptr<Map> value) {
|
||||
return put(key, Map_sptr(value.release()));
|
||||
}
|
||||
Map& put(std::string key, std::unique_ptr<List> value) {
|
||||
return put(key, List_sptr(value.release()));
|
||||
}
|
||||
Map& put(std::string key, int value) {
|
||||
return put(key, Value(static_cast<integer_t>(value)));
|
||||
}
|
||||
Map& put(std::string key, unsigned int value) {
|
||||
return put(key, Value(static_cast<integer_t>(value)));
|
||||
}
|
||||
Map& put(std::string key, int64_t value) {
|
||||
return put(key, Value(static_cast<integer_t>(value)));
|
||||
}
|
||||
Map& put(std::string key, uint64_t value) {
|
||||
return put(key, Value(static_cast<integer_t>(value)));
|
||||
}
|
||||
Map& put(std::string key, float value) {
|
||||
return put(key, Value(static_cast<number_t>(value)));
|
||||
}
|
||||
Map& put(std::string key, double value) {
|
||||
return put(key, Value(static_cast<number_t>(value)));
|
||||
}
|
||||
Map& put(std::string key, bool value) {
|
||||
return put(key, Value(static_cast<bool>(value)));
|
||||
}
|
||||
Map& put(const std::string& key, const ByteBuffer* bytes) {
|
||||
return put(key, std::make_unique<ByteBuffer>(
|
||||
bytes->data(), bytes->size()));
|
||||
}
|
||||
Map& put(std::string key, const ubyte* bytes, size_t size) {
|
||||
return put(key, std::make_unique<ByteBuffer>(bytes, size));
|
||||
}
|
||||
Map& put(std::string key, const char* value) {
|
||||
return put(key, Value(value));
|
||||
}
|
||||
Map& put(const std::string& key, const Value& value);
|
||||
|
||||
void remove(const std::string& key);
|
||||
|
||||
List& putList(const std::string& key);
|
||||
Map& putMap(const std::string& key);
|
||||
ByteBuffer& putBytes(const std::string& key, size_t size);
|
||||
|
||||
bool has(const std::string& key) const;
|
||||
size_t size() const;
|
||||
};
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const dynamic::Value& value);
|
||||
std::ostream& operator<<(std::ostream& stream, const dynamic::Map& value);
|
||||
std::ostream& operator<<(std::ostream& stream, const dynamic::Map_sptr& value);
|
||||
std::ostream& operator<<(std::ostream& stream, const dynamic::List& value);
|
||||
std::ostream& operator<<(std::ostream& stream, const dynamic::List_sptr& value);
|
||||
@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "typedefs.hpp"
|
||||
#include "util/Buffer.hpp"
|
||||
|
||||
namespace dynamic {
|
||||
class Map;
|
||||
class List;
|
||||
|
||||
using ByteBuffer = util::Buffer<ubyte>;
|
||||
using Map_sptr = std::shared_ptr<Map>;
|
||||
using List_sptr = std::shared_ptr<List>;
|
||||
using ByteBuffer_sptr = std::shared_ptr<ByteBuffer>;
|
||||
|
||||
struct none {};
|
||||
|
||||
inline constexpr none NONE = {};
|
||||
|
||||
using Value = std::variant<
|
||||
none,
|
||||
Map_sptr,
|
||||
List_sptr,
|
||||
ByteBuffer_sptr,
|
||||
std::string,
|
||||
number_t,
|
||||
bool,
|
||||
integer_t>;
|
||||
|
||||
using to_string_func = std::function<std::string(const Value&)>;
|
||||
}
|
||||
@ -1,79 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "dynamic.hpp"
|
||||
|
||||
namespace dynamic {
|
||||
template <int n>
|
||||
inline dynamic::List_sptr to_value(glm::vec<n, float> vec) {
|
||||
auto list = dynamic::create_list();
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
list->put(vec[i]);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
template <int n, int m>
|
||||
inline dynamic::List_sptr to_value(glm::mat<n, m, float> mat) {
|
||||
auto list = dynamic::create_list();
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
for (size_t j = 0; j < m; j++) {
|
||||
list->put(mat[i][j]);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
template <int n>
|
||||
void get_vec(
|
||||
const dynamic::Map_sptr& root,
|
||||
const std::string& name,
|
||||
glm::vec<n, float>& vec
|
||||
) {
|
||||
if (const auto& list = root->list(name)) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
vec[i] = list->num(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <int n>
|
||||
void get_vec(
|
||||
const dynamic::List_sptr& root, size_t index, glm::vec<n, float>& vec
|
||||
) {
|
||||
if (const auto& list = root->list(index)) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
vec[i] = list->num(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <int n, int m>
|
||||
void get_mat(
|
||||
const dynamic::Map_sptr& root,
|
||||
const std::string& name,
|
||||
glm::mat<n, m, float>& mat
|
||||
) {
|
||||
if (const auto& list = root->list(name)) {
|
||||
for (size_t y = 0; y < n; y++) {
|
||||
for (size_t x = 0; x < m; x++) {
|
||||
mat[y][x] = list->num(y * m + x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <int n, int m>
|
||||
void get_mat(
|
||||
const dynamic::List_sptr& root, size_t index, glm::mat<n, m, float>& mat
|
||||
) {
|
||||
if (const auto& list = root->list(index)) {
|
||||
for (size_t y = 0; y < n; y++) {
|
||||
for (size_t x = 0; x < m; x++) {
|
||||
mat[y][x] = list->num(y * m + x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,6 @@
|
||||
#include <utility>
|
||||
|
||||
#include "content/ContentLUT.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
#include "files/files.hpp"
|
||||
#include "objects/Player.hpp"
|
||||
@ -108,8 +107,8 @@ void WorldConverter::convertRegion(const fs::path& file) const {
|
||||
void WorldConverter::convertPlayer(const fs::path& file) const {
|
||||
logger.info() << "converting player " << file.u8string();
|
||||
auto map = files::read_json(file);
|
||||
Player::convert(map.get(), lut.get());
|
||||
files::write_json(file, map.get());
|
||||
Player::convert(map, lut.get());
|
||||
files::write_json(file, map);
|
||||
}
|
||||
|
||||
void WorldConverter::convert(const convert_task& task) const {
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
#include "constants.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "core_defs.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
#include "items/Inventory.hpp"
|
||||
#include "items/ItemDef.hpp"
|
||||
@ -101,23 +100,23 @@ void WorldFiles::writePacks(const std::vector<ContentPack>& packs) {
|
||||
|
||||
template <class T>
|
||||
static void write_indices(
|
||||
const ContentUnitIndices<T>& indices, dynamic::List& list
|
||||
const ContentUnitIndices<T>& indices, dv::value& list
|
||||
) {
|
||||
for (auto unit : indices.getIterable()) {
|
||||
list.put(unit->name);
|
||||
list.add(unit->name);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldFiles::writeIndices(const ContentIndices* indices) {
|
||||
dynamic::Map root;
|
||||
write_indices(indices->blocks, root.putList("blocks"));
|
||||
write_indices(indices->items, root.putList("items"));
|
||||
write_indices(indices->entities, root.putList("entities"));
|
||||
files::write_json(getIndicesFile(), &root);
|
||||
dv::value root = dv::object();
|
||||
write_indices(indices->blocks, root.list("blocks"));
|
||||
write_indices(indices->items, root.list("items"));
|
||||
write_indices(indices->entities, root.list("entities"));
|
||||
files::write_json(getIndicesFile(), root);
|
||||
}
|
||||
|
||||
void WorldFiles::writeWorldInfo(const WorldInfo& info) {
|
||||
files::write_json(getWorldFile(), info.serialize().get());
|
||||
files::write_json(getWorldFile(), info.serialize());
|
||||
}
|
||||
|
||||
std::optional<WorldInfo> WorldFiles::readWorldInfo() {
|
||||
@ -128,23 +127,22 @@ std::optional<WorldInfo> WorldFiles::readWorldInfo() {
|
||||
}
|
||||
auto root = files::read_json(file);
|
||||
WorldInfo info {};
|
||||
info.deserialize(root.get());
|
||||
info.deserialize(root);
|
||||
return info;
|
||||
}
|
||||
|
||||
static void read_resources_data(
|
||||
const Content* content, const dynamic::List_sptr& list, ResourceType type
|
||||
const Content* content, const dv::value& list, ResourceType type
|
||||
) {
|
||||
const auto& indices = content->getIndices(type);
|
||||
for (size_t i = 0; i < list->size(); i++) {
|
||||
auto map = list->map(i);
|
||||
std::string name;
|
||||
map->str("name", name);
|
||||
for (size_t i = 0; i < list.size(); i++) {
|
||||
auto& map = list[i];
|
||||
const auto& name = map["name"].asString();
|
||||
size_t index = indices.indexOf(name);
|
||||
if (index == ResourceIndices::MISSING) {
|
||||
logger.warning() << "discard " << name;
|
||||
} else {
|
||||
indices.saveData(index, map->map("saved"));
|
||||
indices.saveData(index, map["saved"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -156,11 +154,9 @@ bool WorldFiles::readResourcesData(const Content* content) {
|
||||
return false;
|
||||
}
|
||||
auto root = files::read_json(file);
|
||||
for (const auto& [key, _] : root->values) {
|
||||
for (const auto& [key, arr] : root.asObject()) {
|
||||
if (auto resType = ResourceType_from(key)) {
|
||||
if (auto arr = root->list(key)) {
|
||||
read_resources_data(content, arr, *resType);
|
||||
}
|
||||
read_resources_data(content, arr, *resType);
|
||||
} else {
|
||||
logger.warning() << "unknown resource type: " << key;
|
||||
}
|
||||
@ -168,31 +164,29 @@ bool WorldFiles::readResourcesData(const Content* content) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void erase_pack_indices(dynamic::Map* root, const std::string& id) {
|
||||
static void erase_pack_indices(dv::value& root, const std::string& id) {
|
||||
auto prefix = id + ":";
|
||||
auto blocks = root->list("blocks");
|
||||
for (uint i = 0; i < blocks->size(); i++) {
|
||||
auto name = blocks->str(i);
|
||||
auto& blocks = root["blocks"];
|
||||
for (uint i = 0; i < blocks.size(); i++) {
|
||||
auto name = blocks[i].asString();
|
||||
if (name.find(prefix) != 0) continue;
|
||||
auto value = blocks->getValueWriteable(i);
|
||||
*value = CORE_AIR;
|
||||
blocks[i] = CORE_AIR;
|
||||
}
|
||||
|
||||
auto items = root->list("items");
|
||||
for (uint i = 0; i < items->size(); i++) {
|
||||
auto name = items->str(i);
|
||||
auto& items = root["items"];
|
||||
for (uint i = 0; i < items.size(); i++) {
|
||||
auto& name = items[i].asString();
|
||||
if (name.find(prefix) != 0) continue;
|
||||
auto value = items->getValueWriteable(i);
|
||||
*value = CORE_EMPTY;
|
||||
items[i] = CORE_EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldFiles::removeIndices(const std::vector<std::string>& packs) {
|
||||
auto root = files::read_json(getIndicesFile());
|
||||
for (const auto& id : packs) {
|
||||
erase_pack_indices(root.get(), id);
|
||||
erase_pack_indices(root, id);
|
||||
}
|
||||
files::write_json(getIndicesFile(), root.get());
|
||||
files::write_json(getIndicesFile(), root);
|
||||
}
|
||||
|
||||
fs::path WorldFiles::getFolder() const {
|
||||
|
||||
@ -6,10 +6,10 @@
|
||||
|
||||
#include "coders/byte_utils.hpp"
|
||||
#include "coders/rle.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "items/Inventory.hpp"
|
||||
#include "maths/voxmaths.hpp"
|
||||
#include "util/data_io.hpp"
|
||||
#include "coders/binary_json.hpp"
|
||||
|
||||
#define REGION_FORMAT_MAGIC ".VOXREG"
|
||||
|
||||
@ -364,7 +364,7 @@ static std::unique_ptr<ubyte[]> write_inventories(
|
||||
for (auto& entry : inventories) {
|
||||
builder.putInt32(entry.first);
|
||||
auto map = entry.second->serialize();
|
||||
auto bytes = json::to_binary(map.get(), true);
|
||||
auto bytes = json::to_binary(map, true);
|
||||
builder.putInt32(bytes.size());
|
||||
builder.put(bytes.data(), bytes.size());
|
||||
}
|
||||
@ -467,21 +467,21 @@ chunk_inventories_map WorldRegions::fetchInventories(int x, int z) {
|
||||
auto map = json::from_binary(reader.pointer(), size);
|
||||
reader.skip(size);
|
||||
auto inv = std::make_shared<Inventory>(0, 0);
|
||||
inv->deserialize(map.get());
|
||||
inv->deserialize(map);
|
||||
meta[index] = inv;
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
||||
dynamic::Map_sptr WorldRegions::fetchEntities(int x, int z) {
|
||||
dv::value WorldRegions::fetchEntities(int x, int z) {
|
||||
uint32_t bytesSize;
|
||||
const ubyte* data = getData(x, z, REGION_LAYER_ENTITIES, bytesSize);
|
||||
if (data == nullptr) {
|
||||
return nullptr;
|
||||
return dv::none;
|
||||
}
|
||||
auto map = json::from_binary(data, bytesSize);
|
||||
if (map->size() == 0) {
|
||||
return nullptr;
|
||||
if (map.size() == 0) {
|
||||
return dv::none;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "data/dynamic_fwd.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "util/BufferPool.hpp"
|
||||
#include "voxels/Chunk.hpp"
|
||||
@ -198,7 +197,7 @@ public:
|
||||
std::unique_ptr<ubyte[]> getChunk(int x, int z);
|
||||
std::unique_ptr<light_t[]> getLights(int x, int z);
|
||||
chunk_inventories_map fetchInventories(int x, int z);
|
||||
dynamic::Map_sptr fetchEntities(int x, int z);
|
||||
dv::value fetchEntities(int x, int z);
|
||||
|
||||
void processRegionVoxels(int x, int z, const regionproc& func);
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#include "coders/gzip.hpp"
|
||||
#include "coders/json.hpp"
|
||||
#include "coders/toml.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
@ -116,30 +115,30 @@ bool files::write_string(const fs::path& filename, const std::string content) {
|
||||
}
|
||||
|
||||
bool files::write_json(
|
||||
const fs::path& filename, const dynamic::Map* obj, bool nice
|
||||
const fs::path& filename, const dv::value& obj, bool nice
|
||||
) {
|
||||
return files::write_string(filename, json::stringify(obj, nice, " "));
|
||||
}
|
||||
|
||||
bool files::write_binary_json(
|
||||
const fs::path& filename, const dynamic::Map* obj, bool compression
|
||||
const fs::path& filename, const dv::value& obj, bool compression
|
||||
) {
|
||||
auto bytes = json::to_binary(obj, compression);
|
||||
return files::write_bytes(filename, bytes.data(), bytes.size());
|
||||
}
|
||||
|
||||
std::shared_ptr<dynamic::Map> files::read_json(const fs::path& filename) {
|
||||
dv::value files::read_json(const fs::path& filename) {
|
||||
std::string text = files::read_string(filename);
|
||||
return json::parse(filename.string(), text);
|
||||
}
|
||||
|
||||
std::shared_ptr<dynamic::Map> files::read_binary_json(const fs::path& file) {
|
||||
dv::value files::read_binary_json(const fs::path& file) {
|
||||
size_t size;
|
||||
std::unique_ptr<ubyte[]> bytes(files::read_bytes(file, size));
|
||||
auto bytes = files::read_bytes(file, size);
|
||||
return json::from_binary(bytes.get(), size);
|
||||
}
|
||||
|
||||
std::shared_ptr<dynamic::Map> files::read_toml(const fs::path& file) {
|
||||
dv::value files::read_toml(const fs::path& file) {
|
||||
return toml::parse(file.u8string(), files::read_string(file));
|
||||
}
|
||||
|
||||
|
||||
@ -7,13 +7,10 @@
|
||||
#include <vector>
|
||||
|
||||
#include "typedefs.hpp"
|
||||
#include "data/dv.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace dynamic {
|
||||
class Map;
|
||||
}
|
||||
|
||||
namespace files {
|
||||
/// @brief Read-only random access file
|
||||
class rafile {
|
||||
@ -46,7 +43,7 @@ namespace files {
|
||||
/// @param nice if true, human readable format will be used, otherwise
|
||||
/// minimal
|
||||
bool write_json(
|
||||
const fs::path& filename, const dynamic::Map* obj, bool nice = true
|
||||
const fs::path& filename, const dv::value& obj, bool nice = true
|
||||
);
|
||||
|
||||
/// @brief Write dynamic data to the binary JSON file
|
||||
@ -54,7 +51,7 @@ namespace files {
|
||||
/// @param compressed use gzip compression
|
||||
bool write_binary_json(
|
||||
const fs::path& filename,
|
||||
const dynamic::Map* obj,
|
||||
const dv::value& obj,
|
||||
bool compressed = false
|
||||
);
|
||||
|
||||
@ -65,8 +62,8 @@ namespace files {
|
||||
|
||||
/// @brief Read JSON or BJSON file
|
||||
/// @param file *.json or *.bjson file
|
||||
std::shared_ptr<dynamic::Map> read_json(const fs::path& file);
|
||||
std::shared_ptr<dynamic::Map> read_binary_json(const fs::path& file);
|
||||
std::shared_ptr<dynamic::Map> read_toml(const fs::path& file);
|
||||
dv::value read_json(const fs::path& file);
|
||||
dv::value read_binary_json(const fs::path& file);
|
||||
dv::value read_toml(const fs::path& file);
|
||||
std::vector<std::string> read_list(const fs::path& file);
|
||||
}
|
||||
|
||||
@ -80,12 +80,13 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
||||
builder.add("do-write-lights", &settings.debug.doWriteLights);
|
||||
}
|
||||
|
||||
dynamic::Value SettingsHandler::getValue(const std::string& name) const {
|
||||
dv::value SettingsHandler::getValue(const std::string& name) const {
|
||||
auto found = map.find(name);
|
||||
if (found == map.end()) {
|
||||
throw std::runtime_error("setting '" + name + "' does not exist");
|
||||
}
|
||||
auto setting = found->second;
|
||||
|
||||
if (auto number = dynamic_cast<NumberSetting*>(setting)) {
|
||||
return static_cast<number_t>(number->get());
|
||||
} else if (auto integer = dynamic_cast<IntegerSetting*>(setting)) {
|
||||
@ -121,20 +122,26 @@ bool SettingsHandler::has(const std::string& name) const {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void set_numeric_value(T* setting, const dynamic::Value& value) {
|
||||
if (auto num = std::get_if<integer_t>(&value)) {
|
||||
setting->set(*num);
|
||||
} else if (auto num = std::get_if<number_t>(&value)) {
|
||||
setting->set(*num);
|
||||
} else if (auto flag = std::get_if<bool>(&value)) {
|
||||
setting->set(*flag);
|
||||
} else {
|
||||
throw std::runtime_error("type error, numeric value expected");
|
||||
static void set_numeric_value(T* setting, const dv::value& value) {
|
||||
using dv::value_type;
|
||||
|
||||
switch (value.getType()) {
|
||||
case value_type::integer:
|
||||
setting->set(value.asInteger());
|
||||
break;
|
||||
case value_type::number:
|
||||
setting->set(value.asNumber());
|
||||
break;
|
||||
case value_type::boolean:
|
||||
setting->set(value.asBoolean());
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("type error, numeric value expected");
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsHandler::setValue(
|
||||
const std::string& name, const dynamic::Value& value
|
||||
const std::string& name, const dv::value& value
|
||||
) {
|
||||
auto found = map.find(name);
|
||||
if (found == map.end()) {
|
||||
@ -148,16 +155,23 @@ void SettingsHandler::setValue(
|
||||
} else if (auto flag = dynamic_cast<FlagSetting*>(setting)) {
|
||||
set_numeric_value(flag, value);
|
||||
} else if (auto string = dynamic_cast<StringSetting*>(setting)) {
|
||||
if (auto num = std::get_if<integer_t>(&value)) {
|
||||
string->set(std::to_string(*num));
|
||||
} else if (auto num = std::get_if<number_t>(&value)) {
|
||||
string->set(std::to_string(*num));
|
||||
} else if (auto flag = std::get_if<bool>(&value)) {
|
||||
string->set(*flag ? "true" : "false");
|
||||
} else if (auto str = std::get_if<std::string>(&value)) {
|
||||
string->set(*str);
|
||||
} else {
|
||||
throw std::runtime_error("not implemented for type");
|
||||
using dv::value_type;
|
||||
|
||||
switch (value.getType()) {
|
||||
case value_type::integer:
|
||||
string->set(std::to_string(value.asInteger()));
|
||||
break;
|
||||
case value_type::number:
|
||||
string->set(std::to_string(value.asNumber()));
|
||||
break;
|
||||
case value_type::boolean:
|
||||
string->set(value.asBoolean() ? "true" : "false");
|
||||
break;
|
||||
case value_type::string:
|
||||
string->set(value.asString());
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("not implemented for type");
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
|
||||
class Setting;
|
||||
struct EngineSettings;
|
||||
@ -21,8 +21,8 @@ class SettingsHandler {
|
||||
public:
|
||||
SettingsHandler(EngineSettings& settings);
|
||||
|
||||
dynamic::Value getValue(const std::string& name) const;
|
||||
void setValue(const std::string& name, const dynamic::Value& value);
|
||||
dv::value getValue(const std::string& name) const;
|
||||
void setValue(const std::string& name, const dv::value& value);
|
||||
std::string toString(const std::string& name) const;
|
||||
Setting* getSetting(const std::string& name) const;
|
||||
bool has(const std::string& name) const;
|
||||
|
||||
@ -403,14 +403,12 @@ void Hud::closeInventory() {
|
||||
}
|
||||
|
||||
void Hud::add(const HudElement& element) {
|
||||
using namespace dynamic;
|
||||
|
||||
gui->add(element.getNode());
|
||||
auto document = element.getDocument();
|
||||
if (document) {
|
||||
auto invview = std::dynamic_pointer_cast<InventoryView>(element.getNode());
|
||||
auto inventory = invview ? invview->getInventory() : nullptr;
|
||||
std::vector<Value> args;
|
||||
std::vector<dv::value> args;
|
||||
args.emplace_back(inventory ? inventory.get()->getId() : 0);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
args.emplace_back(static_cast<integer_t>(blockPos[i]));
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
#include "content/ContentPack.hpp"
|
||||
#include "files/files.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
|
||||
static debug::Logger logger("locale");
|
||||
@ -72,23 +72,21 @@ void langs::loadLocalesInfo(const fs::path& resdir, std::string& fallback) {
|
||||
auto root = files::read_json(file);
|
||||
|
||||
langs::locales_info.clear();
|
||||
root->str("fallback", fallback);
|
||||
root.at("fallback").get(fallback);
|
||||
|
||||
auto langs = root->map("langs");
|
||||
if (langs) {
|
||||
if (auto found = root.at("langs")) {
|
||||
auto& langs = *found;
|
||||
auto logline = logger.info();
|
||||
logline << "locales ";
|
||||
for (auto& entry : langs->values) {
|
||||
auto langInfo = entry.second;
|
||||
|
||||
for (const auto& [key, langInfo] : langs.asObject()) {
|
||||
std::string name;
|
||||
if (auto mapptr = std::get_if<dynamic::Map_sptr>(&langInfo)) {
|
||||
name = (*mapptr)->get("name", "none"s);
|
||||
if (langInfo.isObject()) {
|
||||
name = langInfo["name"].asString("none");
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
logline << "[" << entry.first << " (" << name << ")] ";
|
||||
langs::locales_info[entry.first] = LocaleInfo {entry.first, name};
|
||||
logline << "[" << key << " (" << name << ")] ";
|
||||
langs::locales_info[key] = LocaleInfo {key, name};
|
||||
}
|
||||
logline << "added";
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
#include "delegates.hpp"
|
||||
#include "engine.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "interfaces/Task.hpp"
|
||||
#include "files/engine_paths.hpp"
|
||||
#include "graphics/ui/elements/Menu.hpp"
|
||||
@ -36,9 +36,7 @@ void menus::create_version_label(Engine* engine) {
|
||||
|
||||
gui::page_loader_func menus::create_page_loader(Engine* engine) {
|
||||
return [=](const std::string& query) {
|
||||
using namespace dynamic;
|
||||
|
||||
std::vector<Value> args;
|
||||
std::vector<dv::value> args;
|
||||
|
||||
std::string name;
|
||||
size_t index = query.find('?');
|
||||
@ -46,14 +44,14 @@ gui::page_loader_func menus::create_page_loader(Engine* engine) {
|
||||
auto argstr = query.substr(index+1);
|
||||
name = query.substr(0, index);
|
||||
|
||||
auto map = create_map();
|
||||
auto map = dv::object();
|
||||
auto filename = "query for "+name;
|
||||
BasicParser parser(filename, argstr);
|
||||
while (parser.hasNext()) {
|
||||
auto key = std::string(parser.readUntil('='));
|
||||
parser.nextChar();
|
||||
auto value = std::string(parser.readUntil('&'));
|
||||
map->put(key, value);
|
||||
map[key] = value;
|
||||
}
|
||||
args.emplace_back(map);
|
||||
} else {
|
||||
@ -106,7 +104,7 @@ bool menus::call(Engine* engine, runnable func) {
|
||||
}
|
||||
}
|
||||
|
||||
UiDocument* menus::show(Engine* engine, const std::string& name, std::vector<dynamic::Value> args) {
|
||||
UiDocument* menus::show(Engine* engine, const std::string& name, std::vector<dv::value> args) {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
auto file = engine->getResPaths()->find("layouts/"+name+".xml");
|
||||
auto fullname = "core:layouts/"+name;
|
||||
@ -123,8 +121,6 @@ UiDocument* menus::show(Engine* engine, const std::string& name, std::vector<dyn
|
||||
}
|
||||
|
||||
void menus::show_process_panel(Engine* engine, const std::shared_ptr<Task>& task, const std::wstring& text) {
|
||||
using namespace dynamic;
|
||||
|
||||
uint initialWork = task->getWorkTotal();
|
||||
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "graphics/ui/elements/Menu.hpp"
|
||||
|
||||
#include <string>
|
||||
@ -21,7 +21,7 @@ namespace menus {
|
||||
UiDocument* show(
|
||||
Engine* engine,
|
||||
const std::string& name,
|
||||
std::vector<dynamic::Value> args
|
||||
std::vector<dv::value> args
|
||||
);
|
||||
|
||||
void show_process_panel(Engine* engine, const std::shared_ptr<Task>& task, const std::wstring& text=L"");
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "UINode.hpp"
|
||||
#include "data/dynamic_fwd.hpp"
|
||||
|
||||
namespace gui {
|
||||
class TrackBar : public UINode {
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "coders/json.hpp"
|
||||
#include "data/dv.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class Serializable {
|
||||
public:
|
||||
virtual ~Serializable() { }
|
||||
virtual std::unique_ptr<dynamic::Map> serialize() const = 0;
|
||||
virtual void deserialize(dynamic::Map* src) = 0;
|
||||
virtual ~Serializable() {}
|
||||
virtual dv::value serialize() const = 0;
|
||||
virtual void deserialize(const dv::value& src) = 0;
|
||||
};
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#include "Inventory.hpp"
|
||||
|
||||
#include "content/ContentLUT.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
|
||||
Inventory::Inventory(int64_t id, size_t size) : id(id), slots(size) {
|
||||
}
|
||||
@ -46,50 +45,52 @@ void Inventory::move(
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::deserialize(dynamic::Map* src) {
|
||||
id = src->get("id", 1);
|
||||
auto slotsarr = src->list("slots");
|
||||
size_t slotscount = slotsarr->size();
|
||||
void Inventory::deserialize(const dv::value& src) {
|
||||
id = src["id"].asInteger(1);
|
||||
auto& slotsarr = src["slots"];
|
||||
size_t slotscount = slotsarr.size();
|
||||
while (slots.size() < slotscount) {
|
||||
slots.emplace_back();
|
||||
}
|
||||
for (size_t i = 0; i < slotscount; i++) {
|
||||
auto item = slotsarr->map(i);
|
||||
itemid_t id = item->get("id", ITEM_EMPTY);
|
||||
itemcount_t count = item->get("count", 0);
|
||||
auto& item = slotsarr[i];
|
||||
itemid_t id = item["id"].asInteger();
|
||||
itemcount_t count = 0;
|
||||
if (item.has("count")){
|
||||
count = item["count"].asInteger();
|
||||
}
|
||||
auto& slot = slots[i];
|
||||
slot.set(ItemStack(id, count));
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<dynamic::Map> Inventory::serialize() const {
|
||||
auto map = std::make_unique<dynamic::Map>();
|
||||
map->put("id", id);
|
||||
dv::value Inventory::serialize() const {
|
||||
auto map = dv::object();
|
||||
map["id"] = id;
|
||||
auto& slotsarr = map.list("slots");
|
||||
|
||||
auto& slotsarr = map->putList("slots");
|
||||
for (size_t i = 0; i < slots.size(); i++) {
|
||||
auto& item = slots[i];
|
||||
itemid_t id = item.getItemId();
|
||||
itemcount_t count = item.getCount();
|
||||
|
||||
auto& slotmap = slotsarr.putMap();
|
||||
slotmap.put("id", id);
|
||||
auto& slotmap = slotsarr.object();
|
||||
slotmap["id"] = id;
|
||||
if (count) {
|
||||
slotmap.put("count", count);
|
||||
slotmap["count"] = count;
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
void Inventory::convert(dynamic::Map* data, const ContentLUT* lut) {
|
||||
auto slotsarr = data->list("slots");
|
||||
for (size_t i = 0; i < slotsarr->size(); i++) {
|
||||
auto item = slotsarr->map(i);
|
||||
itemid_t id = item->get("id", ITEM_EMPTY);
|
||||
void Inventory::convert(dv::value& data, const ContentLUT* lut) {
|
||||
auto& slotsarr = data["slots"];
|
||||
for (auto& item : data["slots"]) {
|
||||
itemid_t id = item["id"].asInteger(ITEM_EMPTY);
|
||||
itemid_t replacement = lut->items.getId(id);
|
||||
item->put("id", replacement);
|
||||
if (replacement == 0 && item->has("count")) {
|
||||
item->remove("count");
|
||||
item["id"] = replacement;
|
||||
if (replacement == 0 && item.has("count")) {
|
||||
item.erase("count");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,10 +7,6 @@
|
||||
#include "typedefs.hpp"
|
||||
#include "ItemStack.hpp"
|
||||
|
||||
namespace dynamic {
|
||||
class Map;
|
||||
}
|
||||
|
||||
class ContentLUT;
|
||||
class ContentIndices;
|
||||
|
||||
@ -37,12 +33,11 @@ public:
|
||||
size_t end = -1
|
||||
);
|
||||
|
||||
/* deserializing inventory */
|
||||
void deserialize(dynamic::Map* src) override;
|
||||
/* serializing inventory */
|
||||
std::unique_ptr<dynamic::Map> serialize() const override;
|
||||
void deserialize(const dv::value& src) override;
|
||||
|
||||
static void convert(dynamic::Map* data, const ContentLUT* lut);
|
||||
dv::value serialize() const override;
|
||||
|
||||
static void convert(dv::value& data, const ContentLUT* lut);
|
||||
|
||||
inline void setId(int64_t id) {
|
||||
this->id = id;
|
||||
|
||||
@ -59,7 +59,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
dynamic::Value parseValue() {
|
||||
dv::value parseValue() {
|
||||
char c = peek();
|
||||
if (is_cmd_identifier_start(c) || c == '@') {
|
||||
auto str = parseIdentifier(true);
|
||||
@ -68,7 +68,7 @@ public:
|
||||
} else if (str == "false") {
|
||||
return false;
|
||||
} else if (str == "none" || str == "nil" || str == "null") {
|
||||
return dynamic::NONE;
|
||||
return nullptr;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@ -116,8 +116,8 @@ public:
|
||||
enumname = parseEnum();
|
||||
}
|
||||
bool optional = false;
|
||||
dynamic::Value def {};
|
||||
dynamic::Value origin {};
|
||||
dv::value def;
|
||||
dv::value origin;
|
||||
bool loop = true;
|
||||
while (hasNext() && loop) {
|
||||
char c = peek();
|
||||
@ -173,18 +173,17 @@ public:
|
||||
inline parsing_error typeError(
|
||||
const std::string& argname,
|
||||
const std::string& expected,
|
||||
const dynamic::Value& value
|
||||
const dv::value& value
|
||||
) {
|
||||
return argumentError(
|
||||
argname, expected + " expected, got " + dynamic::type_name(value)
|
||||
argname, expected + " expected, got " + dv::type_name(value)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool typeCheck(
|
||||
Argument* arg, const dynamic::Value& value, const std::string& tname
|
||||
Argument* arg, dv::value_type type, const dv::value& value, const std::string& tname
|
||||
) {
|
||||
if (!std::holds_alternative<T>(value)) {
|
||||
if (value.getType() != type) {
|
||||
if (arg->optional) {
|
||||
return false;
|
||||
} else {
|
||||
@ -194,10 +193,11 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool selectorCheck(Argument* arg, const dynamic::Value& value) {
|
||||
if (auto string = std::get_if<std::string>(&value)) {
|
||||
if ((*string)[0] == '@') {
|
||||
if (!util::is_integer((*string).substr(1))) {
|
||||
inline bool selectorCheck(Argument* arg, const dv::value& value) {
|
||||
if (value.isString()) {
|
||||
const auto& string = value.asString();
|
||||
if (string[0] == '@') {
|
||||
if (!util::is_integer(string.substr(1))) {
|
||||
throw argumentError(arg->name, "invalid selector");
|
||||
}
|
||||
return true;
|
||||
@ -210,12 +210,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool typeCheck(Argument* arg, const dynamic::Value& value) {
|
||||
bool typeCheck(Argument* arg, const dv::value& value) {
|
||||
switch (arg->type) {
|
||||
case ArgType::enumvalue: {
|
||||
if (auto* string = std::get_if<std::string>(&value)) {
|
||||
if (value.getType() == dv::value_type::string) {
|
||||
const auto& string = value.asString();
|
||||
auto& enumname = arg->enumname;
|
||||
if (enumname.find("|" + *string + "|") ==
|
||||
if (enumname.find("|" + string + "|") ==
|
||||
std::string::npos) {
|
||||
throw error(
|
||||
"argument " + util::quote(arg->name) +
|
||||
@ -231,7 +232,7 @@ public:
|
||||
break;
|
||||
}
|
||||
case ArgType::number:
|
||||
if (!dynamic::is_numeric(value)) {
|
||||
if (!dv::is_numeric(value)) {
|
||||
if (arg->optional) {
|
||||
return false;
|
||||
} else {
|
||||
@ -242,9 +243,9 @@ public:
|
||||
case ArgType::selector:
|
||||
return selectorCheck(arg, value);
|
||||
case ArgType::integer:
|
||||
return typeCheck<integer_t>(arg, value, "integer");
|
||||
return typeCheck(arg, dv::value_type::integer, value, "integer");
|
||||
case ArgType::string:
|
||||
if (!std::holds_alternative<std::string>(value)) {
|
||||
if (!value.isString()) {
|
||||
return !arg->optional;
|
||||
}
|
||||
break;
|
||||
@ -252,36 +253,35 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
dynamic::Value fetchOrigin(
|
||||
dv::value fetchOrigin(
|
||||
CommandsInterpreter* interpreter, Argument* arg
|
||||
) {
|
||||
if (dynamic::is_numeric(arg->origin)) {
|
||||
if (dv::is_numeric(arg->origin)) {
|
||||
return arg->origin;
|
||||
} else if (auto string = std::get_if<std::string>(&arg->origin)) {
|
||||
return (*interpreter)[*string];
|
||||
} else if (arg->origin.getType() == dv::value_type::string) {
|
||||
return (*interpreter)[arg->origin.asString()];
|
||||
}
|
||||
return dynamic::NONE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dynamic::Value applyRelative(
|
||||
Argument* arg, dynamic::Value value, const dynamic::Value& origin
|
||||
dv::value applyRelative(
|
||||
Argument* arg, dv::value value, const dv::value& origin
|
||||
) {
|
||||
if (origin.index() == 0) {
|
||||
if (origin == nullptr) {
|
||||
return value;
|
||||
}
|
||||
try {
|
||||
if (arg->type == ArgType::number) {
|
||||
return dynamic::get_number(origin) + dynamic::get_number(value);
|
||||
return origin.asNumber() + value.asNumber();
|
||||
} else {
|
||||
return dynamic::get_integer(origin) +
|
||||
dynamic::get_integer(value);
|
||||
return origin.asInteger() + value.asInteger();
|
||||
}
|
||||
} catch (std::runtime_error& err) {
|
||||
throw argumentError(arg->name, err.what());
|
||||
}
|
||||
}
|
||||
|
||||
dynamic::Value parseRelativeValue(
|
||||
dv::value parseRelativeValue(
|
||||
CommandsInterpreter* interpreter, Argument* arg
|
||||
) {
|
||||
if (arg->type != ArgType::number && arg->type != ArgType::integer) {
|
||||
@ -293,13 +293,13 @@ public:
|
||||
return origin;
|
||||
}
|
||||
auto value = parseValue();
|
||||
if (origin.index() == 0) {
|
||||
if (origin == nullptr) {
|
||||
return value;
|
||||
}
|
||||
return applyRelative(arg, value, origin);
|
||||
}
|
||||
|
||||
inline dynamic::Value performKeywordArg(
|
||||
inline dv::value performKeywordArg(
|
||||
CommandsInterpreter* interpreter,
|
||||
Command* command,
|
||||
const std::string& key
|
||||
@ -322,14 +322,14 @@ public:
|
||||
if (command == nullptr) {
|
||||
throw error("unknown command " + util::quote(name));
|
||||
}
|
||||
auto args = dynamic::create_list();
|
||||
auto kwargs = dynamic::create_map();
|
||||
auto args = dv::list();
|
||||
auto kwargs = dv::object();
|
||||
|
||||
int arg_index = 0;
|
||||
|
||||
while (hasNext()) {
|
||||
bool relative = false;
|
||||
dynamic::Value value = dynamic::NONE;
|
||||
dv::value value;
|
||||
if (peek() == '~') {
|
||||
relative = true;
|
||||
value = static_cast<integer_t>(0);
|
||||
@ -338,18 +338,17 @@ public:
|
||||
|
||||
if (hasNext() && peekNoJump() != ' ') {
|
||||
value = parseValue();
|
||||
if (auto string = std::get_if<std::string>(&value)) {
|
||||
if ((*string)[0] == '$') {
|
||||
value = (*interpreter)[string->substr(1)];
|
||||
if (value.isString()) {
|
||||
const auto& string = value.asString();
|
||||
if (string[0] == '$') {
|
||||
value = (*interpreter)[string.substr(1)];
|
||||
}
|
||||
}
|
||||
|
||||
// keyword argument
|
||||
if (!relative && hasNext() && peek() == '=') {
|
||||
auto key = std::get<std::string>(value);
|
||||
kwargs->put(
|
||||
key, performKeywordArg(interpreter, command, key)
|
||||
);
|
||||
if (value.isString() && !relative && hasNext() && peek() == '=') {
|
||||
const auto& key = value.asString();
|
||||
kwargs[key] = performKeywordArg(interpreter, command, key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,21 +356,22 @@ public:
|
||||
Argument* arg = nullptr;
|
||||
do {
|
||||
if (arg) {
|
||||
if (auto string = std::get_if<std::string>(&arg->def)) {
|
||||
if ((*string)[0] == '$') {
|
||||
args->put((*interpreter)[string->substr(1)]);
|
||||
if (arg->def.isString()) {
|
||||
const auto& string = arg->def.asString();
|
||||
if (string[0] == '$') {
|
||||
args.add((*interpreter)[string.substr(1)]);
|
||||
} else {
|
||||
args->put(arg->def);
|
||||
args.add(arg->def);
|
||||
}
|
||||
} else {
|
||||
args->put(arg->def);
|
||||
args.add(arg->def);
|
||||
}
|
||||
}
|
||||
arg = command->getArgument(arg_index++);
|
||||
if (arg == nullptr) {
|
||||
throw error("extra positional argument");
|
||||
}
|
||||
if (arg->origin.index() && relative) {
|
||||
if (arg->origin != nullptr && relative) {
|
||||
break;
|
||||
}
|
||||
} while (!typeCheck(arg, value));
|
||||
@ -380,20 +380,21 @@ public:
|
||||
value =
|
||||
applyRelative(arg, value, fetchOrigin(interpreter, arg));
|
||||
}
|
||||
args->put(value);
|
||||
args.add(value);
|
||||
}
|
||||
|
||||
while (auto arg = command->getArgument(arg_index++)) {
|
||||
if (!arg->optional) {
|
||||
throw error("missing argument " + util::quote(arg->name));
|
||||
} else {
|
||||
if (auto string = std::get_if<std::string>(&arg->def)) {
|
||||
if ((*string)[0] == '$') {
|
||||
args->put((*interpreter)[string->substr(1)]);
|
||||
if (arg->def.isString()) {
|
||||
const auto& string = arg->def.asString();
|
||||
if (string[0] == '$') {
|
||||
args.add((*interpreter)[string.substr(1)]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
args->put(arg->def);
|
||||
args.add(arg->def);
|
||||
}
|
||||
}
|
||||
return Prompt {command, args, kwargs};
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
|
||||
namespace cmd {
|
||||
enum class ArgType { number, integer, enumvalue, selector, string };
|
||||
@ -31,8 +31,8 @@ namespace cmd {
|
||||
std::string name;
|
||||
ArgType type;
|
||||
bool optional;
|
||||
dynamic::Value def;
|
||||
dynamic::Value origin;
|
||||
dv::value def;
|
||||
dv::value origin;
|
||||
std::string enumname;
|
||||
};
|
||||
|
||||
@ -41,12 +41,12 @@ namespace cmd {
|
||||
|
||||
struct Prompt {
|
||||
Command* command;
|
||||
dynamic::List_sptr args; // positional arguments list
|
||||
dynamic::Map_sptr kwargs; // keyword arguments table
|
||||
dv::value args; // positional arguments list
|
||||
dv::value kwargs; // keyword arguments table
|
||||
};
|
||||
|
||||
using executor_func = std::function<dynamic::Value(
|
||||
CommandsInterpreter*, dynamic::List_sptr args, dynamic::Map_sptr kwargs
|
||||
using executor_func = std::function<dv::value(
|
||||
CommandsInterpreter*, dv::value args, dv::value kwargs
|
||||
)>;
|
||||
|
||||
class Command {
|
||||
@ -85,7 +85,7 @@ namespace cmd {
|
||||
return &found->second;
|
||||
}
|
||||
|
||||
dynamic::Value execute(
|
||||
dv::value execute(
|
||||
CommandsInterpreter* interpreter, const Prompt& prompt
|
||||
) {
|
||||
return executor(interpreter, prompt.args, prompt.kwargs);
|
||||
@ -127,7 +127,7 @@ namespace cmd {
|
||||
|
||||
class CommandsInterpreter {
|
||||
std::unique_ptr<CommandsRepository> repository;
|
||||
std::unordered_map<std::string, dynamic::Value> variables;
|
||||
std::unordered_map<std::string, dv::value> variables;
|
||||
public:
|
||||
CommandsInterpreter()
|
||||
: repository(std::make_unique<CommandsRepository>()) {
|
||||
@ -141,15 +141,15 @@ namespace cmd {
|
||||
|
||||
Prompt parse(std::string_view text);
|
||||
|
||||
dynamic::Value execute(std::string_view input) {
|
||||
dv::value execute(std::string_view input) {
|
||||
return execute(parse(input));
|
||||
}
|
||||
|
||||
dynamic::Value execute(const Prompt& prompt) {
|
||||
dv::value execute(const Prompt& prompt) {
|
||||
return prompt.command->execute(this, prompt);
|
||||
}
|
||||
|
||||
dynamic::Value& operator[](const std::string& name) {
|
||||
dv::value& operator[](const std::string& name) {
|
||||
return variables[name];
|
||||
}
|
||||
|
||||
|
||||
@ -88,14 +88,13 @@ void show_convert_request(
|
||||
static void show_content_missing(
|
||||
Engine* engine, const std::shared_ptr<ContentLUT>& lut
|
||||
) {
|
||||
using namespace dynamic;
|
||||
auto root = create_map();
|
||||
auto& contentEntries = root->putList("content");
|
||||
auto root = dv::object();
|
||||
auto& contentEntries = root.list("content");
|
||||
for (auto& entry : lut->getMissingContent()) {
|
||||
std::string contentName = contenttype_name(entry.type);
|
||||
auto& contentEntry = contentEntries.putMap();
|
||||
contentEntry.put("type", contentName);
|
||||
contentEntry.put("name", entry.name);
|
||||
auto& contentEntry = contentEntries.object();
|
||||
contentEntry["type"] = contentName;
|
||||
contentEntry["name"] = entry.name;
|
||||
}
|
||||
menus::show(engine, "reports/missing_content", {root});
|
||||
}
|
||||
|
||||
@ -50,12 +50,9 @@ static int l_spawn(lua::State* L) {
|
||||
auto defname = lua::tostring(L, 1);
|
||||
auto& def = content->entities.require(defname);
|
||||
auto pos = lua::tovec3(L, 2);
|
||||
dynamic::Map_sptr args = nullptr;
|
||||
dv::value args = nullptr;
|
||||
if (lua::gettop(L) > 2) {
|
||||
auto value = lua::tovalue(L, 3);
|
||||
if (auto map = std::get_if<dynamic::Map_sptr>(&value)) {
|
||||
args = *map;
|
||||
}
|
||||
args = lua::tovalue(L, 3);
|
||||
}
|
||||
level->entities->spawn(def, pos, args);
|
||||
return 1;
|
||||
|
||||
@ -1,17 +1,12 @@
|
||||
#include "coders/json.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
static int l_json_stringify(lua::State* L) {
|
||||
auto value = lua::tovalue(L, 1);
|
||||
|
||||
if (auto mapptr = std::get_if<dynamic::Map_sptr>(&value)) {
|
||||
bool nice = lua::toboolean(L, 2);
|
||||
auto string = json::stringify(mapptr->get(), nice, " ");
|
||||
return lua::pushstring(L, string);
|
||||
} else {
|
||||
throw std::runtime_error("table expected");
|
||||
}
|
||||
bool nice = lua::toboolean(L, 2);
|
||||
auto string = json::stringify(value, nice, " ");
|
||||
return lua::pushstring(L, string);
|
||||
}
|
||||
|
||||
static int l_json_parse(lua::State* L) {
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
#include "coders/toml.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "api_lua.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
@ -7,8 +6,8 @@ using namespace scripting;
|
||||
static int l_toml_stringify(lua::State* L) {
|
||||
auto value = lua::tovalue(L, 1);
|
||||
|
||||
if (auto mapptr = std::get_if<dynamic::Map_sptr>(&value)) {
|
||||
auto string = toml::stringify(**mapptr);
|
||||
if (value.isObject()) {
|
||||
auto string = toml::stringify(value);
|
||||
return lua::pushstring(L, string);
|
||||
} else {
|
||||
throw std::runtime_error("table expected");
|
||||
@ -18,8 +17,7 @@ static int l_toml_stringify(lua::State* L) {
|
||||
static int l_toml_parse(lua::State* L) {
|
||||
auto string = lua::require_string(L, 1);
|
||||
auto element = toml::parse("<string>", string);
|
||||
auto value = std::make_unique<dynamic::Value>(element);
|
||||
return lua::pushvalue(L, *value);
|
||||
return lua::pushvalue(L, element);
|
||||
}
|
||||
|
||||
const luaL_Reg tomllib[] = {
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "delegates.hpp"
|
||||
#include "logic/scripting/scripting_functional.hpp"
|
||||
#include "lua_util.hpp"
|
||||
|
||||
@ -22,33 +22,42 @@ std::string lua::env_name(int env) {
|
||||
return "_ENV" + util::mangleid(env);
|
||||
}
|
||||
|
||||
int lua::pushvalue(State* L, const dynamic::Value& value) {
|
||||
using namespace dynamic;
|
||||
int lua::pushvalue(State* L, const dv::value& value) {
|
||||
using dv::value_type;
|
||||
|
||||
if (auto* flag = std::get_if<bool>(&value)) {
|
||||
pushboolean(L, *flag);
|
||||
} else if (auto* num = std::get_if<integer_t>(&value)) {
|
||||
pushinteger(L, *num);
|
||||
} else if (auto* num = std::get_if<number_t>(&value)) {
|
||||
pushnumber(L, *num);
|
||||
} else if (auto* str = std::get_if<std::string>(&value)) {
|
||||
pushstring(L, *str);
|
||||
} else if (auto listptr = std::get_if<List_sptr>(&value)) {
|
||||
auto list = *listptr;
|
||||
createtable(L, list->size(), 0);
|
||||
for (size_t i = 0; i < list->size(); i++) {
|
||||
pushvalue(L, list->get(i));
|
||||
rawseti(L, i + 1);
|
||||
switch (value.getType()) {
|
||||
case value_type::none:
|
||||
pushnil(L);
|
||||
break;
|
||||
case value_type::boolean:
|
||||
pushboolean(L, value.asBoolean());
|
||||
break;
|
||||
case value_type::number:
|
||||
pushnumber(L, value.asNumber());
|
||||
break;
|
||||
case value_type::integer:
|
||||
pushinteger(L, value.asInteger());
|
||||
break;
|
||||
case value_type::string:
|
||||
pushstring(L, value.asString());
|
||||
break;
|
||||
case value_type::list: {
|
||||
createtable(L, value.size(), 0);
|
||||
size_t index = 1;
|
||||
for (const auto& elem : value) {
|
||||
pushvalue(L, elem);
|
||||
rawseti(L, index);
|
||||
index++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (auto mapptr = std::get_if<Map_sptr>(&value)) {
|
||||
auto map = *mapptr;
|
||||
createtable(L, 0, map->size());
|
||||
for (auto& entry : map->values) {
|
||||
pushvalue(L, entry.second);
|
||||
setfield(L, entry.first);
|
||||
case value_type::object: {
|
||||
createtable(L, 0, value.size());
|
||||
for (const auto& [key, elem] : value.asObject()) {
|
||||
pushvalue(L, elem);
|
||||
setfield(L, key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -61,13 +70,13 @@ int lua::pushwstring(State* L, const std::wstring& str) {
|
||||
return pushstring(L, util::wstr2str_utf8(str));
|
||||
}
|
||||
|
||||
dynamic::Value lua::tovalue(State* L, int idx) {
|
||||
using namespace dynamic;
|
||||
dv::value lua::tovalue(State* L, int idx) {
|
||||
using dv::value_type;
|
||||
auto type = lua::type(L, idx);
|
||||
switch (type) {
|
||||
case LUA_TNIL:
|
||||
case LUA_TNONE:
|
||||
return dynamic::NONE;
|
||||
return nullptr;
|
||||
case LUA_TBOOLEAN:
|
||||
return toboolean(L, idx) == 1;
|
||||
case LUA_TNUMBER: {
|
||||
@ -91,22 +100,22 @@ dynamic::Value lua::tovalue(State* L, int idx) {
|
||||
int len = objlen(L, idx);
|
||||
if (len) {
|
||||
// array
|
||||
auto list = create_list();
|
||||
auto list = dv::list();
|
||||
for (int i = 1; i <= len; i++) {
|
||||
rawgeti(L, i, idx);
|
||||
list->put(tovalue(L, -1));
|
||||
list.add(tovalue(L, -1));
|
||||
pop(L);
|
||||
}
|
||||
return list;
|
||||
} else {
|
||||
// table
|
||||
auto map = create_map();
|
||||
auto map = dv::object();
|
||||
pushvalue(L, idx);
|
||||
pushnil(L);
|
||||
while (next(L, -2)) {
|
||||
pushvalue(L, -2);
|
||||
auto key = tostring(L, -1);
|
||||
map->put(key, tovalue(L, -2));
|
||||
map[key] = tovalue(L, -2);
|
||||
pop(L, 2);
|
||||
}
|
||||
pop(L);
|
||||
@ -219,7 +228,7 @@ runnable lua::create_runnable(State* L) {
|
||||
|
||||
scripting::common_func lua::create_lambda(State* L) {
|
||||
auto funcptr = create_lambda_handler(L);
|
||||
return [=](const std::vector<dynamic::Value>& args) {
|
||||
return [=](const std::vector<dv::value>& args) -> dv::value {
|
||||
getglobal(L, LAMBDAS_TABLE);
|
||||
getfield(L, *funcptr);
|
||||
for (const auto& arg : args) {
|
||||
@ -230,7 +239,7 @@ scripting::common_func lua::create_lambda(State* L) {
|
||||
pop(L);
|
||||
return result;
|
||||
}
|
||||
return dynamic::Value(dynamic::NONE);
|
||||
return nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "data/dv.hpp"
|
||||
#include "lua_wrapper.hpp"
|
||||
#include "lua_custom_types.hpp"
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
@ -394,8 +395,8 @@ namespace lua {
|
||||
return glm::vec4(r / 255, g / 255, b / 255, a / 255);
|
||||
}
|
||||
|
||||
int pushvalue(lua::State*, const dynamic::Value& value);
|
||||
dynamic::Value tovalue(lua::State*, int idx);
|
||||
int pushvalue(lua::State*, const dv::value& value);
|
||||
dv::value tovalue(lua::State*, int idx);
|
||||
|
||||
inline bool getfield(lua::State* L, const std::string& name, int idx = -1) {
|
||||
lua_getfield(L, idx, name.c_str());
|
||||
|
||||
@ -325,7 +325,7 @@ bool scripting::on_item_break_block(
|
||||
);
|
||||
}
|
||||
|
||||
dynamic::Value scripting::get_component_value(
|
||||
dv::value scripting::get_component_value(
|
||||
const scriptenv& env, const std::string& name
|
||||
) {
|
||||
auto L = lua::get_main_thread();
|
||||
@ -333,15 +333,15 @@ dynamic::Value scripting::get_component_value(
|
||||
if (lua::getfield(L, name)) {
|
||||
return lua::tovalue(L, -1);
|
||||
}
|
||||
return dynamic::NONE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void scripting::on_entity_spawn(
|
||||
const EntityDef&,
|
||||
entityid_t eid,
|
||||
const std::vector<std::unique_ptr<UserComponent>>& components,
|
||||
dynamic::Map_sptr args,
|
||||
dynamic::Map_sptr saved
|
||||
dv::value args,
|
||||
dv::value saved
|
||||
) {
|
||||
auto L = lua::get_main_thread();
|
||||
lua::requireglobal(L, STDCOMP);
|
||||
@ -364,8 +364,8 @@ void scripting::on_entity_spawn(
|
||||
if (args != nullptr) {
|
||||
std::string compfieldname = component->name;
|
||||
util::replaceAll(compfieldname, ":", "__");
|
||||
if (auto datamap = args->map(compfieldname)) {
|
||||
lua::pushvalue(L, datamap);
|
||||
if (args.has(compfieldname)) {
|
||||
lua::pushvalue(L, args[compfieldname]);
|
||||
} else {
|
||||
lua::createtable(L, 0, 0);
|
||||
}
|
||||
@ -377,8 +377,8 @@ void scripting::on_entity_spawn(
|
||||
if (saved == nullptr) {
|
||||
lua::createtable(L, 0, 0);
|
||||
} else {
|
||||
if (auto datamap = saved->map(component->name)) {
|
||||
lua::pushvalue(L, datamap);
|
||||
if (saved.has(component->name)) {
|
||||
lua::pushvalue(L, saved[component->name]);
|
||||
} else {
|
||||
lua::createtable(L, 0, 0);
|
||||
}
|
||||
@ -559,10 +559,10 @@ void scripting::on_entities_render(float delta) {
|
||||
}
|
||||
|
||||
void scripting::on_ui_open(
|
||||
UiDocument* layout, std::vector<dynamic::Value> args
|
||||
UiDocument* layout, std::vector<dv::value> args
|
||||
) {
|
||||
auto argsptr =
|
||||
std::make_shared<std::vector<dynamic::Value>>(std::move(args));
|
||||
std::make_shared<std::vector<dv::value>>(std::move(args));
|
||||
std::string name = layout->getId() + ".open";
|
||||
lua::emit_event(lua::get_main_thread(), name, [=](auto L) {
|
||||
for (const auto& value : *argsptr) {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "delegates.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "scripting_functional.hpp"
|
||||
@ -87,15 +87,15 @@ namespace scripting {
|
||||
Player* player, const ItemDef& item, int x, int y, int z
|
||||
);
|
||||
|
||||
dynamic::Value get_component_value(
|
||||
dv::value get_component_value(
|
||||
const scriptenv& env, const std::string& name
|
||||
);
|
||||
void on_entity_spawn(
|
||||
const EntityDef& def,
|
||||
entityid_t eid,
|
||||
const std::vector<std::unique_ptr<UserComponent>>& components,
|
||||
dynamic::Map_sptr args,
|
||||
dynamic::Map_sptr saved
|
||||
dv::value args,
|
||||
dv::value saved
|
||||
);
|
||||
void on_entity_despawn(const Entity& entity);
|
||||
void on_entity_grounded(const Entity& entity, float force);
|
||||
@ -111,7 +111,7 @@ namespace scripting {
|
||||
void on_entity_used(const Entity& entity, Player* player);
|
||||
|
||||
/// @brief Called on UI view show
|
||||
void on_ui_open(UiDocument* layout, std::vector<dynamic::Value> args);
|
||||
void on_ui_open(UiDocument* layout, std::vector<dv::value> args);
|
||||
|
||||
void on_ui_progress(UiDocument* layout, int workDone, int totalWork);
|
||||
|
||||
|
||||
@ -160,7 +160,7 @@ vec2supplier scripting::create_vec2_supplier(
|
||||
};
|
||||
}
|
||||
|
||||
dynamic::to_string_func scripting::create_tostring(
|
||||
dv::to_string_func scripting::create_tostring(
|
||||
const scriptenv& env, const std::string& src, const std::string& file
|
||||
) {
|
||||
auto L = lua::get_main_thread();
|
||||
@ -168,7 +168,7 @@ dynamic::to_string_func scripting::create_tostring(
|
||||
lua::loadbuffer(L, *env, src, file);
|
||||
lua::call(L, 0, 1);
|
||||
auto func = lua::create_lambda(L);
|
||||
return [func](const dynamic::Value& value) {
|
||||
return [func](const dv::value& value) {
|
||||
auto result = func({value});
|
||||
return json::stringify(result, true, " ");
|
||||
};
|
||||
|
||||
@ -3,13 +3,12 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "delegates.hpp"
|
||||
#include "typedefs.hpp"
|
||||
|
||||
namespace scripting {
|
||||
using common_func =
|
||||
std::function<dynamic::Value(const std::vector<dynamic::Value>&)>;
|
||||
using common_func = std::function<dv::value(const std::vector<dv::value>&)>;
|
||||
|
||||
runnable create_runnable(
|
||||
const scriptenv& env,
|
||||
@ -71,7 +70,7 @@ namespace scripting {
|
||||
const std::string& file = "<string>"
|
||||
);
|
||||
|
||||
dynamic::to_string_func create_tostring(
|
||||
dv::to_string_func create_tostring(
|
||||
const scriptenv& env,
|
||||
const std::string& src,
|
||||
const std::string& file = "<string>"
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
#include "assets/Assets.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "data/dynamic_util.hpp"
|
||||
#include "data/dv_util.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
#include "engine.hpp"
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
@ -113,8 +113,8 @@ static void initialize_body(
|
||||
entityid_t Entities::spawn(
|
||||
const EntityDef& def,
|
||||
glm::vec3 position,
|
||||
dynamic::Map_sptr args,
|
||||
dynamic::Map_sptr saved,
|
||||
dv::value args,
|
||||
dv::value saved,
|
||||
entityid_t uid
|
||||
) {
|
||||
auto skeleton = level->content->getSkeleton(def.skeletonName);
|
||||
@ -166,9 +166,9 @@ entityid_t Entities::spawn(
|
||||
);
|
||||
scripting.components.emplace_back(std::move(component));
|
||||
}
|
||||
dynamic::Map_sptr componentsMap = nullptr;
|
||||
if (saved) {
|
||||
componentsMap = saved->map("comps");
|
||||
dv::value componentsMap = nullptr;
|
||||
if (saved != nullptr) {
|
||||
componentsMap = saved["comps"];
|
||||
loadEntity(saved, get(id).value());
|
||||
}
|
||||
body.hitbox.position = tsf.pos;
|
||||
@ -188,54 +188,54 @@ void Entities::despawn(entityid_t id) {
|
||||
}
|
||||
}
|
||||
|
||||
void Entities::loadEntity(const dynamic::Map_sptr& map) {
|
||||
entityid_t uid = 0;
|
||||
std::string defname;
|
||||
map->num("uid", uid);
|
||||
map->str("def", defname);
|
||||
if (uid == 0) {
|
||||
throw std::runtime_error("could not read entity - invalid UID");
|
||||
}
|
||||
void Entities::loadEntity(const dv::value& map) {
|
||||
entityid_t uid = map["uid"].asInteger();
|
||||
std::string defname = map["def"].asString();
|
||||
auto& def = level->content->entities.require(defname);
|
||||
spawn(def, {}, nullptr, map, uid);
|
||||
}
|
||||
|
||||
void Entities::loadEntity(const dynamic::Map_sptr& map, Entity entity) {
|
||||
void Entities::loadEntity(const dv::value& map, Entity entity) {
|
||||
auto& transform = entity.getTransform();
|
||||
auto& body = entity.getRigidbody();
|
||||
auto& skeleton = entity.getSkeleton();
|
||||
|
||||
if (auto bodymap = map->map(COMP_RIGIDBODY)) {
|
||||
dynamic::get_vec(bodymap, "vel", body.hitbox.velocity);
|
||||
if (map.has(COMP_RIGIDBODY)) {
|
||||
auto& bodymap = map[COMP_RIGIDBODY];
|
||||
dv::get_vec(bodymap, "vel", body.hitbox.velocity);
|
||||
std::string bodyTypeName;
|
||||
bodymap->str("type", bodyTypeName);
|
||||
map.at("type").get(bodyTypeName);
|
||||
if (auto bodyType = BodyType_from(bodyTypeName)) {
|
||||
body.hitbox.type = *bodyType;
|
||||
}
|
||||
bodymap->flag("crouch", body.hitbox.crouching);
|
||||
bodymap->num("damping", body.hitbox.linearDamping);
|
||||
bodymap["crouch"].asBoolean(body.hitbox.crouching);
|
||||
bodymap["damping"].asNumber(body.hitbox.linearDamping);
|
||||
}
|
||||
if (auto tsfmap = map->map(COMP_TRANSFORM)) {
|
||||
dynamic::get_vec(tsfmap, "pos", transform.pos);
|
||||
dynamic::get_vec(tsfmap, "size", transform.size);
|
||||
dynamic::get_mat(tsfmap, "rot", transform.rot);
|
||||
if (map.has(COMP_TRANSFORM)) {
|
||||
auto& tsfmap = map[COMP_TRANSFORM];
|
||||
dv::get_vec(tsfmap, "pos", transform.pos);
|
||||
dv::get_vec(tsfmap, "size", transform.size);
|
||||
dv::get_mat(tsfmap, "rot", transform.rot);
|
||||
}
|
||||
std::string skeletonName = skeleton.config->getName();
|
||||
map->str("skeleton", skeletonName);
|
||||
map.at("skeleton").get(skeletonName);
|
||||
if (skeletonName != skeleton.config->getName()) {
|
||||
skeleton.config = level->content->getSkeleton(skeletonName);
|
||||
}
|
||||
if (auto skeletonmap = map->map(COMP_SKELETON)) {
|
||||
if (auto texturesmap = skeletonmap->map("textures")) {
|
||||
for (auto& [slot, _] : texturesmap->values) {
|
||||
texturesmap->str(slot, skeleton.textures[slot]);
|
||||
if (auto found = map.at(COMP_SKELETON)) {
|
||||
auto& skeletonmap = *found;
|
||||
if (auto found = skeletonmap.at("textures")) {
|
||||
auto& texturesmap = *found;
|
||||
for (auto& [slot, _] : texturesmap.asObject()) {
|
||||
texturesmap.at(slot).get(skeleton.textures[slot]);
|
||||
}
|
||||
}
|
||||
if (auto posearr = skeletonmap->list("pose")) {
|
||||
if (auto found = skeletonmap.at("pose")) {
|
||||
auto& posearr = *found;
|
||||
for (size_t i = 0;
|
||||
i < std::min(skeleton.pose.matrices.size(), posearr->size());
|
||||
i < std::min(skeleton.pose.matrices.size(), posearr.size());
|
||||
i++) {
|
||||
dynamic::get_mat(posearr, i, skeleton.pose.matrices[i]);
|
||||
dv::get_mat(posearr[i], skeleton.pose.matrices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -272,12 +272,12 @@ std::optional<Entities::RaycastResult> Entities::rayCast(
|
||||
}
|
||||
}
|
||||
|
||||
void Entities::loadEntities(dynamic::Map_sptr root) {
|
||||
void Entities::loadEntities(dv::value root) {
|
||||
clean();
|
||||
auto list = root->list("data");
|
||||
for (size_t i = 0; i < list->size(); i++) {
|
||||
auto& list = root["data"];
|
||||
for (auto& map : list) {
|
||||
try {
|
||||
loadEntity(list->map(i));
|
||||
loadEntity(map);
|
||||
} catch (const std::runtime_error& err) {
|
||||
logger.error() << "could not read entity: " << err.what();
|
||||
}
|
||||
@ -288,82 +288,82 @@ void Entities::onSave(const Entity& entity) {
|
||||
scripting::on_entity_save(entity);
|
||||
}
|
||||
|
||||
dynamic::Value Entities::serialize(const Entity& entity) {
|
||||
auto root = dynamic::create_map();
|
||||
dv::value Entities::serialize(const Entity& entity) {
|
||||
auto root = dv::object();
|
||||
auto& eid = entity.getID();
|
||||
auto& def = eid.def;
|
||||
root->put("def", def.name);
|
||||
root->put("uid", eid.uid);
|
||||
root["def"] = def.name;
|
||||
root["uid"] = eid.uid;
|
||||
{
|
||||
auto& transform = entity.getTransform();
|
||||
auto& tsfmap = root->putMap(COMP_TRANSFORM);
|
||||
tsfmap.put("pos", dynamic::to_value(transform.pos));
|
||||
auto& tsfmap = root.object(COMP_TRANSFORM);
|
||||
tsfmap["pos"] = dv::to_value(transform.pos);
|
||||
if (transform.size != glm::vec3(1.0f)) {
|
||||
tsfmap.put("size", dynamic::to_value(transform.size));
|
||||
tsfmap["size"] = dv::to_value(transform.size);
|
||||
}
|
||||
if (transform.rot != glm::mat3(1.0f)) {
|
||||
tsfmap.put("rot", dynamic::to_value(transform.rot));
|
||||
tsfmap["rot"] = dv::to_value(transform.rot);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto& rigidbody = entity.getRigidbody();
|
||||
auto& hitbox = rigidbody.hitbox;
|
||||
auto& bodymap = root->putMap(COMP_RIGIDBODY);
|
||||
auto& bodymap = root.object(COMP_RIGIDBODY);
|
||||
if (!rigidbody.enabled) {
|
||||
bodymap.put("enabled", rigidbody.enabled);
|
||||
bodymap["enabled"] = false;
|
||||
}
|
||||
if (def.save.body.velocity) {
|
||||
bodymap.put("vel", dynamic::to_value(rigidbody.hitbox.velocity));
|
||||
bodymap["vel"] = dv::to_value(rigidbody.hitbox.velocity);
|
||||
}
|
||||
if (def.save.body.settings) {
|
||||
bodymap.put("damping", rigidbody.hitbox.linearDamping);
|
||||
bodymap["damping"] = rigidbody.hitbox.linearDamping;
|
||||
if (hitbox.type != def.bodyType) {
|
||||
bodymap.put("type", to_string(hitbox.type));
|
||||
bodymap["type"] = to_string(hitbox.type);
|
||||
}
|
||||
if (hitbox.crouching) {
|
||||
bodymap.put("crouch", hitbox.crouching);
|
||||
bodymap["crouch"] = hitbox.crouching;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto& skeleton = entity.getSkeleton();
|
||||
if (skeleton.config->getName() != def.skeletonName) {
|
||||
root->put("skeleton", skeleton.config->getName());
|
||||
root["skeleton"] = skeleton.config->getName();
|
||||
}
|
||||
if (def.save.skeleton.pose || def.save.skeleton.textures) {
|
||||
auto& skeletonmap = root->putMap(COMP_SKELETON);
|
||||
auto& skeletonmap = root.object(COMP_SKELETON);
|
||||
if (def.save.skeleton.textures) {
|
||||
auto& map = skeletonmap.putMap("textures");
|
||||
auto& map = skeletonmap.object("textures");
|
||||
for (auto& [slot, texture] : skeleton.textures) {
|
||||
map.put(slot, texture);
|
||||
map[slot] = texture;
|
||||
}
|
||||
}
|
||||
if (def.save.skeleton.pose) {
|
||||
auto& list = skeletonmap.putList("pose");
|
||||
auto& list = skeletonmap.list("pose");
|
||||
for (auto& mat : skeleton.pose.matrices) {
|
||||
list.put(dynamic::to_value(mat));
|
||||
list.add(dv::to_value(mat));
|
||||
}
|
||||
}
|
||||
}
|
||||
auto& scripts = entity.getScripting();
|
||||
if (!scripts.components.empty()) {
|
||||
auto& compsMap = root->putMap("comps");
|
||||
auto& compsMap = root.object("comps");
|
||||
for (auto& comp : scripts.components) {
|
||||
auto data =
|
||||
scripting::get_component_value(comp->env, SAVED_DATA_VARNAME);
|
||||
compsMap.put(comp->name, data);
|
||||
compsMap[comp->name] = data;
|
||||
}
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
dynamic::List_sptr Entities::serialize(const std::vector<Entity>& entities) {
|
||||
auto list = dynamic::create_list();
|
||||
dv::value Entities::serialize(const std::vector<Entity>& entities) {
|
||||
auto list = dv::list();
|
||||
for (auto& entity : entities) {
|
||||
if (!entity.getDef().save.enabled) {
|
||||
continue;
|
||||
}
|
||||
level->entities->onSave(entity);
|
||||
list->put(level->entities->serialize(entity));
|
||||
list.add(level->entities->serialize(entity));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "data/dv.hpp"
|
||||
#include "physics/Hitbox.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "util/Clock.hpp"
|
||||
@ -204,8 +204,8 @@ public:
|
||||
entityid_t spawn(
|
||||
const EntityDef& def,
|
||||
glm::vec3 position,
|
||||
dynamic::Map_sptr args = nullptr,
|
||||
dynamic::Map_sptr saved = nullptr,
|
||||
dv::value args = nullptr,
|
||||
dv::value saved = nullptr,
|
||||
entityid_t uid = 0
|
||||
);
|
||||
|
||||
@ -231,17 +231,17 @@ public:
|
||||
entityid_t ignore = -1
|
||||
);
|
||||
|
||||
void loadEntities(dynamic::Map_sptr map);
|
||||
void loadEntity(const dynamic::Map_sptr& map);
|
||||
void loadEntity(const dynamic::Map_sptr& map, Entity entity);
|
||||
void loadEntities(dv::value map);
|
||||
void loadEntity(const dv::value& map);
|
||||
void loadEntity(const dv::value& map, Entity entity);
|
||||
void onSave(const Entity& entity);
|
||||
bool hasBlockingInside(AABB aabb);
|
||||
std::vector<Entity> getAllInside(AABB aabb);
|
||||
std::vector<Entity> getAllInRadius(glm::vec3 center, float radius);
|
||||
void despawn(entityid_t id);
|
||||
void despawn(std::vector<Entity> entities);
|
||||
dynamic::Value serialize(const Entity& entity);
|
||||
dynamic::List_sptr serialize(const std::vector<Entity>& entities);
|
||||
dv::value serialize(const Entity& entity);
|
||||
dv::value serialize(const std::vector<Entity>& entities);
|
||||
|
||||
void setNextID(entityid_t id) {
|
||||
nextID = id;
|
||||
|
||||
@ -256,92 +256,71 @@ glm::vec3 Player::getSpawnPoint() const {
|
||||
return spawnpoint;
|
||||
}
|
||||
|
||||
std::unique_ptr<dynamic::Map> Player::serialize() const {
|
||||
auto root = std::make_unique<dynamic::Map>();
|
||||
auto& posarr = root->putList("position");
|
||||
posarr.put(position.x);
|
||||
posarr.put(position.y);
|
||||
posarr.put(position.z);
|
||||
dv::value Player::serialize() const {
|
||||
auto root = dv::object();
|
||||
|
||||
auto& rotarr = root->putList("rotation");
|
||||
rotarr.put(cam.x);
|
||||
rotarr.put(cam.y);
|
||||
rotarr.put(cam.z);
|
||||
root["position"] = dv::list({position.x, position.y, position.z});
|
||||
root["rotation"] = dv::list({cam.x, cam.y, cam.z});
|
||||
root["spawnpoint"] = dv::list({spawnpoint.x, spawnpoint.y, spawnpoint.z});
|
||||
|
||||
auto& sparr = root->putList("spawnpoint");
|
||||
sparr.put(spawnpoint.x);
|
||||
sparr.put(spawnpoint.y);
|
||||
sparr.put(spawnpoint.z);
|
||||
|
||||
root->put("flight", flight);
|
||||
root->put("noclip", noclip);
|
||||
root->put("chosen-slot", chosenSlot);
|
||||
root->put("entity", eid);
|
||||
root->put("inventory", inventory->serialize());
|
||||
root["flight"] = flight;
|
||||
root["noclip"] = noclip;
|
||||
root["chosen-slot"] = chosenSlot;
|
||||
root["entity"] = eid;
|
||||
root["inventory"] = inventory->serialize();
|
||||
auto found =
|
||||
std::find(level->cameras.begin(), level->cameras.end(), currentCamera);
|
||||
if (found != level->cameras.end()) {
|
||||
root->put(
|
||||
"camera",
|
||||
level->content->getIndices(ResourceType::CAMERA)
|
||||
.getName(found - level->cameras.begin())
|
||||
);
|
||||
root["camera"] = level->content->getIndices(ResourceType::CAMERA)
|
||||
.getName(found - level->cameras.begin());
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
void Player::deserialize(dynamic::Map* src) {
|
||||
auto posarr = src->list("position");
|
||||
position.x = posarr->num(0);
|
||||
position.y = posarr->num(1);
|
||||
position.z = posarr->num(2);
|
||||
void Player::deserialize(const dv::value& src) {
|
||||
const auto& posarr = src["position"];
|
||||
position.x = posarr[0].asNumber();
|
||||
position.y = posarr[1].asNumber();
|
||||
position.z = posarr[2].asNumber();
|
||||
camera->position = position;
|
||||
|
||||
auto rotarr = src->list("rotation");
|
||||
cam.x = rotarr->num(0);
|
||||
cam.y = rotarr->num(1);
|
||||
if (rotarr->size() > 2) {
|
||||
cam.z = rotarr->num(2);
|
||||
const auto& rotarr = src["rotation"];
|
||||
cam.x = rotarr[0].asNumber();
|
||||
cam.y = rotarr[1].asNumber();
|
||||
cam.z = rotarr[2].asNumber();
|
||||
|
||||
const auto& sparr = src["spawnpoint"];
|
||||
setSpawnPoint(glm::vec3(
|
||||
sparr[0].asNumber(), sparr[1].asNumber(), sparr[2].asNumber()));
|
||||
|
||||
flight = src["flight"].asBoolean();
|
||||
noclip = src["noclip"].asBoolean();
|
||||
setChosenSlot(src["chosen-slot"].asInteger());
|
||||
eid = src["entity"].asNumber();
|
||||
|
||||
if (src.has("inventory")) {
|
||||
getInventory()->deserialize(src["inventory"]);
|
||||
}
|
||||
|
||||
if (src->has("spawnpoint")) {
|
||||
auto sparr = src->list("spawnpoint");
|
||||
setSpawnPoint(glm::vec3(sparr->num(0), sparr->num(1), sparr->num(2)));
|
||||
} else {
|
||||
setSpawnPoint(position);
|
||||
}
|
||||
|
||||
src->flag("flight", flight);
|
||||
src->flag("noclip", noclip);
|
||||
setChosenSlot(src->get("chosen-slot", getChosenSlot()));
|
||||
src->num("entity", eid);
|
||||
|
||||
if (auto invmap = src->map("inventory")) {
|
||||
getInventory()->deserialize(invmap.get());
|
||||
}
|
||||
|
||||
if (src->has("camera")) {
|
||||
std::string name;
|
||||
src->str("camera", name);
|
||||
if (src.has("camera")) {
|
||||
std::string name = src["camera"].asString();
|
||||
if (auto camera = level->getCamera(name)) {
|
||||
currentCamera = camera;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::convert(dynamic::Map* data, const ContentLUT* lut) {
|
||||
auto players = data->list("players");
|
||||
if (players) {
|
||||
for (uint i = 0; i < players->size(); i++) {
|
||||
auto playerData = players->map(i);
|
||||
if (auto inventory = playerData->map("inventory")) {
|
||||
Inventory::convert(inventory.get(), lut);
|
||||
void Player::convert(dv::value& data, const ContentLUT* lut) {
|
||||
if (data.has("players")) {
|
||||
auto& players = data["players"];
|
||||
for (uint i = 0; i < players.size(); i++) {
|
||||
auto& playerData = players[i];
|
||||
if (playerData.has("inventory")) {
|
||||
Inventory::convert(playerData["inventory"], lut);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (auto inventory = data->map("inventory")) {
|
||||
Inventory::convert(inventory.get(), lut);
|
||||
}
|
||||
} else if (data.has("inventory")){
|
||||
Inventory::convert(data["inventory"], lut);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "interfaces/Object.hpp"
|
||||
#include "interfaces/Serializable.hpp"
|
||||
#include "settings.hpp"
|
||||
@ -103,10 +102,10 @@ public:
|
||||
void setSpawnPoint(glm::vec3 point);
|
||||
glm::vec3 getSpawnPoint() const;
|
||||
|
||||
std::unique_ptr<dynamic::Map> serialize() const override;
|
||||
void deserialize(dynamic::Map* src) override;
|
||||
dv::value serialize() const override;
|
||||
void deserialize(const dv::value& src) override;
|
||||
|
||||
static void convert(dynamic::Map* data, const ContentLUT* lut);
|
||||
static void convert(dv::value& data, const ContentLUT* lut);
|
||||
|
||||
inline int getId() const {
|
||||
return objectUID;
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
#include "assets/Assets.hpp"
|
||||
#include "coders/json.hpp"
|
||||
#include "data/dynamic_util.hpp"
|
||||
#include "data/dv_util.hpp"
|
||||
#include "graphics/core/Model.hpp"
|
||||
#include "graphics/render/ModelBatch.hpp"
|
||||
|
||||
@ -139,25 +139,23 @@ Bone* SkeletonConfig::find(std::string_view str) const {
|
||||
}
|
||||
|
||||
static std::tuple<size_t, std::unique_ptr<Bone>> read_node(
|
||||
const dynamic::Map_sptr& root, size_t index
|
||||
const dv::value& root, size_t index
|
||||
) {
|
||||
std::string name;
|
||||
std::string model;
|
||||
root->str("name", name);
|
||||
root->str("model", model);
|
||||
|
||||
root.at("name").get(name);
|
||||
root.at("model").get(model);
|
||||
glm::vec3 offset(0.0f);
|
||||
dynamic::get_vec(root, "offset", offset);
|
||||
dv::get_vec(root, "offset", offset);
|
||||
|
||||
std::vector<std::unique_ptr<Bone>> bones;
|
||||
size_t count = 1;
|
||||
if (auto nodesList = root->list("nodes")) {
|
||||
for (size_t i = 0; i < nodesList->size(); i++) {
|
||||
if (const auto& map = nodesList->map(i)) {
|
||||
auto [subcount, subNode] = read_node(map, index + count);
|
||||
count += subcount;
|
||||
bones.push_back(std::move(subNode));
|
||||
}
|
||||
if (auto found = root.at("nodes")) {
|
||||
const auto& nodesList = *found;
|
||||
for (const auto& map : nodesList) {
|
||||
auto [subcount, subNode] = read_node(map, index + count);
|
||||
count += subcount;
|
||||
bones.push_back(std::move(subNode));
|
||||
}
|
||||
}
|
||||
return {
|
||||
@ -169,10 +167,7 @@ std::unique_ptr<SkeletonConfig> SkeletonConfig::parse(
|
||||
std::string_view src, std::string_view file, std::string_view name
|
||||
) {
|
||||
auto root = json::parse(file, src);
|
||||
auto rootNodeMap = root->map("root");
|
||||
if (rootNodeMap == nullptr) {
|
||||
throw std::runtime_error("missing 'root' element");
|
||||
}
|
||||
auto rootNodeMap = root["root"];
|
||||
auto [count, rootNode] = read_node(rootNodeMap, 0);
|
||||
return std::make_unique<SkeletonConfig>(
|
||||
std::string(name), std::move(rootNode), count
|
||||
|
||||
@ -15,10 +15,6 @@ class Lightmap;
|
||||
class ContentLUT;
|
||||
class Inventory;
|
||||
|
||||
namespace dynamic {
|
||||
class Map;
|
||||
}
|
||||
|
||||
using chunk_inventories_map =
|
||||
std::unordered_map<uint, std::shared_ptr<Inventory>>;
|
||||
|
||||
|
||||
@ -746,8 +746,8 @@ void Chunks::save(Chunk* chunk) {
|
||||
)
|
||||
);
|
||||
auto entities = level->entities->getAllInside(aabb);
|
||||
auto root = dynamic::create_map();
|
||||
root->put("data", level->entities->serialize(entities));
|
||||
auto root = dv::object();
|
||||
root["data"] = level->entities->serialize(entities);
|
||||
if (!entities.empty()) {
|
||||
level->entities->despawn(std::move(entities));
|
||||
chunk->flags.entities = true;
|
||||
|
||||
@ -66,8 +66,9 @@ std::shared_ptr<Chunk> ChunksStorage::create(int x, int z) {
|
||||
auto invs = regions.fetchInventories(chunk->x, chunk->z);
|
||||
chunk->setBlockInventories(std::move(invs));
|
||||
|
||||
if (auto map = regions.fetchEntities(chunk->x, chunk->z)) {
|
||||
level->entities->loadEntities(std::move(map));
|
||||
auto entitiesData = regions.fetchEntities(chunk->x, chunk->z);
|
||||
if (entitiesData.getType() == dv::value_type::object) {
|
||||
level->entities->loadEntities(std::move(entitiesData));
|
||||
chunk->flags.entities = true;
|
||||
}
|
||||
|
||||
|
||||
@ -167,10 +167,9 @@ void Events::setPosition(float xpos, float ypos) {
|
||||
|
||||
#include "coders/json.hpp"
|
||||
#include "coders/toml.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
|
||||
std::string Events::writeBindings() {
|
||||
dynamic::Map obj;
|
||||
auto obj = dv::object();
|
||||
for (auto& entry : Events::bindings) {
|
||||
const auto& binding = entry.second;
|
||||
std::string value;
|
||||
@ -188,7 +187,7 @@ std::string Events::writeBindings() {
|
||||
default:
|
||||
throw std::runtime_error("unsupported control type");
|
||||
}
|
||||
obj.put(entry.first, value);
|
||||
obj[entry.first] = std::move(value);
|
||||
}
|
||||
return toml::stringify(obj);
|
||||
}
|
||||
@ -197,26 +196,22 @@ void Events::loadBindings(
|
||||
const std::string& filename, const std::string& source
|
||||
) {
|
||||
auto map = toml::parse(filename, source);
|
||||
for (auto& entry : map->values) {
|
||||
if (auto value = std::get_if<std::string>(&entry.second)) {
|
||||
auto [prefix, codename] = util::split_at(*value, ':');
|
||||
inputtype type;
|
||||
int code;
|
||||
if (prefix == "key") {
|
||||
type = inputtype::keyboard;
|
||||
code = static_cast<int>(input_util::keycode_from(codename));
|
||||
} else if (prefix == "mouse") {
|
||||
type = inputtype::mouse;
|
||||
code = static_cast<int>(input_util::mousecode_from(codename));
|
||||
} else {
|
||||
logger.error()
|
||||
<< "unknown input type: " << prefix << " (binding "
|
||||
<< util::quote(entry.first) << ")";
|
||||
continue;
|
||||
}
|
||||
Events::bind(entry.first, type, code);
|
||||
for (auto& [key, value] : map.asObject()) {
|
||||
auto [prefix, codename] = util::split_at(value.asString(), ':');
|
||||
inputtype type;
|
||||
int code;
|
||||
if (prefix == "key") {
|
||||
type = inputtype::keyboard;
|
||||
code = static_cast<int>(input_util::keycode_from(codename));
|
||||
} else if (prefix == "mouse") {
|
||||
type = inputtype::mouse;
|
||||
code = static_cast<int>(input_util::mousecode_from(codename));
|
||||
} else {
|
||||
logger.error() << "invalid binding entry: " << entry.first;
|
||||
logger.error()
|
||||
<< "unknown input type: " << prefix << " (binding "
|
||||
<< util::quote(key) << ")";
|
||||
continue;
|
||||
}
|
||||
Events::bind(key, type, code);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#include "Level.hpp"
|
||||
|
||||
#include "content/Content.hpp"
|
||||
#include "data/dynamic_util.hpp"
|
||||
#include "data/dv_util.hpp"
|
||||
#include "items/Inventories.hpp"
|
||||
#include "items/Inventory.hpp"
|
||||
#include "lighting/Lighting.hpp"
|
||||
@ -33,14 +33,15 @@ Level::Level(
|
||||
auto& cameraIndices = content->getIndices(ResourceType::CAMERA);
|
||||
for (size_t i = 0; i < cameraIndices.size(); i++) {
|
||||
auto camera = std::make_shared<Camera>();
|
||||
if (auto map = cameraIndices.getSavedData(i)) {
|
||||
dynamic::get_vec(map, "pos", camera->position);
|
||||
dynamic::get_mat(map, "rot", camera->rotation);
|
||||
map->flag("perspective", camera->perspective);
|
||||
map->flag("flipped", camera->flipped);
|
||||
map->num("zoom", camera->zoom);
|
||||
auto map = cameraIndices.getSavedData(i);
|
||||
if (map != nullptr) {
|
||||
dv::get_vec(map, "pos", camera->position);
|
||||
dv::get_mat(map, "rot", camera->rotation);
|
||||
map.at("perspective").get(camera->perspective);
|
||||
map.at("flipped").get(camera->flipped);
|
||||
map.at("zoom").get(camera->zoom);
|
||||
float fov = camera->getFov();
|
||||
map->num("fov", fov);
|
||||
map.at("fov").get(fov);
|
||||
camera->setFov(fov);
|
||||
}
|
||||
camera->updateVectors();
|
||||
@ -99,13 +100,13 @@ void Level::onSave() {
|
||||
auto& cameraIndices = content->getIndices(ResourceType::CAMERA);
|
||||
for (size_t i = 0; i < cameraIndices.size(); i++) {
|
||||
auto& camera = *cameras.at(i);
|
||||
auto map = dynamic::create_map();
|
||||
map->put("pos", dynamic::to_value(camera.position));
|
||||
map->put("rot", dynamic::to_value(camera.rotation));
|
||||
map->put("perspective", camera.perspective);
|
||||
map->put("flipped", camera.flipped);
|
||||
map->put("zoom", camera.zoom);
|
||||
map->put("fov", camera.getFov());
|
||||
auto map = dv::object();
|
||||
map["pos"] = dv::to_value(camera.position);
|
||||
map["rot"] = dv::to_value(camera.rotation);
|
||||
map["perspective"] = camera.perspective;
|
||||
map["flipped"] = camera.flipped;
|
||||
map["zoom"] = camera.zoom;
|
||||
map["fov"] = camera.getFov();
|
||||
cameraIndices.saveData(i, std::move(map));
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,20 +45,21 @@ void World::updateTimers(float delta) {
|
||||
}
|
||||
|
||||
void World::writeResources(const Content* content) {
|
||||
auto root = dynamic::Map();
|
||||
auto root = dv::object();
|
||||
for (size_t typeIndex = 0; typeIndex < RESOURCE_TYPES_COUNT; typeIndex++) {
|
||||
auto typeName = to_string(static_cast<ResourceType>(typeIndex));
|
||||
auto& list = root.putList(typeName);
|
||||
auto& list = root.list(typeName);
|
||||
auto& indices = content->resourceIndices[typeIndex];
|
||||
for (size_t i = 0; i < indices.size(); i++) {
|
||||
auto& map = list.putMap();
|
||||
map.put("name", indices.getName(i));
|
||||
if (auto data = indices.getSavedData(i)) {
|
||||
map.put("saved", data);
|
||||
auto& map = list.object();
|
||||
map["name"] = indices.getName(i);
|
||||
auto data = indices.getSavedData(i);
|
||||
if (data != nullptr) {
|
||||
map["saved"] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
files::write_json(wfile->getResourcesFile(), &root);
|
||||
files::write_json(wfile->getResourcesFile(), root);
|
||||
}
|
||||
|
||||
void World::write(Level* level) {
|
||||
@ -67,14 +68,14 @@ void World::write(Level* level) {
|
||||
info.nextEntityId = level->entities->peekNextID();
|
||||
wfile->write(this, content);
|
||||
|
||||
auto playerFile = dynamic::Map();
|
||||
auto& players = playerFile.putList("players");
|
||||
auto playerFile = dv::object();
|
||||
auto& players = playerFile.list("players");
|
||||
for (const auto& object : level->objects) {
|
||||
if (auto player = std::dynamic_pointer_cast<Player>(object)) {
|
||||
players.put(player->serialize());
|
||||
players.add(player->serialize());
|
||||
}
|
||||
}
|
||||
files::write_json(wfile->getPlayerFile(), &playerFile);
|
||||
files::write_json(wfile->getPlayerFile(), playerFile);
|
||||
|
||||
writeResources(content);
|
||||
}
|
||||
@ -129,11 +130,11 @@ std::unique_ptr<Level> World::load(
|
||||
if (!fs::is_regular_file(file)) {
|
||||
logger.warning() << "player.json does not exists";
|
||||
} else {
|
||||
auto playerFile = files::read_json(file);
|
||||
if (playerFile->has("players")) {
|
||||
auto playerRoot = files::read_json(file);
|
||||
if (playerRoot.has("players")) {
|
||||
level->objects.clear();
|
||||
auto players = playerFile->list("players");
|
||||
for (size_t i = 0; i < players->size(); i++) {
|
||||
const auto& players = playerRoot["players"];
|
||||
for (auto& playerMap : players) {
|
||||
auto player = level->spawnObject<Player>(
|
||||
level.get(),
|
||||
glm::vec3(0, DEF_PLAYER_Y, 0),
|
||||
@ -141,12 +142,12 @@ std::unique_ptr<Level> World::load(
|
||||
level->inventories->create(DEF_PLAYER_INVENTORY_SIZE),
|
||||
0
|
||||
);
|
||||
player->deserialize(players->map(i).get());
|
||||
player->deserialize(playerMap);
|
||||
level->inventories->store(player->getInventory());
|
||||
}
|
||||
} else {
|
||||
auto player = level->getObject<Player>(0);
|
||||
player->deserialize(playerFile.get());
|
||||
player->deserialize(playerRoot);
|
||||
level->inventories->store(player->getInventory());
|
||||
}
|
||||
}
|
||||
@ -199,50 +200,52 @@ const std::vector<ContentPack>& World::getPacks() const {
|
||||
return packs;
|
||||
}
|
||||
|
||||
void WorldInfo::deserialize(dynamic::Map* root) {
|
||||
name = root->get("name", name);
|
||||
generator = root->get("generator", generator);
|
||||
seed = root->get("seed", seed);
|
||||
void WorldInfo::deserialize(const dv::value& root) {
|
||||
name = root["name"].asString();
|
||||
generator = root["generator"].asString(generator);
|
||||
seed = root["seed"].asInteger(seed);
|
||||
|
||||
if (generator.empty()) {
|
||||
generator = WorldGenerators::getDefaultGeneratorID();
|
||||
}
|
||||
if (auto verobj = root->map("version")) {
|
||||
verobj->num("major", major);
|
||||
verobj->num("minor", minor);
|
||||
if (root.has("version")) {
|
||||
auto& verobj = root["version"];
|
||||
major = verobj["major"].asInteger();
|
||||
minor = verobj["minor"].asInteger();
|
||||
}
|
||||
if (auto timeobj = root->map("time")) {
|
||||
timeobj->num("day-time", daytime);
|
||||
timeobj->num("day-time-speed", daytimeSpeed);
|
||||
timeobj->num("total-time", totalTime);
|
||||
if (root.has("time")) {
|
||||
auto& timeobj = root["time"];
|
||||
daytime = timeobj["day-time"].asNumber();
|
||||
daytimeSpeed = timeobj["day-time-speed"].asNumber();
|
||||
totalTime = timeobj["total-time"].asNumber();
|
||||
}
|
||||
if (auto weatherobj = root->map("weather")) {
|
||||
weatherobj->num("fog", fog);
|
||||
if (root.has("weather")) {
|
||||
fog = root["weather"]["fog"].asNumber();
|
||||
}
|
||||
nextInventoryId = root->get("next-inventory-id", 2);
|
||||
nextEntityId = root->get("next-entity-id", 1);
|
||||
nextInventoryId = root["next-inventory-id"].asInteger(2);
|
||||
nextEntityId = root["next-entity-id"].asInteger(1);
|
||||
}
|
||||
|
||||
std::unique_ptr<dynamic::Map> WorldInfo::serialize() const {
|
||||
auto root = std::make_unique<dynamic::Map>();
|
||||
dv::value WorldInfo::serialize() const {
|
||||
auto root = dv::object();
|
||||
|
||||
auto& versionobj = root->putMap("version");
|
||||
versionobj.put("major", ENGINE_VERSION_MAJOR);
|
||||
versionobj.put("minor", ENGINE_VERSION_MINOR);
|
||||
auto& versionobj = root.object("version");
|
||||
versionobj["major"] = ENGINE_VERSION_MAJOR;
|
||||
versionobj["minor"] = ENGINE_VERSION_MINOR;
|
||||
|
||||
root->put("name", name);
|
||||
root->put("generator", generator);
|
||||
root->put("seed", static_cast<integer_t>(seed));
|
||||
root["name"] = name;
|
||||
root["generator"] = generator;
|
||||
root["seed"] = seed;
|
||||
|
||||
auto& timeobj = root->putMap("time");
|
||||
timeobj.put("day-time", daytime);
|
||||
timeobj.put("day-time-speed", daytimeSpeed);
|
||||
timeobj.put("total-time", totalTime);
|
||||
auto& timeobj = root.object("time");
|
||||
timeobj["day-time"] = daytime;
|
||||
timeobj["day-time-speed"] = daytimeSpeed;
|
||||
timeobj["total-time"] = totalTime;
|
||||
|
||||
auto& weatherobj = root->putMap("weather");
|
||||
weatherobj.put("fog", fog);
|
||||
auto& weatherobj = root.object("weather");
|
||||
weatherobj["fog"] = fog;
|
||||
|
||||
root->put("next-inventory-id", nextInventoryId);
|
||||
root->put("next-entity-id", nextEntityId);
|
||||
root["next-inventory-id"] = nextInventoryId;
|
||||
root["next-entity-id"] = nextEntityId;
|
||||
return root;
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "content/ContentPack.hpp"
|
||||
#include "data/dynamic.hpp"
|
||||
#include "interfaces/Serializable.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "util/timeutil.hpp"
|
||||
@ -48,8 +47,8 @@ struct WorldInfo : public Serializable {
|
||||
|
||||
int major = 0, minor = -1;
|
||||
|
||||
std::unique_ptr<dynamic::Map> serialize() const override;
|
||||
void deserialize(dynamic::Map* src) override;
|
||||
dv::value serialize() const override;
|
||||
void deserialize(const dv::value& src) override;
|
||||
};
|
||||
|
||||
/// @brief holds all world data except the level (chunks and objects)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "data/dynamic.hpp"
|
||||
#include "util/Buffer.hpp"
|
||||
#include "coders/binary_json.hpp"
|
||||
|
||||
TEST(BJSON, EncodeDecode) {
|
||||
@ -8,41 +8,7 @@ TEST(BJSON, EncodeDecode) {
|
||||
const int bytesSize = 5000;
|
||||
const int year = 2019;
|
||||
const float score = 3.141592;
|
||||
dynamic::ByteBuffer srcBytes(bytesSize);
|
||||
for (int i = 0; i < bytesSize; i ++) {
|
||||
srcBytes[i] = rand();
|
||||
}
|
||||
|
||||
std::vector<ubyte> bjsonBytes;
|
||||
{
|
||||
dynamic::Map map;
|
||||
map.put("name", name);
|
||||
map.put("year", year);
|
||||
map.put("score", score);
|
||||
map.put("data", &srcBytes);
|
||||
|
||||
bjsonBytes = json::to_binary(&map, false);
|
||||
}
|
||||
{
|
||||
auto map = json::from_binary(bjsonBytes.data(), bjsonBytes.size());
|
||||
EXPECT_EQ(map->get<std::string>("name"), name);
|
||||
EXPECT_EQ(map->get<integer_t>("year"), year);
|
||||
EXPECT_FLOAT_EQ(map->get<number_t>("score"), score);
|
||||
auto bytesptr = map->bytes("data");
|
||||
const auto& bytes = *bytesptr;
|
||||
EXPECT_EQ(bytes.size(), bytesSize);
|
||||
for (int i = 0; i < bytesSize; i++) {
|
||||
EXPECT_EQ(bytes[i], srcBytes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BJSON, EncodeDecodeDV) {
|
||||
const std::string name = "JSON-encoder";
|
||||
const int bytesSize = 5000;
|
||||
const int year = 2019;
|
||||
const float score = 3.141592;
|
||||
dynamic::ByteBuffer srcBytes(bytesSize);
|
||||
dv::objects::Bytes srcBytes(bytesSize);
|
||||
for (int i = 0; i < bytesSize; i ++) {
|
||||
srcBytes[i] = rand();
|
||||
}
|
||||
@ -55,10 +21,10 @@ TEST(BJSON, EncodeDecodeDV) {
|
||||
object["score"] = score;
|
||||
object["data"] = srcBytes;
|
||||
|
||||
bjsonBytes = json::to_binaryDV(object, false);
|
||||
bjsonBytes = json::to_binary(object, false);
|
||||
}
|
||||
{
|
||||
auto object = json::from_binaryDV(bjsonBytes.data(), bjsonBytes.size());
|
||||
auto object = json::from_binary(bjsonBytes.data(), bjsonBytes.size());
|
||||
|
||||
EXPECT_EQ(object["name"].asString(), name);
|
||||
EXPECT_EQ(object["year"].asInteger(), year);
|
||||
|
||||
@ -8,42 +8,7 @@ TEST(JSON, EncodeDecode) {
|
||||
const int bytesSize = 20;
|
||||
const int year = 2019;
|
||||
const float score = 3.141592;
|
||||
dynamic::ByteBuffer srcBytes(bytesSize);
|
||||
for (int i = 0; i < bytesSize; i ++) {
|
||||
srcBytes[i] = rand();
|
||||
}
|
||||
|
||||
std::string text;
|
||||
{
|
||||
dynamic::Map map;
|
||||
map.put("name", name);
|
||||
map.put("year", year);
|
||||
map.put("score", score);
|
||||
map.put("data", &srcBytes);
|
||||
|
||||
text = json::stringify(&map, false, "");
|
||||
}
|
||||
{
|
||||
auto map = json::parse(text);
|
||||
EXPECT_EQ(map->get<std::string>("name"), name);
|
||||
EXPECT_EQ(map->get<integer_t>("year"), year);
|
||||
EXPECT_FLOAT_EQ(map->get<number_t>("score"), score);
|
||||
auto b64string = map->get<std::string>("data");
|
||||
|
||||
auto bytes = util::base64_decode(b64string);
|
||||
EXPECT_EQ(bytes.size(), bytesSize);
|
||||
for (int i = 0; i < bytesSize; i++) {
|
||||
EXPECT_EQ(bytes[i], srcBytes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(JSON, EncodeDecodeDV) {
|
||||
const std::string name = "JSON-encoder";
|
||||
const int bytesSize = 20;
|
||||
const int year = 2019;
|
||||
const float score = 3.141592;
|
||||
dynamic::ByteBuffer srcBytes(bytesSize);
|
||||
dv::objects::Bytes srcBytes(bytesSize);
|
||||
for (int i = 0; i < bytesSize; i ++) {
|
||||
srcBytes[i] = rand();
|
||||
}
|
||||
@ -56,10 +21,10 @@ TEST(JSON, EncodeDecodeDV) {
|
||||
object["score"] = score;
|
||||
object["data"] = srcBytes;
|
||||
|
||||
text = json::stringifyDV(object, false, "");
|
||||
text = json::stringify(object, false, "");
|
||||
}
|
||||
{
|
||||
auto object = json::parseDV(text);
|
||||
auto object = json::parse(text);
|
||||
EXPECT_EQ(object["name"].asString(), name);
|
||||
EXPECT_EQ(object["year"].asInteger(), year);
|
||||
EXPECT_FLOAT_EQ(object["score"].asNumber(), score);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user