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 0a6ad4c3..4f132462 100644 --- a/doc/en/scripting/ui.md +++ b/doc/en/scripting/ui.md @@ -78,14 +78,18 @@ Properties: | 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/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/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 0a955947..4d244210 100644 --- a/doc/ru/scripting/ui.md +++ b/doc/ru/scripting/ui.md @@ -78,14 +78,18 @@ document["worlds-panel"]:clear() | 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/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/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') ".. + "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/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/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..996af40e 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,10 @@ 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 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 b73a3882..ce8b65c9 100644 --- a/src/assets/assetload_funcs.cpp +++ b/src/assets/assetload_funcs.cpp @@ -172,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() 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/xml.cpp b/src/coders/xml.cpp index 6a8777c5..3110d98a 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("", 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/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index 4414999d..cb50e4a5 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -485,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); @@ -511,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 + ); } } @@ -720,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 ); } @@ -795,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/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/hud.cpp b/src/frontend/hud.cpp index 032d0602..889b102f 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -230,7 +230,11 @@ void Hud::processInput(bool visible) { } } if (!pause && Events::jactive(BIND_DEVTOOLS_CONSOLE)) { - showOverlay(assets->get("core:console"), false); + showOverlay( + assets->get("core:console"), + false, + std::string("console") + ); } if (!Window::isFocused() && !pause && !isInventoryOpen()) { setPause(true); @@ -465,7 +469,9 @@ void Hud::showExchangeSlot() { } -void Hud::showOverlay(UiDocument* doc, bool playerInventory) { +void Hud::showOverlay( + UiDocument* doc, bool playerInventory, const dv::value& arg +) { if (isInventoryOpen()) { closeInventory(); } @@ -476,7 +482,8 @@ void Hud::showOverlay(UiDocument* doc, bool playerInventory) { showExchangeSlot(); inventoryOpen = true; } - add(HudElement(hud_element_mode::inventory_bound, doc, secondUI, false)); + add(HudElement(hud_element_mode::inventory_bound, doc, secondUI, false), + arg); } void Hud::openPermanent(UiDocument* doc) { @@ -508,13 +515,13 @@ void Hud::closeInventory() { cleanup(); } -void Hud::add(const HudElement& element) { +void Hud::add(const HudElement& element, const dv::value& arg) { gui->add(element.getNode()); auto document = element.getDocument(); if (document) { auto invview = std::dynamic_pointer_cast(element.getNode()); auto inventory = invview ? invview->getInventory() : nullptr; - std::vector args; + std::vector args {arg}; args.emplace_back(inventory ? inventory.get()->getId() : 0); for (int i = 0; i < 3; i++) { args.emplace_back(static_cast(blockPos[i])); @@ -615,8 +622,11 @@ void Hud::updateElementsPosition(const Viewport& viewport) { } if (secondUI->getPositionFunc() == nullptr) { secondUI->setPos(glm::vec2( - glm::min(width/2-invwidth/2, width-caWidth-(inventoryView ? 10 : 0)-invwidth), - height/2-totalHeight/2 + glm::min( + width / 2.f - invwidth / 2.f, + width - caWidth - (inventoryView ? 10 : 0) - invwidth + ), + height / 2.f - totalHeight / 2.f )); } } diff --git a/src/frontend/hud.hpp b/src/frontend/hud.hpp index c5708527..4a2ecfd5 100644 --- a/src/frontend/hud.hpp +++ b/src/frontend/hud.hpp @@ -2,6 +2,7 @@ #include "typedefs.hpp" #include "util/ObjectsKeeper.hpp" +#include "data/dv.hpp" #include #include @@ -173,7 +174,10 @@ public: /// @brief Show element in inventory-mode /// @param doc element layout /// @param playerInventory show player inventory too - void showOverlay(UiDocument* doc, bool playerInventory); + /// @param arg first argument passing to on_open + void showOverlay( + UiDocument* doc, bool playerInventory, const dv::value& arg = nullptr + ); /// @brief Close all open inventories and overlay void closeInventory(); @@ -182,7 +186,7 @@ public: /// @param doc element layout void openPermanent(UiDocument* doc); - void add(const HudElement& element); + void add(const HudElement& element, const dv::value& arg=nullptr); void onRemove(const HudElement& element); void remove(const std::shared_ptr& node); diff --git a/src/frontend/menu.cpp b/src/frontend/menu.cpp index 7955fad5..0aa0a74e 100644 --- a/src/frontend/menu.cpp +++ b/src/frontend/menu.cpp @@ -62,7 +62,10 @@ gui::page_loader_func menus::create_page_loader(Engine* engine) { auto fullname = "core:pages/"+name; auto document_ptr = UiDocument::read( - scripting::get_root_environment(), fullname, file + scripting::get_root_environment(), + fullname, + file, + "core:layout/pages/" + name ); auto document = document_ptr.get(); engine->getAssets()->store(std::move(document_ptr), fullname); @@ -110,7 +113,7 @@ UiDocument* menus::show(Engine* engine, const std::string& name, std::vectorgetAssets()->store(std::move(document_ptr), fullname); diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index fed19cdd..1acd9200 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -83,7 +83,12 @@ void LevelScreen::initializePack(ContentPackRuntime* pack) { const ContentPack& info = pack->getInfo(); fs::path scriptFile = info.folder/fs::path("scripts/hud.lua"); if (fs::is_regular_file(scriptFile)) { - scripting::load_hud_script(pack->getEnvironment(), info.id, scriptFile); + scripting::load_hud_script( + pack->getEnvironment(), + info.id, + scriptFile, + pack->getId() + ":scripts/hud.lua" + ); } } diff --git a/src/graphics/core/DrawContext.cpp b/src/graphics/core/DrawContext.cpp index 29afae2e..7062ad56 100644 --- a/src/graphics/core/DrawContext.cpp +++ b/src/graphics/core/DrawContext.cpp @@ -91,6 +91,7 @@ DrawContext DrawContext::sub(Flushable* flushable) const { auto ctx = DrawContext(*this); ctx.parent = this; ctx.flushable = flushable; + ctx.scissorsCount = 0; return ctx; } @@ -148,7 +149,7 @@ void DrawContext::setBlendMode(BlendMode mode) { set_blend_mode(mode); } -void DrawContext::setScissors(glm::vec4 area) { +void DrawContext::setScissors(const glm::vec4& area) { Window::pushScissor(area); scissorsCount++; } diff --git a/src/graphics/core/DrawContext.hpp b/src/graphics/core/DrawContext.hpp index 9174be1b..736b053e 100644 --- a/src/graphics/core/DrawContext.hpp +++ b/src/graphics/core/DrawContext.hpp @@ -34,6 +34,6 @@ public: void setDepthTest(bool flag); void setCullFace(bool flag); void setBlendMode(BlendMode mode); - void setScissors(glm::vec4 area); + void setScissors(const glm::vec4& area); void setLineWidth(float width); }; diff --git a/src/graphics/ui/elements/Container.cpp b/src/graphics/ui/elements/Container.cpp index 3b8fd0ac..fdd0bc02 100644 --- a/src/graphics/ui/elements/Container.cpp +++ b/src/graphics/ui/elements/Container.cpp @@ -90,7 +90,7 @@ void Container::draw(const DrawContext* pctx, Assets* assets) { if (!nodes.empty()) { batch->flush(); DrawContext ctx = pctx->sub(); - ctx.setScissors(glm::vec4(pos.x, pos.y, size.x, size.y)); + ctx.setScissors(glm::vec4(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y))); for (const auto& node : nodes) { if (node->isVisible()) node->draw(pctx, assets); @@ -108,7 +108,7 @@ void Container::drawBackground(const DrawContext* pctx, Assets*) { auto batch = pctx->getBatch2D(); batch->texture(nullptr); batch->setColor(color); - batch->rect(pos.x, pos.y, size.x, size.y); + batch->rect(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y)); } void Container::add(const std::shared_ptr &node) { @@ -165,6 +165,14 @@ void Container::setSize(glm::vec2 size) { } } +int Container::getScrollStep() const { + return scrollStep; +} + +void Container::setScrollStep(int step) { + scrollStep = step; +} + void Container::refresh() { std::stable_sort(nodes.begin(), nodes.end(), [](const auto& a, const auto& b) { return a->getZIndex() < b->getZIndex(); diff --git a/src/graphics/ui/elements/Container.hpp b/src/graphics/ui/elements/Container.hpp index a5cca04c..bfe40ab5 100644 --- a/src/graphics/ui/elements/Container.hpp +++ b/src/graphics/ui/elements/Container.hpp @@ -32,6 +32,8 @@ namespace gui { void listenInterval(float interval, ontimeout callback, int repeat=-1); virtual glm::vec2 getContentOffset() override {return glm::vec2(0.0f, scroll);}; virtual void setSize(glm::vec2 size) override; + virtual int getScrollStep() const; + virtual void setScrollStep(int step); virtual void refresh() override; const std::vector>& getNodes() const; diff --git a/src/graphics/ui/elements/TextBox.cpp b/src/graphics/ui/elements/TextBox.cpp index 9fe44327..6a54d682 100644 --- a/src/graphics/ui/elements/TextBox.cpp +++ b/src/graphics/ui/elements/TextBox.cpp @@ -1,5 +1,6 @@ #include "TextBox.hpp" +#include #include #include @@ -14,24 +15,39 @@ using namespace gui; +inline constexpr int LINE_NUMBERS_PANE_WIDTH = 40; + TextBox::TextBox(std::wstring placeholder, glm::vec4 padding) - : Panel(glm::vec2(200,32), padding, 0), + : Container(glm::vec2(200,32)), + padding(padding), input(L""), placeholder(std::move(placeholder)) { setOnUpPressed(nullptr); setOnDownPressed(nullptr); + setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.75f)); label = std::make_shared