mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-12 14:31:50 +00:00
Merge branch 'MihailRis:main' into main
This commit is contained in:
commit
77e1e29eb9
10 changed files with 237 additions and 3 deletions
|
|
@ -52,6 +52,60 @@ yaml.parse(code: str) -> table
|
||||||
|
|
||||||
Parses a YAML string into a table.
|
Parses a YAML string into a table.
|
||||||
|
|
||||||
|
## XML Library
|
||||||
|
|
||||||
|
The library contains functions for serializing and deserializing XML:
|
||||||
|
|
||||||
|
Further, XML as a data type denotes a Lua table with the following structure:
|
||||||
|
- Element tag is accessible by the key `#`
|
||||||
|
- XML attributes are accessible as key = value pairs
|
||||||
|
- Inner elements are accessible by index
|
||||||
|
|
||||||
|
The table is used both as a dictionary and an array.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<panel size='400' color='0' interval='1' context='menu'>
|
||||||
|
<button onclick='menu.page="worlds"'>@Worlds</button>
|
||||||
|
</panel>
|
||||||
|
```
|
||||||
|
|
||||||
|
Equivalent Lua table:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
{
|
||||||
|
['#'] = "panel",
|
||||||
|
size = "400",
|
||||||
|
color = "0",
|
||||||
|
interval = "1",
|
||||||
|
context = "menu",
|
||||||
|
{
|
||||||
|
['#'] = "button",
|
||||||
|
onclick = 'menu.page="worlds"',
|
||||||
|
{
|
||||||
|
"@Worlds"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Consequently, the button element is accessible as `panel_element[1]`.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- Serializes a tree in XML format
|
||||||
|
-- multiline - use multiline formatting
|
||||||
|
xml.tostring(data: XML, multiline: bool = true) -> str
|
||||||
|
|
||||||
|
-- Parses XML
|
||||||
|
xml.parse(code: str) -> XML
|
||||||
|
|
||||||
|
-- Parses the VCD (VoxelCore Declaration) format used by the VCM format.
|
||||||
|
-- root_tag - a root element with the specified tag will be implicitly created,
|
||||||
|
-- containing all root elements
|
||||||
|
xml.parse_vcd(code: str, root_tag: str = "root") -> XML
|
||||||
|
```
|
||||||
|
|
||||||
## *bjson* library
|
## *bjson* library
|
||||||
|
|
||||||
The library contains functions for working with the binary data exchange format [vcbjson](../../specs/binary_json_spec.md).
|
The library contains functions for working with the binary data exchange format [vcbjson](../../specs/binary_json_spec.md).
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,60 @@ yaml.parse(code: str) -> table
|
||||||
|
|
||||||
Парсит YAML строку в таблицу.
|
Парсит YAML строку в таблицу.
|
||||||
|
|
||||||
|
## Библиотека xml
|
||||||
|
|
||||||
|
Библиотека содержит функции для сериализации и десериализации XML:
|
||||||
|
|
||||||
|
Далее XML как тип данных обозначает Lua-таблицу со следующей структурой:
|
||||||
|
- Тег элемента доступен по ключу `#`
|
||||||
|
- XML-аттрибуты доступны как пары ключ = значение
|
||||||
|
- Вложенные элементы доступны по индексу
|
||||||
|
|
||||||
|
Таблица используется как словарь, так и массив.
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<panel size='400' color='0' interval='1' context='menu'>
|
||||||
|
<button onclick='menu.page="worlds"'>@Worlds</button>
|
||||||
|
</panel>
|
||||||
|
```
|
||||||
|
|
||||||
|
Эквивалентная Lua-таблица:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
{
|
||||||
|
['#'] = "panel",
|
||||||
|
size = "400",
|
||||||
|
color = "0",
|
||||||
|
interval = "1",
|
||||||
|
context = "menu",
|
||||||
|
{
|
||||||
|
['#'] = "button",
|
||||||
|
onclick = 'menu.page="worlds"',
|
||||||
|
{
|
||||||
|
"@Worlds"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Соответственно, элемент button доступен как `элемент_panel[1]`.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- Сериализует дерево в формате XML
|
||||||
|
-- multiline - использовать ли многострочное форматирование
|
||||||
|
xml.tostring(data: XML, multiline: bool = true) -> str
|
||||||
|
|
||||||
|
-- Парсит XML
|
||||||
|
xml.parse(code: str) -> XML
|
||||||
|
|
||||||
|
-- Парсит формат VCD (VoxelCore Declaration), используемый форматом VCM.
|
||||||
|
-- root_tag - будет неявно создан корневой элемент с указанным тегом,
|
||||||
|
-- содержащий все корневые элементы
|
||||||
|
xml.parse_vcd(code: str, root_tag: str | nil = nil) -> XML
|
||||||
|
```
|
||||||
|
|
||||||
## Библиотека bjson
|
## Библиотека bjson
|
||||||
|
|
||||||
Библиотека содержит функции для работы с двоичным форматом обмена данными [vcbjson](../../specs/binary_json_spec.md).
|
Библиотека содержит функции для работы с двоичным форматом обмена данными [vcbjson](../../specs/binary_json_spec.md).
|
||||||
|
|
|
||||||
|
|
@ -528,3 +528,11 @@ std::string xml::stringify(
|
||||||
|
|
||||||
return ss.str();
|
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();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,12 @@ namespace xml {
|
||||||
const std::string& indentStr = " "
|
const std::string& indentStr = " "
|
||||||
);
|
);
|
||||||
|
|
||||||
|
std::string stringify(
|
||||||
|
const Node& element,
|
||||||
|
bool nice = true,
|
||||||
|
const std::string& indentStr = " "
|
||||||
|
);
|
||||||
|
|
||||||
/// @brief Read XML Document from string
|
/// @brief Read XML Document from string
|
||||||
/// @param filename file name will be shown in error messages
|
/// @param filename file name will be shown in error messages
|
||||||
/// @param source xml source code string
|
/// @param source xml source code string
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ class Font;
|
||||||
struct FontMetrics {
|
struct FontMetrics {
|
||||||
std::optional<std::weak_ptr<Font>> font;
|
std::optional<std::weak_ptr<Font>> font;
|
||||||
|
|
||||||
int lineHeight;
|
int lineHeight = 0;
|
||||||
int yoffset;
|
int yoffset = 0;
|
||||||
int _glyphInterval = 8;
|
int _glyphInterval = 8;
|
||||||
|
|
||||||
~FontMetrics();
|
~FontMetrics();
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,9 @@ uint Label::getLinesNumber() const {
|
||||||
void Label::draw(const DrawContext& pctx, const Assets& assets) {
|
void Label::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
auto batch = pctx.getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
auto font = assets.getShared<Font>(fontName);
|
auto font = assets.getShared<Font>(fontName);
|
||||||
|
if (font == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
cache.prepare(
|
cache.prepare(
|
||||||
font,
|
font,
|
||||||
font->getMetrics(),
|
font->getMetrics(),
|
||||||
|
|
|
||||||
|
|
@ -353,7 +353,9 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
|
|
||||||
void TextBox::drawBackground(const DrawContext& pctx, const Assets& assets) {
|
void TextBox::drawBackground(const DrawContext& pctx, const Assets& assets) {
|
||||||
auto font = assets.getShared<Font>(label->getFontName());
|
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();
|
glm::vec2 pos = calcPos();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ extern const luaL_Reg vec3lib[]; // vecn.cpp
|
||||||
extern const luaL_Reg vec4lib[]; // vecn.cpp
|
extern const luaL_Reg vec4lib[]; // vecn.cpp
|
||||||
extern const luaL_Reg weatherlib[]; // gfx.weather
|
extern const luaL_Reg weatherlib[]; // gfx.weather
|
||||||
extern const luaL_Reg worldlib[];
|
extern const luaL_Reg worldlib[];
|
||||||
|
extern const luaL_Reg xmllib[];
|
||||||
extern const luaL_Reg yamllib[];
|
extern const luaL_Reg yamllib[];
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
|
|
|
||||||
105
src/logic/scripting/lua/libs/libxml.cpp
Normal file
105
src/logic/scripting/lua/libs/libxml.cpp
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
#include "coders/xml.hpp"
|
||||||
|
#include "api_lua.hpp"
|
||||||
|
|
||||||
|
static const char* TAG_ATTR = "#";
|
||||||
|
static const char* DEFAULT_ROOT_TAG = "root";
|
||||||
|
|
||||||
|
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);
|
||||||
|
auto document = xml::parse("[string]", string);
|
||||||
|
return push_xml(L, *document->getRoot());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int l_parse_vcd(lua::State* L) {
|
||||||
|
auto string = lua::require_string(L, 1);
|
||||||
|
auto rootTag = lua::tostring(L, 2);
|
||||||
|
auto document = xml::parse_vcm(
|
||||||
|
"[string]", string, rootTag ? rootTag : ""
|
||||||
|
);
|
||||||
|
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}
|
||||||
|
};
|
||||||
|
|
@ -66,6 +66,7 @@ static void create_libs(State* L, StateType stateType) {
|
||||||
openlib(L, "vec2", vec2lib);
|
openlib(L, "vec2", vec2lib);
|
||||||
openlib(L, "vec3", vec3lib);
|
openlib(L, "vec3", vec3lib);
|
||||||
openlib(L, "vec4", vec4lib);
|
openlib(L, "vec4", vec4lib);
|
||||||
|
openlib(L, "xml", xmllib);
|
||||||
openlib(L, "yaml", yamllib);
|
openlib(L, "yaml", yamllib);
|
||||||
|
|
||||||
openlib(L, "__vc_app", applib);
|
openlib(L, "__vc_app", applib);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue