Merge branch 'MihailRis:main' into main

This commit is contained in:
Astazium 2026-07-24 11:10:21 +03:00 • committed by GitHub
commit b7295da941
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 477 additions and 28 deletions

View file

@ -57,3 +57,7 @@ std::string parsing_error::errorLog() const {
ss << "^";
return ss.str();
}
std::runtime_error parsing_error::toRuntimeError() const {
return std::runtime_error("parsing error: " + errorLog());
}

View file

@ -73,4 +73,6 @@ public:
uint linestart
);
std::string errorLog() const;
std::runtime_error toRuntimeError() const;
};

View file

@ -385,10 +385,22 @@ public:
}
if (c == '(') {
nextChar();
// TODO: replace with array parsing after moving to dv::value's
std::string value = std::string(readUntil(')'));
int depth = 1;
size_t start = pos;
while (hasNext()) {
char c = nextChar();
if (c == '(') {
depth++;
} else if (c == ')') {
depth--;
if (depth == 0) {
goBack(1);
break;
}
}
}
expect(')');
return value;
return std::string(source.substr(start, pos - start - 1));
}
return std::string(readUntilWhitespace());
}
@ -528,3 +540,11 @@ std::string xml::stringify(
return ss.str();
}
std::string xml::stringify(
const Node& element, bool nice, const std::string& indentStr
) {
std::stringstream ss;
stringifyElement(ss, element, nice, indentStr, 0);
return ss.str();
}

View file

@ -119,6 +119,12 @@ namespace xml {
const std::string& indentStr = " "
);
std::string stringify(
const Node& element,
bool nice = true,
const std::string& indentStr = " "
);
/// @brief Read XML Document from string
/// @param filename file name will be shown in error messages
/// @param source xml source code string

View file

