mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-12 14:31:50 +00:00
Merge pull request #843 from MihailRis/common-vc-funcs
new functions and settings
This commit is contained in:
commit
025e32eec1
33 changed files with 617 additions and 421 deletions
|
|
@ -149,16 +149,22 @@ gui.load_document(
|
||||||
args: table
|
args: table
|
||||||
) -> str
|
) -> str
|
||||||
|
|
||||||
-- Loads a template into the layout
|
-- Loads and processes layout template from file
|
||||||
gui.template(
|
gui.template(
|
||||||
-- template name in /layouts/templates without path and extension
|
-- template name in /layouts/templates without path and extension
|
||||||
name: str,
|
name: str,
|
||||||
-- variable table (can be used in markup)
|
-- variable table (can be used in markup)
|
||||||
-- * Ex: <label>%{text}</label>
|
-- * Ex: <label>%{text}</label>
|
||||||
-- * text in this case is the value from params with the text key
|
-- * text in this case is the value from params with the text key
|
||||||
params: table,
|
params: table
|
||||||
-- table, available in events as the global variable DATA
|
) -> str
|
||||||
[optional] data: table
|
|
||||||
|
-- Processes layout template from string
|
||||||
|
gui.process_template(
|
||||||
|
-- template source code
|
||||||
|
source: str,
|
||||||
|
-- variable table (same as gui.template)
|
||||||
|
params: table
|
||||||
) -> str
|
) -> str
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -147,17 +147,23 @@ gui.load_document(
|
||||||
args: table -- параметры для события on_open
|
args: table -- параметры для события on_open
|
||||||
) -> string
|
) -> string
|
||||||
|
|
||||||
-- Загружает шаблон в лояут
|
-- Обрабатывает xml шаблон макета из файла
|
||||||
gui.template(
|
gui.template(
|
||||||
-- имя шаблона в /layouts/templates без пути и расширения
|
-- имя шаблона в /layouts/templates без пути и расширения
|
||||||
name: string,
|
name: string,
|
||||||
-- таблица переменных (может быть использована в разметке)
|
-- таблица переменных (может быть использована в разметке)
|
||||||
-- * Пр: <label>%{text}</label>
|
-- * Пр: <label>%{text}</label>
|
||||||
-- * text в данном случае, это значение из params по ключу text
|
-- * text в данном случае, это значение из params по ключу text
|
||||||
params: table,
|
params: table
|
||||||
-- таблица, доступная в событиях как глобальная переменная DATA
|
|
||||||
[опционально] data: table
|
|
||||||
) -> string
|
) -> string
|
||||||
|
|
||||||
|
-- Обрабатывает xml шаблон макета из строки
|
||||||
|
gui.process_template(
|
||||||
|
-- шаблон в виде строки
|
||||||
|
source: string,
|
||||||
|
-- таблица переменных, как в gui.template
|
||||||
|
params: table
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Корневой документ
|
## Корневой документ
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
function create_setting(id, name, step, postfix)
|
function create_trackbar_setting(id, name, step, postfix)
|
||||||
local info = app.get_setting_info(id)
|
local info = app.get_setting_info(id)
|
||||||
postfix = postfix or ""
|
postfix = postfix or ""
|
||||||
document.root:add(gui.template("track_setting", {
|
document.root:add(gui.template("track_setting", {
|
||||||
|
|
@ -10,10 +10,10 @@ function create_setting(id, name, step, postfix)
|
||||||
step=step,
|
step=step,
|
||||||
postfix=postfix
|
postfix=postfix
|
||||||
}))
|
}))
|
||||||
update_setting(app.get_setting(id), id, name, postfix)
|
update_trackbar_label(app.get_setting(id), id, name, postfix)
|
||||||
end
|
end
|
||||||
|
|
||||||
function update_setting(x, id, name, postfix)
|
function update_trackbar_label(x, id, name, postfix)
|
||||||
app.set_setting(id, x)
|
app.set_setting(id, x)
|
||||||
-- updating label
|
-- updating label
|
||||||
document[id..".L"].text = string.format(
|
document[id..".L"].text = string.format(
|
||||||
|
|
@ -24,12 +24,22 @@ function update_setting(x, id, name, postfix)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function update_checkbox_setting(id, value)
|
||||||
|
app.set_setting(id, value)
|
||||||
|
|
||||||
|
local recording_enabled = app.get_setting("audio.recording-enabled")
|
||||||
|
document.input_device_select.enabled = recording_enabled
|
||||||
|
document.input_volume_inner.enabled = recording_enabled
|
||||||
|
document.input_volume_outer.enabled = recording_enabled
|
||||||
|
end
|
||||||
|
|
||||||
function create_checkbox(id, name, tooltip)
|
function create_checkbox(id, name, tooltip)
|
||||||
tooltip = tooltip or ''
|
tooltip = tooltip or ''
|
||||||
document.root:add(string.format(
|
document.root:add(string.format(
|
||||||
"<checkbox consumer='function(x) app.set_setting(\"%s\", x) end' checked='%s' tooltip='%s'>%s</checkbox>",
|
"<checkbox consumer='function(x) update_checkbox_setting(\"%s\", x) end' checked='%s' tooltip='%s'>%s</checkbox>",
|
||||||
id, app.str_setting(id), gui.str(tooltip, "settings"), gui.str(name, "settings")
|
id, app.str_setting(id), gui.str(tooltip, "settings"), gui.str(name, "settings")
|
||||||
))
|
))
|
||||||
|
update_checkbox_setting(id, app.get_setting(id))
|
||||||
end
|
end
|
||||||
|
|
||||||
local initialized = false
|
local initialized = false
|
||||||
|
|
@ -55,11 +65,12 @@ function on_open()
|
||||||
prev_amplitude = amplitude
|
prev_amplitude = amplitude
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
create_setting("audio.volume-master", "Master Volume", 0.01)
|
create_trackbar_setting("audio.volume-master", "Master Volume", 0.01)
|
||||||
create_setting("audio.volume-regular", "Regular Sounds", 0.01)
|
create_trackbar_setting("audio.volume-regular", "Regular Sounds", 0.01)
|
||||||
create_setting("audio.volume-ui", "UI Sounds", 0.01)
|
create_trackbar_setting("audio.volume-ui", "UI Sounds", 0.01)
|
||||||
create_setting("audio.volume-ambient", "Ambient", 0.01)
|
create_trackbar_setting("audio.volume-ambient", "Ambient", 0.01)
|
||||||
create_setting("audio.volume-music", "Music", 0.01)
|
create_trackbar_setting("audio.volume-music", "Music", 0.01)
|
||||||
|
|
||||||
document.root:add("<label context='settings'>@Microphone</label>")
|
document.root:add("<label context='settings'>@Microphone</label>")
|
||||||
document.root:add("<select id='input_device_select' "..
|
document.root:add("<select id='input_device_select' "..
|
||||||
"onselect='function(opt) app.set_setting(\"audio.input-device\", opt) end'/>")
|
"onselect='function(opt) app.set_setting(\"audio.input-device\", opt) end'/>")
|
||||||
|
|
@ -67,9 +78,7 @@ function on_open()
|
||||||
.."<container id='input_volume_inner' color='#00FF00FF' pos='1' size='2'/>"
|
.."<container id='input_volume_inner' color='#00FF00FF' pos='1' size='2'/>"
|
||||||
.."</container>")
|
.."</container>")
|
||||||
local selectbox = document.input_device_select
|
local selectbox = document.input_device_select
|
||||||
local devices = {
|
local devices = {}
|
||||||
{value="none", text=gui.str("None", "settings.microphone")},
|
|
||||||
}
|
|
||||||
local names = audio.__get_input_devices_names()
|
local names = audio.__get_input_devices_names()
|
||||||
for i, name in ipairs(names) do
|
for i, name in ipairs(names) do
|
||||||
table.insert(devices, {value=name, text=name})
|
table.insert(devices, {value=name, text=name})
|
||||||
|
|
@ -78,7 +87,10 @@ function on_open()
|
||||||
local info = audio.input.get_input_info()
|
local info = audio.input.get_input_info()
|
||||||
if info then
|
if info then
|
||||||
selectbox.value = info.device_specifier
|
selectbox.value = info.device_specifier
|
||||||
|
else
|
||||||
|
selectbox.value = app.get_setting("audio.input-device")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_checkbox("audio.recording-enabled", "Microphone access", "audio.recording-enabled.tooltip")
|
||||||
create_checkbox("audio.acoustic-effects", "Acoustic effects", "audio.acoustic-effects.tooltip")
|
create_checkbox("audio.acoustic-effects", "Acoustic effects", "audio.acoustic-effects.tooltip")
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
<textbox id='search_textbox' multiline='false' size='300,20' sub-consumer='function(x) refresh_search() end'></textbox>
|
<textbox id='search_textbox' multiline='false' size='300,20' sub-consumer='function(x) refresh_search() end'></textbox>
|
||||||
<checkbox size='100,24' id='search_key_checkbox' consumer='function(x) refresh_search() end'>@settings.Controls Search Mode</checkbox>
|
<checkbox size='100,24' id='search_key_checkbox' consumer='function(x) refresh_search() end'>@settings.Controls Search Mode</checkbox>
|
||||||
</panel>
|
</panel>
|
||||||
<panel id='bindings_panel' size='380,204' padding='2' interval='1' max-length='300' color='#0000004C'>
|
<panel id='bindings_panel' size='380,204' padding='2' interval='1' max-length='333' color='#0000004C'>
|
||||||
<!-- content is generated in script -->
|
<!-- content is generated in script -->
|
||||||
</panel>
|
</panel>
|
||||||
</panel>
|
</panel>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ tostring_overrides["display.framerate"] = function(x)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function create_setting(id, name, step, postfix, tooltip, changeonrelease)
|
function create_trackbar_setting(id, name, step, postfix, tooltip, changeonrelease)
|
||||||
local info = app.get_setting_info(id)
|
local info = app.get_setting_info(id)
|
||||||
postfix = postfix or ""
|
postfix = postfix or ""
|
||||||
tooltip = tooltip or ""
|
tooltip = tooltip or ""
|
||||||
|
|
@ -25,10 +25,10 @@ function create_setting(id, name, step, postfix, tooltip, changeonrelease)
|
||||||
tooltip=tooltip,
|
tooltip=tooltip,
|
||||||
changeonrelease=changeonrelease
|
changeonrelease=changeonrelease
|
||||||
}))
|
}))
|
||||||
update_setting(app.get_setting(id), id, name, postfix)
|
update_trackbar_label(app.get_setting(id), id, name, postfix)
|
||||||
end
|
end
|
||||||
|
|
||||||
function update_setting(x, id, name, postfix)
|
function update_trackbar_label(x, id, name, postfix)
|
||||||
local str
|
local str
|
||||||
local func = tostring_overrides[id]
|
local func = tostring_overrides[id]
|
||||||
if func then
|
if func then
|
||||||
|
|
@ -55,8 +55,8 @@ end
|
||||||
|
|
||||||
|
|
||||||
function on_open()
|
function on_open()
|
||||||
create_setting("camera.fov", "FOV", 1, "°")
|
create_trackbar_setting("camera.fov", "FOV", 1, "°")
|
||||||
create_setting("display.framerate", "Framerate", 1, "", "", true)
|
create_trackbar_setting("display.framerate", "Framerate", 1, "", "", true)
|
||||||
|
|
||||||
document.root:add(string.format(
|
document.root:add(string.format(
|
||||||
"<select context='settings' onselect='function(opt) app.set_setting(\"display.window-mode\", tonumber(opt)) end' selected='%s'>"..
|
"<select context='settings' onselect='function(opt) app.set_setting(\"display.window-mode\", tonumber(opt)) end' selected='%s'>"..
|
||||||
|
|
@ -70,5 +70,5 @@ function on_open()
|
||||||
create_checkbox("camera.inertia", "Camera Inertia")
|
create_checkbox("camera.inertia", "Camera Inertia")
|
||||||
create_checkbox("camera.fov-effects", "Camera FOV Effects")
|
create_checkbox("camera.fov-effects", "Camera FOV Effects")
|
||||||
create_checkbox("display.limit-fps-iconified", "Limit Background FPS")
|
create_checkbox("display.limit-fps-iconified", "Limit Background FPS")
|
||||||
create_setting("graphics.gamma", "Gamma", 0.05, "", "graphics.gamma.tooltip")
|
create_trackbar_setting("graphics.gamma", "Gamma", 0.05, "", "graphics.gamma.tooltip")
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
function create_setting(id, name, step, postfix, tooltip, changeonrelease)
|
function create_trackbar_setting(id, name, step, postfix, tooltip, changeonrelease)
|
||||||
local info = app.get_setting_info(id)
|
local info = app.get_setting_info(id)
|
||||||
postfix = postfix or ""
|
postfix = postfix or ""
|
||||||
tooltip = tooltip or ""
|
tooltip = tooltip or ""
|
||||||
|
|
@ -14,10 +14,10 @@ function create_setting(id, name, step, postfix, tooltip, changeonrelease)
|
||||||
tooltip=tooltip,
|
tooltip=tooltip,
|
||||||
changeonrelease=changeonrelease
|
changeonrelease=changeonrelease
|
||||||
}))
|
}))
|
||||||
update_setting(app.get_setting(id), id, name, postfix)
|
update_trackbar_label(app.get_setting(id), id, name, postfix)
|
||||||
end
|
end
|
||||||
|
|
||||||
function update_setting(x, id, name, postfix)
|
function update_trackbar_label(x, id, name, postfix)
|
||||||
-- updating label
|
-- updating label
|
||||||
document[id..".L"].text = string.format(
|
document[id..".L"].text = string.format(
|
||||||
"%s: %s%s",
|
"%s: %s%s",
|
||||||
|
|
@ -36,15 +36,15 @@ function create_checkbox(id, name, tooltip)
|
||||||
end
|
end
|
||||||
|
|
||||||
function on_open()
|
function on_open()
|
||||||
create_setting("chunks.load-distance", "Load Distance", 1)
|
create_trackbar_setting("chunks.load-distance", "Load Distance", 1)
|
||||||
create_setting("chunks.load-speed", "Load Speed", 1)
|
create_trackbar_setting("chunks.load-speed", "Load Speed", 1)
|
||||||
create_setting("graphics.fog-curve", "Fog Curve", 0.1)
|
create_trackbar_setting("graphics.fog-curve", "Fog Curve", 0.1)
|
||||||
|
|
||||||
create_checkbox("graphics.backlight", "Backlight", "graphics.backlight.tooltip")
|
create_checkbox("graphics.backlight", "Backlight", "graphics.backlight.tooltip")
|
||||||
create_checkbox("graphics.soft-lighting", "Soft lighting", "graphics.soft-lighting.tooltip")
|
create_checkbox("graphics.soft-lighting", "Soft lighting", "graphics.soft-lighting.tooltip")
|
||||||
create_checkbox("graphics.dense-render", "Dense blocks render", "graphics.dense-render.tooltip")
|
create_checkbox("graphics.dense-render", "Dense blocks render", "graphics.dense-render.tooltip")
|
||||||
create_checkbox("graphics.advanced-render", "Advanced render", "graphics.advanced-render.tooltip")
|
create_checkbox("graphics.advanced-render", "Advanced render", "graphics.advanced-render.tooltip")
|
||||||
create_setting("graphics.ssao", "SSAO", 1, "", "graphics.ssao.tooltip")
|
create_trackbar_setting("graphics.ssao", "SSAO", 1, "", "graphics.ssao.tooltip")
|
||||||
create_setting("graphics.shadows-quality", "Shadows quality", 1)
|
create_trackbar_setting("graphics.shadows-quality", "Shadows quality", 1)
|
||||||
create_setting("graphics.clouds-quality", "Clouds quality", 1)
|
create_trackbar_setting("graphics.clouds-quality", "Clouds quality", 1)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@
|
||||||
<trackbar
|
<trackbar
|
||||||
value='%{value}' min='%{min}' max='%{max}' step='%{step}' tooltip='%{tooltip}'
|
value='%{value}' min='%{min}' max='%{max}' step='%{step}' tooltip='%{tooltip}'
|
||||||
consumer='function(x) app.set_setting("%{id}", x) end' change-on-release='%{changeonrelease}'
|
consumer='function(x) app.set_setting("%{id}", x) end' change-on-release='%{changeonrelease}'
|
||||||
sub-consumer='function(x) update_setting(x, "%{id}", "%{name}", "%{postfix}") end'/>
|
sub-consumer='function(x) update_trackbar_label(x, "%{id}", "%{name}", "%{postfix}") end'/>
|
||||||
</panel>
|
</panel>
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,13 @@ FFIBytearray = {
|
||||||
}
|
}
|
||||||
table.merge(FFIBytearray, bytearray_methods)
|
table.merge(FFIBytearray, bytearray_methods)
|
||||||
|
|
||||||
|
local function FFIBytearray_as_ptr(bytes)
|
||||||
|
if type(bytes) == "cdata" then
|
||||||
|
return tostring(bytes.bytes):sub(27), bytes.size
|
||||||
|
end
|
||||||
|
return "0"
|
||||||
|
end
|
||||||
|
|
||||||
local function FFIBytearray_as_string(bytes)
|
local function FFIBytearray_as_string(bytes)
|
||||||
local t = type(bytes)
|
local t = type(bytes)
|
||||||
if t == "cdata" then
|
if t == "cdata" then
|
||||||
|
|
@ -283,6 +290,7 @@ local FFIU32view = create_FFIview_class("FFIU32view", "uint32_t", 4)
|
||||||
return {
|
return {
|
||||||
FFIBytearray = setmetatable(FFIBytearray, FFIBytearray),
|
FFIBytearray = setmetatable(FFIBytearray, FFIBytearray),
|
||||||
FFIBytearray_as_string = FFIBytearray_as_string,
|
FFIBytearray_as_string = FFIBytearray_as_string,
|
||||||
|
FFIBytearray_as_ptr = FFIBytearray_as_ptr,
|
||||||
FFIU16view = FFIU16view,
|
FFIU16view = FFIU16view,
|
||||||
FFII16view = FFII16view,
|
FFII16view = FFII16view,
|
||||||
FFIU32view = FFIU32view,
|
FFIU32view = FFIU32view,
|
||||||
|
|
|
||||||
62
res/modules/internal/console.lua
Normal file
62
res/modules/internal/console.lua
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
|
||||||
|
--- Console library extension ---
|
||||||
|
console.cheats = {}
|
||||||
|
|
||||||
|
local log_element = Document.new("core:console").log
|
||||||
|
function console.log(...)
|
||||||
|
local args = {...}
|
||||||
|
local text = ''
|
||||||
|
for i,v in ipairs(args) do
|
||||||
|
if i ~= 1 then
|
||||||
|
text = text..' '..v
|
||||||
|
else
|
||||||
|
text = text..v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
log_element.caret = -1
|
||||||
|
if log_element.caret > 0 then
|
||||||
|
text = '\n'..text
|
||||||
|
end
|
||||||
|
log_element:paste(text)
|
||||||
|
end
|
||||||
|
|
||||||
|
local console_add_command = console.__add_command
|
||||||
|
console.__add_command = nil
|
||||||
|
|
||||||
|
function console.add_command(scheme, description, handler, is_cheat)
|
||||||
|
console_add_command(scheme, description, handler)
|
||||||
|
if not is_cheat then return end
|
||||||
|
|
||||||
|
local name = string.match(scheme, "^(%S+)")
|
||||||
|
if not name then
|
||||||
|
error("Incorrect command syntax, command name not found")
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert_unique(console.cheats, name)
|
||||||
|
end
|
||||||
|
|
||||||
|
function console.is_cheat(name)
|
||||||
|
if not table.has(console.get_commands_list(), name) then
|
||||||
|
error(string.format("command \"%s\" not found", name))
|
||||||
|
end
|
||||||
|
|
||||||
|
return table.has(console.cheats, name)
|
||||||
|
end
|
||||||
|
|
||||||
|
function console.set_cheat(name, status)
|
||||||
|
local is_cheat = console.is_cheat(name)
|
||||||
|
if status and not is_cheat then
|
||||||
|
table.insert(console.cheats, name)
|
||||||
|
return true
|
||||||
|
elseif not status and is_cheat then
|
||||||
|
table.remove_value(console.cheats, name)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function console.chat(...)
|
||||||
|
console.log(...)
|
||||||
|
events.emit("core:chat", ...)
|
||||||
|
end
|
||||||
|
|
@ -57,6 +57,18 @@ function table.merge(t1, t2)
|
||||||
return t1
|
return t1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function table.extend(t1, t2)
|
||||||
|
for i, v in pairs(t2) do
|
||||||
|
if type(i) == "number" then
|
||||||
|
t1[#t1 + 1] = v
|
||||||
|
else
|
||||||
|
t1[i] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return t1
|
||||||
|
end
|
||||||
|
|
||||||
function table.map(t, func)
|
function table.map(t, func)
|
||||||
for i, v in pairs(t) do
|
for i, v in pairs(t) do
|
||||||
t[i] = func(i, v)
|
t[i] = func(i, v)
|
||||||
|
|
|
||||||
224
res/modules/internal/lifetime_events.lua
Normal file
224
res/modules/internal/lifetime_events.lua
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
local __app = __vc_app
|
||||||
|
local __rules = rules
|
||||||
|
|
||||||
|
local function configure_SSAO()
|
||||||
|
-- Temporary using slot to configure built-in SSAO effect
|
||||||
|
local slot = gfx.posteffects.index("core:ssao")
|
||||||
|
gfx.posteffects.set_effect(slot, "ssao")
|
||||||
|
|
||||||
|
-- Generating random SSAO samples
|
||||||
|
local buffer = Bytearray(0)
|
||||||
|
for i = 0, 63 do
|
||||||
|
local x = math.random() * 2.0 - 1.0
|
||||||
|
local y = math.random() * 2.0 - 1.0
|
||||||
|
local z = math.random() * 2.0
|
||||||
|
local len = math.sqrt(x * x + y * y + z * z)
|
||||||
|
if len > 0 then
|
||||||
|
x = x / len
|
||||||
|
y = y / len
|
||||||
|
z = z / len
|
||||||
|
end
|
||||||
|
Bytearray.append(buffer, byteutil.pack("fff", x, y, z))
|
||||||
|
end
|
||||||
|
gfx.posteffects.set_array(slot, "u_ssaoSamples", Bytearray_as_string(buffer))
|
||||||
|
|
||||||
|
local function update_ssao_quality(value)
|
||||||
|
value = math.min(value, 3)
|
||||||
|
gfx.posteffects.set_params(slot, {
|
||||||
|
u_kernelSize = value * 16,
|
||||||
|
u_radius = 0.4 / value,
|
||||||
|
u_bias = 0.006 / value / value,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
events.on("core:setting.graphics.ssao.set", update_ssao_quality)
|
||||||
|
|
||||||
|
update_ssao_quality(__app.get_setting("graphics.ssao"))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function __vc_on_hud_open()
|
||||||
|
local _hud_is_content_access = hud._is_content_access
|
||||||
|
local _hud_set_content_access = hud._set_content_access
|
||||||
|
local _hud_set_debug_cheats = hud._set_debug_cheats
|
||||||
|
|
||||||
|
__rules.create("allow-cheats", true)
|
||||||
|
|
||||||
|
__rules.create("allow-content-access", _hud_is_content_access(), function(value)
|
||||||
|
_hud_set_content_access(value)
|
||||||
|
end)
|
||||||
|
__rules.create("allow-flight", true, function(value)
|
||||||
|
input.set_enabled("player.flight", value)
|
||||||
|
end)
|
||||||
|
__rules.create("allow-noclip", true, function(value)
|
||||||
|
input.set_enabled("player.noclip", value)
|
||||||
|
end)
|
||||||
|
__rules.create("allow-attack", true, function(value)
|
||||||
|
input.set_enabled("player.attack", value)
|
||||||
|
end)
|
||||||
|
__rules.create("allow-destroy", true, function(value)
|
||||||
|
input.set_enabled("player.destroy", value)
|
||||||
|
end)
|
||||||
|
__rules.create("allow-cheat-movement", true, function(value)
|
||||||
|
input.set_enabled("movement.cheat", value)
|
||||||
|
end)
|
||||||
|
__rules.create("allow-fast-interaction", true, function(value)
|
||||||
|
input.set_enabled("player.fast_interaction", value)
|
||||||
|
end)
|
||||||
|
__rules.create("allow-debug-cheats", true, function(value)
|
||||||
|
_hud_set_debug_cheats(value)
|
||||||
|
end)
|
||||||
|
input.add_callback("devtools.console", function()
|
||||||
|
if menu.page ~= "" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
time.post_runnable(function()
|
||||||
|
hud.show_overlay("core:console", false, {"console"})
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
input.add_callback("hud.chat", function()
|
||||||
|
if menu.page ~= "" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
time.post_runnable(function()
|
||||||
|
hud.show_overlay("core:console", false, {"chat"})
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
input.add_callback("key:escape", function()
|
||||||
|
if menu.page ~= "" then
|
||||||
|
if not menu:back() then
|
||||||
|
menu:reset()
|
||||||
|
gui.set_active_frame("")
|
||||||
|
end
|
||||||
|
elseif hud.is_inventory_open() then
|
||||||
|
hud.close_inventory()
|
||||||
|
elseif gui.get_active_frame() then
|
||||||
|
gui.set_active_frame("")
|
||||||
|
else
|
||||||
|
hud.pause()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
hud.open_permanent("core:ingame_chat")
|
||||||
|
|
||||||
|
configure_SSAO()
|
||||||
|
end
|
||||||
|
|
||||||
|
local Schedule = require "core:schedule"
|
||||||
|
local ScheduleGroup_mt = {
|
||||||
|
__index = {
|
||||||
|
publish = function(self, schedule)
|
||||||
|
local id = self._next_schedule
|
||||||
|
self._schedules[id] = schedule
|
||||||
|
self._next_schedule = id + 1
|
||||||
|
end,
|
||||||
|
tick = function(self, dt)
|
||||||
|
for id, schedule in pairs(self._schedules) do
|
||||||
|
schedule:tick(dt)
|
||||||
|
end
|
||||||
|
self.common:tick(dt)
|
||||||
|
end,
|
||||||
|
remove = function(self, id)
|
||||||
|
self._schedules[id] = nil
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local function ScheduleGroup()
|
||||||
|
return setmetatable({
|
||||||
|
_next_schedule = 1,
|
||||||
|
_schedules = {},
|
||||||
|
common = Schedule()
|
||||||
|
}, ScheduleGroup_mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
local RULES_FILE = "world:rules.toml"
|
||||||
|
local function __vc_on_world_open()
|
||||||
|
time.schedules.world = ScheduleGroup()
|
||||||
|
|
||||||
|
if not file.exists(RULES_FILE) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local rule_values = toml.parse(file.read(RULES_FILE))
|
||||||
|
for name, value in pairs(rule_values) do
|
||||||
|
__rules.set(name, value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function __vc_on_world_tick(tps)
|
||||||
|
time.schedules.world:tick(1.0 / tps)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function __vc_process_before_quit()
|
||||||
|
block.__process_register_events()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function __vc_on_world_save()
|
||||||
|
local rule_values = {}
|
||||||
|
for name, rule in pairs(__rules.rules) do
|
||||||
|
rule_values[name] = rule.value
|
||||||
|
end
|
||||||
|
file.write(RULES_FILE, toml.tostring(rule_values))
|
||||||
|
end
|
||||||
|
|
||||||
|
local __close_all_descriptors = file.__close_all_descriptors
|
||||||
|
local __gui_util_reset_local = gui_util.__reset_local
|
||||||
|
local __stdcomp_reset = stdcomp.__reset
|
||||||
|
file.__close_all_descriptors = nil
|
||||||
|
gui_util.__reset_local = nil
|
||||||
|
stdcomp.reset = nil
|
||||||
|
|
||||||
|
local function __vc_on_world_quit()
|
||||||
|
__rules.clear()
|
||||||
|
__gui_util_reset_local()
|
||||||
|
__stdcomp_reset()
|
||||||
|
__close_all_descriptors()
|
||||||
|
end
|
||||||
|
|
||||||
|
local __post_runnables = {}
|
||||||
|
local fn_audio_reset_fetch_buffer = audio.__reset_fetch_buffer
|
||||||
|
audio.__reset_fetch_buffer = nil
|
||||||
|
|
||||||
|
local __vc_update_coroutines = _G.__vc_update_coroutines
|
||||||
|
|
||||||
|
local function __process_post_runnables()
|
||||||
|
if #__post_runnables > 0 then
|
||||||
|
for _, func in ipairs(__post_runnables) do
|
||||||
|
local status, result = xpcall(func, __vc__error)
|
||||||
|
if not status then
|
||||||
|
debug.error("error in post_runnable: "..result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
__post_runnables = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
__vc_update_coroutines()
|
||||||
|
|
||||||
|
fn_audio_reset_fetch_buffer()
|
||||||
|
debug.pull_events()
|
||||||
|
network.__process_events()
|
||||||
|
if not hud or not hud.is_paused() then
|
||||||
|
block.__process_register_events()
|
||||||
|
block.__perform_ticks(time.delta())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function __vc__process_post_runnables()
|
||||||
|
__vc__is_post_runnable = true
|
||||||
|
local success, err = pcall(__process_post_runnables)
|
||||||
|
if not success then
|
||||||
|
debug.error("an error ocurred while processing post-runnables: ".. err)
|
||||||
|
end
|
||||||
|
__vc__is_post_runnable = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function time.post_runnable(runnable)
|
||||||
|
table.insert(__post_runnables, runnable)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
__vc_on_hud_open = __vc_on_hud_open,
|
||||||
|
__vc_on_world_open = __vc_on_world_open,
|
||||||
|
__vc_on_world_tick = __vc_on_world_tick,
|
||||||
|
__vc_process_before_quit = __vc_process_before_quit,
|
||||||
|
__vc_on_world_save = __vc_on_world_save,
|
||||||
|
__vc_on_world_quit = __vc_on_world_quit,
|
||||||
|
__vc__process_post_runnables = __vc__process_post_runnables,
|
||||||
|
}
|
||||||
|
|
@ -12,7 +12,7 @@ function sleep(timesec)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function tb_frame_tostring(frame)
|
local function tb_frame_tostring(frame)
|
||||||
local s = frame.short_src
|
local s = frame.short_src
|
||||||
if frame.what ~= "C" then
|
if frame.what ~= "C" then
|
||||||
s = s .. ":" .. tostring(frame.currentline)
|
s = s .. ":" .. tostring(frame.currentline)
|
||||||
|
|
@ -192,6 +192,22 @@ function start_coroutine(chunk, name)
|
||||||
__vc_named_coroutines[name] = co
|
__vc_named_coroutines[name] = co
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function __vc_update_coroutines()
|
||||||
|
local dead = {}
|
||||||
|
for name, co in pairs(__vc_named_coroutines) do
|
||||||
|
local success, err = coroutine.resume(co)
|
||||||
|
if not success then
|
||||||
|
debug.error(err)
|
||||||
|
end
|
||||||
|
if coroutine.status(co) == "dead" then
|
||||||
|
table.insert(dead, name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, name in ipairs(dead) do
|
||||||
|
__vc_named_coroutines[name] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function __vc_start_app_script(path, name)
|
function __vc_start_app_script(path, name)
|
||||||
debug.log("starting application script "..path)
|
debug.log("starting application script "..path)
|
||||||
|
|
||||||
|
|
@ -257,71 +273,8 @@ do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Console library extension ---
|
function gui.process_template(source, params)
|
||||||
console.cheats = {}
|
local text = source:gsub("%%{([^}]+)}", function(n)
|
||||||
|
|
||||||
local log_element = Document.new("core:console").log
|
|
||||||
function console.log(...)
|
|
||||||
local args = {...}
|
|
||||||
local text = ''
|
|
||||||
for i,v in ipairs(args) do
|
|
||||||
if i ~= 1 then
|
|
||||||
text = text..' '..v
|
|
||||||
else
|
|
||||||
text = text..v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
log_element.caret = -1
|
|
||||||
if log_element.caret > 0 then
|
|
||||||
text = '\n'..text
|
|
||||||
end
|
|
||||||
log_element:paste(text)
|
|
||||||
end
|
|
||||||
|
|
||||||
local console_add_command = console.__add_command
|
|
||||||
console.__add_command = nil
|
|
||||||
|
|
||||||
function console.add_command(scheme, description, handler, is_cheat)
|
|
||||||
console_add_command(scheme, description, handler)
|
|
||||||
if not is_cheat then return end
|
|
||||||
|
|
||||||
local name = string.match(scheme, "^(%S+)")
|
|
||||||
if not name then
|
|
||||||
error("Incorrect command syntax, command name not found")
|
|
||||||
end
|
|
||||||
|
|
||||||
table.insert_unique(console.cheats, name)
|
|
||||||
end
|
|
||||||
|
|
||||||
function console.is_cheat(name)
|
|
||||||
if not table.has(console.get_commands_list(), name) then
|
|
||||||
error(string.format("command \"%s\" not found", name))
|
|
||||||
end
|
|
||||||
|
|
||||||
return table.has(console.cheats, name)
|
|
||||||
end
|
|
||||||
|
|
||||||
function console.set_cheat(name, status)
|
|
||||||
local is_cheat = console.is_cheat(name)
|
|
||||||
if status and not is_cheat then
|
|
||||||
table.insert(console.cheats, name)
|
|
||||||
return true
|
|
||||||
elseif not status and is_cheat then
|
|
||||||
table.remove_value(console.cheats, name)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
function console.chat(...)
|
|
||||||
console.log(...)
|
|
||||||
events.emit("core:chat", ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
function gui.template(name, params)
|
|
||||||
local text = file.read(file.find("layouts/templates/"..name..".xml"))
|
|
||||||
text = text:gsub("%%{([^}]+)}", function(n)
|
|
||||||
local s = params[n]
|
local s = params[n]
|
||||||
if s == nil then
|
if s == nil then
|
||||||
return
|
return
|
||||||
|
|
@ -341,6 +294,11 @@ function gui.template(name, params)
|
||||||
return text
|
return text
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function gui.template(name, params)
|
||||||
|
local text = file.read(file.find("layouts/templates/"..name..".xml"))
|
||||||
|
return gui.process_template(text, params)
|
||||||
|
end
|
||||||
|
|
||||||
session = require "core:internal/session"
|
session = require "core:internal/session"
|
||||||
stdcomp = require "core:internal/stdcomp"
|
stdcomp = require "core:internal/stdcomp"
|
||||||
entities.get = stdcomp.get_Entity
|
entities.get = stdcomp.get_Entity
|
||||||
|
|
@ -378,236 +336,20 @@ end
|
||||||
math.randomseed(time.uptime() * 1536227939)
|
math.randomseed(time.uptime() * 1536227939)
|
||||||
|
|
||||||
rules = require "core:internal/rules"
|
rules = require "core:internal/rules"
|
||||||
local _rules = rules
|
|
||||||
|
|
||||||
local function configure_SSAO()
|
|
||||||
-- Temporary using slot to configure built-in SSAO effect
|
|
||||||
local slot = gfx.posteffects.index("core:ssao")
|
|
||||||
gfx.posteffects.set_effect(slot, "ssao")
|
|
||||||
|
|
||||||
-- Generating random SSAO samples
|
|
||||||
local buffer = Bytearray(0)
|
|
||||||
for i = 0, 63 do
|
|
||||||
local x = math.random() * 2.0 - 1.0
|
|
||||||
local y = math.random() * 2.0 - 1.0
|
|
||||||
local z = math.random() * 2.0
|
|
||||||
local len = math.sqrt(x * x + y * y + z * z)
|
|
||||||
if len > 0 then
|
|
||||||
x = x / len
|
|
||||||
y = y / len
|
|
||||||
z = z / len
|
|
||||||
end
|
|
||||||
Bytearray.append(buffer, byteutil.pack("fff", x, y, z))
|
|
||||||
end
|
|
||||||
gfx.posteffects.set_array(slot, "u_ssaoSamples", Bytearray_as_string(buffer))
|
|
||||||
|
|
||||||
local function update_ssao_quality(value)
|
|
||||||
value = math.min(value, 3)
|
|
||||||
gfx.posteffects.set_params(slot, {
|
|
||||||
u_kernelSize = value * 16,
|
|
||||||
u_radius = 0.4 / value,
|
|
||||||
u_bias = 0.006 / value / value,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
events.on("core:setting.graphics.ssao.set", update_ssao_quality)
|
|
||||||
|
|
||||||
update_ssao_quality(__app.get_setting("graphics.ssao"))
|
|
||||||
end
|
|
||||||
|
|
||||||
function __vc_on_hud_open()
|
|
||||||
local _hud_is_content_access = hud._is_content_access
|
|
||||||
local _hud_set_content_access = hud._set_content_access
|
|
||||||
local _hud_set_debug_cheats = hud._set_debug_cheats
|
|
||||||
|
|
||||||
_rules.create("allow-cheats", true)
|
|
||||||
|
|
||||||
_rules.create("allow-content-access", _hud_is_content_access(), function(value)
|
|
||||||
_hud_set_content_access(value)
|
|
||||||
end)
|
|
||||||
_rules.create("allow-flight", true, function(value)
|
|
||||||
input.set_enabled("player.flight", value)
|
|
||||||
end)
|
|
||||||
_rules.create("allow-noclip", true, function(value)
|
|
||||||
input.set_enabled("player.noclip", value)
|
|
||||||
end)
|
|
||||||
_rules.create("allow-attack", true, function(value)
|
|
||||||
input.set_enabled("player.attack", value)
|
|
||||||
end)
|
|
||||||
_rules.create("allow-destroy", true, function(value)
|
|
||||||
input.set_enabled("player.destroy", value)
|
|
||||||
end)
|
|
||||||
_rules.create("allow-cheat-movement", true, function(value)
|
|
||||||
input.set_enabled("movement.cheat", value)
|
|
||||||
end)
|
|
||||||
_rules.create("allow-fast-interaction", true, function(value)
|
|
||||||
input.set_enabled("player.fast_interaction", value)
|
|
||||||
end)
|
|
||||||
_rules.create("allow-debug-cheats", true, function(value)
|
|
||||||
_hud_set_debug_cheats(value)
|
|
||||||
end)
|
|
||||||
input.add_callback("devtools.console", function()
|
|
||||||
if menu.page ~= "" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
time.post_runnable(function()
|
|
||||||
hud.show_overlay("core:console", false, {"console"})
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
input.add_callback("hud.chat", function()
|
|
||||||
if menu.page ~= "" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
time.post_runnable(function()
|
|
||||||
hud.show_overlay("core:console", false, {"chat"})
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
input.add_callback("key:escape", function()
|
|
||||||
if menu.page ~= "" then
|
|
||||||
if not menu:back() then
|
|
||||||
menu:reset()
|
|
||||||
gui.set_active_frame("")
|
|
||||||
end
|
|
||||||
elseif hud.is_inventory_open() then
|
|
||||||
hud.close_inventory()
|
|
||||||
elseif gui.get_active_frame() then
|
|
||||||
gui.set_active_frame("")
|
|
||||||
else
|
|
||||||
hud.pause()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
hud.open_permanent("core:ingame_chat")
|
|
||||||
|
|
||||||
configure_SSAO()
|
|
||||||
end
|
|
||||||
|
|
||||||
local Schedule = require "core:schedule"
|
|
||||||
|
|
||||||
local ScheduleGroup_mt = {
|
|
||||||
__index = {
|
|
||||||
publish = function(self, schedule)
|
|
||||||
local id = self._next_schedule
|
|
||||||
self._schedules[id] = schedule
|
|
||||||
self._next_schedule = id + 1
|
|
||||||
end,
|
|
||||||
tick = function(self, dt)
|
|
||||||
for id, schedule in pairs(self._schedules) do
|
|
||||||
schedule:tick(dt)
|
|
||||||
end
|
|
||||||
self.common:tick(dt)
|
|
||||||
end,
|
|
||||||
remove = function(self, id)
|
|
||||||
self._schedules[id] = nil
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local function ScheduleGroup()
|
|
||||||
return setmetatable({
|
|
||||||
_next_schedule = 1,
|
|
||||||
_schedules = {},
|
|
||||||
common = Schedule()
|
|
||||||
}, ScheduleGroup_mt)
|
|
||||||
end
|
|
||||||
|
|
||||||
time.schedules = {}
|
time.schedules = {}
|
||||||
|
|
||||||
local RULES_FILE = "world:rules.toml"
|
table.merge(_G, require "core:internal/lifetime_events")
|
||||||
function __vc_on_world_open()
|
|
||||||
time.schedules.world = ScheduleGroup()
|
|
||||||
|
|
||||||
if not file.exists(RULES_FILE) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local rule_values = toml.parse(file.read(RULES_FILE))
|
|
||||||
for name, value in pairs(rule_values) do
|
|
||||||
_rules.set(name, value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function __vc_on_world_tick(tps)
|
|
||||||
time.schedules.world:tick(1.0 / tps)
|
|
||||||
end
|
|
||||||
|
|
||||||
function __vc_process_before_quit()
|
|
||||||
block.__process_register_events()
|
|
||||||
end
|
|
||||||
|
|
||||||
function __vc_on_world_save()
|
|
||||||
local rule_values = {}
|
|
||||||
for name, rule in pairs(rules.rules) do
|
|
||||||
rule_values[name] = rule.value
|
|
||||||
end
|
|
||||||
file.write(RULES_FILE, toml.tostring(rule_values))
|
|
||||||
end
|
|
||||||
|
|
||||||
local __close_all_descriptors = file.__close_all_descriptors
|
|
||||||
local __gui_util_reset_local = gui_util.__reset_local
|
|
||||||
local __stdcomp_reset = stdcomp.__reset
|
|
||||||
file.__close_all_descriptors = nil
|
|
||||||
gui_util.__reset_local = nil
|
|
||||||
stdcomp.reset = nil
|
|
||||||
|
|
||||||
function __vc_on_world_quit()
|
|
||||||
_rules.clear()
|
|
||||||
__gui_util_reset_local()
|
|
||||||
__stdcomp_reset()
|
|
||||||
__close_all_descriptors()
|
|
||||||
end
|
|
||||||
|
|
||||||
local fn_audio_reset_fetch_buffer = audio.__reset_fetch_buffer
|
|
||||||
audio.__reset_fetch_buffer = nil
|
|
||||||
core.get_core_token = audio.input.__get_core_token
|
core.get_core_token = audio.input.__get_core_token
|
||||||
|
|
||||||
local __post_runnables = {}
|
require "core:internal/console"
|
||||||
|
require "core:internal/deprecated"
|
||||||
|
|
||||||
local function __process_post_runnables()
|
|
||||||
if #__post_runnables > 0 then
|
|
||||||
for _, func in ipairs(__post_runnables) do
|
|
||||||
local status, result = xpcall(func, __vc__error)
|
|
||||||
if not status then
|
|
||||||
debug.error("error in post_runnable: "..result)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
__post_runnables = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
local dead = {}
|
------------------------------------------
|
||||||
for name, co in pairs(__vc_named_coroutines) do
|
---- Unsafe functions cleanup section ----
|
||||||
local success, err = coroutine.resume(co)
|
------------------------------------------
|
||||||
if not success then
|
|
||||||
debug.error(err)
|
|
||||||
end
|
|
||||||
if coroutine.status(co) == "dead" then
|
|
||||||
table.insert(dead, name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for _, name in ipairs(dead) do
|
|
||||||
__vc_named_coroutines[name] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
fn_audio_reset_fetch_buffer()
|
|
||||||
debug.pull_events()
|
|
||||||
network.__process_events()
|
|
||||||
if not hud or not hud.is_paused() then
|
|
||||||
block.__process_register_events()
|
|
||||||
block.__perform_ticks(time.delta())
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function __vc__process_post_runnables()
|
|
||||||
__vc__is_post_runnable = true
|
|
||||||
local success, err = pcall(__process_post_runnables)
|
|
||||||
if not success then
|
|
||||||
debug.error("an error ocurred while processing post-runnables: ".. err)
|
|
||||||
end
|
|
||||||
__vc__is_post_runnable = false
|
|
||||||
end
|
|
||||||
|
|
||||||
function time.post_runnable(runnable)
|
|
||||||
table.insert(__post_runnables, runnable)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Hide unsafe debug.* functions
|
|
||||||
local removed_names = {
|
local removed_names = {
|
||||||
"getregistry", "getupvalue", "setupvalue", "upvalueid", "upvaluejoin",
|
"getregistry", "getupvalue", "setupvalue", "upvalueid", "upvaluejoin",
|
||||||
"sethook", "gethook", "getinfo"
|
"sethook", "gethook", "getinfo"
|
||||||
|
|
@ -626,9 +368,9 @@ debug.getinfo = function(lvl, fields)
|
||||||
return debuginfo
|
return debuginfo
|
||||||
end
|
end
|
||||||
|
|
||||||
require "core:internal/deprecated"
|
|
||||||
|
|
||||||
ffi = nil
|
ffi = nil
|
||||||
__vc_app = nil
|
__vc_app = nil
|
||||||
__vc_lock_internal_modules()
|
__vc_lock_internal_modules()
|
||||||
__vc_lock_internal_modules = nil
|
__vc_lock_internal_modules = nil
|
||||||
|
__vc_update_coroutines = nil
|
||||||
|
__VC_SCRIPT_NAME = ""
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,18 @@
|
||||||
local _vc_headless = __VC_HEADLESS
|
local _vc_headless = __VC_HEADLESS
|
||||||
|
local _vc_project_args = __VC_PROJECT_ARGS
|
||||||
__VC_HEADLESS = nil
|
__VC_HEADLESS = nil
|
||||||
|
__VC_PROJECT_ARGS = nil
|
||||||
|
|
||||||
vc = {
|
vc = {
|
||||||
is_headless = function()
|
is_headless = function()
|
||||||
return _vc_headless
|
return _vc_headless
|
||||||
end,
|
end,
|
||||||
is_client = function ()
|
is_client = function()
|
||||||
return not _vc_headless
|
return not _vc_headless
|
||||||
end
|
end,
|
||||||
|
get_setting = __vc_app.get_setting,
|
||||||
|
get_setting_str = __vc_app.get_setting_str,
|
||||||
|
get_setting_info = __vc_app.get_setting_info,
|
||||||
}
|
}
|
||||||
|
|
||||||
local _ffi = ffi
|
local _ffi = ffi
|
||||||
|
|
@ -297,9 +302,14 @@ require "core:internal/extensions/file"
|
||||||
require "core:internal/extensions/table"
|
require "core:internal/extensions/table"
|
||||||
require "core:internal/extensions/string"
|
require "core:internal/extensions/string"
|
||||||
|
|
||||||
|
vc.get_project_arg = function (name)
|
||||||
|
return _vc_project_args[name]
|
||||||
|
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_as_ptr = bytearray.FFIBytearray_as_ptr
|
||||||
U16view = bytearray.FFIU16view
|
U16view = bytearray.FFIU16view
|
||||||
I16view = bytearray.FFII16view
|
I16view = bytearray.FFII16view
|
||||||
U32view = bytearray.FFIU32view
|
U32view = bytearray.FFIU32view
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ devtools.output=Output
|
||||||
|
|
||||||
# Tooltips
|
# Tooltips
|
||||||
audio.acoustic-effects.tooltip=Acoustic effects may not be supported by your system
|
audio.acoustic-effects.tooltip=Acoustic effects may not be supported by your system
|
||||||
|
audio.recording-enabled.tooltip=Enables audio recording features
|
||||||
graphics.gamma.tooltip=Lighting brightness curve
|
graphics.gamma.tooltip=Lighting brightness curve
|
||||||
graphics.backlight.tooltip=Backlight to prevent total darkness
|
graphics.backlight.tooltip=Backlight to prevent total darkness
|
||||||
graphics.dense-render.tooltip=Enables transparency in blocks like leaves
|
graphics.dense-render.tooltip=Enables transparency in blocks like leaves
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ pack.remove-confirm=Удалить весь поставляемый паком/
|
||||||
|
|
||||||
# Подсказки
|
# Подсказки
|
||||||
audio.acoustic-effects.tooltip=Акустические эффекты могут не поддерживаться системой
|
audio.acoustic-effects.tooltip=Акустические эффекты могут не поддерживаться системой
|
||||||
|
audio.recording-enabled.tooltip=Включает функции записи звука
|
||||||
graphics.gamma.tooltip=Кривая яркости освещения
|
graphics.gamma.tooltip=Кривая яркости освещения
|
||||||
graphics.backlight.tooltip=Подсветка, предотвращающая полную темноту
|
graphics.backlight.tooltip=Подсветка, предотвращающая полную темноту
|
||||||
graphics.dense-render.tooltip=Включает прозрачность блоков, таких как листья
|
graphics.dense-render.tooltip=Включает прозрачность блоков, таких как листья
|
||||||
|
|
@ -114,6 +115,7 @@ settings.Microphone=Микрофон
|
||||||
settings.microphone.None=Нет
|
settings.microphone.None=Нет
|
||||||
settings.Clouds quality=Качество облаков
|
settings.Clouds quality=Качество облаков
|
||||||
settings.Acoustic effects=Акустические эффекты
|
settings.Acoustic effects=Акустические эффекты
|
||||||
|
settings.Microphone access=Доступ к микрофону
|
||||||
|
|
||||||
# Управление
|
# Управление
|
||||||
chunks.reload=Перезагрузить Чанки
|
chunks.reload=Перезагрузить Чанки
|
||||||
|
|
|
||||||
|
|
@ -190,18 +190,34 @@ void audio::initialize(
|
||||||
audio::get_channel(channel.name)->setVolume(value * value);
|
audio::get_channel(channel.name)->setVolume(value * value);
|
||||||
}, true));
|
}, true));
|
||||||
}
|
}
|
||||||
objects_keeper.keepAlive(settings.acousticEffects.observe([=](auto value) {
|
objects_keeper.keepAlive(settings.acousticEffects.observe([=](bool value) {
|
||||||
if (value) return;
|
if (value) return;
|
||||||
backend->setAcoustics(audio::Acoustics {});
|
backend->setAcoustics(audio::Acoustics {});
|
||||||
}, true));
|
}, true));
|
||||||
|
|
||||||
if (inputEnabled) {
|
::input_enabled = inputEnabled;
|
||||||
::input_device = backend->openInputDevice("", 44100, 1, 16);
|
|
||||||
::input_enabled = true;
|
objects_keeper.keepAlive(settings.recordingEnabled.observe([&settings](bool enabled) {
|
||||||
}
|
if (!::input_enabled) {
|
||||||
if (::input_device) {
|
return;
|
||||||
::input_device->startCapture();
|
}
|
||||||
}
|
if (!enabled && ::input_device == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (enabled) {
|
||||||
|
logger.info() << "recording enabled; input device is "
|
||||||
|
<< settings.inputDevice.get();
|
||||||
|
::input_device = backend->openInputDevice(
|
||||||
|
settings.inputDevice.get(), 44100, 1, 16
|
||||||
|
);
|
||||||
|
::input_device->startCapture();
|
||||||
|
} else {
|
||||||
|
if (::input_device) {
|
||||||
|
::input_device->stopCapture();
|
||||||
|
}
|
||||||
|
::input_device = nullptr;
|
||||||
|
}
|
||||||
|
}, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
InputDevice* audio::get_input_device() {
|
InputDevice* audio::get_input_device() {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
struct CoreParameters {
|
struct CoreParameters {
|
||||||
bool headless = false;
|
bool headless = false;
|
||||||
|
|
@ -13,4 +14,5 @@ struct CoreParameters {
|
||||||
std::filesystem::path projectFolder;
|
std::filesystem::path projectFolder;
|
||||||
std::string debugServerString;
|
std::string debugServerString;
|
||||||
int tps = 20;
|
int tps = 20;
|
||||||
|
std::unordered_map<std::string, std::string> projectArgs;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ void Engine::initialize(CoreParameters coreParameters) {
|
||||||
|
|
||||||
keepAlive(settings.audio.inputDevice.observe([](auto name) {
|
keepAlive(settings.audio.inputDevice.observe([](auto name) {
|
||||||
audio::set_input_device(name == "auto" ? "" : name);
|
audio::set_input_device(name == "auto" ? "" : name);
|
||||||
}, true));
|
}));
|
||||||
|
|
||||||
project->loadProjectStartScript();
|
project->loadProjectStartScript();
|
||||||
if (!params.headless) {
|
if (!params.headless) {
|
||||||
|
|
|
||||||
|
|
@ -61,16 +61,19 @@ std::unique_ptr<UiDocument> UiDocument::read(
|
||||||
const scriptenv& penv,
|
const scriptenv& penv,
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
const io::path& file,
|
const io::path& file,
|
||||||
const std::string& fileName
|
const std::string& fileName,
|
||||||
|
scriptenv&& env
|
||||||
) {
|
) {
|
||||||
const std::string text = io::read_string(file);
|
const std::string text = io::read_string(file);
|
||||||
auto xmldoc = xml::parse(file.string(), text);
|
auto xmldoc = xml::parse(file.string(), text);
|
||||||
|
|
||||||
auto env = penv == nullptr
|
if (env == nullptr) {
|
||||||
? scripting::create_doc_environment(scripting::get_root_environment(), name)
|
env = penv == nullptr
|
||||||
: scripting::create_doc_environment(penv, name);
|
? scripting::create_doc_environment(scripting::get_root_environment(), name)
|
||||||
|
: scripting::create_doc_environment(penv, name);
|
||||||
|
}
|
||||||
|
|
||||||
gui::UiXmlReader reader(gui, scriptenv(env));
|
gui::UiXmlReader reader(gui, env);
|
||||||
auto view = reader.readXML(file.string(), *xmldoc->getRoot());
|
auto view = reader.readXML(file.string(), *xmldoc->getRoot());
|
||||||
view->setId("root");
|
view->setId("root");
|
||||||
UiDocScript script {};
|
UiDocScript script {};
|
||||||
|
|
@ -82,9 +85,3 @@ std::unique_ptr<UiDocument> UiDocument::read(
|
||||||
}
|
}
|
||||||
return std::make_unique<UiDocument>(name, script, view, env);
|
return std::make_unique<UiDocument>(name, script, view, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<gui::UINode> UiDocument::readElement(
|
|
||||||
gui::GUI& gui, const io::path& file, const std::string& fileName
|
|
||||||
) {
|
|
||||||
return read(gui, nullptr, file.name(), file, fileName)->getRoot();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,7 @@ public:
|
||||||
const scriptenv& parent_env,
|
const scriptenv& parent_env,
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
const io::path& file,
|
const io::path& file,
|
||||||
const std::string& fileName
|
const std::string& fileName,
|
||||||
);
|
scriptenv&& env = nullptr
|
||||||
static std::shared_ptr<gui::UINode> readElement(
|
|
||||||
gui::GUI&, const io::path& file, const std::string& fileName
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,10 @@ FullCheckBox::FullCheckBox(
|
||||||
|
|
||||||
add(checkbox);
|
add(checkbox);
|
||||||
|
|
||||||
|
auto& checkboxActions = actions;
|
||||||
label->setMargin(glm::vec4(5.f, 5.f, 0.f, 0.f));
|
label->setMargin(glm::vec4(5.f, 5.f, 0.f, 0.f));
|
||||||
|
label->listenAction(UIAction::CLICK, [&checkboxActions](auto& gui) {
|
||||||
|
checkboxActions.notify(UIAction::CLICK, gui);
|
||||||
|
});
|
||||||
add(label);
|
add(label);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -889,8 +889,8 @@ static std::shared_ptr<UINode> read_iframe(
|
||||||
return iframe;
|
return iframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
UiXmlReader::UiXmlReader(gui::GUI& gui, scriptenv&& env)
|
UiXmlReader::UiXmlReader(gui::GUI& gui, const scriptenv& env)
|
||||||
: gui(gui), env(std::move(env)) {
|
: gui(gui), env(env) {
|
||||||
contextStack.emplace("");
|
contextStack.emplace("");
|
||||||
add("image", read_image);
|
add("image", read_image);
|
||||||
add("canvas", read_canvas);
|
add("canvas", read_canvas);
|
||||||
|
|
@ -922,8 +922,7 @@ void UiXmlReader::addIgnore(const std::string& tag) {
|
||||||
ignored.insert(tag);
|
ignored.insert(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element
|
std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element) {
|
||||||
) {
|
|
||||||
if (element.has("if")) {
|
if (element.has("if")) {
|
||||||
const auto& cond = element.attr("if").getText();
|
const auto& cond = element.attr("if").getText();
|
||||||
if (cond.empty() || cond == "false" || cond == "nil") return nullptr;
|
if (cond.empty() || cond == "false" || cond == "nil") return nullptr;
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ namespace gui {
|
||||||
std::unordered_set<std::string> ignored;
|
std::unordered_set<std::string> ignored;
|
||||||
std::stack<std::string> contextStack;
|
std::stack<std::string> contextStack;
|
||||||
std::string filename;
|
std::string filename;
|
||||||
scriptenv env;
|
const scriptenv& env;
|
||||||
public:
|
public:
|
||||||
UiXmlReader(gui::GUI& gui, scriptenv&& env);
|
UiXmlReader(gui::GUI& gui, const scriptenv& env);
|
||||||
|
|
||||||
void add(const std::string& tag, uinode_reader reader);
|
void add(const std::string& tag, uinode_reader reader);
|
||||||
bool hasReader(const std::string& tag) const;
|
bool hasReader(const std::string& tag) const;
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
||||||
|
|
||||||
builder.addSection("audio");
|
builder.addSection("audio");
|
||||||
builder.add("enabled", &settings.audio.enabled, false);
|
builder.add("enabled", &settings.audio.enabled, false);
|
||||||
|
builder.add("recording-enabled", &settings.audio.recordingEnabled);
|
||||||
builder.add("volume-master", &settings.audio.volumeMaster);
|
builder.add("volume-master", &settings.audio.volumeMaster);
|
||||||
builder.add("volume-regular", &settings.audio.volumeRegular);
|
builder.add("volume-regular", &settings.audio.volumeRegular);
|
||||||
builder.add("volume-ui", &settings.audio.volumeUI);
|
builder.add("volume-ui", &settings.audio.volumeUI);
|
||||||
|
|
@ -101,6 +102,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
||||||
builder.addSection("system");
|
builder.addSection("system");
|
||||||
builder.add("max-bg-asset-loaders", &settings.system.maxBgAssetLoaders);
|
builder.add("max-bg-asset-loaders", &settings.system.maxBgAssetLoaders);
|
||||||
builder.add("preserve-assets-during-frame", &settings.system.preserveAssetsDuringFrame);
|
builder.add("preserve-assets-during-frame", &settings.system.preserveAssetsDuringFrame);
|
||||||
|
builder.add("direct-scripting-data-access", &settings.system.directScriptingDataAccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
dv::value SettingsHandler::getValue(const std::string& name) const {
|
dv::value SettingsHandler::getValue(const std::string& name) const {
|
||||||
|
|
|
||||||
|
|
@ -1116,28 +1116,34 @@ static int l_gui_load_document(lua::State* L) {
|
||||||
auto args = lua::tovalue(L, 3);
|
auto args = lua::tovalue(L, 3);
|
||||||
auto prefix = filename.entryPoint();
|
auto prefix = filename.entryPoint();
|
||||||
|
|
||||||
auto env = scripting::get_root_environment();
|
auto parentEnv = scripting::get_root_environment();
|
||||||
if (content) {
|
if (content) {
|
||||||
if (auto runtime = content->getPackRuntime(prefix)) {
|
if (auto runtime = content->getPackRuntime(prefix)) {
|
||||||
env = runtime->getEnvironment();
|
parentEnv = runtime->getEnvironment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto documentPtr = UiDocument::read(
|
auto env = scripting::create_doc_environment(parentEnv, alias);
|
||||||
engine->getGUI(), std::move(env), alias, filename, filename.string()
|
|
||||||
);
|
|
||||||
auto document = documentPtr.get();
|
|
||||||
engine->requireAssets().store(std::move(documentPtr), alias);
|
|
||||||
|
|
||||||
// namespace extension
|
// namespace extension
|
||||||
if (lua::istable(L, 4)) {
|
if (lua::istable(L, 4)) {
|
||||||
if (lua::get_from(L, "table", "merge")) {
|
if (lua::get_from(L, "table", "extend")) {
|
||||||
lua::pushenv(L, *document->getEnvironment());
|
lua::pushenv(L, *env);
|
||||||
lua::pushvalue(L, 4);
|
lua::pushvalue(L, 4);
|
||||||
lua::call(L, 2, 0);
|
lua::call(L, 2, 0);
|
||||||
lua::pop(L);
|
lua::pop(L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
auto documentPtr = UiDocument::read(
|
||||||
|
engine->getGUI(),
|
||||||
|
nullptr,
|
||||||
|
alias,
|
||||||
|
filename,
|
||||||
|
filename.string(),
|
||||||
|
std::move(env)
|
||||||
|
);
|
||||||
|
auto document = documentPtr.get();
|
||||||
|
engine->requireAssets().store(std::move(documentPtr), alias);
|
||||||
|
|
||||||
scripting::on_ui_open(document, {args});
|
scripting::on_ui_open(document, {args});
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,11 @@
|
||||||
#error LuaJIT required
|
#error LuaJIT required
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef LUA_TCDATA
|
||||||
|
// unsafe, use for filtering only
|
||||||
|
#define LUA_TCDATA 10
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace lua {
|
namespace lua {
|
||||||
class luaerror : public std::runtime_error {
|
class luaerror : public std::runtime_error {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,12 @@
|
||||||
#include "usertypes/lua_type_pcmstream.hpp"
|
#include "usertypes/lua_type_pcmstream.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
|
|
||||||
static debug::Logger logger("lua-state");
|
namespace {
|
||||||
static lua::State* main_thread = nullptr;
|
debug::Logger logger("lua-state");
|
||||||
|
lua::State* main_thread = nullptr;
|
||||||
|
bool headless_mode = false;
|
||||||
|
const std::unordered_map<std::string, std::string>* project_args;
|
||||||
|
}
|
||||||
|
|
||||||
using namespace lua;
|
using namespace lua;
|
||||||
|
|
||||||
|
|
@ -146,20 +150,53 @@ void lua::init_state(State* L, StateType stateType) {
|
||||||
newusertype<LuaHeightmap>(L);
|
newusertype<LuaHeightmap>(L);
|
||||||
newusertype<LuaVoxelFragment>(L);
|
newusertype<LuaVoxelFragment>(L);
|
||||||
newusertype<LuaCanvas>(L);
|
newusertype<LuaCanvas>(L);
|
||||||
|
|
||||||
|
pushboolean(L, headless_mode);
|
||||||
|
setglobal(L, "__VC_HEADLESS");
|
||||||
|
|
||||||
|
createtable(L, 0, project_args->size());
|
||||||
|
for (const auto& [key, value] : *project_args) {
|
||||||
|
pushstring(L, value);
|
||||||
|
setfield(L, key);
|
||||||
|
}
|
||||||
|
setglobal(L, "__VC_PROJECT_ARGS");
|
||||||
|
|
||||||
|
auto file = "res:scripts/stdmin.lua";
|
||||||
|
auto src = io::read_string(file);
|
||||||
|
lua::pop(L, lua::execute(L, 0, src, "core:scripts/stdmin.lua"));
|
||||||
|
|
||||||
|
newusertype<LuaRandom>(L);
|
||||||
|
if (getglobal(L, "random")) {
|
||||||
|
if (getglobal(L, "__vc_Random")) {
|
||||||
|
setfield(L, "Random");
|
||||||
|
}
|
||||||
|
pop(L);
|
||||||
|
}
|
||||||
|
newusertype<LuaPCMStream>(L);
|
||||||
|
if (getglobal(L, "audio")) {
|
||||||
|
if (getglobal(L, "__vc_PCMStream")) {
|
||||||
|
setfield(L, "PCMStream");
|
||||||
|
}
|
||||||
|
pop(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateType == StateType::GENERATOR) {
|
||||||
|
pushnil(L);
|
||||||
|
setglobal(L, "ffi");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua::initialize(const EnginePaths& paths, const CoreParameters& params) {
|
void lua::initialize(const EnginePaths& paths, const CoreParameters& params) {
|
||||||
logger.info() << LUA_VERSION;
|
logger.info() << LUA_VERSION;
|
||||||
logger.info() << LUAJIT_VERSION;
|
logger.info() << LUAJIT_VERSION;
|
||||||
|
|
||||||
|
headless_mode = params.headless;
|
||||||
|
project_args = ¶ms.projectArgs;
|
||||||
main_thread = create_state(
|
main_thread = create_state(
|
||||||
paths, params.headless ? StateType::SCRIPT : StateType::BASE
|
paths, params.headless ? StateType::SCRIPT : StateType::BASE
|
||||||
);
|
);
|
||||||
lua::pushstring(main_thread, params.scriptFile.stem().u8string());
|
lua::pushstring(main_thread, params.scriptFile.stem().u8string());
|
||||||
lua::setglobal(main_thread, "__VC_SCRIPT_NAME");
|
lua::setglobal(main_thread, "__VC_SCRIPT_NAME");
|
||||||
|
|
||||||
lua::pushboolean(main_thread, params.headless);
|
|
||||||
lua::setglobal(main_thread, "__VC_HEADLESS");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua::finalize() {
|
void lua::finalize() {
|
||||||
|
|
@ -191,29 +228,5 @@ State* lua::create_state(const EnginePaths& paths, StateType stateType) {
|
||||||
throw luaerror("could not initialize Lua state");
|
throw luaerror("could not initialize Lua state");
|
||||||
}
|
}
|
||||||
init_state(L, stateType);
|
init_state(L, stateType);
|
||||||
|
|
||||||
auto file = "res:scripts/stdmin.lua";
|
|
||||||
auto src = io::read_string(file);
|
|
||||||
lua::pop(L, lua::execute(L, 0, src, "core:scripts/stdmin.lua"));
|
|
||||||
|
|
||||||
newusertype<LuaRandom>(L);
|
|
||||||
if (getglobal(L, "random")) {
|
|
||||||
if (getglobal(L, "__vc_Random")) {
|
|
||||||
setfield(L, "Random");
|
|
||||||
}
|
|
||||||
pop(L);
|
|
||||||
}
|
|
||||||
newusertype<LuaPCMStream>(L);
|
|
||||||
if (getglobal(L, "audio")) {
|
|
||||||
if (getglobal(L, "__vc_PCMStream")) {
|
|
||||||
setfield(L, "PCMStream");
|
|
||||||
}
|
|
||||||
pop(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stateType == StateType::GENERATOR) {
|
|
||||||
pushnil(L);
|
|
||||||
setglobal(L, "ffi");
|
|
||||||
}
|
|
||||||
return L;
|
return L;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
|
#include "engine/Engine.hpp"
|
||||||
|
#include "debug/Logger.hpp"
|
||||||
|
|
||||||
using namespace lua;
|
using namespace lua;
|
||||||
|
|
||||||
|
|
@ -12,6 +14,8 @@ static int next_environment = 1;
|
||||||
|
|
||||||
std::unordered_map<std::type_index, std::string> lua::usertypeNames;
|
std::unordered_map<std::type_index, std::string> lua::usertypeNames;
|
||||||
|
|
||||||
|
static debug::Logger logger("lua-util");
|
||||||
|
|
||||||
int lua::userdata_destructor(lua::State* L) {
|
int lua::userdata_destructor(lua::State* L) {
|
||||||
if (auto obj = touserdata<Userdata>(L, 1)) {
|
if (auto obj = touserdata<Userdata>(L, 1)) {
|
||||||
obj->~Userdata();
|
obj->~Userdata();
|
||||||
|
|
@ -369,3 +373,55 @@ void lua::remove_environment(State* L, int id) {
|
||||||
pushnil(L);
|
pushnil(L);
|
||||||
store_env(L, id);
|
store_env(L, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline std::string_view bytearray_as_string_indirect(lua::State* L, int idx) {
|
||||||
|
requireglobal(L, "Bytearray_as_string");
|
||||||
|
pushvalue(L, -2);
|
||||||
|
call(L, 1, 1);
|
||||||
|
auto view = tolstring(L, -1);
|
||||||
|
pop(L, 2);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view lua::bytearray_as_string(lua::State* L, int idx) {
|
||||||
|
const auto& settings = scripting::engine->getSettings();
|
||||||
|
|
||||||
|
int luaType = type(L, idx);
|
||||||
|
if (luaType == LUA_TSTRING) {
|
||||||
|
return tolstring(L, idx);
|
||||||
|
} else if (luaType == LUA_TTABLE) {
|
||||||
|
return bytearray_as_string_indirect(L, idx);
|
||||||
|
}
|
||||||
|
pushvalue(L, idx);
|
||||||
|
|
||||||
|
if (settings.system.directScriptingDataAccess.get()) {
|
||||||
|
requireglobal(L, "Bytearray_as_ptr");
|
||||||
|
pushvalue(L, -2);
|
||||||
|
call(L, 1, 2);
|
||||||
|
auto view = tolstring(L, -2);
|
||||||
|
if (view == "0") {
|
||||||
|
if (luaType == LUA_TCDATA) {
|
||||||
|
logger.error() << "FFI-based Bytearray_as_ptr returned null-pointer";
|
||||||
|
}
|
||||||
|
pop(L, 2);
|
||||||
|
return bytearray_as_string_indirect(L, idx);
|
||||||
|
}
|
||||||
|
uint64_t size = touinteger(L, -1);
|
||||||
|
auto ptr = (const char*)std::stoull(std::string(view), nullptr, 16);
|
||||||
|
pop(L, 3);
|
||||||
|
return std::string_view(ptr, size);
|
||||||
|
} else {
|
||||||
|
return bytearray_as_string_indirect(L, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lua::loadbuffer(
|
||||||
|
lua::State* L, int env, const std::string& src, const std::string& file
|
||||||
|
) {
|
||||||
|
if (luaL_loadbuffer(L, src.c_str(), src.length(), file.c_str())) {
|
||||||
|
throw luaerror(tostring(L, -1));
|
||||||
|
}
|
||||||
|
if (env && getregistry(L, ENVS_TABLE, env_name(env))) {
|
||||||
|
lua_setfenv(L, -2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -555,16 +555,9 @@ namespace lua {
|
||||||
return lua_setfenv(L, idx);
|
return lua_setfenv(L, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void loadbuffer(
|
void loadbuffer(
|
||||||
lua::State* L, int env, const std::string& src, const std::string& file
|
lua::State* L, int env, const std::string& src, const std::string& file
|
||||||
) {
|
);
|
||||||
if (luaL_loadbuffer(L, src.c_str(), src.length(), file.c_str())) {
|
|
||||||
throw luaerror(tostring(L, -1));
|
|
||||||
}
|
|
||||||
if (env && getregistry(L, ENVS_TABLE, env_name(env))) {
|
|
||||||
lua_setfenv(L, -2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void store_in(
|
inline void store_in(
|
||||||
lua::State* L, const std::string& tableName, const std::string& name
|
lua::State* L, const std::string& tableName, const std::string& name
|
||||||
|
|
@ -828,16 +821,5 @@ namespace lua {
|
||||||
return create_bytearray(L, bytes.data(), bytes.size());
|
return create_bytearray(L, bytes.data(), bytes.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string_view bytearray_as_string(lua::State* L, int idx) {
|
std::string_view bytearray_as_string(lua::State* L, int idx);
|
||||||
if (type(L, idx) == LUA_TSTRING) {
|
|
||||||
return tolstring(L, idx);
|
|
||||||
}
|
|
||||||
pushvalue(L, idx);
|
|
||||||
requireglobal(L, "Bytearray_as_string");
|
|
||||||
pushvalue(L, -2);
|
|
||||||
call(L, 1, 1);
|
|
||||||
auto view = tolstring(L, -1);
|
|
||||||
pop(L, 2);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ std::unique_ptr<IClientProjectScript> scripting::load_client_project_script(
|
||||||
auto source = io::read_string(script);
|
auto source = io::read_string(script);
|
||||||
auto env = create_environment(nullptr);
|
auto env = create_environment(nullptr);
|
||||||
lua::pushenv(L, *env);
|
lua::pushenv(L, *env);
|
||||||
if (lua::getglobal(L, "__vc_app")) {
|
if (lua::getregistry(L, "app")) {
|
||||||
lua::setfield(L, "app");
|
lua::setfield(L, "app");
|
||||||
}
|
}
|
||||||
lua::pop(L);
|
lua::pop(L);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
struct AudioSettings {
|
struct AudioSettings {
|
||||||
/// @brief try to initialize AL backend
|
/// @brief try to initialize AL backend
|
||||||
FlagSetting enabled {true};
|
FlagSetting enabled {true};
|
||||||
|
FlagSetting recordingEnabled {false};
|
||||||
|
|
||||||
NumberSetting volumeMaster {1.0f, 0.0f, 1.0f, setting_format::percent};
|
NumberSetting volumeMaster {1.0f, 0.0f, 1.0f, setting_format::percent};
|
||||||
NumberSetting volumeRegular {1.0f, 0.0f, 1.0f, setting_format::percent};
|
NumberSetting volumeRegular {1.0f, 0.0f, 1.0f, setting_format::percent};
|
||||||
|
|
@ -126,6 +127,8 @@ struct SystemSettings {
|
||||||
IntegerSetting maxBgAssetLoaders {3, -4, 16};
|
IntegerSetting maxBgAssetLoaders {3, -4, 16};
|
||||||
/// @brief Preserve assets during current frame from being destroyed
|
/// @brief Preserve assets during current frame from being destroyed
|
||||||
FlagSetting preserveAssetsDuringFrame {true};
|
FlagSetting preserveAssetsDuringFrame {true};
|
||||||
|
/// @brief Allow luajit cdata objects direct data access optimizations
|
||||||
|
FlagSetting directScriptingDataAccess {true};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EngineSettings {
|
struct EngineSettings {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,13 @@ namespace util {
|
||||||
return last[0] == '-';
|
return last[0] == '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isNextKeywordArg() const {
|
||||||
|
if (pos >= argc) {
|
||||||
|
throw std::runtime_error("unexpected end");
|
||||||
|
}
|
||||||
|
return argv[pos][0] == '-';
|
||||||
|
}
|
||||||
|
|
||||||
std::string next() {
|
std::string next() {
|
||||||
if (pos >= argc) {
|
if (pos >= argc) {
|
||||||
throw std::runtime_error("unexpected end");
|
throw std::runtime_error("unexpected end");
|
||||||
|
|
|
||||||
|
|
@ -97,11 +97,32 @@ static bool perform_keyword(
|
||||||
throw std::runtime_error("unknown argument " + keyword);
|
throw std::runtime_error("unknown argument " + keyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void parse_project_args(util::ArgsReader& reader, CoreParameters& params) {
|
||||||
|
while (reader.hasNext()) {
|
||||||
|
std::string key = reader.next();
|
||||||
|
if (!reader.isKeywordArg()) {
|
||||||
|
std::cerr << "--<keyword> argument expected" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
key = key.substr(2);
|
||||||
|
if (!reader.hasNext() || reader.isNextKeywordArg()) {
|
||||||
|
params.projectArgs[std::move(key)] = "";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string value = reader.next();
|
||||||
|
params.projectArgs[std::move(key)] = std::move(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool parse_cmdline(int argc, char** argv, CoreParameters& params) {
|
bool parse_cmdline(int argc, char** argv, CoreParameters& params) {
|
||||||
util::ArgsReader reader(argc, argv);
|
util::ArgsReader reader(argc, argv);
|
||||||
reader.skip();
|
reader.skip();
|
||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
std::string token = reader.next();
|
std::string token = reader.next();
|
||||||
|
if (token == "--") {
|
||||||
|
parse_project_args(reader, params);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (reader.isKeywordArg()) {
|
if (reader.isKeywordArg()) {
|
||||||
if (!perform_keyword(reader, token, params)) {
|
if (!perform_keyword(reader, token, params)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue