Merge pull request #586 from MihailRis/more-about-projects
More about projects
This commit is contained in:
commit
a8f2de967f
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,6 +9,7 @@ Debug/voxel_engine
|
|||||||
/export
|
/export
|
||||||
/config
|
/config
|
||||||
/out
|
/out
|
||||||
|
/projects
|
||||||
|
|
||||||
/misc
|
/misc
|
||||||
/world
|
/world
|
||||||
|
|||||||
@ -10,6 +10,7 @@ Subsections:
|
|||||||
- [Entities and components](scripting/ecs.md)
|
- [Entities and components](scripting/ecs.md)
|
||||||
- [Libraries](#)
|
- [Libraries](#)
|
||||||
- [app](scripting/builtins/libapp.md)
|
- [app](scripting/builtins/libapp.md)
|
||||||
|
- [assets](scripting/builtins/libassets.md)
|
||||||
- [base64](scripting/builtins/libbase64.md)
|
- [base64](scripting/builtins/libbase64.md)
|
||||||
- [bjson, json, toml, yaml](scripting/filesystem.md)
|
- [bjson, json, toml, yaml](scripting/filesystem.md)
|
||||||
- [block](scripting/builtins/libblock.md)
|
- [block](scripting/builtins/libblock.md)
|
||||||
|
|||||||
28
doc/en/scripting/builtins/libassets.md
Normal file
28
doc/en/scripting/builtins/libassets.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# *assets* library
|
||||||
|
|
||||||
|
A library for working with audio/visual assets.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- Loads a texture
|
||||||
|
assets.load_texture(
|
||||||
|
-- Array of bytes of an image file
|
||||||
|
data: table | Bytearray,
|
||||||
|
-- Texture name after loading
|
||||||
|
name: str,
|
||||||
|
-- Image file format (only png is supported)
|
||||||
|
[optional]
|
||||||
|
format: str = "png"
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Parses and loads a 3D model
|
||||||
|
assets.parse_model(
|
||||||
|
-- Model file format (xml / vcm)
|
||||||
|
format: str,
|
||||||
|
-- Contents of the model file
|
||||||
|
content: str,
|
||||||
|
-- Model name after loading
|
||||||
|
name: str
|
||||||
|
)
|
||||||
|
```
|
||||||
@ -103,3 +103,9 @@ gui.load_document(
|
|||||||
```
|
```
|
||||||
|
|
||||||
Loads a UI document with its script, returns the name of the document if successfully loaded.
|
Loads a UI document with its script, returns the name of the document if successfully loaded.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
gui.root: Document
|
||||||
|
```
|
||||||
|
|
||||||
|
Root UI document
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
- [Сущности и компоненты](scripting/ecs.md)
|
- [Сущности и компоненты](scripting/ecs.md)
|
||||||
- [Библиотеки](#)
|
- [Библиотеки](#)
|
||||||
- [app](scripting/builtins/libapp.md)
|
- [app](scripting/builtins/libapp.md)
|
||||||
|
- [assets](scripting/builtins/libassets.md)
|
||||||
- [base64](scripting/builtins/libbase64.md)
|
- [base64](scripting/builtins/libbase64.md)
|
||||||
- [bjson, json, toml, yaml](scripting/filesystem.md)
|
- [bjson, json, toml, yaml](scripting/filesystem.md)
|
||||||
- [block](scripting/builtins/libblock.md)
|
- [block](scripting/builtins/libblock.md)
|
||||||
|
|||||||
28
doc/ru/scripting/builtins/libassets.md
Normal file
28
doc/ru/scripting/builtins/libassets.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Библиотека *assets*
|
||||||
|
|
||||||
|
Библиотека для работы с аудио/визуальными загружаемыми ресурсами.
|
||||||
|
|
||||||
|
## Функции
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- Загружает текстуру
|
||||||
|
assets.load_texture(
|
||||||
|
-- Массив байт файла изображения
|
||||||
|
data: table | Bytearray,
|
||||||
|
-- Имя текстуры после загрузки
|
||||||
|
name: str,
|
||||||
|
-- Формат файла изображения (поддерживается только png)
|
||||||
|
[опционально]
|
||||||
|
format: str = "png"
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Парсит и загружает 3D модель
|
||||||
|
assets.parse_model(
|
||||||
|
-- Формат файла модели (xml / vcm)
|
||||||
|
format: str,
|
||||||
|
-- Содержимое файла модели
|
||||||
|
content: str,
|
||||||
|
-- Имя модели после загрузки
|
||||||
|
name: str
|
||||||
|
)
|
||||||
|
```
|
||||||
@ -100,3 +100,9 @@ gui.load_document(
|
|||||||
```
|
```
|
||||||
|
|
||||||
Загружает UI документ с его скриптом, возвращает имя документа, если успешно загружен.
|
Загружает UI документ с его скриптом, возвращает имя документа, если успешно загружен.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
gui.root: Document
|
||||||
|
```
|
||||||
|
|
||||||
|
Корневой UI документ
|
||||||
|
|||||||
@ -21,6 +21,9 @@ function on_hud_open()
|
|||||||
local ppos = vec3.add({player.get_pos(pid)}, {0, 0.7, 0})
|
local ppos = vec3.add({player.get_pos(pid)}, {0, 0.7, 0})
|
||||||
local throw_force = vec3.mul(player.get_dir(pid), DROP_FORCE)
|
local throw_force = vec3.mul(player.get_dir(pid), DROP_FORCE)
|
||||||
local drop = base_util.drop(ppos, itemid, 1, data, 1.5)
|
local drop = base_util.drop(ppos, itemid, 1, data, 1.5)
|
||||||
|
if not drop then
|
||||||
|
return
|
||||||
|
end
|
||||||
local velocity = vec3.add(throw_force, vec3.add(pvel, DROP_INIT_VEL))
|
local velocity = vec3.add(throw_force, vec3.add(pvel, DROP_INIT_VEL))
|
||||||
drop.rigidbody:set_vel(velocity)
|
drop.rigidbody:set_vel(velocity)
|
||||||
end)
|
end)
|
||||||
|
|||||||
@ -81,6 +81,11 @@ local function refresh_file_title()
|
|||||||
document.saveIcon.enabled = edited
|
document.saveIcon.enabled = edited
|
||||||
document.title.text = gui.str('File')..' - '..current_file.filename
|
document.title.text = gui.str('File')..' - '..current_file.filename
|
||||||
..(edited and ' *' or '')
|
..(edited and ' *' or '')
|
||||||
|
|
||||||
|
local info = registry.get_info(current_file.filename)
|
||||||
|
if info and info.type == "model" then
|
||||||
|
pcall(run_current_file)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function on_control_combination(keycode)
|
function on_control_combination(keycode)
|
||||||
@ -118,7 +123,6 @@ function run_current_file()
|
|||||||
local unit = info and info.unit
|
local unit = info and info.unit
|
||||||
|
|
||||||
if script_type == "model" then
|
if script_type == "model" then
|
||||||
print(current_file.filename)
|
|
||||||
clear_output()
|
clear_output()
|
||||||
local _, err = pcall(reload_model, current_file.filename, unit)
|
local _, err = pcall(reload_model, current_file.filename, unit)
|
||||||
if err then
|
if err then
|
||||||
@ -256,7 +260,7 @@ function open_file_in_editor(filename, line, mutable)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function on_open(mode)
|
function on_open(mode)
|
||||||
registry = require "core:internal/scripts_registry"
|
registry = __vc_scripts_registry
|
||||||
|
|
||||||
document.codePanel:setInterval(200, refresh_file_title)
|
document.codePanel:setInterval(200, refresh_file_title)
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ history = session.get_entry("commands_history")
|
|||||||
history_pointer = #history
|
history_pointer = #history
|
||||||
|
|
||||||
events.on("core:open_traceback", function()
|
events.on("core:open_traceback", function()
|
||||||
if modes then
|
if modes and modes.current ~= 'debug' then
|
||||||
modes:set('debug')
|
modes:set('debug')
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|||||||
@ -43,11 +43,8 @@ function build_files_list(filenames, highlighted_part)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function on_open(mode)
|
function on_open()
|
||||||
registry = require "core:internal/scripts_registry"
|
registry = __vc_scripts_registry
|
||||||
|
|
||||||
local files_list = document.filesList
|
|
||||||
|
|
||||||
filenames = registry.filenames
|
filenames = registry.filenames
|
||||||
table.sort(filenames)
|
table.sort(filenames)
|
||||||
build_files_list(filenames)
|
build_files_list(filenames)
|
||||||
|
|||||||
48
res/modules/internal/events.lua
Normal file
48
res/modules/internal/events.lua
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
local events = {
|
||||||
|
handlers = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function events.on(event, func)
|
||||||
|
if events.handlers[event] == nil then
|
||||||
|
events.handlers[event] = {}
|
||||||
|
end
|
||||||
|
table.insert(events.handlers[event], func)
|
||||||
|
end
|
||||||
|
|
||||||
|
function events.reset(event, func)
|
||||||
|
if func == nil then
|
||||||
|
events.handlers[event] = nil
|
||||||
|
else
|
||||||
|
events.handlers[event] = {func}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function events.remove_by_prefix(prefix)
|
||||||
|
for name, handlers in pairs(events.handlers) do
|
||||||
|
local actualname = name
|
||||||
|
if type(name) == 'table' then
|
||||||
|
actualname = name[1]
|
||||||
|
end
|
||||||
|
if actualname:sub(1, #prefix+1) == prefix..':' then
|
||||||
|
events.handlers[actualname] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function events.emit(event, ...)
|
||||||
|
local result = nil
|
||||||
|
local handlers = events.handlers[event]
|
||||||
|
if handlers == nil then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
for _, func in ipairs(handlers) do
|
||||||
|
local status, newres = xpcall(func, __vc__error, ...)
|
||||||
|
if not status then
|
||||||
|
debug.error("error in event ("..event..") handler: "..newres)
|
||||||
|
else
|
||||||
|
result = result or newres
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
return events
|
||||||
212
res/modules/internal/maths_inline.lua
Normal file
212
res/modules/internal/maths_inline.lua
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
-- =================================================== --
|
||||||
|
-- ====================== vec3 ======================= --
|
||||||
|
-- =================================================== --
|
||||||
|
function vec3.add(a, b, dst)
|
||||||
|
local btype = type(b)
|
||||||
|
if dst then
|
||||||
|
if btype == "table" then
|
||||||
|
dst[1] = a[1] + b[1]
|
||||||
|
dst[2] = a[2] + b[2]
|
||||||
|
dst[3] = a[3] + b[3]
|
||||||
|
else
|
||||||
|
dst[1] = a[1] + b
|
||||||
|
dst[2] = a[2] + b
|
||||||
|
dst[3] = a[3] + b
|
||||||
|
end
|
||||||
|
return dst
|
||||||
|
else
|
||||||
|
if btype == "table" then
|
||||||
|
return {a[1] + b[1], a[2] + b[2], a[3] + b[3]}
|
||||||
|
else
|
||||||
|
return {a[1] + b, a[2] + b, a[3] + b}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function vec3.sub(a, b, dst)
|
||||||
|
local btype = type(b)
|
||||||
|
if dst then
|
||||||
|
if btype == "table" then
|
||||||
|
dst[1] = a[1] - b[1]
|
||||||
|
dst[2] = a[2] - b[2]
|
||||||
|
dst[3] = a[3] - b[3]
|
||||||
|
else
|
||||||
|
dst[1] = a[1] - b
|
||||||
|
dst[2] = a[2] - b
|
||||||
|
dst[3] = a[3] - b
|
||||||
|
end
|
||||||
|
return dst
|
||||||
|
else
|
||||||
|
if btype == "table" then
|
||||||
|
return {a[1] - b[1], a[2] - b[2], a[3] - b[3]}
|
||||||
|
else
|
||||||
|
return {a[1] - b, a[2] - b, a[3] - b}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function vec3.mul(a, b, dst)
|
||||||
|
local btype = type(b)
|
||||||
|
if dst then
|
||||||
|
if btype == "table" then
|
||||||
|
dst[1] = a[1] * b[1]
|
||||||
|
dst[2] = a[2] * b[2]
|
||||||
|
dst[3] = a[3] * b[3]
|
||||||
|
else
|
||||||
|
dst[1] = a[1] * b
|
||||||
|
dst[2] = a[2] * b
|
||||||
|
dst[3] = a[3] * b
|
||||||
|
end
|
||||||
|
return dst
|
||||||
|
else
|
||||||
|
if btype == "table" then
|
||||||
|
return {a[1] * b[1], a[2] * b[2], a[3] * b[3]}
|
||||||
|
else
|
||||||
|
return {a[1] * b, a[2] * b, a[3] * b}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function vec3.div(a, b, dst)
|
||||||
|
local btype = type(b)
|
||||||
|
if dst then
|
||||||
|
if btype == "table" then
|
||||||
|
dst[1] = a[1] / b[1]
|
||||||
|
dst[2] = a[2] / b[2]
|
||||||
|
dst[3] = a[3] / b[3]
|
||||||
|
else
|
||||||
|
dst[1] = a[1] / b
|
||||||
|
dst[2] = a[2] / b
|
||||||
|
dst[3] = a[3] / b
|
||||||
|
end
|
||||||
|
return dst
|
||||||
|
else
|
||||||
|
if btype == "table" then
|
||||||
|
return {a[1] / b[1], a[2] / b[2], a[3] / b[3]}
|
||||||
|
else
|
||||||
|
return {a[1] / b, a[2] / b, a[3] / b}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function vec3.abs(a, dst)
|
||||||
|
local x = a[1]
|
||||||
|
local y = a[2]
|
||||||
|
local z = a[3]
|
||||||
|
if dst then
|
||||||
|
dst[1] = x < 0.0 and -x or x
|
||||||
|
dst[2] = y < 0.0 and -y or y
|
||||||
|
dst[3] = z < 0.0 and -z or z
|
||||||
|
else
|
||||||
|
return {
|
||||||
|
x < 0.0 and -x or x,
|
||||||
|
y < 0.0 and -y or y,
|
||||||
|
z < 0.0 and -z or z,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function vec3.dot(a, b)
|
||||||
|
return a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- =================================================== --
|
||||||
|
-- ====================== vec2 ======================= --
|
||||||
|
-- =================================================== --
|
||||||
|
function vec2.add(a, b, dst)
|
||||||
|
local btype = type(b)
|
||||||
|
if dst then
|
||||||
|
if btype == "table" then
|
||||||
|
dst[1] = a[1] + b[1]
|
||||||
|
dst[2] = a[2] + b[2]
|
||||||
|
else
|
||||||
|
dst[1] = a[1] + b
|
||||||
|
dst[2] = a[2] + b
|
||||||
|
end
|
||||||
|
return dst
|
||||||
|
else
|
||||||
|
if btype == "table" then
|
||||||
|
return {a[1] + b[1], a[2] + b[2]}
|
||||||
|
else
|
||||||
|
return {a[1] + b, a[2] + b}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function vec2.sub(a, b, dst)
|
||||||
|
local btype = type(b)
|
||||||
|
if dst then
|
||||||
|
if btype == "table" then
|
||||||
|
dst[1] = a[1] - b[1]
|
||||||
|
dst[2] = a[2] - b[2]
|
||||||
|
else
|
||||||
|
dst[1] = a[1] - b
|
||||||
|
dst[2] = a[2] - b
|
||||||
|
end
|
||||||
|
return dst
|
||||||
|
else
|
||||||
|
if btype == "table" then
|
||||||
|
return {a[1] - b[1], a[2] - b[2]}
|
||||||
|
else
|
||||||
|
return {a[1] - b, a[2] - b}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function vec2.mul(a, b, dst)
|
||||||
|
local btype = type(b)
|
||||||
|
if dst then
|
||||||
|
if btype == "table" then
|
||||||
|
dst[1] = a[1] * b[1]
|
||||||
|
dst[2] = a[2] * b[2]
|
||||||
|
else
|
||||||
|
dst[1] = a[1] * b
|
||||||
|
dst[2] = a[2] * b
|
||||||
|
end
|
||||||
|
return dst
|
||||||
|
else
|
||||||
|
if btype == "table" then
|
||||||
|
return {a[1] * b[1], a[2] * b[2]}
|
||||||
|
else
|
||||||
|
return {a[1] * b, a[2] * b}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function vec2.div(a, b, dst)
|
||||||
|
local btype = type(b)
|
||||||
|
if dst then
|
||||||
|
if btype == "table" then
|
||||||
|
dst[1] = a[1] / b[1]
|
||||||
|
dst[2] = a[2] / b[2]
|
||||||
|
else
|
||||||
|
dst[1] = a[1] / b
|
||||||
|
dst[2] = a[2] / b
|
||||||
|
end
|
||||||
|
return dst
|
||||||
|
else
|
||||||
|
if btype == "table" then
|
||||||
|
return {a[1] / b[1], a[2] / b[2]}
|
||||||
|
else
|
||||||
|
return {a[1] / b, a[2] / b}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function vec2.abs(a, dst)
|
||||||
|
local x = a[1]
|
||||||
|
local y = a[2]
|
||||||
|
if dst then
|
||||||
|
dst[1] = x < 0.0 and -x or x
|
||||||
|
dst[2] = y < 0.0 and -y or y
|
||||||
|
else
|
||||||
|
return {
|
||||||
|
x < 0.0 and -x or x,
|
||||||
|
y < 0.0 and -y or y,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function vec2.dot(a, b)
|
||||||
|
return a[1] * b[1] + a[2] * b[2]
|
||||||
|
end
|
||||||
@ -22,16 +22,16 @@ local O_NONBLOCK = 0x800
|
|||||||
local F_GETFL = 3
|
local F_GETFL = 3
|
||||||
|
|
||||||
local function getError()
|
local function getError()
|
||||||
local err = ffi.errno()
|
local err = FFI.errno()
|
||||||
|
|
||||||
return ffi.string(C.strerror(err)).." ("..err..")"
|
return FFI.string(C.strerror(err)).." ("..err..")"
|
||||||
end
|
end
|
||||||
|
|
||||||
local lib = {}
|
local lib = {}
|
||||||
|
|
||||||
function lib.read(fd, len)
|
function lib.read(fd, len)
|
||||||
local buffer = FFI.new("uint8_t[?]", len)
|
local buffer = FFI.new("uint8_t[?]", len)
|
||||||
local result = C.read(fd, buffer, len)
|
local result = tonumber(C.read(fd, buffer, len))
|
||||||
|
|
||||||
local out = Bytearray()
|
local out = Bytearray()
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,9 @@ local Schedule = {
|
|||||||
local timer = self._timer + dt
|
local timer = self._timer + dt
|
||||||
for id, interval in pairs(self._intervals) do
|
for id, interval in pairs(self._intervals) do
|
||||||
if timer - interval.last_called >= interval.delay then
|
if timer - interval.last_called >= interval.delay then
|
||||||
xpcall(interval.callback, function(s)
|
local stack_size = debug.count_frames()
|
||||||
debug.error(s..'\n'..debug.traceback())
|
xpcall(interval.callback, function(msg)
|
||||||
|
__vc__error(msg, 1, 1, stack_size)
|
||||||
end)
|
end)
|
||||||
interval.last_called = timer
|
interval.last_called = timer
|
||||||
local repetions = interval.repetions
|
local repetions = interval.repetions
|
||||||
|
|||||||
26
res/project_client.lua
Normal file
26
res/project_client.lua
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
local menubg
|
||||||
|
|
||||||
|
function on_menu_clear()
|
||||||
|
if menubg then
|
||||||
|
menubg:destruct()
|
||||||
|
menubg = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_menu_setup()
|
||||||
|
local controller = {}
|
||||||
|
function controller.resize_menu_bg()
|
||||||
|
local w, h = unpack(gui.get_viewport())
|
||||||
|
if menubg then
|
||||||
|
menubg.region = {0, math.floor(h / 48), math.floor(w / 48), 0}
|
||||||
|
menubg.pos = {0, 0}
|
||||||
|
end
|
||||||
|
return w, h
|
||||||
|
end
|
||||||
|
gui.root.root:add(
|
||||||
|
"<image id='menubg' src='gui/menubg' size-func='DATA.resize_menu_bg' "..
|
||||||
|
"z-index='-1' interactive='true'/>", controller)
|
||||||
|
menubg = gui.root.menubg
|
||||||
|
controller.resize_menu_bg()
|
||||||
|
menu.page = "main"
|
||||||
|
end
|
||||||
@ -62,5 +62,4 @@ end
|
|||||||
cache_names(block)
|
cache_names(block)
|
||||||
cache_names(item)
|
cache_names(item)
|
||||||
|
|
||||||
local scripts_registry = require "core:internal/scripts_registry"
|
__vc_scripts_registry.build_registry()
|
||||||
scripts_registry.build_registry()
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
local enable_experimental = core.get_setting("debug.enable-experimental")
|
||||||
|
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
------ Extended kit of standard functions ------
|
------ Extended kit of standard functions ------
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
@ -168,61 +170,16 @@ function inventory.set_description(invid, slot, description)
|
|||||||
inventory.set_data(invid, slot, "description", description)
|
inventory.set_data(invid, slot, "description", description)
|
||||||
end
|
end
|
||||||
|
|
||||||
------------------------------------------------
|
if enable_experimental then
|
||||||
------------------- Events ---------------------
|
require "core:internal/maths_inline"
|
||||||
------------------------------------------------
|
|
||||||
events = {
|
|
||||||
handlers = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
function events.on(event, func)
|
|
||||||
if events.handlers[event] == nil then
|
|
||||||
events.handlers[event] = {}
|
|
||||||
end
|
|
||||||
table.insert(events.handlers[event], func)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function events.reset(event, func)
|
events = require "core:internal/events"
|
||||||
if func == nil then
|
|
||||||
events.handlers[event] = nil
|
|
||||||
else
|
|
||||||
events.handlers[event] = {func}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function events.remove_by_prefix(prefix)
|
|
||||||
for name, handlers in pairs(events.handlers) do
|
|
||||||
local actualname = name
|
|
||||||
if type(name) == 'table' then
|
|
||||||
actualname = name[1]
|
|
||||||
end
|
|
||||||
if actualname:sub(1, #prefix+1) == prefix..':' then
|
|
||||||
events.handlers[actualname] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function pack.unload(prefix)
|
function pack.unload(prefix)
|
||||||
events.remove_by_prefix(prefix)
|
events.remove_by_prefix(prefix)
|
||||||
end
|
end
|
||||||
|
|
||||||
function events.emit(event, ...)
|
|
||||||
local result = nil
|
|
||||||
local handlers = events.handlers[event]
|
|
||||||
if handlers == nil then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
for _, func in ipairs(handlers) do
|
|
||||||
local status, newres = xpcall(func, __vc__error, ...)
|
|
||||||
if not status then
|
|
||||||
debug.error("error in event ("..event..") handler: "..newres)
|
|
||||||
else
|
|
||||||
result = result or newres
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
gui_util = require "core:internal/gui_util"
|
gui_util = require "core:internal/gui_util"
|
||||||
|
|
||||||
Document = gui_util.Document
|
Document = gui_util.Document
|
||||||
@ -237,6 +194,7 @@ end
|
|||||||
_GUI_ROOT = Document.new("core:root")
|
_GUI_ROOT = Document.new("core:root")
|
||||||
_MENU = _GUI_ROOT.menu
|
_MENU = _GUI_ROOT.menu
|
||||||
menu = _MENU
|
menu = _MENU
|
||||||
|
gui.root = _GUI_ROOT
|
||||||
|
|
||||||
--- Console library extension ---
|
--- Console library extension ---
|
||||||
console.cheats = {}
|
console.cheats = {}
|
||||||
@ -318,11 +276,12 @@ entities.get_all = function(uids)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local bytearray = require "core:internal/bytearray"
|
local bytearray = require "core:internal/bytearray"
|
||||||
|
|
||||||
Bytearray = bytearray.FFIBytearray
|
Bytearray = bytearray.FFIBytearray
|
||||||
Bytearray_as_string = bytearray.FFIBytearray_as_string
|
Bytearray_as_string = bytearray.FFIBytearray_as_string
|
||||||
Bytearray_construct = function(...) return Bytearray(...) end
|
Bytearray_construct = function(...) return Bytearray(...) end
|
||||||
|
|
||||||
|
__vc_scripts_registry = require "core:internal/scripts_registry"
|
||||||
|
|
||||||
file.open = require "core:internal/stream_providers/file"
|
file.open = require "core:internal/stream_providers/file"
|
||||||
file.open_named_pipe = require "core:internal/stream_providers/named_pipe"
|
file.open_named_pipe = require "core:internal/stream_providers/named_pipe"
|
||||||
|
|
||||||
@ -341,6 +300,7 @@ else
|
|||||||
end
|
end
|
||||||
|
|
||||||
ffi = nil
|
ffi = nil
|
||||||
|
__vc_lock_internal_modules()
|
||||||
|
|
||||||
math.randomseed(time.uptime() * 1536227939)
|
math.randomseed(time.uptime() * 1536227939)
|
||||||
|
|
||||||
|
|||||||
@ -550,6 +550,8 @@ function reload_module(name)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local internal_locked = false
|
||||||
|
|
||||||
-- Load script with caching
|
-- Load script with caching
|
||||||
--
|
--
|
||||||
-- path - script path `contentpack:filename`.
|
-- path - script path `contentpack:filename`.
|
||||||
@ -559,6 +561,11 @@ end
|
|||||||
function __load_script(path, nocache)
|
function __load_script(path, nocache)
|
||||||
local packname, filename = parse_path(path)
|
local packname, filename = parse_path(path)
|
||||||
|
|
||||||
|
if internal_locked and (packname == "res" or packname == "core")
|
||||||
|
and filename:starts_with("modules/internal") then
|
||||||
|
error("access to core:internal modules outside of [core]")
|
||||||
|
end
|
||||||
|
|
||||||
-- __cached_scripts used in condition because cached result may be nil
|
-- __cached_scripts used in condition because cached result may be nil
|
||||||
if not nocache and __cached_scripts[path] ~= nil then
|
if not nocache and __cached_scripts[path] ~= nil then
|
||||||
return package.loaded[path]
|
return package.loaded[path]
|
||||||
@ -579,6 +586,10 @@ function __load_script(path, nocache)
|
|||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function __vc_lock_internal_modules()
|
||||||
|
internal_locked = true
|
||||||
|
end
|
||||||
|
|
||||||
function require(path)
|
function require(path)
|
||||||
if not string.find(path, ':') then
|
if not string.find(path, ':') then
|
||||||
local prefix, _ = parse_path(_debug_getinfo(2).source)
|
local prefix, _ = parse_path(_debug_getinfo(2).source)
|
||||||
|
|||||||
@ -174,7 +174,6 @@ std::unique_ptr<model::Model> vcm::parse(
|
|||||||
"'model' tag expected as root, got '" + root.getTag() + "'"
|
"'model' tag expected as root, got '" + root.getTag() + "'"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
std::cout << xml::stringify(*doc) << std::endl;
|
|
||||||
return load_model(root);
|
return load_model(root);
|
||||||
} catch (const parsing_error& err) {
|
} catch (const parsing_error& err) {
|
||||||
throw std::runtime_error(err.errorLog());
|
throw std::runtime_error(err.errorLog());
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
#include "Project.hpp"
|
#include "Project.hpp"
|
||||||
|
|
||||||
#include "data/dv_util.hpp"
|
#include "data/dv_util.hpp"
|
||||||
|
#include "logic/scripting/scripting.hpp"
|
||||||
|
|
||||||
|
Project::~Project() = default;
|
||||||
|
|
||||||
dv::value Project::serialize() const {
|
dv::value Project::serialize() const {
|
||||||
return dv::object({
|
return dv::object({
|
||||||
|
|||||||
@ -2,13 +2,21 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "interfaces/Serializable.hpp"
|
#include "interfaces/Serializable.hpp"
|
||||||
|
|
||||||
|
namespace scripting {
|
||||||
|
class IClientProjectScript;
|
||||||
|
}
|
||||||
|
|
||||||
struct Project : Serializable {
|
struct Project : Serializable {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string title;
|
std::string title;
|
||||||
std::vector<std::string> basePacks;
|
std::vector<std::string> basePacks;
|
||||||
|
std::unique_ptr<scripting::IClientProjectScript> clientScript;
|
||||||
|
|
||||||
|
~Project();
|
||||||
|
|
||||||
dv::value serialize() const override;
|
dv::value serialize() const override;
|
||||||
void deserialize(const dv::value& src) override;
|
void deserialize(const dv::value& src) override;
|
||||||
|
|||||||
@ -60,6 +60,17 @@ static std::unique_ptr<ImageData> load_icon() {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<scripting::IClientProjectScript> load_client_project_script() {
|
||||||
|
io::path scriptFile = "project:project_client.lua";
|
||||||
|
if (io::exists(scriptFile)) {
|
||||||
|
logger.info() << "starting project script";
|
||||||
|
return scripting::load_client_project_script(scriptFile);
|
||||||
|
} else {
|
||||||
|
logger.warning() << "project script does not exists";
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Engine::Engine() = default;
|
Engine::Engine() = default;
|
||||||
Engine::~Engine() = default;
|
Engine::~Engine() = default;
|
||||||
|
|
||||||
@ -72,6 +83,68 @@ Engine& Engine::getInstance() {
|
|||||||
return *instance;
|
return *instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Engine::onContentLoad() {
|
||||||
|
editor->loadTools();
|
||||||
|
langs::setup(langs::get_current(), paths.resPaths.collectRoots());
|
||||||
|
|
||||||
|
if (isHeadless()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto& pack : content->getAllContentPacks()) {
|
||||||
|
auto configFolder = pack.folder / "config";
|
||||||
|
auto bindsFile = configFolder / "bindings.toml";
|
||||||
|
if (io::is_regular_file(bindsFile)) {
|
||||||
|
input->getBindings().read(
|
||||||
|
toml::parse(
|
||||||
|
bindsFile.string(), io::read_string(bindsFile)
|
||||||
|
),
|
||||||
|
BindType::BIND
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadAssets();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::initializeClient() {
|
||||||
|
std::string title = project->title;
|
||||||
|
if (title.empty()) {
|
||||||
|
title = "VoxelCore v" +
|
||||||
|
std::to_string(ENGINE_VERSION_MAJOR) + "." +
|
||||||
|
std::to_string(ENGINE_VERSION_MINOR);
|
||||||
|
}
|
||||||
|
if (ENGINE_DEBUG_BUILD) {
|
||||||
|
title += " [debug]";
|
||||||
|
}
|
||||||
|
auto [window, input] = Window::initialize(&settings.display, title);
|
||||||
|
if (!window || !input){
|
||||||
|
throw initialize_error("could not initialize window");
|
||||||
|
}
|
||||||
|
window->setFramerate(settings.display.framerate.get());
|
||||||
|
|
||||||
|
time.set(window->time());
|
||||||
|
if (auto icon = load_icon()) {
|
||||||
|
icon->flipY();
|
||||||
|
window->setIcon(icon.get());
|
||||||
|
}
|
||||||
|
this->window = std::move(window);
|
||||||
|
this->input = std::move(input);
|
||||||
|
|
||||||
|
loadControls();
|
||||||
|
|
||||||
|
gui = std::make_unique<gui::GUI>(*this);
|
||||||
|
if (ENGINE_DEBUG_BUILD) {
|
||||||
|
menus::create_version_label(*gui);
|
||||||
|
}
|
||||||
|
keepAlive(settings.display.fullscreen.observe(
|
||||||
|
[this](bool value) {
|
||||||
|
if (value != this->window->isFullscreen()) {
|
||||||
|
this->window->toggleFullscreen();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
void Engine::initialize(CoreParameters coreParameters) {
|
void Engine::initialize(CoreParameters coreParameters) {
|
||||||
params = std::move(coreParameters);
|
params = std::move(coreParameters);
|
||||||
settingsHandler = std::make_unique<SettingsHandler>(settings);
|
settingsHandler = std::make_unique<SettingsHandler>(settings);
|
||||||
@ -100,78 +173,28 @@ void Engine::initialize(CoreParameters coreParameters) {
|
|||||||
|
|
||||||
controller = std::make_unique<EngineController>(*this);
|
controller = std::make_unique<EngineController>(*this);
|
||||||
if (!params.headless) {
|
if (!params.headless) {
|
||||||
std::string title = project->title;
|
initializeClient();
|
||||||
if (title.empty()) {
|
|
||||||
title = "VoxelCore v" +
|
|
||||||
std::to_string(ENGINE_VERSION_MAJOR) + "." +
|
|
||||||
std::to_string(ENGINE_VERSION_MINOR);
|
|
||||||
}
|
|
||||||
if (ENGINE_DEBUG_BUILD) {
|
|
||||||
title += " [debug]";
|
|
||||||
}
|
|
||||||
auto [window, input] = Window::initialize(&settings.display, title);
|
|
||||||
if (!window || !input){
|
|
||||||
throw initialize_error("could not initialize window");
|
|
||||||
}
|
|
||||||
window->setFramerate(settings.display.framerate.get());
|
|
||||||
|
|
||||||
time.set(window->time());
|
|
||||||
if (auto icon = load_icon()) {
|
|
||||||
icon->flipY();
|
|
||||||
window->setIcon(icon.get());
|
|
||||||
}
|
|
||||||
this->window = std::move(window);
|
|
||||||
this->input = std::move(input);
|
|
||||||
|
|
||||||
loadControls();
|
|
||||||
|
|
||||||
gui = std::make_unique<gui::GUI>(*this);
|
|
||||||
if (ENGINE_DEBUG_BUILD) {
|
|
||||||
menus::create_version_label(*gui);
|
|
||||||
}
|
|
||||||
keepAlive(settings.display.fullscreen.observe(
|
|
||||||
[this](bool value) {
|
|
||||||
if (value != this->window->isFullscreen()) {
|
|
||||||
this->window->toggleFullscreen();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
audio::initialize(!params.headless, settings.audio);
|
audio::initialize(!params.headless, settings.audio);
|
||||||
|
|
||||||
bool langNotSet = settings.ui.language.get() == "auto";
|
if (settings.ui.language.get() == "auto") {
|
||||||
if (langNotSet) {
|
|
||||||
settings.ui.language.set(
|
settings.ui.language.set(
|
||||||
langs::locale_by_envlocale(platform::detect_locale())
|
langs::locale_by_envlocale(platform::detect_locale())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
content = std::make_unique<ContentControl>(*project, paths, *input, [this]() {
|
content = std::make_unique<ContentControl>(*project, paths, *input, [this]() {
|
||||||
editor->loadTools();
|
onContentLoad();
|
||||||
langs::setup(langs::get_current(), paths.resPaths.collectRoots());
|
|
||||||
if (!isHeadless()) {
|
|
||||||
for (auto& pack : content->getAllContentPacks()) {
|
|
||||||
auto configFolder = pack.folder / "config";
|
|
||||||
auto bindsFile = configFolder / "bindings.toml";
|
|
||||||
if (io::is_regular_file(bindsFile)) {
|
|
||||||
input->getBindings().read(
|
|
||||||
toml::parse(
|
|
||||||
bindsFile.string(), io::read_string(bindsFile)
|
|
||||||
),
|
|
||||||
BindType::BIND
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loadAssets();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
scripting::initialize(this);
|
scripting::initialize(this);
|
||||||
|
|
||||||
if (!isHeadless()) {
|
if (!isHeadless()) {
|
||||||
gui->setPageLoader(scripting::create_page_loader());
|
gui->setPageLoader(scripting::create_page_loader());
|
||||||
}
|
}
|
||||||
keepAlive(settings.ui.language.observe([this](auto lang) {
|
keepAlive(settings.ui.language.observe([this](auto lang) {
|
||||||
langs::setup(lang, paths.resPaths.collectRoots());
|
langs::setup(lang, paths.resPaths.collectRoots());
|
||||||
}, true));
|
}, true));
|
||||||
|
|
||||||
|
project->clientScript = load_client_project_script();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::loadSettings() {
|
void Engine::loadSettings() {
|
||||||
@ -286,6 +309,7 @@ void Engine::close() {
|
|||||||
audio::close();
|
audio::close();
|
||||||
network.reset();
|
network.reset();
|
||||||
clearKeepedObjects();
|
clearKeepedObjects();
|
||||||
|
project.reset();
|
||||||
scripting::close();
|
scripting::close();
|
||||||
logger.info() << "scripting finished";
|
logger.info() << "scripting finished";
|
||||||
if (!params.headless) {
|
if (!params.headless) {
|
||||||
@ -345,10 +369,19 @@ void Engine::loadProject() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Engine::setScreen(std::shared_ptr<Screen> screen) {
|
void Engine::setScreen(std::shared_ptr<Screen> screen) {
|
||||||
|
if (project->clientScript && this->screen) {
|
||||||
|
project->clientScript->onScreenChange(this->screen->getName(), false);
|
||||||
|
}
|
||||||
// reset audio channels (stop all sources)
|
// reset audio channels (stop all sources)
|
||||||
audio::reset_channel(audio::get_channel_index("regular"));
|
audio::reset_channel(audio::get_channel_index("regular"));
|
||||||
audio::reset_channel(audio::get_channel_index("ambient"));
|
audio::reset_channel(audio::get_channel_index("ambient"));
|
||||||
this->screen = std::move(screen);
|
this->screen = std::move(screen);
|
||||||
|
if (this->screen) {
|
||||||
|
this->screen->onOpen();
|
||||||
|
}
|
||||||
|
if (project->clientScript && this->screen) {
|
||||||
|
project->clientScript->onScreenChange(this->screen->getName(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::onWorldOpen(std::unique_ptr<Level> level, int64_t localPlayer) {
|
void Engine::onWorldOpen(std::unique_ptr<Level> level, int64_t localPlayer) {
|
||||||
|
|||||||
@ -82,6 +82,9 @@ class Engine : public util::ObjectsKeeper {
|
|||||||
void updateHotkeys();
|
void updateHotkeys();
|
||||||
void loadAssets();
|
void loadAssets();
|
||||||
void loadProject();
|
void loadProject();
|
||||||
|
|
||||||
|
void initializeClient();
|
||||||
|
void onContentLoad();
|
||||||
public:
|
public:
|
||||||
Engine();
|
Engine();
|
||||||
~Engine();
|
~Engine();
|
||||||
@ -174,4 +177,8 @@ public:
|
|||||||
devtools::Editor& getEditor() {
|
devtools::Editor& getEditor() {
|
||||||
return *editor;
|
return *editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Project& getProject() {
|
||||||
|
return *project;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
#include "Engine.hpp"
|
#include "Engine.hpp"
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
|
#include "devtools/Project.hpp"
|
||||||
#include "frontend/screens/MenuScreen.hpp"
|
#include "frontend/screens/MenuScreen.hpp"
|
||||||
#include "frontend/screens/LevelScreen.hpp"
|
#include "frontend/screens/LevelScreen.hpp"
|
||||||
#include "window/Window.hpp"
|
#include "window/Window.hpp"
|
||||||
#include "world/Level.hpp"
|
#include "world/Level.hpp"
|
||||||
|
#include "graphics/ui/GUI.hpp"
|
||||||
|
#include "graphics/ui/elements/Container.hpp"
|
||||||
|
|
||||||
static debug::Logger logger("mainloop");
|
static debug::Logger logger("mainloop");
|
||||||
|
|
||||||
@ -36,6 +39,7 @@ void Mainloop::run() {
|
|||||||
while (!window.isShouldClose()){
|
while (!window.isShouldClose()){
|
||||||
time.update(window.time());
|
time.update(window.time());
|
||||||
engine.updateFrontend();
|
engine.updateFrontend();
|
||||||
|
|
||||||
if (!window.isIconified()) {
|
if (!window.isIconified()) {
|
||||||
engine.renderFrame();
|
engine.renderFrame();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,11 +14,13 @@ UiDocument::UiDocument(
|
|||||||
const std::shared_ptr<gui::UINode>& root,
|
const std::shared_ptr<gui::UINode>& root,
|
||||||
scriptenv env
|
scriptenv env
|
||||||
) : id(std::move(id)), script(script), root(root), env(std::move(env)) {
|
) : id(std::move(id)), script(script), root(root), env(std::move(env)) {
|
||||||
gui::UINode::getIndices(root, map);
|
rebuildIndices();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UiDocument::rebuildIndices() {
|
void UiDocument::rebuildIndices() {
|
||||||
|
map.clear();
|
||||||
gui::UINode::getIndices(root, map);
|
gui::UINode::getIndices(root, map);
|
||||||
|
map["root"] = root;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UINodesMap& UiDocument::getMap() const {
|
const UINodesMap& UiDocument::getMap() const {
|
||||||
|
|||||||
@ -324,7 +324,7 @@ void Hud::updateWorldGenDebug() {
|
|||||||
|
|
||||||
void Hud::update(bool visible) {
|
void Hud::update(bool visible) {
|
||||||
const auto& chunks = *player.chunks;
|
const auto& chunks = *player.chunks;
|
||||||
bool is_menu_open = menu.hasOpenPage();
|
bool isMenuOpen = menu.hasOpenPage();
|
||||||
|
|
||||||
debugPanel->setVisible(
|
debugPanel->setVisible(
|
||||||
debug && visible && !(inventoryOpen && inventoryView == nullptr)
|
debug && visible && !(inventoryOpen && inventoryView == nullptr)
|
||||||
@ -333,13 +333,13 @@ void Hud::update(bool visible) {
|
|||||||
if (!visible && inventoryOpen) {
|
if (!visible && inventoryOpen) {
|
||||||
closeInventory();
|
closeInventory();
|
||||||
}
|
}
|
||||||
if (pause && !is_menu_open) {
|
if (pause && !isMenuOpen) {
|
||||||
setPause(false);
|
setPause(false);
|
||||||
}
|
}
|
||||||
if (!gui.isFocusCaught()) {
|
if (!gui.isFocusCaught()) {
|
||||||
processInput(visible);
|
processInput(visible);
|
||||||
}
|
}
|
||||||
if ((is_menu_open || inventoryOpen) == input.getCursor().locked) {
|
if ((isMenuOpen || inventoryOpen) == input.getCursor().locked) {
|
||||||
input.toggleCursor();
|
input.toggleCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,8 +360,8 @@ void Hud::update(bool visible) {
|
|||||||
contentAccessPanel->setSize(glm::vec2(caSize.x, windowSize.y));
|
contentAccessPanel->setSize(glm::vec2(caSize.x, windowSize.y));
|
||||||
contentAccess->setMinSize(glm::vec2(1, windowSize.y));
|
contentAccess->setMinSize(glm::vec2(1, windowSize.y));
|
||||||
hotbarView->setVisible(visible && !(secondUI && !inventoryView));
|
hotbarView->setVisible(visible && !(secondUI && !inventoryView));
|
||||||
darkOverlay->setVisible(is_menu_open);
|
darkOverlay->setVisible(isMenuOpen);
|
||||||
menu.setVisible(is_menu_open);
|
menu.setVisible(isMenuOpen);
|
||||||
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
for (auto& element : elements) {
|
for (auto& element : elements) {
|
||||||
|
|||||||
@ -97,7 +97,6 @@ LevelScreen::LevelScreen(
|
|||||||
animator->addAnimations(assets.getAnimations());
|
animator->addAnimations(assets.getAnimations());
|
||||||
|
|
||||||
loadDecorations();
|
loadDecorations();
|
||||||
initializeContent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LevelScreen::~LevelScreen() {
|
LevelScreen::~LevelScreen() {
|
||||||
@ -112,6 +111,10 @@ LevelScreen::~LevelScreen() {
|
|||||||
engine.getPaths().setCurrentWorldFolder("");
|
engine.getPaths().setCurrentWorldFolder("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LevelScreen::onOpen() {
|
||||||
|
initializeContent();
|
||||||
|
}
|
||||||
|
|
||||||
void LevelScreen::initializeContent() {
|
void LevelScreen::initializeContent() {
|
||||||
auto& content = controller->getLevel()->content;
|
auto& content = controller->getLevel()->content;
|
||||||
for (auto& entry : content.getPacks()) {
|
for (auto& entry : content.getPacks()) {
|
||||||
|
|||||||
@ -53,8 +53,13 @@ public:
|
|||||||
);
|
);
|
||||||
~LevelScreen();
|
~LevelScreen();
|
||||||
|
|
||||||
|
void onOpen() override;
|
||||||
void update(float delta) override;
|
void update(float delta) override;
|
||||||
void draw(float delta) override;
|
void draw(float delta) override;
|
||||||
|
|
||||||
void onEngineShutdown() override;
|
void onEngineShutdown() override;
|
||||||
|
|
||||||
|
const char* getName() const override {
|
||||||
|
return "level";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -13,12 +13,6 @@
|
|||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
|
|
||||||
MenuScreen::MenuScreen(Engine& engine) : Screen(engine) {
|
MenuScreen::MenuScreen(Engine& engine) : Screen(engine) {
|
||||||
engine.getContentControl().resetContent();
|
|
||||||
|
|
||||||
auto menu = engine.getGUI().getMenu();
|
|
||||||
menu->reset();
|
|
||||||
menu->setPage("main");
|
|
||||||
|
|
||||||
uicamera =
|
uicamera =
|
||||||
std::make_unique<Camera>(glm::vec3(), engine.getWindow().getSize().y);
|
std::make_unique<Camera>(glm::vec3(), engine.getWindow().getSize().y);
|
||||||
uicamera->perspective = false;
|
uicamera->perspective = false;
|
||||||
@ -29,33 +23,17 @@ MenuScreen::MenuScreen(Engine& engine) : Screen(engine) {
|
|||||||
|
|
||||||
MenuScreen::~MenuScreen() = default;
|
MenuScreen::~MenuScreen() = default;
|
||||||
|
|
||||||
|
void MenuScreen::onOpen() {
|
||||||
|
engine.getContentControl().resetContent();
|
||||||
|
|
||||||
|
auto menu = engine.getGUI().getMenu();
|
||||||
|
menu->reset();
|
||||||
|
}
|
||||||
|
|
||||||
void MenuScreen::update(float delta) {
|
void MenuScreen::update(float delta) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuScreen::draw(float delta) {
|
void MenuScreen::draw(float delta) {
|
||||||
auto assets = engine.getAssets();
|
|
||||||
|
|
||||||
display::clear();
|
display::clear();
|
||||||
display::setBgColor(glm::vec3(0.2f));
|
display::setBgColor(glm::vec3(0.2f));
|
||||||
|
|
||||||
const auto& size = engine.getWindow().getSize();
|
|
||||||
uint width = size.x;
|
|
||||||
uint height = size.y;
|
|
||||||
|
|
||||||
uicamera->setFov(height);
|
|
||||||
uicamera->setAspectRatio(width / static_cast<float>(height));
|
|
||||||
auto uishader = assets->get<Shader>("ui");
|
|
||||||
uishader->use();
|
|
||||||
uishader->uniformMatrix("u_projview", uicamera->getProjView());
|
|
||||||
|
|
||||||
auto bg = assets->get<Texture>("gui/menubg");
|
|
||||||
batch->begin();
|
|
||||||
batch->texture(bg);
|
|
||||||
batch->rect(
|
|
||||||
0, 0,
|
|
||||||
width, height, 0, 0, 0,
|
|
||||||
UVRegion(0, 0, width / bg->getWidth(), height / bg->getHeight()),
|
|
||||||
false, false, glm::vec4(1.0f)
|
|
||||||
);
|
|
||||||
batch->flush();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,12 @@ public:
|
|||||||
MenuScreen(Engine& engine);
|
MenuScreen(Engine& engine);
|
||||||
~MenuScreen();
|
~MenuScreen();
|
||||||
|
|
||||||
|
void onOpen() override;
|
||||||
|
|
||||||
void update(float delta) override;
|
void update(float delta) override;
|
||||||
void draw(float delta) override;
|
void draw(float delta) override;
|
||||||
|
|
||||||
|
const char* getName() const override {
|
||||||
|
return "menu";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -13,7 +13,9 @@ protected:
|
|||||||
public:
|
public:
|
||||||
Screen(Engine& engine);
|
Screen(Engine& engine);
|
||||||
virtual ~Screen();
|
virtual ~Screen();
|
||||||
|
virtual void onOpen() = 0;
|
||||||
virtual void update(float delta) = 0;
|
virtual void update(float delta) = 0;
|
||||||
virtual void draw(float delta) = 0;
|
virtual void draw(float delta) = 0;
|
||||||
virtual void onEngineShutdown() {};
|
virtual void onEngineShutdown() {};
|
||||||
|
virtual const char* getName() const = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -56,6 +56,13 @@ GUI::GUI(Engine& engine)
|
|||||||
store("tooltip", tooltip);
|
store("tooltip", tooltip);
|
||||||
store("tooltip.label", UINode::find(tooltip, "tooltip.label"));
|
store("tooltip.label", UINode::find(tooltip, "tooltip.label"));
|
||||||
container->add(tooltip);
|
container->add(tooltip);
|
||||||
|
|
||||||
|
rootDocument = std::make_unique<UiDocument>(
|
||||||
|
"core:root",
|
||||||
|
uidocscript {},
|
||||||
|
std::dynamic_pointer_cast<gui::UINode>(container),
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI::~GUI() = default;
|
GUI::~GUI() = default;
|
||||||
@ -74,15 +81,8 @@ std::shared_ptr<Menu> GUI::getMenu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GUI::onAssetsLoad(Assets* assets) {
|
void GUI::onAssetsLoad(Assets* assets) {
|
||||||
assets->store(
|
rootDocument->rebuildIndices();
|
||||||
std::make_unique<UiDocument>(
|
assets->store(rootDocument, "core:root");
|
||||||
"core:root",
|
|
||||||
uidocscript {},
|
|
||||||
std::dynamic_pointer_cast<gui::UINode>(container),
|
|
||||||
nullptr
|
|
||||||
),
|
|
||||||
"core:root"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::resetTooltip() {
|
void GUI::resetTooltip() {
|
||||||
@ -302,6 +302,7 @@ bool GUI::isFocusCaught() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GUI::add(std::shared_ptr<UINode> node) {
|
void GUI::add(std::shared_ptr<UINode> node) {
|
||||||
|
UINode::getIndices(node, rootDocument->getMapWriteable());
|
||||||
container->add(std::move(node));
|
container->add(std::move(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,8 @@ namespace devtools {
|
|||||||
class Editor;
|
class Editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UiDocument;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Some info about padding and margin.
|
Some info about padding and margin.
|
||||||
Padding is element inner space, margin is outer
|
Padding is element inner space, margin is outer
|
||||||
@ -70,6 +72,7 @@ namespace gui {
|
|||||||
std::shared_ptr<UINode> pressed;
|
std::shared_ptr<UINode> pressed;
|
||||||
std::shared_ptr<UINode> focus;
|
std::shared_ptr<UINode> focus;
|
||||||
std::shared_ptr<UINode> tooltip;
|
std::shared_ptr<UINode> tooltip;
|
||||||
|
std::shared_ptr<UiDocument> rootDocument;
|
||||||
std::unordered_map<std::string, std::shared_ptr<UINode>> storage;
|
std::unordered_map<std::string, std::shared_ptr<UINode>> storage;
|
||||||
|
|
||||||
std::unique_ptr<Camera> uicamera;
|
std::unique_ptr<Camera> uicamera;
|
||||||
|
|||||||
@ -810,6 +810,85 @@ void TextBox::stepDefaultUp(bool shiftPressed, bool breakSelection) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int calc_indent(int linestart, std::wstring_view input) {
|
||||||
|
int indent = 0;
|
||||||
|
while (linestart + indent < input.length() &&
|
||||||
|
input[linestart + indent] == L' ')
|
||||||
|
indent++;
|
||||||
|
return indent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextBox::onTab(bool shiftPressed) {
|
||||||
|
std::wstring indentStr = L" ";
|
||||||
|
|
||||||
|
if (!shiftPressed && getSelectionLength() == 0) {
|
||||||
|
paste(indentStr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (getSelectionLength() == 0) {
|
||||||
|
selectionStart = caret;
|
||||||
|
selectionEnd = caret;
|
||||||
|
selectionOrigin = caret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lineA = getLineAt(selectionStart);
|
||||||
|
int lineB = getLineAt(selectionEnd);
|
||||||
|
int caretLine = getLineAt(caret);
|
||||||
|
|
||||||
|
size_t lineAStart = getLinePos(lineA);
|
||||||
|
size_t lineBStart = getLinePos(lineB);
|
||||||
|
size_t caretLineStart = getLinePos(caretLine);
|
||||||
|
size_t caretIndent = calc_indent(caretLineStart, input);
|
||||||
|
size_t aIndent = calc_indent(lineAStart, input);
|
||||||
|
size_t bIndent = calc_indent(lineBStart, input);
|
||||||
|
|
||||||
|
int lastSelectionStart = selectionStart;
|
||||||
|
int lastSelectionEnd = selectionEnd;
|
||||||
|
size_t lastCaret = caret;
|
||||||
|
|
||||||
|
auto combination = history->beginCombination();
|
||||||
|
|
||||||
|
resetSelection();
|
||||||
|
|
||||||
|
for (int line = lineA; line <= lineB; line++) {
|
||||||
|
size_t linestart = getLinePos(line);
|
||||||
|
int indent = calc_indent(linestart, input);
|
||||||
|
|
||||||
|
if (shiftPressed) {
|
||||||
|
if (indent >= indentStr.length()) {
|
||||||
|
setCaret(linestart);
|
||||||
|
select(linestart, linestart + indentStr.length());
|
||||||
|
eraseSelected();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setCaret(linestart);
|
||||||
|
paste(indentStr);
|
||||||
|
}
|
||||||
|
refreshLabel(); // todo: replace with textbox cache
|
||||||
|
}
|
||||||
|
|
||||||
|
int linestart = getLinePos(caretLine);
|
||||||
|
int linestartA = getLinePos(lineA);
|
||||||
|
int linestartB = getLinePos(lineB);
|
||||||
|
int la = lastSelectionStart - lineAStart;
|
||||||
|
int lb = lastSelectionEnd - lineBStart;
|
||||||
|
if (shiftPressed) {
|
||||||
|
setCaret(lastCaret - caretLineStart + linestart - std::min<int>(caretIndent, indentStr.length()));
|
||||||
|
selectionStart = la + linestartA - std::min<int>(std::min<int>(la, aIndent), indentStr.length());
|
||||||
|
selectionEnd = lb + linestartB - std::min<int>(std::min<int>(lb, bIndent), indentStr.length());
|
||||||
|
} else {
|
||||||
|
setCaret(lastCaret - caretLineStart + linestart + indentStr.length());
|
||||||
|
selectionStart = la + linestartA + indentStr.length();
|
||||||
|
selectionEnd = lb + linestartB + indentStr.length();
|
||||||
|
}
|
||||||
|
if (selectionOrigin == lastSelectionStart) {
|
||||||
|
selectionOrigin = selectionStart;
|
||||||
|
} else {
|
||||||
|
selectionOrigin = selectionEnd;
|
||||||
|
}
|
||||||
|
historian->sync();
|
||||||
|
}
|
||||||
|
|
||||||
void TextBox::refreshSyntax() {
|
void TextBox::refreshSyntax() {
|
||||||
if (!syntax.empty()) {
|
if (!syntax.empty()) {
|
||||||
const auto& processor = gui.getEditor().getSyntaxProcessor();
|
const auto& processor = gui.getEditor().getSyntaxProcessor();
|
||||||
@ -868,7 +947,7 @@ void TextBox::performEditingKeyboardEvents(Keycode key) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (key == Keycode::TAB) {
|
} else if (key == Keycode::TAB) {
|
||||||
paste(L" ");
|
onTab(shiftPressed);
|
||||||
} else if (key == Keycode::LEFT) {
|
} else if (key == Keycode::LEFT) {
|
||||||
stepLeft(shiftPressed, breakSelection);
|
stepLeft(shiftPressed, breakSelection);
|
||||||
} else if (key == Keycode::RIGHT) {
|
} else if (key == Keycode::RIGHT) {
|
||||||
|
|||||||
@ -71,6 +71,8 @@ namespace gui {
|
|||||||
void stepDefaultDown(bool shiftPressed, bool breakSelection);
|
void stepDefaultDown(bool shiftPressed, bool breakSelection);
|
||||||
void stepDefaultUp(bool shiftPressed, bool breakSelection);
|
void stepDefaultUp(bool shiftPressed, bool breakSelection);
|
||||||
|
|
||||||
|
void onTab(bool shiftPressed);
|
||||||
|
|
||||||
size_t normalizeIndex(int index);
|
size_t normalizeIndex(int index);
|
||||||
|
|
||||||
int calcIndexAt(int x, int y) const;
|
int calcIndexAt(int x, int y) const;
|
||||||
|
|||||||
@ -86,6 +86,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
|||||||
builder.section("debug");
|
builder.section("debug");
|
||||||
builder.add("generator-test-mode", &settings.debug.generatorTestMode);
|
builder.add("generator-test-mode", &settings.debug.generatorTestMode);
|
||||||
builder.add("do-write-lights", &settings.debug.doWriteLights);
|
builder.add("do-write-lights", &settings.debug.doWriteLights);
|
||||||
|
builder.add("enable-experimental", &settings.debug.enableExperimental);
|
||||||
}
|
}
|
||||||
|
|
||||||
dv::value SettingsHandler::getValue(const std::string& name) const {
|
dv::value SettingsHandler::getValue(const std::string& name) const {
|
||||||
|
|||||||
@ -23,6 +23,9 @@ static void load_texture(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int l_load_texture(lua::State* L) {
|
static int l_load_texture(lua::State* L) {
|
||||||
|
if (lua::isstring(L, 3) && lua::require_lstring(L, 3) != "png") {
|
||||||
|
throw std::runtime_error("unsupportd image format");
|
||||||
|
}
|
||||||
if (lua::istable(L, 1)) {
|
if (lua::istable(L, 1)) {
|
||||||
lua::pushvalue(L, 1);
|
lua::pushvalue(L, 1);
|
||||||
size_t size = lua::objlen(L, 1);
|
size_t size = lua::objlen(L, 1);
|
||||||
|
|||||||
@ -79,9 +79,12 @@ static int l_textbox_paste(lua::State* L) {
|
|||||||
|
|
||||||
static int l_container_add(lua::State* L) {
|
static int l_container_add(lua::State* L) {
|
||||||
auto docnode = get_document_node(L);
|
auto docnode = get_document_node(L);
|
||||||
|
if (docnode.document == nullptr) {
|
||||||
|
throw std::runtime_error("target document not found");
|
||||||
|
}
|
||||||
auto node = dynamic_cast<Container*>(docnode.node.get());
|
auto node = dynamic_cast<Container*>(docnode.node.get());
|
||||||
if (node == nullptr) {
|
if (node == nullptr) {
|
||||||
return 0;
|
throw std::runtime_error("target container not found");
|
||||||
}
|
}
|
||||||
auto xmlsrc = lua::require_string(L, 2);
|
auto xmlsrc = lua::require_string(L, 2);
|
||||||
try {
|
try {
|
||||||
@ -99,7 +102,7 @@ static int l_container_add(lua::State* L) {
|
|||||||
UINode::getIndices(subnode, docnode.document->getMapWriteable());
|
UINode::getIndices(subnode, docnode.document->getMapWriteable());
|
||||||
node->add(std::move(subnode));
|
node->add(std::move(subnode));
|
||||||
} catch (const std::exception& err) {
|
} catch (const std::exception& err) {
|
||||||
throw std::runtime_error(err.what());
|
throw std::runtime_error("container:add(...): " + std::string(err.what()));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,6 +45,12 @@ namespace {
|
|||||||
|
|
||||||
template <SlotFunc func>
|
template <SlotFunc func>
|
||||||
int wrap_slot(lua::State* L) {
|
int wrap_slot(lua::State* L) {
|
||||||
|
if (lua::isnoneornil(L, 1)) {
|
||||||
|
throw std::runtime_error("inventory id is nil");
|
||||||
|
}
|
||||||
|
if (lua::isnoneornil(L, 2)) {
|
||||||
|
throw std::runtime_error("slot index is nil");
|
||||||
|
}
|
||||||
auto invid = lua::tointeger(L, 1);
|
auto invid = lua::tointeger(L, 1);
|
||||||
auto slotid = lua::tointeger(L, 2);
|
auto slotid = lua::tointeger(L, 2);
|
||||||
auto& inv = get_inventory(invid);
|
auto& inv = get_inventory(invid);
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
#include "voxels/Block.hpp"
|
#include "voxels/Block.hpp"
|
||||||
#include "voxels/Chunk.hpp"
|
#include "voxels/Chunk.hpp"
|
||||||
#include "world/Level.hpp"
|
#include "world/Level.hpp"
|
||||||
|
#include "world/World.hpp"
|
||||||
#include "interfaces/Process.hpp"
|
#include "interfaces/Process.hpp"
|
||||||
|
|
||||||
using namespace scripting;
|
using namespace scripting;
|
||||||
@ -116,11 +117,47 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Process> scripting::start_coroutine(
|
class LuaProjectScript : public IClientProjectScript {
|
||||||
|
public:
|
||||||
|
LuaProjectScript(lua::State* L, scriptenv env) : L(L), env(std::move(env)) {}
|
||||||
|
|
||||||
|
void onScreenChange(const std::string& name, bool show) override {
|
||||||
|
if (!lua::pushenv(L, *env)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!lua::getfield(L, "on_" + name + (show ? "_setup" : "_clear"))) {
|
||||||
|
lua::pop(L);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lua::call_nothrow(L, 0, 0);
|
||||||
|
lua::pop(L);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
lua::State* L;
|
||||||
|
scriptenv env;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<IClientProjectScript> scripting::load_client_project_script(
|
||||||
const io::path& script
|
const io::path& script
|
||||||
) {
|
) {
|
||||||
auto L = lua::get_main_state();
|
auto L = lua::get_main_state();
|
||||||
if (lua::getglobal(L, "__vc_start_coroutine")) {
|
auto source = io::read_string(script);
|
||||||
|
auto env = create_environment(nullptr);
|
||||||
|
lua::pushenv(L, *env);
|
||||||
|
if (lua::getglobal(L, "__vc_app")) {
|
||||||
|
lua::setfield(L, "app");
|
||||||
|
}
|
||||||
|
lua::pop(L);
|
||||||
|
|
||||||
|
lua::loadbuffer(L, *env, source, script.name());
|
||||||
|
lua::call(L, 0);
|
||||||
|
return std::make_unique<LuaProjectScript>(L, std::move(env));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Process> scripting::start_coroutine(const io::path& script) {
|
||||||
|
auto L = lua::get_main_state();
|
||||||
|
auto method = "__vc_start_coroutine";
|
||||||
|
if (lua::getglobal(L, method)) {
|
||||||
auto source = io::read_string(script);
|
auto source = io::read_string(script);
|
||||||
lua::loadbuffer(L, 0, source, script.name());
|
lua::loadbuffer(L, 0, source, script.name());
|
||||||
if (lua::call(L, 1)) {
|
if (lua::call(L, 1)) {
|
||||||
@ -293,7 +330,11 @@ void scripting::on_world_load(LevelController* controller) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto& pack : content_control->getAllContentPacks()) {
|
for (auto& pack : content_control->getAllContentPacks()) {
|
||||||
lua::emit_event(L, pack.id + ":.worldopen");
|
lua::emit_event(L, pack.id + ":.worldopen", [](auto L) {
|
||||||
|
return lua::pushboolean(
|
||||||
|
L, !scripting::level->getWorld()->getInfo().isLoaded
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -65,10 +65,19 @@ namespace scripting {
|
|||||||
|
|
||||||
void process_post_runnables();
|
void process_post_runnables();
|
||||||
|
|
||||||
std::unique_ptr<Process> start_coroutine(
|
class IClientProjectScript {
|
||||||
|
public:
|
||||||
|
virtual ~IClientProjectScript() {}
|
||||||
|
|
||||||
|
virtual void onScreenChange(const std::string& name, bool show) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<IClientProjectScript> load_client_project_script(
|
||||||
const io::path& script
|
const io::path& script
|
||||||
);
|
);
|
||||||
|
|
||||||
|
std::unique_ptr<Process> start_coroutine(const io::path& script);
|
||||||
|
|
||||||
void on_world_load(LevelController* controller);
|
void on_world_load(LevelController* controller);
|
||||||
void on_world_tick(int tps);
|
void on_world_tick(int tps);
|
||||||
void on_world_save();
|
void on_world_save();
|
||||||
|
|||||||
@ -90,6 +90,8 @@ struct DebugSettings {
|
|||||||
FlagSetting generatorTestMode {false};
|
FlagSetting generatorTestMode {false};
|
||||||
/// @brief Write lights cache
|
/// @brief Write lights cache
|
||||||
FlagSetting doWriteLights {true};
|
FlagSetting doWriteLights {true};
|
||||||
|
/// @brief Enable experimental optimizations and features
|
||||||
|
FlagSetting enableExperimental {false};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UiSettings {
|
struct UiSettings {
|
||||||
|
|||||||
@ -116,6 +116,8 @@ std::unique_ptr<Level> World::load(
|
|||||||
if (!info.has_value()) {
|
if (!info.has_value()) {
|
||||||
throw world_load_error("could not to find world.json");
|
throw world_load_error("could not to find world.json");
|
||||||
}
|
}
|
||||||
|
info->isLoaded = true;
|
||||||
|
|
||||||
logger.info() << "loading world " << info->name << " ("
|
logger.info() << "loading world " << info->name << " ("
|
||||||
<< worldFilesPtr->getFolder().string() << ")";
|
<< worldFilesPtr->getFolder().string() << ")";
|
||||||
logger.info() << "world version: " << info->major << "." << info->minor
|
logger.info() << "world version: " << info->major << "." << info->minor
|
||||||
|
|||||||
@ -45,6 +45,8 @@ struct WorldInfo : public Serializable {
|
|||||||
|
|
||||||
int major = 0, minor = -1;
|
int major = 0, minor = -1;
|
||||||
|
|
||||||
|
bool isLoaded = false;
|
||||||
|
|
||||||
dv::value serialize() const override;
|
dv::value serialize() const override;
|
||||||
void deserialize(const dv::value& src) override;
|
void deserialize(const dv::value& src) override;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user