@ -178,7 +178,16 @@ void ContentUnitLoader<DefT>::loadUnit(
) {
auto folder = pack.folder;
auto configFile = folder / (defsDir + "/" + name + ".json");
if (io::exists(configFile)) loadUnit(def, full, configFile);
if (io::exists(configFile)) {
try {
loadUnit(def, full, configFile);
} catch (const std::runtime_error& err) {
throw std::runtime_error(
"file " + util::quote(configFile.string()) + ": " +
std::string(err.what())
);
}
}
}
void ContentLoader::loadBlockMaterial(

View file

@ -53,6 +53,9 @@ static void load_variant(
}
} else if (root.has("texture-faces")) {
const auto& texarr = root["texture-faces"];
if (texarr.length() < 6) {
throw std::runtime_error("texture-faces requires 6 elements");
}
for (uint i = 0; i < 6; i++) {
variant.textureFaces[i] = texarr[i].asString();
}

View file

@ -9,8 +9,8 @@ class Font;
struct FontMetrics {
std::optional<std::weak_ptr<Font>> font;
int lineHeight;
int yoffset;
int lineHeight = 0;
int yoffset = 0;
int _glyphInterval = 8;
~FontMetrics();

View file

@ -207,6 +207,9 @@ uint Label::getLinesNumber() const {
void Label::draw(const DrawContext& pctx, const Assets& assets) {
auto batch = pctx.getBatch2D();
auto font = assets.getShared<Font>(fontName);
if (font == nullptr) {
return;
}
cache.prepare(
font,
font->getMetrics(),

View file

@ -353,7 +353,9 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
void TextBox::drawBackground(const DrawContext& pctx, const Assets& assets) {
auto font = assets.getShared<Font>(label->getFontName());
rawTextCache.prepare(font, font->getMetrics(), label->getSize().x);
if (font != nullptr) {
rawTextCache.prepare(font, font->getMetrics(), label->getSize().x);
}
glm::vec2 pos = calcPos();

View file

@ -173,8 +173,12 @@ bool io::write_binary_json(
}
dv::value io::read_json(const path& filename) {
std::string text = io::read_string(filename);
return json::parse(filename.string(), text);
auto text = io::read_string(filename);
try {
return json::parse(filename.string(), text);
} catch (const parsing_error& err) {
throw err.toRuntimeError();
}
}
dv::value io::read_binary_json(const path& file) {
@ -184,7 +188,12 @@ dv::value io::read_binary_json(const path& file) {
}
dv::value io::read_toml(const path& file) {
return toml::parse(file.string(), io::read_string(file));
auto text = io::read_string(file);
try {
return toml::parse(file.string(), text);
} catch (const parsing_error& err) {
throw err.toRuntimeError();
}
}
std::vector<std::string> io::read_list(const io::path& filename) {

View file

@ -53,6 +53,7 @@ extern const luaL_Reg vec3lib[]; // vecn.cpp
extern const luaL_Reg vec4lib[]; // vecn.cpp
extern const luaL_Reg weatherlib[]; // gfx.weather
extern const luaL_Reg worldlib[];
extern const luaL_Reg xmllib[];
extern const luaL_Reg yamllib[];
// Components

View file

@ -50,6 +50,13 @@ static int l_def_hitbox(lua::State* L) {
return 0;
}
static int l_def_solid(lua::State* L) {
if (auto def = require_entity_def(L)) {
return lua::pushboolean(L, def->solid);
}
return 0;
}
static int l_defs_count(lua::State* L) {
return lua::pushinteger(L, indices->entities.count());
}
@ -376,6 +383,7 @@ const luaL_Reg entitylib[] = {
{"def_index", lua::wrap<l_def_index>},
{"def_name", lua::wrap<l_def_name>},
{"def_hitbox", lua::wrap<l_def_hitbox>},
{"def_solid", lua::wrap<l_def_solid>},
{"get_def", lua::wrap<l_get_def>},
{"defs_count", lua::wrap<l_defs_count>},
{"spawn", lua::wrap<l_spawn>},

View file

@ -1,4 +1,5 @@
#include "coders/json.hpp"
#include "coders/commons.hpp"
#include "api_lua.hpp"
static int l_json_stringify(lua::State* L) {
@ -12,8 +13,12 @@ static int l_json_stringify(lua::State* L) {
static int l_json_parse(lua::State* L) {
auto string = lua::require_string(L, 1);
auto element = json::parse("[string]", string);
return lua::pushvalue(L, element);
try {
auto element = json::parse("[string]", string);
return lua::pushvalue(L, element);
} catch (const parsing_error& err) {
throw err.toRuntimeError();
}
}
const luaL_Reg jsonlib[] = {

View file

@ -1,4 +1,5 @@
#include "coders/toml.hpp"
#include "coders/commons.hpp"
#include "api_lua.hpp"
using namespace scripting;
@ -16,8 +17,12 @@ 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);
return lua::pushvalue(L, element);
try {
auto element = toml::parse("[string]", string);
return lua::pushvalue(L, element);
} catch (const parsing_error& err) {
throw err.toRuntimeError();
}
}
const luaL_Reg tomllib[] = {

View file

@ -0,0 +1,114 @@
#include "coders/xml.hpp"
#include "coders/commons.hpp"
#include "api_lua.hpp"
static const char* TAG_ATTR = "#";
static int push_xml(lua::State* L, const xml::xmlelement& elem) {
if (elem.isText()) {
return lua::pushlstring(L, elem.getInnerText());
}
const auto& attrs = elem.getAttributes();
const auto& elems = elem.getElements();
const auto& tag = elem.getTag();
lua::createtable(L, elem.size(), attrs.size() + 1);
lua::pushlstring(L, tag);
lua::setfield(L, TAG_ATTR);
for (int i = 0; i < elems.size(); i++) {
push_xml(L, *elems[i]);
lua::rawseti(L, i + 1);
}
for (const auto& [key, value] : attrs) {
lua::pushlstring(L, value.getText());
lua::setfield(L, key);
}
return 1;
}
static std::unique_ptr<xml::xmlelement> toxml(lua::State* L) {
lua::getfield(L, TAG_ATTR);
auto tag = lua::require_lstring(L, -1);
lua::pop(L);
auto elem = std::make_unique<xml::xmlelement>(std::string(tag));
int length = lua::objlen(L, -1);
for (int i = 0; i < length; i++) {
lua::rawgeti(L, i + 1);
elem->add(toxml(L));
lua::pop(L);
}
lua::pushnil(L);
while (lua::next(L, -2)) {
lua::pushvalue(L, -2);
do {
if (!lua::isstring(L, -1)) {
break;
}
auto key = lua::require_lstring(L, -1);
if (key == "@") {
break;
}
auto value = lua::require_lstring(L, -2);
elem->set(std::string(key), std::string(value));
} while (false);
lua::pop(L, 2);
}
return elem;
}
static int l_tostring(lua::State* L) {
bool nice = lua::isboolean(L, 2) ? lua::toboolean(L, 2) : true;
lua::pushvalue(L, 1);
auto xml = toxml(L);
lua::pop(L);
return lua::pushstring(L, xml::stringify(*xml, nice));
}
static int l_parse(lua::State* L) {
auto string = lua::require_string(L, 1);
try {
auto document = xml::parse("[string]", string);
return push_xml(L, *document->getRoot());
} catch (const parsing_error& err) {
throw err.toRuntimeError();
}
}
static int l_parse_vcd(lua::State* L) {
auto string = lua::require_string(L, 1);
auto rootTag = lua::tostring(L, 2);
std::unique_ptr<xml::Document> document;
try {
document = xml::parse_vcm(
"[string]", string, rootTag ? rootTag : ""
);
} catch (const parsing_error& err) {
throw err.toRuntimeError();
}
const auto& root = *document->getRoot();
if (rootTag != nullptr) {
return push_xml(L, root);
}
int rootElements = root.size();
if (rootElements != 1) {
throw std::runtime_error(
"one root element expected, got " + std::to_string(rootElements)
);
}
return push_xml(L, *root.getElements()[0]);
}
const luaL_Reg xmllib[] = {
{"tostring", lua::wrap<l_tostring>},
{"parse", lua::wrap<l_parse>},
{"parse_vcd", lua::wrap<l_parse_vcd>},
{nullptr, nullptr}
};

View file

@ -1,4 +1,5 @@
#include "coders/yaml.hpp"
#include "coders/commons.hpp"
#include "api_lua.hpp"
static int l_stringify(lua::State* L) {
@ -9,8 +10,12 @@ static int l_stringify(lua::State* L) {
static int l_parse(lua::State* L) {
auto string = lua::require_string(L, 1);
auto element = yaml::parse("[string]", string);
return lua::pushvalue(L, element);
try {
auto element = yaml::parse("[string]", string);
return lua::pushvalue(L, element);
} catch (const parsing_error& err) {
throw err.toRuntimeError();
}
}
const luaL_Reg yamllib[] = {

View file

@ -66,6 +66,7 @@ static void create_libs(State* L, StateType stateType) {
openlib(L, "vec2", vec2lib);
openlib(L, "vec3", vec3lib);
openlib(L, "vec4", vec4lib);
openlib(L, "xml", xmllib);
openlib(L, "yaml", yamllib);
openlib(L, "__vc_app", applib);