diff --git a/doc/en/block-properties.md b/doc/en/block-properties.md index cef58a9a..18c068ca 100644 --- a/doc/en/block-properties.md +++ b/doc/en/block-properties.md @@ -39,6 +39,12 @@ Block model type from list: Integer specifying number of block draw group (render order). Used for semi-transparent blocks. +### *translucent* + +Enables translucency support in block textures (examples: water, ice). +Should only be used when needed, as it impacts performance. +Not required for full transparency (grass, flowers). + ### *rotation* Rotation profile (set of available block rotations and behaviour of placing block rotation) from list: diff --git a/doc/en/main-page.md b/doc/en/main-page.md index 06636ea0..4d487f5a 100644 --- a/doc/en/main-page.md +++ b/doc/en/main-page.md @@ -1,6 +1,8 @@ # Documentation -Documentation for the engine of version 0.24. +Documentation for the engine of in-development version 0.25. + +[Documentation for stable release 0.24.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.24/doc/en/main-page.md) ## Sections diff --git a/doc/en/scripting/builtins/libhud.md b/doc/en/scripting/builtins/libhud.md index b823ab50..4beb5d93 100644 --- a/doc/en/scripting/builtins/libhud.md +++ b/doc/en/scripting/builtins/libhud.md @@ -7,7 +7,11 @@ hud.open_inventory() -- Close inventory. hud.close_inventory() --- Open block UI and inventory. +-- Open UI and inventory. +-- Throws an exception if has no UI layout. +hud.open(invid: int, layoutid: str) + +-- Open block UI and inventory. -- Throws an exception if block has no UI layout. -- Returns block inventory ID (if *"inventory-size"=0* a virtual -- inventory will be created), and UI layout ID. diff --git a/doc/en/scripting/builtins/libinventory.md b/doc/en/scripting/builtins/libinventory.md index a719878a..344840f1 100644 --- a/doc/en/scripting/builtins/libinventory.md +++ b/doc/en/scripting/builtins/libinventory.md @@ -40,12 +40,18 @@ inventory.bind_block(invid: int, x: int, y: int, z: int) -- Unbind inventory from the specified block. inventory.unbind_block(x: int, y: int, z: int) + +-- Remove inventory. +inventory.remove(invid: int) ``` > [!WARNING] > Unbound inventories will be deleted on world close. ```lua +-- Create inventory. Returns the created ID. +inventory.create(size: int) -> int + -- Create inventory copy. Returns the created copy ID. inventory.clone(invid: int) -> int diff --git a/doc/en/scripting/builtins/libutf8.md b/doc/en/scripting/builtins/libutf8.md index 86714fce..bd8dd22b 100644 --- a/doc/en/scripting/builtins/libutf8.md +++ b/doc/en/scripting/builtins/libutf8.md @@ -27,4 +27,7 @@ utf8.upper(text: str) -> str -- Converts a string to lowercase utf8.lower(text: str) -> str + +-- Escapes a string +utf8.escape(text: str) -> str ``` diff --git a/doc/en/scripting/ui.md b/doc/en/scripting/ui.md index e209c267..4f132462 100644 --- a/doc/en/scripting/ui.md +++ b/doc/en/scripting/ui.md @@ -74,17 +74,22 @@ Properties: | ----------- | ------ | ---- | ----- | ------------------------------------------------------------------------------------ | | text | string | yes | yes | entered text or placeholder | | placeholder | string | yes | yes | placeholder (used if nothing has been entered) | +| hint | string | yes | yes | text to display when nothing is entered | | caret | int | yes | yes | carriage position. `textbox.caret = -1` will set the position to the end of the text | | editable | bool | yes | yes | text mutability | | multiline | bool | yes | yes | multiline support | +| lineNumbers | bool | yes | yes | display line numbers | | textWrap | bool | yes | yes | automatic text wrapping (only with multiline: "true") | | valid | bool | yes | no | is the entered text correct | +| textColor | vec4 | yes | yes | text color | Methods: -| Method | Description | -| ----------- | ------------------------------------------------ | -| paste(text) | inserts the specified text at the caret position | +| Method | Description | +| ------------------------- | ---------------------------------------------------------------- | +| paste(text: str) | inserts the specified text at the caret position | +| lineAt(pos: int) -> int | determines the line number by position in the text | +| linePos(line: int) -> int | determines the position of the beginning of the line in the text | ## Slider (trackbar) diff --git a/doc/en/world-generator.md b/doc/en/world-generator.md index 47f46b80..2112bce2 100644 --- a/doc/en/world-generator.md +++ b/doc/en/world-generator.md @@ -72,17 +72,20 @@ Fragments used by the generator must present in the directory: ## Structures -A structure is a set of rules for inserting a fragment into the world by the generator. It currently has no properties, being created as empty objects in the `generators/generator_name.files/structures.toml` file. Example: +A structure is a set of rules for inserting a fragment into the world by the generator. Structures are declared as objects in the file `generators/generator_name.files/structures.toml`. Example: ```toml tree0 = {} tree1 = {} tree2 = {} -tower = {} +tower = {lowering=2} coal_ore0 = {} ``` Currently, the name of the structure must match the name of the fragment used. +Available properties: +- lowering - depth of structure lowering. + ## Biomes A biome defines what blocks and layers the terrain is generated from, as well as a set of plants and structures. diff --git a/doc/en/xml-ui-layouts.md b/doc/en/xml-ui-layouts.md index ac657e44..788814e5 100644 --- a/doc/en/xml-ui-layouts.md +++ b/doc/en/xml-ui-layouts.md @@ -56,7 +56,8 @@ Buttons and panels are also containers. - `padding` - element padding. Type: 4D vector. *left, top, right, bottom* - `scrollable` - element scrollability. Works on panels only. Type: boolean +- `scrollable` - element scrollability. Type: boolean. +- `scroll-step` - scrolling step. Type: integer. # Common *panel* attributes @@ -104,7 +105,9 @@ Inner text - initially entered text - `multiline` - allows display of multiline text. - `text-wrap` - allows automatic text wrapping (works only with multiline: "true") - `editable` - determines whether the text can be edited. +- `line-numbers` - enables line numbers display. - `error-color` - color when entering incorrect data (the text does not pass the validator check). Type: RGBA color. +- `text-color` - text color. Type: RGBA color. - `validator` - lua function that checks text for correctness. Takes a string as input, returns true if the text is correct. - `onup` - lua function called when the up arrow is pressed. - `ondown` - lua function called when the down arrow is pressed. diff --git a/doc/ru/block-properties.md b/doc/ru/block-properties.md index 62ef8ec4..79b08da2 100644 --- a/doc/ru/block-properties.md +++ b/doc/ru/block-properties.md @@ -40,6 +40,12 @@ Целое число определяющее номер группы отрисовки данного блока. Актуально для полупрозрачных блоков - решает проблемы невидимых сторон блоков за этим блоком. +### Полупрозрачность - *translucent* + +Включает поддержку полупрозрачности в текстурах блока (примеры: вода, лёд). +Следует использовать только при надобности, так как влияет на производительность. +Не требуется для полной прозрачности (трава, цветы). + ### Вращение - *rotation* Профиль вращения (набор положений, в которые можно установить блок) из списка: diff --git a/doc/ru/content-packs.md b/doc/ru/content-packs.md index 33d46ffb..77a78636 100644 --- a/doc/ru/content-packs.md +++ b/doc/ru/content-packs.md @@ -22,6 +22,8 @@ } ``` +Вместо `creator` можно указать массив `creators` + Уровни зависимостей указываются с помощью префиксов в имени: - '!' - обязательная зависимость - '?' - опциональная зависимость diff --git a/doc/ru/main-page.md b/doc/ru/main-page.md index 30445fb6..800415c6 100644 --- a/doc/ru/main-page.md +++ b/doc/ru/main-page.md @@ -1,6 +1,8 @@ # Документация -Документация движка версии 0.24. +Документация движка разрабатываемой версии 0.25. + +[Документация стабильной версии 0.24.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.24/doc/ru/main-page.md) ## Разделы diff --git a/doc/ru/scripting/builtins/libhud.md b/doc/ru/scripting/builtins/libhud.md index cba34dee..ae5a69c3 100644 --- a/doc/ru/scripting/builtins/libhud.md +++ b/doc/ru/scripting/builtins/libhud.md @@ -7,7 +7,11 @@ hud.open_inventory() -- Закрывает инвентарь. hud.close_inventory() --- Открывает инвентарь и UI блока. +-- Открывает инвентарь и UI. +-- Если не имеет макета UI - бросается исключение. +hud.open(invid: int, layoutid: str) + +-- Открывает инвентарь и UI блока. -- Если блок не имеет макета UI - бросается исключение. -- Возвращает id инвентаря блока -- (при *"inventory-size"=0* создаётся виртуальный инвентарь, diff --git a/doc/ru/scripting/builtins/libinventory.md b/doc/ru/scripting/builtins/libinventory.md index 4d937358..01ecc5cc 100644 --- a/doc/ru/scripting/builtins/libinventory.md +++ b/doc/ru/scripting/builtins/libinventory.md @@ -23,7 +23,7 @@ inventory.set( count: int ) --- Возращает размер инвентаря (число слотов). +-- Возвращает размер инвентаря (число слотов). -- Если указанного инвентаря не существует, бросает исключение. inventory.size(invid: int) -> int @@ -47,13 +47,19 @@ inventory.bind_block(invid: int, x: int, y: int, z: int) -- Отвязывает инвентарь от блока. inventory.unbind_block(x: int, y: int, z: int) + +-- Удаляет инвентарь. +inventory.remove(invid: int) ``` > [!WARNING] > Инвентари, не привязанные ни к одному из блоков, удаляются при выходе из мира. ```lua --- Создает копию инвентаря и возвращает id копии. +-- Создаёт инвентарь и возвращает id. +inventory.create(size: int) -> int + +-- Создает копию инвентаря и возвращает id копии. -- Если копируемого инвентаря не существует, возвращает 0. inventory.clone(invid: int) -> int @@ -62,5 +68,3 @@ inventory.clone(invid: int) -> int -- slotB будет выбран автоматически, если не указывать явно. inventory.move(invA: int, slotA: int, invB: int, slotB: int) ``` - - diff --git a/doc/ru/scripting/builtins/libutf8.md b/doc/ru/scripting/builtins/libutf8.md index 394eb522..ce933417 100644 --- a/doc/ru/scripting/builtins/libutf8.md +++ b/doc/ru/scripting/builtins/libutf8.md @@ -27,4 +27,7 @@ utf8.upper(text: str) -> str -- Переводит строку в нижний регистр utf8.lower(text: str) -> str + +-- Экранирует строку +utf8.escape(text: str) -> str ``` diff --git a/doc/ru/scripting/extensions.md b/doc/ru/scripting/extensions.md index a6b40a38..d4502f64 100644 --- a/doc/ru/scripting/extensions.md +++ b/doc/ru/scripting/extensions.md @@ -4,92 +4,109 @@ ## Расширения для table -Создаёт и возвращает копию переданной таблицы путём создания новой и копирования в неё всех элементов из переданной ```lua -function table.copy(t: table) -> table +table.copy(t: table) -> table ``` -Возвращает количество пар в переданной таблице +Создаёт и возвращает копию переданной таблицы путём создания новой и копирования в неё всех элементов из переданной. + ```lua -function table.count_pairs(t: table) -> integer +table.count_pairs(t: table) -> integer ``` -Возвращает один элемент из переданной таблицы на случайной позиции +Возвращает количество пар в переданной таблице. + ```lua -function table.random(t: table) -> object +table.random(t: table) -> object ``` -Возвращает **true**, если **x** содержится в **t** +Возвращает один элемент из переданной таблицы на случайной позиции. + ```lua -function table.has(t: table, x: object) -> bool +table.has(t: table, x: object) -> bool ``` -Возвращает индекс обьекта **x** в **t**. Если переданный обьект не содержится в таблице, то функция вернёт значение **-1** +Возвращает **true**, если **x** содержится в **t**. + ```lua -function table.index(t: table, x: object) -> integer +table.index(t: table, x: object) -> integer ``` -Удаляет элемент **x** из **t** +Возвращает индекс обьекта **x** в **t**. Если переданный обьект не содержится в таблице, то функция вернёт значение **-1**. + ```lua -function table.remove_value(t: table, x: object) +table.remove_value(t: table, x: object) ``` -Конвертирует переданную таблицу в строку +Удаляет элемент **x** из **t**. + ```lua -function table.tostring(t: table) -> string +table.tostring(t: table) -> string ``` +Конвертирует переданную таблицу в строку. + ## Расширения для string -Разбивает строку **str** на части по указанному разделителю/выражению **separator** и возвращает результат ввиде таблицы из строк. Если **withpattern** равен **true**, то параметр **separator** будет определяться как регулярное выражение ```lua -function string.explode(separator: string, str: string, withpattern: bool) -> table[string] +string.explode(separator: string, str: string, withpattern: bool) -> table[string] ``` -Разбивает строку **str** на части по указанному разделителю **delimiter** и возвращает результат ввиде таблицы из строк +Разбивает строку **str** на части по указанному разделителю/выражению **separator** и возвращает результат ввиде таблицы из строк. Если **withpattern** равен **true**, то параметр **separator** будет определяться как регулярное выражение. + ```lua -function string.split(str: string, delimiter: string) -> table[string] +string.split(str: string, delimiter: string) -> table[string] ``` -Экранирует специальные символы в строке, такие как `()[]+-.$%^?*` в формате `%символ`. Символ `NUL` (`\0`) будет преобразован в `%z` +Разбивает строку **str** на части по указанному разделителю **delimiter** и возвращает результат ввиде таблицы из строк. + ```lua -function string.pattern_safe(str: string) +string.pattern_safe(str: string) ``` -Разбивает секунды на часы, минуты и миллисекунды и форматирует в **format** с следующим порядком параметров: `минуты, секунды, миллисекунды` и после возвращает результат. Если **format** не указан, то возвращает таблицу, где: **h** - hours, **m** - minutes, **s** - seconds, **ms** - milliseconds +Экранирует специальные символы в строке, такие как `()[]+-.$%^?*` в формате `%символ`. Символ `NUL` (`\0`) будет преобразован в `%z`. + ```lua -function string.formatted_time(seconds: number, format: string) -> string | table +string.formatted_time(seconds: number, format: string) -> string | table ``` -Заменяет все подстроки в **str**, равные **tofind** на **toreplace** и возвращает строку со всеми измененными подстроками +Разбивает секунды на часы, минуты и миллисекунды и форматирует в **format** с следующим порядком параметров: `минуты, секунды, миллисекунды` и после возвращает результат. Если **format** не указан, то возвращает таблицу, где: **h** - hours, **m** - minutes, **s** - seconds, **ms** - milliseconds. + ```lua -function string.replace(str: string, tofind: string, toreplace: string) -> string +string.replace(str: string, tofind: string, toreplace: string) -> string +``` + +Заменяет все подстроки в **str**, равные **tofind** на **toreplace** и возвращает строку со всеми измененными подстроками. + +```lua +string.trim(str: string, char: string) -> string ``` Удаляет все символы, равные **char** из строки **str** с левого и правого конца и возвращает результат. Если параметр **char** не определен, то будут выбраны все пустые символы. + ```lua -function string.trim(str: string, char: string) -> string +string.trim_left(str: string, char: string) -> string ``` Удаляет все символы, равные **char** из строки **str** с левого конца и возвращает результат. Если параметр **char** не определен, то будут выбраны все пустые символы. + ```lua -function string.trim_left(str: string, char: string) -> string +string.trim_right(str: string, char: string) -> string ``` Удаляет все символы, равные **char** из строки **str** с правого конца и возвращает результат. Если параметр **char** не определен, то будут выбраны все пустые символы. + ```lua -function string.trim_right(str: string, char: string) -> string +string.starts_with(str: string, start: string) -> bool ``` Возвращает **true**, если строка **str** начинается на подстроку **start** + ```lua -function string.starts_with(str: string, start: string) -> bool +string.ends_with(str: string, endStr: string) -> bool ``` Возвращает **true**, если строка **str** заканчивается на подстроку **endStr** -```lua -function string.ends_with(str: string, endStr: string) -> bool -``` Также важно подметить, что все выше перечисленные функции, расширяющие **string** можно использовать как мета-методы на экземплярах строк, т.е.: @@ -103,39 +120,51 @@ end Также функции `string.lower` и `string.upper` переопределены на `utf8.lower` и `utf8.upper` +```lua +string.escape(str: string) -> string +``` + +Экранирует строку. Является псевдонимом `utf8.escape`. + ## Расширения для math -Ограничивает число **_in** по лимитам **low** и **high**. Т.е.: Если **_in** больше чем **high** - вернётся **high**, если **_in** меньше чем **low** - вернётся **low**. В противном случае вернётся само число ```lua -function math.clamp(_in, low, high) +math.clamp(_in, low, high) ``` -Возвращает случайное дробное число в диапазоне от **low** до **high** +Ограничивает число **_in** по лимитам **low** и **high**. Т.е.: Если **_in** больше чем **high** - вернётся **high**, если **_in** меньше чем **low** - вернётся **low**. В противном случае вернётся само число. + ```lua -function math.rand(low, high) +math.rand(low, high) ``` +Возвращает случайное дробное число в диапазоне от **low** до **high**. + ## Дополнительные глобальные функции В этом же скрипте также определены и другие глобальные функции которые доступны для использования. Ниже их список -Возвращает **true**, если переданная таблица является массивом, тоесть если каждый ключ это целое число больше или равное единице и если каждый ключ следует за прошлым ```lua -function is_array(x: table) -> bool +is_array(x: table) -> bool ``` -Разбивает путь на две части и возвращает их: входную точку и путь к файлу +Возвращает **true**, если переданная таблица является массивом, тоесть если каждый ключ это целое число больше или равное единице и если каждый ключ следует за прошлым. + ```lua function parse_path(path: string) -> string, string ``` -Вызывает функцию **func** **iters** раз, передавая ей аргументы `...`, а после выводит в консоль время в микросекундах, которое прошло с момента вызова **timeit** +Разбивает путь на две части и возвращает их: входную точку и путь к файлу. + ```lua function timeit(iters: integer, func: func, ...) ``` -Вызывает остановку корутины до тех пор, пока не пройдёт количество секунд, указанное в **timesec**. Функция может быть использована только внутри корутины +Вызывает функцию **func** **iters** раз, передавая ей аргументы `...`, а после выводит в консоль время в микросекундах, которое прошло с момента вызова **timeit**. + ```lua function sleep(timesec: number) -``` \ No newline at end of file +``` + +Вызывает остановку корутины до тех пор, пока не пройдёт количество секунд, указанное в **timesec**. Функция может быть использована только внутри корутины. diff --git a/doc/ru/scripting/ui.md b/doc/ru/scripting/ui.md index 6d39c6c7..4d244210 100644 --- a/doc/ru/scripting/ui.md +++ b/doc/ru/scripting/ui.md @@ -74,17 +74,22 @@ document["worlds-panel"]:clear() | ----------- | ------ | ------ | ------ | ---------------------------------------------------------------------- | | text | string | да | да | введенный текст или заполнитель | | placeholder | string | да | да | заполнитель (используется если ничего не было введено) | +| hint | string | да | да | текст, отображаемый, когда ничего не введено | | caret | int | да | да | позиция каретки. `textbox.caret = -1` установит позицию в конец текста | | editable | bool | да | да | изменяемость текста | | multiline | bool | да | да | поддержка многострочности | +| lineNumbers | bool | да | да | отображение номеров строк | | textWrap | bool | да | да | автоматический перенос текста (только при multiline: "true") | | valid | bool | да | нет | является ли введенный текст корректным | +| textColor | vec4 | да | да | цвет текста | Методы: -| Метод | Описание | -| ----------- | -------------------------------------------- | -| paste(text) | вставляет указанный текст на позицию каретки | +| Метод | Описание | +| ------------------------- | -------------------------------------------- | +| paste(text: str) | вставляет указанный текст на позицию каретки | +| lineAt(pos: int) -> int | определяет номер строки по позиции в тексте | +| linePos(line: int) -> int | определяет позицию начала строки в тексте | ## Ползунок (trackbar) diff --git a/doc/ru/world-generator.md b/doc/ru/world-generator.md index 284ea067..1523f94a 100644 --- a/doc/ru/world-generator.md +++ b/doc/ru/world-generator.md @@ -72,17 +72,20 @@ ## Структуры -Структура - набор правил по вставке фрагмента в мир генератором. На данный момент не имеет свойств, создаваясь в виде пустых объектов в файле `generators/имя_генератора.files/structures.toml`. Пример: +Структура - набор правил по вставке фрагмента в мир генератором. Структуры объявляются в виде объектов в файле `generators/имя_генератора.files/structures.toml`. Пример: ```toml tree0 = {} tree1 = {} tree2 = {} -tower = {} +tower = {lowering=-2} coal_ore0 = {} ``` На данный момент, имя структуры должно совпадать с именем использованного фрагмента. +Доступные свойства: +- lowering - глубина погружения структуры под поверхность. + ## Биомы Биом определяет то, из каких блоков и какими слоями генерируется ландшафт, а так же набор растений, структур. diff --git a/doc/ru/xml-ui-layouts.md b/doc/ru/xml-ui-layouts.md index bdf82f1b..28777950 100644 --- a/doc/ru/xml-ui-layouts.md +++ b/doc/ru/xml-ui-layouts.md @@ -59,7 +59,8 @@ В число контейнеров также входят панели и кнопки. - `padding` - внутренний отступ элемента. Тип: 4D вектор. Порядок: `"left,top,right,bottom"` -- `scrollable` - возможность скроллинга. Работает только у Panel. Тип: логический. +- `scrollable` - возможность скроллинга. Тип: логический. +- `scroll-step` - шаг скроллинга. Тип: целочисленный. # Общие атрибуты панелей @@ -105,7 +106,9 @@ - `multiline` - разрешает отображение многострочного текста. - `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true") - `editable`- определяет возможность редактирования текста. +- `line-numbers` - включает отображение номеров строк. - `error-color` - цвет при вводе некорректных данных (текст не проходит проверку валидатора). Тип: RGBA цвет. +- `text-color` - цвет текста. Тип: RGBA цвет. - `validator` - lua функция, проверяющая текст на корректность. Принимает на вход строку, возвращает true если текст корректен. - `onup` - lua функция вызываемая при нажатии стрелки вверх. - `ondown` - lua функция вызываемая при нажатии стрелки вниз. diff --git a/res/content/base/blocks/glass.json b/res/content/base/blocks/glass.json index 902a2cf1..9bd4f021 100644 --- a/res/content/base/blocks/glass.json +++ b/res/content/base/blocks/glass.json @@ -3,5 +3,6 @@ "material": "base:glass", "draw-group": 2, "light-passing": true, - "sky-light-passing": true + "sky-light-passing": true, + "translucent": true } diff --git a/res/content/base/blocks/ice.json b/res/content/base/blocks/ice.json new file mode 100644 index 00000000..19d9af12 --- /dev/null +++ b/res/content/base/blocks/ice.json @@ -0,0 +1,7 @@ +{ + "texture": "ice", + "material": "base:glass", + "draw-group": 4, + "light-passing": true, + "translucent": true +} diff --git a/res/content/base/blocks/water.json b/res/content/base/blocks/water.json index 943640e8..f7785044 100644 --- a/res/content/base/blocks/water.json +++ b/res/content/base/blocks/water.json @@ -6,5 +6,6 @@ "sky-light-passing": false, "obstacle": false, "selectable": false, - "replaceable": true + "replaceable": true, + "translucent": true } diff --git a/res/content/base/content.json b/res/content/base/content.json index cec825a8..db13bae2 100644 --- a/res/content/base/content.json +++ b/res/content/base/content.json @@ -1,6 +1,8 @@ { - "items": [ - "bazalt_breaker" + "entities": [ + "drop", + "player", + "falling_block" ], "blocks": [ "dirt", @@ -27,11 +29,10 @@ "lightbulb", "torch", "wooden_door", - "coal_ore" + "coal_ore", + "ice" ], - "entities": [ - "drop", - "player", - "falling_block" + "items": [ + "bazalt_breaker" ] } \ No newline at end of file diff --git a/res/content/base/entities/falling_block.json b/res/content/base/entities/falling_block.json index cd0459b5..cf5146fd 100644 --- a/res/content/base/entities/falling_block.json +++ b/res/content/base/entities/falling_block.json @@ -3,5 +3,5 @@ "base:falling_block" ], "skeleton-name": "base:block", - "hitbox": [0.8, 0.8, 0.8] + "hitbox": [0.98, 0.98, 0.98] } diff --git a/res/content/base/generators/demo.files/structures.toml b/res/content/base/generators/demo.files/structures.toml index 3dcf3cda..12edb165 100644 --- a/res/content/base/generators/demo.files/structures.toml +++ b/res/content/base/generators/demo.files/structures.toml @@ -1,5 +1,5 @@ tree0 = {} tree1 = {} tree2 = {} -tower = {} +tower = {lowering=2} coal_ore0 = {} diff --git a/res/content/base/package.json b/res/content/base/package.json index 0ed25d38..7645a6e0 100644 --- a/res/content/base/package.json +++ b/res/content/base/package.json @@ -1,6 +1,6 @@ { "id": "base", "title": "Base", - "version": "0.24", + "version": "0.25", "description": "basic content package" } diff --git a/res/content/base/texts/ru_RU.txt b/res/content/base/texts/ru_RU.txt index f6a3ab51..cf55ec54 100644 --- a/res/content/base/texts/ru_RU.txt +++ b/res/content/base/texts/ru_RU.txt @@ -1,3 +1,4 @@ +bazalt breaker=крушитель базальта bazalt=базальт blue lamp=синяя лампа brick=кирпич @@ -5,8 +6,8 @@ dirt=земля flower=цветок glass=стекло grass block=дёрн -tall grass=высокая трава green lamp=зелёная лампа +ice=лёд lamp=лампа leaves=листва light bulb=лампочка @@ -18,8 +19,8 @@ red lamp=красная лампа rust=ржавчина sand=песок stone=камень +tall grass=высокая трава +torch=факел water=вода wood=бревно -torch=факел -bazalt breaker=крушитель базальта wooden door=деревянная дверь diff --git a/res/content/base/textures/blocks/ice.png b/res/content/base/textures/blocks/ice.png new file mode 100644 index 00000000..707ee89a Binary files /dev/null and b/res/content/base/textures/blocks/ice.png differ diff --git a/res/layouts/console.xml b/res/layouts/console.xml index 3e1b802d..c367545c 100644 --- a/res/layouts/console.xml +++ b/res/layouts/console.xml @@ -1,5 +1,18 @@ - + + + + + + + + + + + + + + + - + @devtools.traceback") + for _, frame in ipairs(traceback.frames) do + local callback = "" + local framestr = "" + if frame.what == "C" then + framestr = "C/C++ " + else + framestr = frame.source..":"..tostring(frame.currentline).." " + if file.exists(frame.source) then + callback = string.format( + "local editor = document.editor ".. + "local source = file.read('%s'):gsub('\t', ' ') ".. + "editor.text = source ".. + "editor.focused = true ".. + "time.post_runnable(function()".. + "editor.caret = editor:linePos(%s) ".. + "end)", + frame.source, frame.currentline-1 + ) + else + callback = "document.editor.text = 'Could not open source file'" + end + callback = string.format( + "%s document.title.text = gui.str('File')..' - %s'", + callback, + frame.source + ) + end + if frame.name then + framestr = framestr.."("..tostring(frame.name)..")" + end + local color = "#FFFFFF" + if frame.source:starts_with("core:") then + color = "#C0D0C5" + end + tb_list:add(gui.template("stack_frame", { + location=framestr, + color=color, + callback=callback + })) + end + tb_list.size = srcsize +end) + function setup_variables() local pid = hud.get_player() local x,y,z = player.get_pos(pid) @@ -56,10 +136,19 @@ function add_to_history(text) end function submit(text) + text = text:trim() add_to_history(text) + + if console_mode == "chat" then + if not text:starts_with("/") then + text = "chat "..string.escape(text) + else + text = text:sub(2) + end + end + setup_variables() - text = text:trim() local name for s in text:gmatch("%S+") do name = s @@ -84,6 +173,38 @@ function submit(text) document.prompt.focused = true end -function on_open() - document.prompt.focused = true +function set_mode(mode) + local show_prompt = mode == 'chat' or mode == 'console' + + document.title.text = "" + document.editorContainer.visible = mode == 'debug' + document.logContainer.visible = mode ~= 'debug' + + if mode == 'debug' then + document.root.color = {16, 18, 20, 220} + else + document.root.color = {0, 0, 0, 128} + end + + document.traceback.visible = mode == 'debug' + document.prompt.visible = show_prompt + if show_prompt then + document.prompt.focused = true + end + console_mode = mode +end + +function on_open(mode) + if modes == nil then + modes = RadioGroup({ + chat=document.s_chat, + console=document.s_console, + debug=document.s_debug + }, function (mode) + set_mode(mode) + end, "console") + end + if mode then + modes:set(mode) + end end diff --git a/res/layouts/pages/content_menu.xml b/res/layouts/pages/content_menu.xml index 322a3dd9..af15b32c 100644 --- a/res/layouts/pages/content_menu.xml +++ b/res/layouts/pages/content_menu.xml @@ -1,9 +1,13 @@ - - + + - - + + + + + + diff --git a/res/layouts/pages/content_menu.xml.lua b/res/layouts/pages/content_menu.xml.lua index e601b01e..130b7387 100644 --- a/res/layouts/pages/content_menu.xml.lua +++ b/res/layouts/pages/content_menu.xml.lua @@ -1,3 +1,5 @@ +local packs_installed = {} + function on_open(params) refresh() end @@ -13,11 +15,33 @@ function place_pack(panel, packinfo, callback) end packinfo.callback = callback panel:add(gui.template("pack", packinfo)) - if not callback then - document["pack_"..packinfo.id].enabled = false +end + +function refresh_search() + local search_text = document.search_textbox.text:lower() + local visible = 0 + local interval = 4 + local step = -1 + + for i, v in ipairs(packs_installed) do + local id = v[1] + local title = v[2] + local content = document["pack_" .. id] + local pos = content.pos + local size = content.size + + if title:lower():find(search_text) or search_text == '' then + content.enabled = true + content.pos = {pos[1], visible * (size[2] + interval) - step} + visible = visible + 1 + else + content.enabled = false + content.pos = {pos[1], (visible + #packs_installed - i) * (size[2] + interval) - step} + end end end + function open_pack(id) local packinfo = pack.get_info(id) @@ -28,8 +52,8 @@ function open_pack(id) end function refresh() - local packs_installed = pack.get_installed() local packs_available = pack.get_available() + packs_installed = pack.get_installed() for i,k in ipairs(packs_available) do table.insert(packs_installed, k) @@ -41,7 +65,8 @@ function refresh() for i,id in ipairs(packs_installed) do local packinfo = pack.get_info(id) - packinfo.index = i + packinfo.id = id + packs_installed[i] = {packinfo.id, packinfo.title} local callback = string.format('open_pack("%s")', id) place_pack(contents, packinfo, callback) end diff --git a/res/layouts/pages/settings.xml b/res/layouts/pages/settings.xml index f5ec33d7..00437e68 100644 --- a/res/layouts/pages/settings.xml +++ b/res/layouts/pages/settings.xml @@ -1,9 +1,9 @@ - - - - + + + + @@ -11,7 +11,7 @@ - + diff --git a/res/layouts/pages/settings.xml.lua b/res/layouts/pages/settings.xml.lua index 24256c84..8b41491a 100644 --- a/res/layouts/pages/settings.xml.lua +++ b/res/layouts/pages/settings.xml.lua @@ -3,15 +3,13 @@ function on_open() "%s: %s", gui.str("Language", "settings"), gui.get_locales_info()[core.get_setting("ui.language")].name ) - set_page("s_gfx", "settings_graphics") -end - -function set_page(btn, page) - document.s_aud.enabled = true - document.s_dsp.enabled = true - document.s_gfx.enabled = true - document.s_ctl.enabled = true - document.s_rst.enabled = true - document[btn].enabled = false - document.menu.page = page + sections = RadioGroup({ + audio=document.s_aud, + display=document.s_dsp, + graphics=document.s_gfx, + controls=document.s_ctl, + reset=document.s_rst + }, function (page) + document.menu.page = "settings_"..page + end, "graphics") end diff --git a/res/layouts/templates/problem.xml b/res/layouts/templates/problem.xml index 0dfb2794..ea70022a 100644 --- a/res/layouts/templates/problem.xml +++ b/res/layouts/templates/problem.xml @@ -1,4 +1,5 @@ - + + %{location} + diff --git a/res/scripts/hud_classes.lua b/res/scripts/hud_classes.lua new file mode 100644 index 00000000..dc373c6e --- /dev/null +++ b/res/scripts/hud_classes.lua @@ -0,0 +1,18 @@ +local Text3D = {__index={ + hide=function(self) return gfx.text3d.hide(self.id) end, + get_pos=function(self) return gfx.text3d.get_pos(self.id) end, + set_pos=function(self, v) return gfx.text3d.set_pos(self.id, v) end, + get_axis_x=function(self) return gfx.text3d.get_axis_x(self.id) end, + set_axis_x=function(self, v) return gfx.text3d.set_axis_x(self.id, v) end, + get_axis_y=function(self) return gfx.text3d.get_axis_y(self.id) end, + set_axis_y=function(self, v) return gfx.text3d.set_axis_y(self.id, v) end, + set_rotation=function(self, m) return gfx.text3d.set_rotation(self.id, m) end, + get_text=function(self) return gfx.text3d.get_text(self.id) end, + set_text=function(self, s) return gfx.text3d.set_text(self.id, s) end, + update_settings=function(self, t) return gfx.text3d.update_settings(self.id, t) end, +}} + +gfx.text3d.new = function(pos, text, preset, extension) + local id = gfx.text3d.show(pos, text, preset, extension) + return setmetatable({id=id}, Text3D) +end diff --git a/res/scripts/stdcmd.lua b/res/scripts/stdcmd.lua index 98609688..ccb65a71 100644 --- a/res/scripts/stdcmd.lua +++ b/res/scripts/stdcmd.lua @@ -256,6 +256,14 @@ console.add_command( end ) +console.add_command( + "chat text:str", + "Send chat message", + function (args, kwargs) + console.log("[you] "..args[1]) + end +) + console.cheats = { "blocks.fill", "tp", diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index f53323db..7fc726f8 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -84,6 +84,32 @@ function Document.new(docname) }) end +local _RadioGroup = {} +function _RadioGroup.set(self, key) + if type(self) ~= 'table' then + error("called as non-OOP via '.', use radiogroup:set") + end + if self.current then + self.elements[self.current].enabled = true + end + self.elements[key].enabled = false + self.current = key + if self.callback then + self.callback(key) + end +end +function _RadioGroup.__call(self, elements, onset, default) + local group = setmetatable({ + elements=elements, + callback=onset, + current=nil + }, {__index=_RadioGroup}) + group:set(default) + return group +end +setmetatable(_RadioGroup, _RadioGroup) +RadioGroup = _RadioGroup + _GUI_ROOT = Document.new("core:root") _MENU = _GUI_ROOT.menu menu = _MENU diff --git a/res/scripts/stdmin.lua b/res/scripts/stdmin.lua index 530ec091..924c235f 100644 --- a/res/scripts/stdmin.lua +++ b/res/scripts/stdmin.lua @@ -162,6 +162,7 @@ end string.lower = utf8.lower string.upper = utf8.upper +string.escape = utf8.escape local meta = getmetatable("") @@ -227,8 +228,22 @@ function file.readlines(path) return lines end +function debug.get_traceback(start) + local frames = {} + local n = 2 + (start or 0) + while true do + local info = debug.getinfo(n) + if info then + table.insert(frames, info) + else + return frames + end + n = n + 1 + end +end + package = { - loaded={} + loaded = {} } local __cached_scripts = {} local __warnings_hidden = {} @@ -238,7 +253,7 @@ function on_deprecated_call(name, alternatives) return end __warnings_hidden[name] = true - events.emit("core:warning", "deprecated call", name) + events.emit("core:warning", "deprecated call", name, debug.get_traceback(2)) if alternatives then debug.warning("deprecated function called ("..name.."), use ".. alternatives.." instead\n"..debug.traceback()) @@ -292,3 +307,17 @@ function __scripts_cleanup() end end end + +function __vc__error(msg, frame) + if events then + events.emit("core:error", msg, debug.get_traceback(1)) + end + return debug.traceback(msg, frame) +end + +function __vc_warning(msg, detail, n) + if events then + events.emit( + "core:warning", msg, detail, debug.get_traceback(1 + (n or 0))) + end +end diff --git a/res/shaders/main.glslf b/res/shaders/main.glslf index 4c1cb014..7db1a544 100644 --- a/res/shaders/main.glslf +++ b/res/shaders/main.glslf @@ -9,14 +9,14 @@ uniform samplerCube u_cubemap; uniform vec3 u_fogColor; uniform float u_fogFactor; uniform float u_fogCurve; +uniform bool u_alphaClip; void main() { vec3 fogColor = texture(u_cubemap, a_dir).rgb; vec4 tex_color = texture(u_texture0, a_texCoord); float depth = (a_distance/256.0); float alpha = a_color.a * tex_color.a; - // anyway it's any alpha-test alternative required - if (alpha < 0.3f) + if (u_alphaClip && alpha < 0.9f) discard; f_color = mix(a_color * tex_color, vec4(fogColor,1.0), min(1.0, pow(depth*u_fogFactor, u_fogCurve))); diff --git a/res/texts/en_US.txt b/res/texts/en_US.txt index 9c9cc2a5..c19fe00a 100644 --- a/res/texts/en_US.txt +++ b/res/texts/en_US.txt @@ -11,6 +11,8 @@ world.delete-confirm=Do you want to delete world forever? world.generators.default=Default world.generators.flat=Flat +devtools.traceback=Traceback (most recent call first) + # Tooltips graphics.gamma.tooltip=Lighting brightness curve graphics.backlight.tooltip=Backlight to prevent total darkness diff --git a/res/texts/ru_RU.txt b/res/texts/ru_RU.txt index 74717336..346c5993 100644 --- a/res/texts/ru_RU.txt +++ b/res/texts/ru_RU.txt @@ -12,7 +12,15 @@ Dependencies=Зависимости Description=Описание Converting world...=Выполняется конвертация мира... Unlimited=Неограниченно +Chat=Чат +Console=Консоль +Log=Лог +Problems=Проблемы +Monitor=Мониторинг +Debug=Отладка +File=Файл +devtools.traceback=Стек вызовов (от последнего) error.pack-not-found=Не удалось найти пакет error.dependency-not-found=Используемая зависимость не найдена pack.remove-confirm=Удалить весь поставляемый паком/паками контент из мира (безвозвратно)? diff --git a/src/assets/assetload_funcs.cpp b/src/assets/assetload_funcs.cpp index a7d258ec..ce8b65c9 100644 --- a/src/assets/assetload_funcs.cpp +++ b/src/assets/assetload_funcs.cpp @@ -32,7 +32,7 @@ static debug::Logger logger("assetload-funcs"); namespace fs = std::filesystem; -static bool animation( +static bool load_animation( Assets* assets, const ResPaths* paths, const std::string& atlasName, @@ -102,8 +102,13 @@ static bool append_atlas(AtlasBuilder& atlas, const fs::path& file) { return true; } -assetload::postfunc assetload:: - atlas(AssetsLoader*, const ResPaths* paths, const std::string& directory, const std::string& name, const std::shared_ptr&) { +assetload::postfunc assetload::atlas( + AssetsLoader*, + const ResPaths* paths, + const std::string& directory, + const std::string& name, + const std::shared_ptr& +) { AtlasBuilder builder; for (const auto& file : paths->listdir(directory)) { if (!imageio::is_read_supported(file.extension().u8string())) continue; @@ -115,24 +120,41 @@ assetload::postfunc assetload:: atlas->prepare(); assets->store(std::unique_ptr(atlas), name); for (const auto& file : names) { - animation(assets, paths, name, directory, file, atlas); + load_animation(assets, paths, name, directory, file, atlas); } }; } -assetload::postfunc assetload:: - font(AssetsLoader*, const ResPaths* paths, const std::string& filename, const std::string& name, const std::shared_ptr&) { +assetload::postfunc assetload::font( + AssetsLoader*, + const ResPaths* paths, + const std::string& filename, + const std::string& name, + const std::shared_ptr& +) { auto pages = std::make_shared>>(); - for (size_t i = 0; i <= 4; i++) { + for (size_t i = 0; i <= 1024; i++) { std::string pagefile = filename + "_" + std::to_string(i) + ".png"; - pagefile = paths->find(pagefile).string(); - pages->push_back(imageio::read(pagefile)); + auto file = paths->find(pagefile); + if (fs::exists(file)) { + pages->push_back(imageio::read(file.u8string())); + } else if (i == 0) { + throw std::runtime_error("font must have page 0"); + } else { + pages->push_back(nullptr); + } } return [=](auto assets) { int res = pages->at(0)->getHeight() / 16; std::vector> textures; for (auto& page : *pages) { - textures.emplace_back(Texture::from(page.get())); + if (page == nullptr) { + textures.emplace_back(nullptr); + } else { + auto texture = Texture::from(page.get()); + texture->setMipMapping(false); + textures.emplace_back(std::move(texture)); + } } assets->store( std::make_unique(std::move(textures), res, 4), name @@ -150,7 +172,9 @@ assetload::postfunc assetload::layout( return [=](auto assets) { try { auto cfg = std::dynamic_pointer_cast(config); - assets->store(UiDocument::read(cfg->env, name, file), name); + assets->store( + UiDocument::read(cfg->env, name, file, "abs:" + file), name + ); } catch (const parsing_error& err) { throw std::runtime_error( "failed to parse layout XML '" + file + "':\n" + err.errorLog() @@ -316,11 +340,9 @@ static TextureAnimation create_animation( if (elem.second > 0) { frame.duration = static_cast(elem.second) / 1000.0f; } - frame.srcPos = - glm::ivec2( - region.u1 * srcWidth, srcHeight - region.v2 * srcHeight - ) - - extension; + frame.srcPos = glm::ivec2( + region.u1 * srcWidth, srcHeight - region.v2 * srcHeight + ) - extension; animation.addFrame(frame); } return animation; @@ -338,7 +360,7 @@ inline bool contains( return false; } -static bool animation( +static bool load_animation( Assets* assets, const ResPaths* paths, const std::string& atlasName, diff --git a/src/coders/commons.cpp b/src/coders/commons.cpp index 985c3440..de4fb755 100644 --- a/src/coders/commons.cpp +++ b/src/coders/commons.cpp @@ -373,7 +373,7 @@ std::string BasicParser::parseString(char quote, bool closeRequired) { case 'b': ss << '\b'; break; case 't': ss << '\t'; break; case 'f': ss << '\f'; break; - case '\'': ss << '\\'; break; + case '\'': ss << '\''; break; case '"': ss << '"'; break; case '\\': ss << '\\'; break; case '/': ss << '/'; break; diff --git a/src/coders/json.cpp b/src/coders/json.cpp index 05db4e13..f6b27f51 100644 --- a/src/coders/json.cpp +++ b/src/coders/json.cpp @@ -265,5 +265,5 @@ dv::value json::parse( } dv::value json::parse(std::string_view source) { - return parse("", source); + return parse("[string]", source); } diff --git a/src/coders/xml.cpp b/src/coders/xml.cpp index 6a8777c5..faf84f15 100644 --- a/src/coders/xml.cpp +++ b/src/coders/xml.cpp @@ -250,7 +250,8 @@ std::string Parser::parseText() { } nextChar(); } - return std::string(source.substr(start, pos - start)); + return Parser("[string]", std::string(source.substr(start, pos - start))) + .parseString('\0', false); } inline bool is_xml_identifier_start(char c) { @@ -336,7 +337,7 @@ xmldocument Parser::parse() { return document; } -xmldocument xml::parse(const std::string& filename, const std::string& source) { +xmldocument xml::parse(std::string_view filename, std::string_view source) { Parser parser(filename, source); return parser.parse(); } diff --git a/src/coders/xml.hpp b/src/coders/xml.hpp index 136c60df..54a2b589 100644 --- a/src/coders/xml.hpp +++ b/src/coders/xml.hpp @@ -140,6 +140,6 @@ namespace xml { /// @param source xml source code string /// @return xml document extern xmldocument parse( - const std::string& filename, const std::string& source + std::string_view filename, std::string_view source ); } diff --git a/src/constants.hpp b/src/constants.hpp index 53be95d2..84d8b22c 100644 --- a/src/constants.hpp +++ b/src/constants.hpp @@ -6,7 +6,7 @@ #include inline constexpr int ENGINE_VERSION_MAJOR = 0; -inline constexpr int ENGINE_VERSION_MINOR = 24; +inline constexpr int ENGINE_VERSION_MINOR = 25; #ifdef NDEBUG inline constexpr bool ENGINE_DEBUG_BUILD = false; @@ -14,7 +14,7 @@ inline constexpr bool ENGINE_DEBUG_BUILD = false; inline constexpr bool ENGINE_DEBUG_BUILD = true; #endif // NDEBUG -inline const std::string ENGINE_VERSION_STRING = "0.24"; +inline const std::string ENGINE_VERSION_STRING = "0.25"; /// @brief world regions format version inline constexpr uint REGION_FORMAT_VERSION = 3; @@ -35,9 +35,6 @@ inline constexpr int CHUNK_D = 16; inline constexpr uint VOXEL_USER_BITS = 8; inline constexpr uint VOXEL_USER_BITS_OFFSET = sizeof(blockstate_t)*8-VOXEL_USER_BITS; -/// @brief pixel size of an item inventory icon -inline constexpr int ITEM_ICON_SIZE = 48; - /// @brief chunk volume (count of voxels per Chunk) inline constexpr int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D); @@ -53,6 +50,11 @@ inline constexpr uint vox_index(uint x, uint y, uint z, uint w=CHUNK_W, uint d=C return (y * d + z) * w + x; } +/// @brief pixel size of an item inventory icon +inline constexpr int ITEM_ICON_SIZE = 48; + +inline constexpr int TRANSLUCENT_BLOCKS_SORT_INTERVAL = 8; + inline const std::string SHADERS_FOLDER = "shaders"; inline const std::string TEXTURES_FOLDER = "textures"; inline const std::string FONTS_FOLDER = "fonts"; diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index a801500e..cb50e4a5 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -333,6 +333,7 @@ void ContentLoader::loadBlock( root.at("inventory-size").get(def.inventorySize); root.at("tick-interval").get(def.tickInterval); root.at("overlay-texture").get(def.overlayTexture); + root.at("translucent").get(def.translucent); if (root.has("fields")) { def.dataStruct = std::make_unique(); @@ -484,7 +485,13 @@ void ContentLoader::loadBlock( auto scriptfile = folder / fs::path("scripts/" + def.scriptName + ".lua"); if (fs::is_regular_file(scriptfile)) { - scripting::load_block_script(env, full, scriptfile, def.rt.funcsset); + scripting::load_block_script( + env, + full, + scriptfile, + pack->id + ":scripts/" + def.scriptName + ".lua", + def.rt.funcsset + ); } if (!def.hidden) { auto& item = builder.items.create(full + BLOCK_ITEM_SUFFIX); @@ -510,7 +517,13 @@ void ContentLoader::loadItem( auto scriptfile = folder / fs::path("scripts/" + def.scriptName + ".lua"); if (fs::is_regular_file(scriptfile)) { - scripting::load_item_script(env, full, scriptfile, def.rt.funcsset); + scripting::load_item_script( + env, + full, + scriptfile, + pack->id + ":scripts/" + def.scriptName + ".lua", + def.rt.funcsset + ); } } @@ -719,7 +732,11 @@ void ContentLoader::load() { fs::path scriptFile = folder / fs::path("scripts/world.lua"); if (fs::is_regular_file(scriptFile)) { scripting::load_world_script( - env, pack->id, scriptFile, runtime->worldfuncsset + env, + pack->id, + scriptFile, + pack->id + ":scripts/world.lua", + runtime->worldfuncsset ); } @@ -794,7 +811,11 @@ void ContentLoader::load() { fs::path componentsDir = folder / fs::u8path("scripts/components"); foreach_file(componentsDir, [this](const fs::path& file) { auto name = pack->id + ":" + file.stem().u8string(); - scripting::load_entity_component(name, file); + scripting::load_entity_component( + name, + file, + pack->id + ":scripts/components/" + file.filename().u8string() + ); }); // Process content.json and load defined content units diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index 777e8ae1..166400c6 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -76,8 +76,19 @@ ContentPack ContentPack::read(const fs::path& folder) { root.at("id").get(pack.id); root.at("title").get(pack.title); root.at("version").get(pack.version); - root.at("creator").get(pack.creator); + if (root.has("creators")) { + const auto& creators = root["creators"]; + for (int i = 0; i < creators.size(); i++) { + if (i > 0) { + pack.creator += ", "; + } + pack.creator += creators[i].asString(); + } + } else { + root.at("creator").get(pack.creator); + } root.at("description").get(pack.description); + root.at("source").get(pack.source); pack.folder = folder; if (auto found = root.at("dependencies")) { diff --git a/src/content/ContentPack.hpp b/src/content/ContentPack.hpp index 5aa1a22b..9d25d752 100644 --- a/src/content/ContentPack.hpp +++ b/src/content/ContentPack.hpp @@ -44,6 +44,7 @@ struct ContentPack { std::string description = "no description"; fs::path folder; std::vector dependencies; + std::string source = ""; fs::path getContentFile() const; diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp index ebae9118..8aef7f7b 100644 --- a/src/content/loading/GeneratorLoader.cpp +++ b/src/content/loading/GeneratorLoader.cpp @@ -127,7 +127,7 @@ static VoxelStructureMeta load_structure_meta( ) { VoxelStructureMeta meta; meta.name = name; - + config.at("lowering").get(meta.lowering); return meta; } diff --git a/src/frontend/ContentGfxCache.cpp b/src/frontend/ContentGfxCache.cpp index 7d3944b7..c6ba4e1c 100644 --- a/src/frontend/ContentGfxCache.cpp +++ b/src/frontend/ContentGfxCache.cpp @@ -11,25 +11,25 @@ #include "maths/UVRegion.hpp" #include "voxels/Block.hpp" -ContentGfxCache::ContentGfxCache(const Content* content, Assets* assets) +ContentGfxCache::ContentGfxCache(const Content* content, const Assets& assets) : content(content) { auto indices = content->getIndices(); sideregions = std::make_unique(indices->blocks.count() * 6); - auto atlas = assets->get("blocks"); + const auto& atlas = assets.require("blocks"); const auto& blocks = indices->blocks.getIterable(); for (blockid_t i = 0; i < blocks.size(); i++) { auto def = blocks[i]; for (uint side = 0; side < 6; side++) { const std::string& tex = def->textureFaces[side]; - if (atlas->has(tex)) { - sideregions[i * 6 + side] = atlas->get(tex); - } else if (atlas->has(TEXTURE_NOTFOUND)) { - sideregions[i * 6 + side] = atlas->get(TEXTURE_NOTFOUND); + if (atlas.has(tex)) { + sideregions[i * 6 + side] = atlas.get(tex); + } else if (atlas.has(TEXTURE_NOTFOUND)) { + sideregions[i * 6 + side] = atlas.get(TEXTURE_NOTFOUND); } } if (def->model == BlockModel::custom) { - auto model = assets->require(def->modelName); + auto model = assets.require(def->modelName); // temporary dirty fix tbh if (def->modelName.find(':') == std::string::npos) { for (auto& mesh : model.meshes) { @@ -37,7 +37,7 @@ ContentGfxCache::ContentGfxCache(const Content* content, Assets* assets) if (pos == std::string::npos) { continue; } - if (auto region = atlas->getIf(mesh.texture.substr(pos+1))) { + if (auto region = atlas.getIf(mesh.texture.substr(pos+1))) { for (auto& vertex : mesh.vertices) { vertex.uv = region->apply(vertex.uv); } diff --git a/src/frontend/ContentGfxCache.hpp b/src/frontend/ContentGfxCache.hpp index 3d3161d3..96d46ea5 100644 --- a/src/frontend/ContentGfxCache.hpp +++ b/src/frontend/ContentGfxCache.hpp @@ -22,7 +22,7 @@ class ContentGfxCache { std::unique_ptr sideregions; std::unordered_map models; public: - ContentGfxCache(const Content* content, Assets* assets); + ContentGfxCache(const Content* content, const Assets& assets); ~ContentGfxCache(); inline const UVRegion& getRegion(blockid_t id, int side) const { @@ -30,6 +30,6 @@ public: } const model::Model& getModel(blockid_t id) const; - + const Content* getContent() const; }; diff --git a/src/frontend/LevelFrontend.cpp b/src/frontend/LevelFrontend.cpp index 977a0350..79784375 100644 --- a/src/frontend/LevelFrontend.cpp +++ b/src/frontend/LevelFrontend.cpp @@ -14,25 +14,28 @@ #include "world/Level.hpp" LevelFrontend::LevelFrontend( - Player* currentPlayer, LevelController* controller, Assets* assets -) : level(controller->getLevel()), + Player* currentPlayer, LevelController* controller, Assets& assets +) : level(*controller->getLevel()), controller(controller), assets(assets), - contentCache(std::make_unique(level->content, assets)) + contentCache(std::make_unique(level.content, assets)) { - assets->store( - BlocksPreview::build(contentCache.get(), assets, level->content), + assets.store( + BlocksPreview::build( + *contentCache, assets, *level.content->getIndices() + ), "block-previews" ); controller->getBlocksController()->listenBlockInteraction( - [=](auto player, const auto& pos, const auto& def, BlockInteraction type) { - auto material = level->content->findBlockMaterial(def.material); + [currentPlayer, controller, &assets](auto player, const auto& pos, const auto& def, BlockInteraction type) { + const auto& level = *controller->getLevel(); + auto material = level.content->findBlockMaterial(def.material); if (material == nullptr) { return; } if (type == BlockInteraction::step) { - auto sound = assets->get(material->stepsSound); + auto sound = assets.get(material->stepsSound); glm::vec3 pos {}; auto soundsCamera = currentPlayer->currentCamera.get(); if (soundsCamera == currentPlayer->spCamera.get() || @@ -58,10 +61,10 @@ LevelFrontend::LevelFrontend( audio::Sound* sound = nullptr; switch (type) { case BlockInteraction::placing: - sound = assets->get(material->placeSound); + sound = assets.get(material->placeSound); break; case BlockInteraction::destruction: - sound = assets->get(material->breakSound); + sound = assets.get(material->breakSound); break; default: break; @@ -83,16 +86,20 @@ LevelFrontend::LevelFrontend( LevelFrontend::~LevelFrontend() = default; -Level* LevelFrontend::getLevel() const { +Level& LevelFrontend::getLevel() { return level; } -Assets* LevelFrontend::getAssets() const { +const Level& LevelFrontend::getLevel() const { + return level; +} + +const Assets& LevelFrontend::getAssets() const { return assets; } -ContentGfxCache* LevelFrontend::getContentGfxCache() const { - return contentCache.get(); +const ContentGfxCache& LevelFrontend::getContentGfxCache() const { + return *contentCache; } LevelController* LevelFrontend::getController() const { diff --git a/src/frontend/LevelFrontend.hpp b/src/frontend/LevelFrontend.hpp index ed149598..163fc678 100644 --- a/src/frontend/LevelFrontend.hpp +++ b/src/frontend/LevelFrontend.hpp @@ -9,16 +9,17 @@ class ContentGfxCache; class LevelController; class LevelFrontend { - Level* level; + Level& level; LevelController* controller; - Assets* assets; + const Assets& assets; std::unique_ptr contentCache; public: - LevelFrontend(Player* currentPlayer, LevelController* controller, Assets* assets); + LevelFrontend(Player* currentPlayer, LevelController* controller, Assets& assets); ~LevelFrontend(); - Level* getLevel() const; - Assets* getAssets() const; - ContentGfxCache* getContentGfxCache() const; + Level& getLevel(); + const Level& getLevel() const; + const Assets& getAssets() const; + const ContentGfxCache& getContentGfxCache() const; LevelController* getController() const; }; diff --git a/src/frontend/UiDocument.cpp b/src/frontend/UiDocument.cpp index e218d975..fff98f3f 100644 --- a/src/frontend/UiDocument.cpp +++ b/src/frontend/UiDocument.cpp @@ -53,7 +53,12 @@ scriptenv UiDocument::getEnvironment() const { return env; } -std::unique_ptr UiDocument::read(const scriptenv& penv, const std::string& name, const fs::path& file) { +std::unique_ptr UiDocument::read( + const scriptenv& penv, + const std::string& name, + const fs::path& file, + const std::string& fileName +) { const std::string text = files::read_string(file); auto xmldoc = xml::parse(file.u8string(), text); @@ -69,12 +74,16 @@ std::unique_ptr UiDocument::read(const scriptenv& penv, const std::s uidocscript script {}; auto scriptFile = fs::path(file.u8string()+".lua"); if (fs::is_regular_file(scriptFile)) { - scripting::load_layout_script(env, name, scriptFile, script); + scripting::load_layout_script( + env, name, scriptFile, fileName + ".lua", script + ); } return std::make_unique(name, script, view, env); } -std::shared_ptr UiDocument::readElement(const fs::path& file) { - auto document = read(nullptr, file.filename().u8string(), file); +std::shared_ptr UiDocument::readElement( + const fs::path& file, const std::string& fileName +) { + auto document = read(nullptr, file.filename().u8string(), file, fileName); return document->getRoot(); } diff --git a/src/frontend/UiDocument.hpp b/src/frontend/UiDocument.hpp index dcd2a34e..dbf91ef1 100644 --- a/src/frontend/UiDocument.hpp +++ b/src/frontend/UiDocument.hpp @@ -45,6 +45,13 @@ public: const uidocscript& getScript() const; scriptenv getEnvironment() const; - static std::unique_ptr read(const scriptenv& parent_env, const std::string& name, const fs::path& file); - static std::shared_ptr readElement(const fs::path& file); + static std::unique_ptr read( + const scriptenv& parent_env, + const std::string& name, + const fs::path& file, + const std::string& fileName + ); + static std::shared_ptr readElement( + const fs::path& file, const std::string& fileName + ); }; diff --git a/src/frontend/debug_panel.cpp b/src/frontend/debug_panel.cpp index b3d6aca0..9043f5b9 100644 --- a/src/frontend/debug_panel.cpp +++ b/src/frontend/debug_panel.cpp @@ -11,6 +11,7 @@ #include "graphics/ui/elements/InputBindBox.hpp" #include "graphics/render/WorldRenderer.hpp" #include "graphics/render/ParticlesRenderer.hpp" +#include "graphics/render/ChunksRenderer.hpp" #include "logic/scripting/scripting.hpp" #include "objects/Player.hpp" #include "objects/Entities.hpp" @@ -41,8 +42,8 @@ static std::shared_ptr