mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-14 07:21:51 +00:00
commit
c4d5812b4f
46 changed files with 754 additions and 342 deletions
2
.github/workflows/windows-clang.yml
vendored
2
.github/workflows/windows-clang.yml
vendored
|
|
@ -4,7 +4,7 @@ on:
|
||||||
push:
|
push:
|
||||||
branches: [ "main", "release-**"]
|
branches: [ "main", "release-**"]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "main", "dev" ]
|
branches: [ "main", "dev" ]
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
build_name:
|
build_name:
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,14 @@ gfx.text3d.set_rotation(id: int, rotation: mat4)
|
||||||
|
|
||||||
Sets the text rotation (Sets the rotated vectors X,Y).
|
Sets the text rotation (Sets the rotated vectors X,Y).
|
||||||
|
|
||||||
|
```lua
|
||||||
|
gfx.text3d.get_entity(id: int) -> int
|
||||||
|
gfx.text3d.set_entity(id: int, entity: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Getter and setter for the entity to which the 3D text position is bound.
|
||||||
|
The position set via `gfx.text3d.set_pos` is then relative to the entity's position.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
gfx.text3d.update_settings(id: int, preset: table)
|
gfx.text3d.update_settings(id: int, preset: table)
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
# Documentation
|
# Documentation
|
||||||
|
|
||||||
Documentation for 0.31.
|
> [!WARNING]
|
||||||
|
> Version is in development. Proceed to [Documentation for 0.31.](https://github.com/MihailRis/voxelcore/blob/release-0.31/doc/en/main-page.md)
|
||||||
|
|
||||||
## Sections
|
## Sections
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ gfx.posteffects.set_array(
|
||||||
slot: int,
|
slot: int,
|
||||||
-- parameter (array) name
|
-- parameter (array) name
|
||||||
name: str
|
name: str
|
||||||
-- data string (use Bytearray_as_string function)
|
-- data
|
||||||
data: str
|
data: Bytearray
|
||||||
)
|
)
|
||||||
|
|
||||||
-- Example of filling an array `#param vec3 u_arrayName[64]`:
|
-- Example of filling an array `#param vec3 u_arrayName[64]`:
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,10 @@ rig:get_color() -> vec3
|
||||||
rig:set_color(color: vec3)
|
rig:set_color(color: vec3)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> When an entity moves outside the loaded area, it is removed, triggering the event.
|
||||||
|
> When it re-enters the loaded area, the entity is spawned again.
|
||||||
|
|
||||||
## Component events
|
## Component events
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,17 @@ function on_block_interact(blockid, x, y, z, playerid) -> bool
|
||||||
|
|
||||||
Called on block RMB click interaction. Prevents block placing if **true** returned.
|
Called on block RMB click interaction. Prevents block placing if **true** returned.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_entity_spawn(uid)
|
||||||
|
```
|
||||||
|
Called after an entity is spawned.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_entity_despawn(uid)
|
||||||
|
```
|
||||||
|
|
||||||
|
Called before an entity is despawned.
|
||||||
|
|
||||||
### Chunk Events (world.lua)
|
### Chunk Events (world.lua)
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
|
@ -198,11 +209,26 @@ function on_close(invid: int)
|
||||||
|
|
||||||
Called on element removed from the screen.
|
Called on element removed from the screen.
|
||||||
|
|
||||||
|
## Content events
|
||||||
|
|
||||||
|
Callbacks specified in *content.lua* script.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_scripts_loading()
|
||||||
|
```
|
||||||
|
|
||||||
|
Called before the content pack scripts are loaded
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_content_loaded()
|
||||||
|
```
|
||||||
|
|
||||||
|
Called after the content pack has been fully loaded
|
||||||
|
|
||||||
## HUD events
|
## HUD events
|
||||||
|
|
||||||
Callbacks specified in *hud.lua* script.
|
Callbacks specified in *hud.lua* script.
|
||||||
|
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function on_hud_open(playerid: int)
|
function on_hud_open(playerid: int)
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,14 @@ gfx.text3d.set_rotation(id: int, rotation: mat4)
|
||||||
|
|
||||||
Устанавливает вращение текста (Устанавливает повернутые вектора X,Y).
|
Устанавливает вращение текста (Устанавливает повернутые вектора X,Y).
|
||||||
|
|
||||||
|
```lua
|
||||||
|
gfx.text3d.get_entity(id: int) -> int
|
||||||
|
gfx.text3d.set_entity(id: int, entity: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Геттер и сеттер сущности, к позиции которой привязан 3D текст.
|
||||||
|
Позиция, устанавливаемая через `gfx.text3d.set_pos`, в таком случае, относительна позиции сущности.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
gfx.text3d.update_settings(id: int, preset: table)
|
gfx.text3d.update_settings(id: int, preset: table)
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
# Документация
|
# Документация
|
||||||
|
|
||||||
Документация версии 0.31.
|
> [!WARNING]
|
||||||
|
> Версия находится в разработке. Перейдите к [документации для 0.31.](https://github.com/MihailRis/voxelcore/blob/release-0.31/doc/ru/main-page.md)
|
||||||
|
|
||||||
## Разделы
|
## Разделы
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ gfx.posteffects.set_array(
|
||||||
slot: int,
|
slot: int,
|
||||||
-- имя параметра (массива)
|
-- имя параметра (массива)
|
||||||
name: string
|
name: string
|
||||||
-- строка данных (используйте функцию Bytearray_as_string)
|
-- данные
|
||||||
data: string
|
data: Bytearray
|
||||||
)
|
)
|
||||||
|
|
||||||
-- Пример заполнения массива `#param vec3 u_имяМассива[64]`:
|
-- Пример заполнения массива `#param vec3 u_имяМассива[64]`:
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,10 @@ rig:get_color() -> vec3
|
||||||
rig:set_color(color: vec3)
|
rig:set_color(color: vec3)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> При выходе сущности за пределы зоны прогрузки она удаляется, вызывая события.
|
||||||
|
> При повторном попадании в зону прогрузки сущность спавнится заново.
|
||||||
|
|
||||||
## События компонента
|
## События компонента
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
- [События предметов](#события-предметов)
|
- [События предметов](#события-предметов)
|
||||||
- [События мира](#события-мира)
|
- [События мира](#события-мира)
|
||||||
- [События макета](#события-макета)
|
- [События макета](#события-макета)
|
||||||
|
- [События контента](#события-контента)
|
||||||
- [События HUD](#события-hud)
|
- [События HUD](#события-hud)
|
||||||
- [События ECS](ecs.md#события-компонента)
|
- [События ECS](ecs.md#события-компонента)
|
||||||
- [Библиотека *Events*](#библиотека-events)
|
- [Библиотека *Events*](#библиотека-events)
|
||||||
|
|
@ -155,6 +156,18 @@ function on_block_interact(blockid, x, y, z, playerid) -> bool
|
||||||
|
|
||||||
Вызывается при нажатии на блок ПКМ. Предотвращает установку блоков, если возвращает `true`
|
Вызывается при нажатии на блок ПКМ. Предотвращает установку блоков, если возвращает `true`
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_entity_spawn(uid)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается после спавна сущности
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_entity_despawn(uid)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается перед удалением сущности
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function on_player_tick(playerid: int, tps: int)
|
function on_player_tick(playerid: int, tps: int)
|
||||||
```
|
```
|
||||||
|
|
@ -189,7 +202,6 @@ function on_inventory_closed(invid: int, playerid: int)
|
||||||
|
|
||||||
Вызывается при закрытии инвентаря.
|
Вызывается при закрытии инвентаря.
|
||||||
|
|
||||||
|
|
||||||
## События макета
|
## События макета
|
||||||
|
|
||||||
События прописываются в файле `layouts/имя_макета.xml.lua`.
|
События прописываются в файле `layouts/имя_макета.xml.lua`.
|
||||||
|
|
@ -208,6 +220,22 @@ function on_close(invid: int)
|
||||||
|
|
||||||
Вызывается при удалении элемента с экрана.
|
Вызывается при удалении элемента с экрана.
|
||||||
|
|
||||||
|
## События контента
|
||||||
|
|
||||||
|
События жизненного цикла контент-пака прописываются в файле `scripts/content.lua`
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_scripts_loading()
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается перед загрузкой скриптов контент-пака
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_content_loaded()
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается после того, как контент-пак был полностью загружен
|
||||||
|
|
||||||
## События HUD
|
## События HUD
|
||||||
|
|
||||||
События связанные с игровым интерфейсом прописываются в файле `scripts/hud.lua`
|
События связанные с игровым интерфейсом прописываются в файле `scripts/hud.lua`
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"id": "base",
|
"id": "base",
|
||||||
"title": "Base",
|
"title": "Base",
|
||||||
"version": "0.31",
|
"version": "0.32",
|
||||||
"description": "basic content package"
|
"description": "basic content package"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ local tsf = entity.transform
|
||||||
local body = entity.rigidbody
|
local body = entity.rigidbody
|
||||||
local rig = entity.skeleton
|
local rig = entity.skeleton
|
||||||
|
|
||||||
inair = true
|
|
||||||
target = -1
|
target = -1
|
||||||
timer = 0.3
|
timer = 0.3
|
||||||
|
|
||||||
|
|
@ -20,40 +19,58 @@ if SAVED_DATA.item then
|
||||||
dropitem.data = SAVED_DATA.data
|
dropitem.data = SAVED_DATA.data
|
||||||
end
|
end
|
||||||
|
|
||||||
local DROP_SCALE = 0.3
|
|
||||||
local scale = {1, 1, 1}
|
|
||||||
local rotation = mat4.rotate({
|
|
||||||
math.random(), math.random(), math.random()
|
|
||||||
}, 360)
|
|
||||||
|
|
||||||
function on_save()
|
function on_save()
|
||||||
SAVED_DATA.item = item.name(dropitem.id)
|
SAVED_DATA.item = item.name(dropitem.id)
|
||||||
SAVED_DATA.count = dropitem.count
|
SAVED_DATA.count = dropitem.count
|
||||||
SAVED_DATA.data = dropitem.data
|
SAVED_DATA.data = dropitem.data
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- setup visuals
|
if vc.is_client() then
|
||||||
local matrix = mat4.idt()
|
local scale = {1, 1, 1}
|
||||||
rig:set_model(0, item.model_name(dropitem.id))
|
local rotation = mat4.rotate({
|
||||||
local bodysize = math.min(scale[1], scale[2], scale[3]) * DROP_SCALE
|
math.random(), math.random(), math.random()
|
||||||
body:set_size({scale[1] * DROP_SCALE, bodysize, scale[3] * DROP_SCALE})
|
}, 360)
|
||||||
mat4.mul(matrix, rotation, matrix)
|
|
||||||
mat4.scale(matrix, scale, matrix)
|
do
|
||||||
rig:set_matrix(0, matrix)
|
local matrix = mat4.idt()
|
||||||
|
rig:set_model(0, item.model_name(dropitem.id))
|
||||||
|
local bodysize = math.min(scale[1], scale[2], scale[3])
|
||||||
|
body:set_size({scale[1], bodysize, scale[3]})
|
||||||
|
mat4.mul(matrix, rotation, matrix)
|
||||||
|
mat4.scale(matrix, scale, matrix)
|
||||||
|
rig:set_matrix(0, matrix)
|
||||||
|
end
|
||||||
|
|
||||||
|
local inair = true
|
||||||
|
|
||||||
|
function on_grounded()
|
||||||
|
local matrix = mat4.idt()
|
||||||
|
mat4.rotate(matrix, {0, 1, 0}, math.random() * 360, matrix)
|
||||||
|
mat4.rotate(matrix, {1, 0, 0}, 90, matrix)
|
||||||
|
mat4.scale(matrix, scale, matrix)
|
||||||
|
rig:set_matrix(0, matrix)
|
||||||
|
inair = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_fall()
|
||||||
|
inair = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_render()
|
||||||
|
if inair then
|
||||||
|
local dt = time.delta();
|
||||||
|
|
||||||
|
mat4.rotate(rotation, {0, 1, 0}, 240*dt, rotation)
|
||||||
|
mat4.rotate(rotation, {0, 0, 1}, 240*dt, rotation)
|
||||||
|
|
||||||
|
local matrix = mat4.idt()
|
||||||
|
mat4.mul(matrix, rotation, matrix)
|
||||||
|
mat4.scale(matrix, scale, matrix)
|
||||||
|
rig:set_matrix(0, matrix)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function on_grounded(force)
|
|
||||||
local matrix = mat4.idt()
|
|
||||||
mat4.rotate(matrix, {0, 1, 0}, math.random() * 360, matrix)
|
|
||||||
mat4.rotate(matrix, {1, 0, 0}, 90, matrix)
|
|
||||||
mat4.scale(matrix, scale, matrix)
|
|
||||||
rig:set_matrix(0, matrix)
|
|
||||||
inair = false
|
|
||||||
end
|
|
||||||
|
|
||||||
function on_fall()
|
|
||||||
inair = true
|
|
||||||
end
|
|
||||||
|
|
||||||
function on_sensor_enter(index, oid)
|
function on_sensor_enter(index, oid)
|
||||||
local other = entities.get(oid)
|
local other = entities.get(oid)
|
||||||
|
|
@ -98,20 +115,6 @@ function on_sensor_exit(index, oid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function on_render()
|
|
||||||
if inair then
|
|
||||||
local dt = time.delta();
|
|
||||||
|
|
||||||
mat4.rotate(rotation, {0, 1, 0}, 240*dt, rotation)
|
|
||||||
mat4.rotate(rotation, {0, 0, 1}, 240*dt, rotation)
|
|
||||||
|
|
||||||
local matrix = mat4.idt()
|
|
||||||
mat4.mul(matrix, rotation, matrix)
|
|
||||||
mat4.scale(matrix, scale, matrix)
|
|
||||||
rig:set_matrix(0, matrix)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function on_update(tps)
|
function on_update(tps)
|
||||||
timer = timer - 1.0/tps
|
timer = timer - 1.0/tps
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
local tsf = entity.transform
|
local tsf = entity.transform
|
||||||
local body = entity.rigidbody
|
local body = entity.rigidbody
|
||||||
local rig = entity.skeleton
|
|
||||||
|
|
||||||
local blockid = ARGS.block
|
local blockid = ARGS.block
|
||||||
local blockstates = ARGS.states or 0
|
local blockstates = ARGS.states or 0
|
||||||
|
|
@ -12,7 +11,8 @@ else
|
||||||
SAVED_DATA.states = blockstates
|
SAVED_DATA.states = blockstates
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- setup visuals
|
if vc.is_client() then-- setup visuals
|
||||||
|
local rig = entity.skeleton
|
||||||
local id = block.index(blockid)
|
local id = block.index(blockid)
|
||||||
local rotation = block.decompose_state(blockstates)[1]
|
local rotation = block.decompose_state(blockstates)[1]
|
||||||
local textures = block.get_textures(id)
|
local textures = block.get_textures(id)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
local tsf = entity.transform
|
|
||||||
local body = entity.rigidbody
|
|
||||||
local rig = entity.skeleton
|
local rig = entity.skeleton
|
||||||
local mob = entity:require_component("core:mob")
|
local mob = entity:require_component("core:mob")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,26 @@
|
||||||
|
local offsets = {}
|
||||||
|
for lx=-1,1 do
|
||||||
|
for ly=-1,1 do
|
||||||
|
for lz=-1,1 do
|
||||||
|
offsets[(lx * 3 + ly) * 3 + lz] = {lx, ly, lz}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function on_random_update(x, y, z)
|
function on_random_update(x, y, z)
|
||||||
local dirtid = block.index('base:dirt');
|
local dirtid = block.index('base:dirt');
|
||||||
if block.is_solid_at(x, y+1, z) then
|
if block.is_solid_at(x, y+1, z) then
|
||||||
block.set(x, y, z, dirtid, 0)
|
block.set(x, y, z, dirtid, 0)
|
||||||
else
|
return
|
||||||
local grassblockid = block.index('base:grass_block')
|
end
|
||||||
for lx=-1,1 do
|
local grassblockid = block.index('base:grass_block')
|
||||||
for ly=-1,1 do
|
for _, offset in ipairs(offsets) do
|
||||||
for lz=-1,1 do
|
local nx, ny, nz = x + offset[1], y + offset[2], z + offset[3]
|
||||||
if block.get(x + lx, y + ly, z + lz) == dirtid then
|
|
||||||
if not block.is_solid_at(x + lx, y + ly + 1, z + lz) then
|
if block.get(nx, ny, nz) == dirtid and
|
||||||
block.set(x + lx, y + ly, z + lz, grassblockid, 0)
|
not block.is_solid_at(nx, ny + 1, nz) then
|
||||||
return
|
block.set(nx, ny, nz, grassblockid, 0)
|
||||||
end
|
return
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
function on_block_broken(id, x, y, z, playerid)
|
function on_block_broken(id, x, y, z, playerid)
|
||||||
if gfx then
|
if vc.is_client() then
|
||||||
local size = {block.get_size(id)}
|
local size = {block.get_size(id)}
|
||||||
gfx.particles.emit({
|
gfx.particles.emit({
|
||||||
x + size[1] * 0.5,
|
x + size[1] * 0.5,
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ function gui_util.parse_query(query)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param query string page query string
|
--- @param query string page query string
|
||||||
function gui_util.load_page(query)
|
function gui_util.load_page(app, query)
|
||||||
local name, args = gui_util.parse_query(query)
|
local name, args = gui_util.parse_query(query)
|
||||||
for i = #gui_util.local_dispatchers, 1, -1 do
|
for i = #gui_util.local_dispatchers, 1, -1 do
|
||||||
local newname, newargs = gui_util.local_dispatchers[i](name, args)
|
local newname, newargs = gui_util.local_dispatchers[i](name, args)
|
||||||
|
|
@ -34,7 +34,7 @@ function gui_util.load_page(query)
|
||||||
local filename = file.find(string.format("layouts/pages/%s.xml", name))
|
local filename = file.find(string.format("layouts/pages/%s.xml", name))
|
||||||
if filename then
|
if filename then
|
||||||
name = file.prefix(filename)..":pages/"..name
|
name = file.prefix(filename)..":pages/"..name
|
||||||
gui.load_document(filename, name, args, { app = __vc_app })
|
gui.load_document(filename, name, args, { app = app })
|
||||||
return name
|
return name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,10 @@
|
||||||
"gui/hud",
|
"gui/hud",
|
||||||
"gui/entity",
|
"gui/entity",
|
||||||
"gui/half_block",
|
"gui/half_block",
|
||||||
"misc/blank"
|
{
|
||||||
|
"name": "",
|
||||||
|
"path": "textures/misc/blank"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"fonts": [
|
"fonts": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ function on_physics_update(delta)
|
||||||
local front = mat4.mul(rot, {0, 0, -1})
|
local front = mat4.mul(rot, {0, 0, -1})
|
||||||
local pos = tsf:get_pos()
|
local pos = tsf:get_pos()
|
||||||
|
|
||||||
if hud and pid == hud.get_player() then
|
if vc.is_client() and pid == hud.get_player() then
|
||||||
process_player_inputs(pid, rot, delta)
|
process_player_inputs(pid, rot, delta)
|
||||||
end
|
end
|
||||||
mob.look_at(vec3.add(pos, front))
|
mob.look_at(vec3.add(pos, front))
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,3 @@
|
||||||
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(__vc_app.get_setting("graphics.ssao"))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function update_hand()
|
local function update_hand()
|
||||||
local skeleton = gfx.skeletons
|
local skeleton = gfx.skeletons
|
||||||
local pid = hud.get_player()
|
local pid = hud.get_player()
|
||||||
|
|
@ -123,8 +89,6 @@ function on_hud_open()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
configure_SSAO()
|
|
||||||
|
|
||||||
hud.default_hand_controller = update_hand
|
hud.default_hand_controller = update_hand
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
local enable_experimental = __vc_app.get_setting("debug.enable-experimental")
|
local __app = __vc_app
|
||||||
|
local enable_experimental = __app.get_setting("debug.enable-experimental")
|
||||||
|
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
------ Extended kit of standard functions ------
|
------ Extended kit of standard functions ------
|
||||||
|
|
@ -119,12 +120,7 @@ local function complete_app_lib(app)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if app then
|
complete_app_lib(__app)
|
||||||
complete_app_lib(app)
|
|
||||||
elseif __vc_app then
|
|
||||||
complete_app_lib(__vc_app)
|
|
||||||
end
|
|
||||||
|
|
||||||
require "core:internal/maths_inline"
|
require "core:internal/maths_inline"
|
||||||
require "core:internal/debugging"
|
require "core:internal/debugging"
|
||||||
require "core:internal/audio_input"
|
require "core:internal/audio_input"
|
||||||
|
|
@ -175,18 +171,18 @@ function start_coroutine(chunk, name)
|
||||||
local co = coroutine.create(function()
|
local co = coroutine.create(function()
|
||||||
local status, error = xpcall(chunk, function(err)
|
local status, error = xpcall(chunk, function(err)
|
||||||
local fullmsg = "error: "..string.match(err, ": (.+)").."\n"..debug.traceback()
|
local fullmsg = "error: "..string.match(err, ": (.+)").."\n"..debug.traceback()
|
||||||
|
if vc.is_headless() then
|
||||||
if hud then
|
return fullmsg
|
||||||
gui.alert(fullmsg, function()
|
|
||||||
if world.is_open() then
|
|
||||||
__vc_app.close_world()
|
|
||||||
else
|
|
||||||
__vc_app.reset_content()
|
|
||||||
menu:reset()
|
|
||||||
menu.page = "main"
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
|
gui.alert(fullmsg, function()
|
||||||
|
if world.is_open() then
|
||||||
|
__app.close_world()
|
||||||
|
else
|
||||||
|
__app.reset_content()
|
||||||
|
menu:reset()
|
||||||
|
menu.page = "main"
|
||||||
|
end
|
||||||
|
end)
|
||||||
return fullmsg
|
return fullmsg
|
||||||
end)
|
end)
|
||||||
if not status then
|
if not status then
|
||||||
|
|
@ -204,7 +200,7 @@ function __vc_start_app_script(path, name)
|
||||||
if chunk == nil then
|
if chunk == nil then
|
||||||
error(err)
|
error(err)
|
||||||
end
|
end
|
||||||
local script_env = setmetatable({app = app or __vc_app}, {__index=_G})
|
local script_env = setmetatable({app = __app}, {__index=_G})
|
||||||
chunk = setfenv(chunk, script_env)
|
chunk = setfenv(chunk, script_env)
|
||||||
if name then
|
if name then
|
||||||
start_coroutine(chunk, name)
|
start_coroutine(chunk, name)
|
||||||
|
|
@ -222,7 +218,7 @@ gui_util = require "core:internal/gui_util"
|
||||||
Document = gui_util.Document
|
Document = gui_util.Document
|
||||||
Element = gui_util.Element
|
Element = gui_util.Element
|
||||||
RadioGroup = gui_util.RadioGroup
|
RadioGroup = gui_util.RadioGroup
|
||||||
__vc_page_loader = gui_util.load_page
|
__vc_page_loader = function(...) return gui_util.load_page(__app, ...) end
|
||||||
|
|
||||||
function __vc_get_document_node(docname, nodeid)
|
function __vc_get_document_node(docname, nodeid)
|
||||||
return Element.new(docname, nodeid)
|
return Element.new(docname, nodeid)
|
||||||
|
|
@ -384,6 +380,40 @@ math.randomseed(time.uptime() * 1536227939)
|
||||||
rules = require "core:internal/rules"
|
rules = require "core:internal/rules"
|
||||||
local _rules = 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()
|
function __vc_on_hud_open()
|
||||||
local _hud_is_content_access = hud._is_content_access
|
local _hud_is_content_access = hud._is_content_access
|
||||||
local _hud_set_content_access = hud._set_content_access
|
local _hud_set_content_access = hud._set_content_access
|
||||||
|
|
@ -446,6 +476,8 @@ function __vc_on_hud_open()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
hud.open_permanent("core:ingame_chat")
|
hud.open_permanent("core:ingame_chat")
|
||||||
|
|
||||||
|
configure_SSAO()
|
||||||
end
|
end
|
||||||
|
|
||||||
local Schedule = require "core:schedule"
|
local Schedule = require "core:schedule"
|
||||||
|
|
@ -508,20 +540,27 @@ function __vc_on_world_save()
|
||||||
file.write(RULES_FILE, toml.tostring(rule_values))
|
file.write(RULES_FILE, toml.tostring(rule_values))
|
||||||
end
|
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()
|
function __vc_on_world_quit()
|
||||||
_rules.clear()
|
_rules.clear()
|
||||||
gui_util:__reset_local()
|
__gui_util_reset_local()
|
||||||
stdcomp.__reset()
|
__stdcomp_reset()
|
||||||
file.__close_all_descriptors()
|
__close_all_descriptors()
|
||||||
end
|
end
|
||||||
|
|
||||||
local __post_runnables = {}
|
|
||||||
|
|
||||||
local fn_audio_reset_fetch_buffer = audio.__reset_fetch_buffer
|
local fn_audio_reset_fetch_buffer = audio.__reset_fetch_buffer
|
||||||
audio.__reset_fetch_buffer = nil
|
audio.__reset_fetch_buffer = nil
|
||||||
core.get_core_token = audio.input.__get_core_token
|
core.get_core_token = audio.input.__get_core_token
|
||||||
|
|
||||||
local function __vc__process_post_runnables()
|
local __post_runnables = {}
|
||||||
|
|
||||||
|
local function __process_post_runnables()
|
||||||
if #__post_runnables > 0 then
|
if #__post_runnables > 0 then
|
||||||
for _, func in ipairs(__post_runnables) do
|
for _, func in ipairs(__post_runnables) do
|
||||||
local status, result = xpcall(func, __vc__error)
|
local status, result = xpcall(func, __vc__error)
|
||||||
|
|
@ -555,9 +594,9 @@ local function __vc__process_post_runnables()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function __process_post_runnables()
|
function __vc__process_post_runnables()
|
||||||
__vc__is_post_runnable = true
|
__vc__is_post_runnable = true
|
||||||
local success, err = pcall(__vc__process_post_runnables)
|
local success, err = pcall(__process_post_runnables)
|
||||||
if not success then
|
if not success then
|
||||||
debug.error("an error ocurred while processing post-runnables: ".. err)
|
debug.error("an error ocurred while processing post-runnables: ".. err)
|
||||||
end
|
end
|
||||||
|
|
@ -590,4 +629,6 @@ end
|
||||||
require "core:internal/deprecated"
|
require "core:internal/deprecated"
|
||||||
|
|
||||||
ffi = nil
|
ffi = nil
|
||||||
|
__vc_app = nil
|
||||||
__vc_lock_internal_modules()
|
__vc_lock_internal_modules()
|
||||||
|
__vc_lock_internal_modules = nil
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,17 @@
|
||||||
|
local _vc_headless = __VC_HEADLESS
|
||||||
|
__VC_HEADLESS = nil
|
||||||
|
|
||||||
|
vc = {
|
||||||
|
is_headless = function()
|
||||||
|
return _vc_headless
|
||||||
|
end,
|
||||||
|
is_client = function ()
|
||||||
|
return not _vc_headless
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
local _ffi = ffi
|
local _ffi = ffi
|
||||||
local _debug_getinfo = debug.getinfo
|
local _crc32 = crc32
|
||||||
|
|
||||||
function crc32(bytes, chksum)
|
function crc32(bytes, chksum)
|
||||||
chksum = chksum or 0
|
chksum = chksum or 0
|
||||||
|
|
@ -103,6 +115,8 @@ end
|
||||||
|
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
|
local _debug_getinfo = debug.getinfo
|
||||||
|
|
||||||
function debug.count_frames()
|
function debug.count_frames()
|
||||||
local frames = 1
|
local frames = 1
|
||||||
while true do
|
while true do
|
||||||
|
|
@ -178,7 +192,7 @@ function reload_module(name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local internal_locked = false
|
local __internal_locked = false
|
||||||
|
|
||||||
-- Load script with caching
|
-- Load script with caching
|
||||||
--
|
--
|
||||||
|
|
@ -188,9 +202,12 @@ local internal_locked = false
|
||||||
-- nocache - ignore cached script, load anyway
|
-- nocache - ignore cached script, load anyway
|
||||||
function __load_script(path, nocache, env)
|
function __load_script(path, nocache, env)
|
||||||
local packname, filename = parse_path(path)
|
local packname, filename = parse_path(path)
|
||||||
|
local is_internal = (packname == "res" or packname == "core")
|
||||||
|
and filename:find("modules/internal") == 1
|
||||||
|
|
||||||
if internal_locked and (packname == "res" or packname == "core")
|
nocache = nocache or is_internal
|
||||||
and filename:starts_with("modules/internal") then
|
|
||||||
|
if is_internal and __internal_locked then
|
||||||
error("access to core:internal modules outside of [core]")
|
error("access to core:internal modules outside of [core]")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -218,16 +235,19 @@ function __load_script(path, nocache, env)
|
||||||
end
|
end
|
||||||
|
|
||||||
function __vc_lock_internal_modules()
|
function __vc_lock_internal_modules()
|
||||||
internal_locked = true
|
__internal_locked = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local __pack_envs = __vc__pack_envs
|
||||||
|
__vc__pack_envs = nil
|
||||||
|
|
||||||
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)
|
||||||
return require(prefix .. ':' .. path)
|
return require(prefix .. ':' .. path)
|
||||||
end
|
end
|
||||||
local prefix, file = parse_path(path)
|
local prefix, file = parse_path(path)
|
||||||
local env = __vc__pack_envs[prefix]
|
local env = __pack_envs[prefix]
|
||||||
return __load_script(prefix .. ":modules/" .. file .. ".lua", nil, env)
|
return __load_script(prefix .. ":modules/" .. file .. ".lua", nil, env)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -248,7 +268,7 @@ function __scripts_cleanup(non_reset_packs)
|
||||||
__cached_scripts[k] = nil
|
__cached_scripts[k] = nil
|
||||||
package.loaded[k] = nil
|
package.loaded[k] = nil
|
||||||
end
|
end
|
||||||
__vc__pack_envs[packname] = nil
|
__pack_envs[packname] = nil
|
||||||
::continue::
|
::continue::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
inline constexpr int ENGINE_VERSION_MAJOR = 0;
|
inline constexpr int ENGINE_VERSION_MAJOR = 0;
|
||||||
inline constexpr int ENGINE_VERSION_MINOR = 31;
|
inline constexpr int ENGINE_VERSION_MINOR = 32;
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
inline constexpr bool ENGINE_DEBUG_BUILD = false;
|
inline constexpr bool ENGINE_DEBUG_BUILD = false;
|
||||||
|
|
@ -14,7 +14,7 @@ inline constexpr bool ENGINE_DEBUG_BUILD = false;
|
||||||
inline constexpr bool ENGINE_DEBUG_BUILD = true;
|
inline constexpr bool ENGINE_DEBUG_BUILD = true;
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
|
||||||
inline const std::string ENGINE_VERSION_STRING = "0.31";
|
inline const std::string ENGINE_VERSION_STRING = "0.32";
|
||||||
|
|
||||||
/// @brief world regions format version
|
/// @brief world regions format version
|
||||||
inline constexpr uint REGION_FORMAT_VERSION = 3;
|
inline constexpr uint REGION_FORMAT_VERSION = 3;
|
||||||
|
|
|
||||||
|
|
@ -334,6 +334,8 @@ void ContentLoader::load() {
|
||||||
|
|
||||||
fixPackIndices();
|
fixPackIndices();
|
||||||
|
|
||||||
|
loadContentScript(*runtime);
|
||||||
|
|
||||||
auto folder = pack->folder;
|
auto folder = pack->folder;
|
||||||
|
|
||||||
builder.defaults = paths.readCombinedObject(
|
builder.defaults = paths.readCombinedObject(
|
||||||
|
|
@ -462,6 +464,20 @@ void ContentLoader::reloadScript(const Content& content, ItemDef& item) {
|
||||||
load_script(content, item);
|
load_script(content, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContentLoader::loadContentScript(ContentPackRuntime& runtime) {
|
||||||
|
const auto& pack = runtime.getInfo();
|
||||||
|
const auto& folder = pack.folder;
|
||||||
|
io::path scriptFile = folder / "scripts/content.lua";
|
||||||
|
if (io::is_regular_file(scriptFile)) {
|
||||||
|
scripting::load_content_script(
|
||||||
|
runtime.getEnvironment(),
|
||||||
|
pack.id,
|
||||||
|
scriptFile,
|
||||||
|
pack.id + ":scripts/content.lua"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ContentLoader::loadWorldScript(ContentPackRuntime& runtime) {
|
void ContentLoader::loadWorldScript(ContentPackRuntime& runtime) {
|
||||||
const auto& pack = runtime.getInfo();
|
const auto& pack = runtime.getInfo();
|
||||||
const auto& folder = pack.folder;
|
const auto& folder = pack.folder;
|
||||||
|
|
@ -478,6 +494,7 @@ void ContentLoader::loadWorldScript(ContentPackRuntime& runtime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentLoader::loadScripts(Content& content) {
|
void ContentLoader::loadScripts(Content& content) {
|
||||||
|
scripting::on_scripts_loading();
|
||||||
load_scripts(content, content.blocks);
|
load_scripts(content, content.blocks);
|
||||||
load_scripts(content, content.items);
|
load_scripts(content, content.items);
|
||||||
|
|
||||||
|
|
@ -486,7 +503,6 @@ void ContentLoader::loadScripts(Content& content) {
|
||||||
const auto& pack = runtime->getInfo();
|
const auto& pack = runtime->getInfo();
|
||||||
const auto& folder = pack.folder;
|
const auto& folder = pack.folder;
|
||||||
|
|
||||||
// Load main world script
|
|
||||||
loadWorldScript(*runtime);
|
loadWorldScript(*runtime);
|
||||||
|
|
||||||
// Load entity components
|
// Load entity components
|
||||||
|
|
@ -501,6 +517,8 @@ void ContentLoader::loadScripts(Content& content) {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scripting::on_content_loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentLoader::loadResources(ResourceType type, const dv::value& list) {
|
void ContentLoader::loadResources(ResourceType type, const dv::value& list) {
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ public:
|
||||||
void load();
|
void load();
|
||||||
|
|
||||||
static void loadScripts(Content& content);
|
static void loadScripts(Content& content);
|
||||||
|
static void loadContentScript(ContentPackRuntime& pack);
|
||||||
static void loadWorldScript(ContentPackRuntime& pack);
|
static void loadWorldScript(ContentPackRuntime& pack);
|
||||||
static void reloadScript(const Content& content, Block& block);
|
static void reloadScript(const Content& content, Block& block);
|
||||||
static void reloadScript(const Content& content, ItemDef& item);
|
static void reloadScript(const Content& content, ItemDef& item);
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,6 @@ io::path ContentPack::getContentFile() const {
|
||||||
return folder / CONTENT_FILENAME;
|
return folder / CONTENT_FILENAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContentPack::is_pack(const io::path& folder) {
|
|
||||||
return io::is_regular_file(folder / PACKAGE_FILENAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<ContentPackStats> ContentPack::loadStats() const {
|
std::optional<ContentPackStats> ContentPack::loadStats() const {
|
||||||
auto contentFile = getContentFile();
|
auto contentFile = getContentFile();
|
||||||
if (!io::exists(contentFile)) {
|
if (!io::exists(contentFile)) {
|
||||||
|
|
@ -85,6 +81,9 @@ static void checkContentPackId(const std::string& id, const io::path& folder) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (id == "none") {
|
||||||
|
throw contentpack_error(id, folder, "content-pack id is not specified");
|
||||||
|
}
|
||||||
if (std::find(
|
if (std::find(
|
||||||
ContentPack::RESERVED_NAMES.begin(),
|
ContentPack::RESERVED_NAMES.begin(),
|
||||||
ContentPack::RESERVED_NAMES.end(),
|
ContentPack::RESERVED_NAMES.end(),
|
||||||
|
|
@ -94,10 +93,71 @@ static void checkContentPackId(const std::string& id, const io::path& folder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DependencyPack parse_dependency(std::string depName) {
|
||||||
|
auto level = DependencyLevel::REQUIRED;
|
||||||
|
switch (depName.at(0)) {
|
||||||
|
case '!':
|
||||||
|
depName = depName.substr(1);
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
depName = depName.substr(1);
|
||||||
|
level = DependencyLevel::OPTIONAL;
|
||||||
|
break;
|
||||||
|
case '~':
|
||||||
|
depName = depName.substr(1);
|
||||||
|
level = DependencyLevel::WEAK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string depVer = "*";
|
||||||
|
std::string depVerOperator = "=";
|
||||||
|
|
||||||
|
size_t versionPos = depName.rfind("@");
|
||||||
|
if (versionPos != std::string::npos) {
|
||||||
|
depVer = depName.substr(versionPos + 1);
|
||||||
|
depName = depName.substr(0, versionPos);
|
||||||
|
|
||||||
|
if (depVer.size() >= 2) {
|
||||||
|
std::string op = depVer.substr(0, 2);
|
||||||
|
std::uint8_t op_size = 0;
|
||||||
|
|
||||||
|
// Two symbol operators
|
||||||
|
if (op == ">=" || op == "<=") {
|
||||||
|
op_size = 2;
|
||||||
|
depVerOperator = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
// One symbol operators
|
||||||
|
else {
|
||||||
|
op = depVer.substr(0, 1);
|
||||||
|
|
||||||
|
if (op == ">" || op == "<") {
|
||||||
|
op_size = 1;
|
||||||
|
depVerOperator = op;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
depVer = depVer.substr(op_size);
|
||||||
|
} else {
|
||||||
|
if (depVer == ">" || depVer == "<"){
|
||||||
|
depVer = "*";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionOperator versionOperator;
|
||||||
|
if (VersionOperatorMeta.getItem(depVerOperator, versionOperator)) {
|
||||||
|
return DependencyPack{level, depName, depVer, versionOperator};
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("invalid version operator");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ContentPack ContentPack::read(const io::path& folder) {
|
ContentPack ContentPack::read(const io::path& folder) {
|
||||||
auto root = io::read_json(folder / PACKAGE_FILENAME);
|
auto root = io::read_json(folder / PACKAGE_FILENAME);
|
||||||
ContentPack pack;
|
ContentPack pack;
|
||||||
root.at("id").get(pack.id);
|
root.at("id").get(pack.id);
|
||||||
|
checkContentPackId(pack.id, folder);
|
||||||
root.at("title").get(pack.title);
|
root.at("title").get(pack.title);
|
||||||
root.at("version").get(pack.version);
|
root.at("version").get(pack.version);
|
||||||
if (root.has("creators")) {
|
if (root.has("creators")) {
|
||||||
|
|
@ -115,81 +175,26 @@ ContentPack ContentPack::read(const io::path& folder) {
|
||||||
root.at("source").get(pack.source);
|
root.at("source").get(pack.source);
|
||||||
pack.folder = folder;
|
pack.folder = folder;
|
||||||
|
|
||||||
|
auto dependenciesList = root.at("dependencies");
|
||||||
|
if (!dependenciesList) {
|
||||||
|
return pack;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto found = root.at("dependencies")) {
|
if (auto found = root.at("dependencies")) {
|
||||||
const auto& dependencies = *found;
|
const auto& dependencies = *found;
|
||||||
for (const auto& elem : dependencies) {
|
for (const auto& elem : dependencies) {
|
||||||
std::string depName = elem.asString();
|
std::string depName = elem.asString();
|
||||||
auto level = DependencyLevel::REQUIRED;
|
try {
|
||||||
switch (depName.at(0)) {
|
pack.dependencies.push_back(parse_dependency(std::move(depName)));
|
||||||
case '!':
|
} catch (const std::runtime_error& err) {
|
||||||
depName = depName.substr(1);
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
depName = depName.substr(1);
|
|
||||||
level = DependencyLevel::OPTIONAL;
|
|
||||||
break;
|
|
||||||
case '~':
|
|
||||||
depName = depName.substr(1);
|
|
||||||
level = DependencyLevel::WEAK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string depVer = "*";
|
|
||||||
std::string depVerOperator = "=";
|
|
||||||
|
|
||||||
size_t versionPos = depName.rfind("@");
|
|
||||||
if (versionPos != std::string::npos) {
|
|
||||||
depVer = depName.substr(versionPos + 1);
|
|
||||||
depName = depName.substr(0, versionPos);
|
|
||||||
|
|
||||||
if (depVer.size() >= 2) {
|
|
||||||
std::string op = depVer.substr(0, 2);
|
|
||||||
std::uint8_t op_size = 0;
|
|
||||||
|
|
||||||
// Two symbol operators
|
|
||||||
if (op == ">=" || op == "<=") {
|
|
||||||
op_size = 2;
|
|
||||||
depVerOperator = op;
|
|
||||||
}
|
|
||||||
|
|
||||||
// One symbol operators
|
|
||||||
else {
|
|
||||||
op = depVer.substr(0, 1);
|
|
||||||
|
|
||||||
if (op == ">" || op == "<") {
|
|
||||||
op_size = 1;
|
|
||||||
depVerOperator = op;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
depVer = depVer.substr(op_size);
|
|
||||||
} else {
|
|
||||||
if (depVer == ">" || depVer == "<"){
|
|
||||||
depVer = "*";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VersionOperator versionOperator;
|
|
||||||
if (VersionOperatorMeta.getItem(depVerOperator, versionOperator)) {
|
|
||||||
pack.dependencies.push_back(
|
|
||||||
{level, depName, depVer, versionOperator}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
throw contentpack_error(
|
throw contentpack_error(
|
||||||
pack.id, folder, "invalid version operator"
|
pack.id,
|
||||||
|
folder,
|
||||||
|
"dependency parsing error: " + std::string(err.what())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pack.id == "none") {
|
|
||||||
throw contentpack_error(
|
|
||||||
pack.id, folder, "content-pack id is not specified"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
checkContentPackId(pack.id, folder);
|
|
||||||
|
|
||||||
return pack;
|
return pack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,15 +205,21 @@ void ContentPack::scanFolder(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const auto& packFolder : io::directory_iterator(folder)) {
|
for (const auto& packFolder : io::directory_iterator(folder)) {
|
||||||
if (!io::is_directory(packFolder)) continue;
|
if (!io::is_directory(packFolder)) {
|
||||||
if (!is_pack(packFolder)) continue;
|
continue;
|
||||||
|
}
|
||||||
|
auto packageFile = packFolder / PACKAGE_FILENAME;
|
||||||
|
if (!io::is_regular_file(packageFile)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
packs.push_back(read(packFolder));
|
packs.push_back(read(packFolder));
|
||||||
} catch (const contentpack_error& err) {
|
} catch (const contentpack_error& err) {
|
||||||
std::cerr << "package.json error at " << err.getFolder().string();
|
logger.warning() << "package.json error at "
|
||||||
std::cerr << ": " << err.what() << std::endl;
|
<< err.getFolder().string() << ": " << err.what();
|
||||||
} catch (const std::runtime_error& err) {
|
} catch (const std::runtime_error& err) {
|
||||||
std::cerr << err.what() << std::endl;
|
logger.error() << "reading " << packageFile.string()
|
||||||
|
<< " error: " << err.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@ struct ContentPack {
|
||||||
static inline const io::path GENERATORS_FOLDER = "generators";
|
static inline const io::path GENERATORS_FOLDER = "generators";
|
||||||
static const std::vector<std::string> RESERVED_NAMES;
|
static const std::vector<std::string> RESERVED_NAMES;
|
||||||
|
|
||||||
static bool is_pack(const io::path& folder);
|
|
||||||
static ContentPack read(const io::path& folder);
|
static ContentPack read(const io::path& folder);
|
||||||
|
|
||||||
static void scanFolder(
|
static void scanFolder(
|
||||||
|
|
@ -114,6 +113,14 @@ struct ContentPack {
|
||||||
default: return "";
|
default: return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string_view getPrefix(std::string_view path) {
|
||||||
|
size_t pos = path.find(':');
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return path.substr(0, pos);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WorldFuncsSet {
|
struct WorldFuncsSet {
|
||||||
|
|
@ -127,6 +134,8 @@ struct WorldFuncsSet {
|
||||||
bool onchunkremove;
|
bool onchunkremove;
|
||||||
bool oninventoryopen;
|
bool oninventoryopen;
|
||||||
bool oninventoryclosed;
|
bool oninventoryclosed;
|
||||||
|
bool onentityspawn;
|
||||||
|
bool onentitydespawn;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContentPackRuntime {
|
class ContentPackRuntime {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,14 @@ void TextNote::setText(std::wstring_view text) {
|
||||||
this->text = text;
|
this->text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextNote::setEntity(entityid_t eid) {
|
||||||
|
this->entity = eid;
|
||||||
|
}
|
||||||
|
|
||||||
|
entityid_t TextNote::getEntity() const {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
const std::wstring& TextNote::getText() const {
|
const std::wstring& TextNote::getText() const {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "constants.hpp"
|
||||||
#include "presets/NotePreset.hpp"
|
#include "presets/NotePreset.hpp"
|
||||||
|
|
||||||
/// @brief 3D text instance
|
/// @brief 3D text instance
|
||||||
|
|
@ -7,6 +8,7 @@ class TextNote {
|
||||||
std::wstring text;
|
std::wstring text;
|
||||||
NotePreset preset;
|
NotePreset preset;
|
||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
|
entityid_t entity = ENTITY_NONE;
|
||||||
|
|
||||||
glm::vec3 xAxis {1, 0, 0};
|
glm::vec3 xAxis {1, 0, 0};
|
||||||
glm::vec3 yAxis {0, 1, 0};
|
glm::vec3 yAxis {0, 1, 0};
|
||||||
|
|
@ -14,6 +16,8 @@ public:
|
||||||
TextNote(std::wstring text, NotePreset preset, glm::vec3 position);
|
TextNote(std::wstring text, NotePreset preset, glm::vec3 position);
|
||||||
|
|
||||||
void setText(std::wstring_view text);
|
void setText(std::wstring_view text);
|
||||||
|
void setEntity(entityid_t eid);
|
||||||
|
entityid_t getEntity() const;
|
||||||
|
|
||||||
const std::wstring& getText() const;
|
const std::wstring& getText() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,18 @@
|
||||||
#include "graphics/core/Shader.hpp"
|
#include "graphics/core/Shader.hpp"
|
||||||
#include "graphics/core/DrawContext.hpp"
|
#include "graphics/core/DrawContext.hpp"
|
||||||
#include "presets/NotePreset.hpp"
|
#include "presets/NotePreset.hpp"
|
||||||
|
#include "world/Level.hpp"
|
||||||
|
#include "objects/Entities.hpp"
|
||||||
|
#include "objects/Entity.hpp"
|
||||||
#include "constants.hpp"
|
#include "constants.hpp"
|
||||||
|
|
||||||
TextsRenderer::TextsRenderer(
|
TextsRenderer::TextsRenderer(
|
||||||
Batch3D& batch, const Assets& assets, const Frustum& frustum
|
const Level& level,
|
||||||
|
Batch3D& batch,
|
||||||
|
const Assets& assets,
|
||||||
|
const Frustum& frustum
|
||||||
)
|
)
|
||||||
: batch(batch), assets(assets), frustum(frustum) {
|
: level(level), batch(batch), assets(assets), frustum(frustum) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextsRenderer::renderNote(
|
void TextsRenderer::renderNote(
|
||||||
|
|
@ -31,6 +37,13 @@ void TextsRenderer::renderNote(
|
||||||
const auto& preset = note.getPreset();
|
const auto& preset = note.getPreset();
|
||||||
auto pos = note.getPosition();
|
auto pos = note.getPosition();
|
||||||
|
|
||||||
|
entityid_t eid = note.getEntity();
|
||||||
|
if (eid != ENTITY_NONE) {
|
||||||
|
if (auto entity = level.entities->get(eid)) {
|
||||||
|
pos += entity->getTransform().displayPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (util::distance2(pos, camera.position) >
|
if (util::distance2(pos, camera.position) >
|
||||||
util::sqr(preset.renderDistance / camera.zoom)) {
|
util::sqr(preset.renderDistance / camera.zoom)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,10 @@ class Batch3D;
|
||||||
class Frustum;
|
class Frustum;
|
||||||
class TextNote;
|
class TextNote;
|
||||||
struct EngineSettings;
|
struct EngineSettings;
|
||||||
|
class Level;
|
||||||
|
|
||||||
class TextsRenderer {
|
class TextsRenderer {
|
||||||
|
const Level& level;
|
||||||
Batch3D& batch;
|
Batch3D& batch;
|
||||||
const Assets& assets;
|
const Assets& assets;
|
||||||
const Frustum& frustum;
|
const Frustum& frustum;
|
||||||
|
|
@ -31,7 +33,12 @@ class TextsRenderer {
|
||||||
bool projected
|
bool projected
|
||||||
);
|
);
|
||||||
public:
|
public:
|
||||||
TextsRenderer(Batch3D& batch, const Assets& assets, const Frustum& frustum);
|
TextsRenderer(
|
||||||
|
const Level& level,
|
||||||
|
Batch3D& batch,
|
||||||
|
const Assets& assets,
|
||||||
|
const Frustum& frustum
|
||||||
|
);
|
||||||
|
|
||||||
void render(
|
void render(
|
||||||
const DrawContext& context,
|
const DrawContext& context,
|
||||||
|
|
|
||||||
|
|
@ -91,9 +91,11 @@ WorldRenderer::WorldRenderer(
|
||||||
assets, level, *player.chunks, &engine.getSettings().graphics
|
assets, level, *player.chunks, &engine.getSettings().graphics
|
||||||
)),
|
)),
|
||||||
particles(std::make_unique<ParticlesRenderer>(
|
particles(std::make_unique<ParticlesRenderer>(
|
||||||
assets, level, *player.chunks, engine.getSettings().graphics
|
assets, level, *player.chunks, engine.getSettings().graphics
|
||||||
|
)),
|
||||||
|
texts(std::make_unique<TextsRenderer>(
|
||||||
|
level, *batch3d, assets, *frustumCulling
|
||||||
)),
|
)),
|
||||||
texts(std::make_unique<TextsRenderer>(*batch3d, assets, *frustumCulling)),
|
|
||||||
blockWraps(std::make_unique<BlockWrapsRenderer>(
|
blockWraps(std::make_unique<BlockWrapsRenderer>(
|
||||||
assets, level.content, *player.chunks
|
assets, level.content, *player.chunks
|
||||||
)) {
|
)) {
|
||||||
|
|
|
||||||
|
|
@ -350,6 +350,7 @@ static int l_start_debug_instance(lua::State* L) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto projectPath = lua::isstring(L, 2) ? lua::require_lstring(L, 2) : "";
|
auto projectPath = lua::isstring(L, 2) ? lua::require_lstring(L, 2) : "";
|
||||||
|
auto outputPath = lua::isstring(L, 3) ? lua::require_lstring(L, 3) : "";
|
||||||
const auto& paths = engine->getPaths();
|
const auto& paths = engine->getPaths();
|
||||||
|
|
||||||
std::vector<std::string> args {
|
std::vector<std::string> args {
|
||||||
|
|
@ -362,7 +363,10 @@ static int l_start_debug_instance(lua::State* L) {
|
||||||
args.emplace_back(io::resolve(std::string(projectPath)).string());
|
args.emplace_back(io::resolve(std::string(projectPath)).string());
|
||||||
}
|
}
|
||||||
|
|
||||||
platform::new_engine_instance(std::move(args));
|
platform::new_engine_instance(
|
||||||
|
std::move(args),
|
||||||
|
outputPath.empty() ? "" : io::resolve(std::string(outputPath))
|
||||||
|
);
|
||||||
return lua::pushinteger(L, port);
|
return lua::pushinteger(L, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1011,8 +1011,9 @@ static int l_gui_get_env(lua::State* L) {
|
||||||
"document '" + std::string(name) + "' not found"
|
"document '" + std::string(name) + "' not found"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
lua::getglobal(L, lua::env_name(*doc->getEnvironment()));
|
return lua::getregistry(
|
||||||
return 1;
|
L, lua::ENVS_TABLE, lua::env_name(*doc->getEnvironment())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_gui_str(lua::State* L) {
|
static int l_gui_str(lua::State* L) {
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ static int l_set_params(lua::State* L) {
|
||||||
static int l_set_array(lua::State* L) {
|
static int l_set_array(lua::State* L) {
|
||||||
size_t index = static_cast<size_t>(lua::tointeger(L, 1));
|
size_t index = static_cast<size_t>(lua::tointeger(L, 1));
|
||||||
auto key = lua::require_string(L, 2);
|
auto key = lua::require_string(L, 2);
|
||||||
auto data = lua::require_lstring(L, 3);
|
auto data = lua::bytearray_as_string(L, 3);
|
||||||
auto effect = post_processing->getEffect(index);
|
auto effect = post_processing->getEffect(index);
|
||||||
if (effect == nullptr) {
|
if (effect == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,20 @@ static int l_set_rotation(lua::State* L) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_get_entity(lua::State* L) {
|
||||||
|
if (auto note = renderer->texts->get(lua::tointeger(L, 1))) {
|
||||||
|
return lua::pushinteger(L, note->getEntity());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_set_entity(lua::State* L) {
|
||||||
|
if (auto note = renderer->texts->get(lua::tointeger(L, 1))) {
|
||||||
|
note->setEntity(lua::touinteger(L, 2));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const luaL_Reg text3dlib[] = {
|
const luaL_Reg text3dlib[] = {
|
||||||
{"show", wrap_hud<l_show>},
|
{"show", wrap_hud<l_show>},
|
||||||
{"hide", wrap_hud<l_hide>},
|
{"hide", wrap_hud<l_hide>},
|
||||||
|
|
@ -108,5 +122,7 @@ const luaL_Reg text3dlib[] = {
|
||||||
{"set_axis_y", wrap_hud<l_set_axis_y>},
|
{"set_axis_y", wrap_hud<l_set_axis_y>},
|
||||||
{"set_rotation", wrap_hud<l_set_rotation>},
|
{"set_rotation", wrap_hud<l_set_rotation>},
|
||||||
{"update_settings", wrap_hud<l_update_settings>},
|
{"update_settings", wrap_hud<l_update_settings>},
|
||||||
|
{"get_entity", wrap_hud<l_get_entity>},
|
||||||
|
{"set_entity", wrap_hud<l_set_entity>},
|
||||||
{nullptr, nullptr}
|
{nullptr, nullptr}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -64,12 +64,13 @@ static void create_libs(State* L, StateType stateType) {
|
||||||
openlib(L, "vec4", vec4lib);
|
openlib(L, "vec4", vec4lib);
|
||||||
openlib(L, "yaml", yamllib);
|
openlib(L, "yaml", yamllib);
|
||||||
|
|
||||||
|
openlib(L, "__vc_app", applib);
|
||||||
|
lua::getglobal(L, "__vc_app");
|
||||||
|
lua::setregistry(L, "app");
|
||||||
|
|
||||||
if (stateType == StateType::SCRIPT) {
|
if (stateType == StateType::SCRIPT) {
|
||||||
openlib(L, "app", applib);
|
lua::getregistry(L, "app");
|
||||||
lua::getglobal(L, "app");
|
lua::setglobal(L, "app");
|
||||||
lua::setglobal(L, "__vc_app");
|
|
||||||
} else if (stateType == StateType::BASE) {
|
|
||||||
openlib(L, "__vc_app", applib);
|
|
||||||
}
|
}
|
||||||
if (stateType == StateType::BASE || stateType == StateType::SCRIPT) {
|
if (stateType == StateType::BASE || stateType == StateType::SCRIPT) {
|
||||||
openlib(L, "assets", assetslib);
|
openlib(L, "assets", assetslib);
|
||||||
|
|
@ -95,10 +96,18 @@ static void create_libs(State* L, StateType stateType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
addfunc(L, "print", lua::wrap<l_print>);
|
addfunc(L, "print", lua::wrap<l_print>);
|
||||||
addfunc(L, "_crc32", lua::wrap<l_crc32>);
|
addfunc(L, "crc32", lua::wrap<l_crc32>);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_panic_handler(lua::State* L) {
|
||||||
|
logger.error() << "PANIC: unprotected error in call to Lua API: " << lua::tostring(L, -1);
|
||||||
|
logger.flush();
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua::init_state(State* L, StateType stateType) {
|
void lua::init_state(State* L, StateType stateType) {
|
||||||
|
lua_atpanic(L, l_panic_handler);
|
||||||
|
|
||||||
// Allowed standard libraries
|
// Allowed standard libraries
|
||||||
luaL_openlibs(L);
|
luaL_openlibs(L);
|
||||||
|
|
||||||
|
|
@ -112,21 +121,25 @@ void lua::init_state(State* L, StateType stateType) {
|
||||||
setglobal(L, "io");
|
setglobal(L, "io");
|
||||||
|
|
||||||
createtable(L, 0, 0);
|
createtable(L, 0, 0);
|
||||||
|
pushvalue(L, -1);
|
||||||
setglobal(L, "__vc__pack_envs");
|
setglobal(L, "__vc__pack_envs");
|
||||||
|
setregistry(L, lua::PACK_ENVS_TABLE);
|
||||||
|
|
||||||
const char* removed_os[] {
|
const char* removed_os[] {
|
||||||
"execute", "exit", "remove", "rename", "setlocale", "tmpname", nullptr};
|
"execute", "exit", "remove", "rename", "setlocale", "tmpname", nullptr};
|
||||||
remove_lib_funcs(L, "os", removed_os);
|
remove_lib_funcs(L, "os", removed_os);
|
||||||
create_libs(L, stateType);
|
create_libs(L, stateType);
|
||||||
|
|
||||||
|
createtable(L, 0, 0);
|
||||||
|
setregistry(L, LAMBDAS_TABLE);
|
||||||
|
|
||||||
|
createtable(L, 0, 0);
|
||||||
|
setregistry(L, CHUNKS_TABLE);
|
||||||
|
|
||||||
|
createtable(L, 0, 0);
|
||||||
pushglobals(L);
|
pushglobals(L);
|
||||||
setglobal(L, env_name(0));
|
setfield(L, env_name(0));
|
||||||
|
setregistry(L, ENVS_TABLE);
|
||||||
createtable(L, 0, 0);
|
|
||||||
setglobal(L, LAMBDAS_TABLE);
|
|
||||||
|
|
||||||
createtable(L, 0, 0);
|
|
||||||
setglobal(L, CHUNKS_TABLE);
|
|
||||||
|
|
||||||
initialize_libs_extends(L);
|
initialize_libs_extends(L);
|
||||||
|
|
||||||
|
|
@ -144,6 +157,9 @@ void lua::initialize(const EnginePaths& paths, const CoreParameters& params) {
|
||||||
);
|
);
|
||||||
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() {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
using namespace lua;
|
using namespace lua;
|
||||||
|
|
||||||
static int nextEnvironment = 1;
|
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;
|
||||||
|
|
||||||
|
|
@ -20,7 +20,7 @@ int lua::userdata_destructor(lua::State* L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string lua::env_name(int env) {
|
std::string lua::env_name(int env) {
|
||||||
return "_ENV" + util::mangleid(env);
|
return std::to_string(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua::pushvalue(State* L, const dv::value& value) {
|
int lua::pushvalue(State* L, const dv::value& value) {
|
||||||
|
|
@ -220,7 +220,7 @@ void lua::dump_stack(State* L) {
|
||||||
static std::shared_ptr<std::string> create_lambda_handler(State* L) {
|
static std::shared_ptr<std::string> create_lambda_handler(State* L) {
|
||||||
auto ptr = reinterpret_cast<ptrdiff_t>(topointer(L, -1));
|
auto ptr = reinterpret_cast<ptrdiff_t>(topointer(L, -1));
|
||||||
auto name = util::mangleid(ptr);
|
auto name = util::mangleid(ptr);
|
||||||
requireglobal(L, LAMBDAS_TABLE);
|
requireregistry(L, LAMBDAS_TABLE);
|
||||||
pushvalue(L, -2);
|
pushvalue(L, -2);
|
||||||
setfield(L, name);
|
setfield(L, name);
|
||||||
pop(L, 2);
|
pop(L, 2);
|
||||||
|
|
@ -229,7 +229,7 @@ static std::shared_ptr<std::string> create_lambda_handler(State* L) {
|
||||||
new std::string(name),
|
new std::string(name),
|
||||||
[=](std::string* name) {
|
[=](std::string* name) {
|
||||||
auto L = lua::get_main_state();
|
auto L = lua::get_main_state();
|
||||||
requireglobal(L, LAMBDAS_TABLE);
|
requireregistry(L, LAMBDAS_TABLE);
|
||||||
pushnil(L);
|
pushnil(L);
|
||||||
setfield(L, *name);
|
setfield(L, *name);
|
||||||
pop(L);
|
pop(L);
|
||||||
|
|
@ -242,8 +242,9 @@ runnable lua::create_runnable(State* L) {
|
||||||
auto funcptr = create_lambda_handler(L);
|
auto funcptr = create_lambda_handler(L);
|
||||||
return [=]() {
|
return [=]() {
|
||||||
auto L = lua::get_main_state();
|
auto L = lua::get_main_state();
|
||||||
if (!get_from(L, LAMBDAS_TABLE, *funcptr, false))
|
if (!get_from_registry(L, LAMBDAS_TABLE, *funcptr, false)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
call_nothrow(L, 0, 0);
|
call_nothrow(L, 0, 0);
|
||||||
pop(L);
|
pop(L);
|
||||||
};
|
};
|
||||||
|
|
@ -252,8 +253,9 @@ runnable lua::create_runnable(State* L) {
|
||||||
KeyCallback lua::create_simple_handler(State* L) {
|
KeyCallback lua::create_simple_handler(State* L) {
|
||||||
auto funcptr = create_lambda_handler(L);
|
auto funcptr = create_lambda_handler(L);
|
||||||
return [=]() -> bool {
|
return [=]() -> bool {
|
||||||
if (!get_from(L, LAMBDAS_TABLE, *funcptr, false))
|
if (!get_from_registry(L, LAMBDAS_TABLE, *funcptr, false)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
int top = gettop(L) - 1;
|
int top = gettop(L) - 1;
|
||||||
if (call_nothrow(L, 0)) {
|
if (call_nothrow(L, 0)) {
|
||||||
int nres = gettop(L) - top;
|
int nres = gettop(L) - top;
|
||||||
|
|
@ -271,8 +273,9 @@ KeyCallback lua::create_simple_handler(State* L) {
|
||||||
scripting::common_func lua::create_lambda(State* L) {
|
scripting::common_func lua::create_lambda(State* L) {
|
||||||
auto funcptr = create_lambda_handler(L);
|
auto funcptr = create_lambda_handler(L);
|
||||||
return [=](const std::vector<dv::value>& args) -> dv::value {
|
return [=](const std::vector<dv::value>& args) -> dv::value {
|
||||||
if (!get_from(L, LAMBDAS_TABLE, *funcptr, false))
|
if (!get_from_registry(L, LAMBDAS_TABLE, *funcptr, false)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
int top = gettop(L) - 1;
|
int top = gettop(L) - 1;
|
||||||
for (const auto& arg : args) {
|
for (const auto& arg : args) {
|
||||||
pushvalue(L, arg);
|
pushvalue(L, arg);
|
||||||
|
|
@ -294,8 +297,9 @@ scripting::common_func lua::create_lambda(State* L) {
|
||||||
scripting::common_func lua::create_lambda_nothrow(State* L) {
|
scripting::common_func lua::create_lambda_nothrow(State* L) {
|
||||||
auto funcptr = create_lambda_handler(L);
|
auto funcptr = create_lambda_handler(L);
|
||||||
return [=](const std::vector<dv::value>& args) -> dv::value {
|
return [=](const std::vector<dv::value>& args) -> dv::value {
|
||||||
if (!get_from(L, LAMBDAS_TABLE, *funcptr, false))
|
if (!get_from_registry(L, LAMBDAS_TABLE, *funcptr, false)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
int top = gettop(L) - 1;
|
int top = gettop(L) - 1;
|
||||||
for (const auto& arg : args) {
|
for (const auto& arg : args) {
|
||||||
pushvalue(L, arg);
|
pushvalue(L, arg);
|
||||||
|
|
@ -313,8 +317,16 @@ scripting::common_func lua::create_lambda_nothrow(State* L) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void store_env(lua::State* L, int id) {
|
||||||
|
requireregistry(L, ENVS_TABLE);
|
||||||
|
pushvalue(L, -2);
|
||||||
|
lua_remove(L, -3);
|
||||||
|
setfield(L, env_name(id));
|
||||||
|
pop(L);
|
||||||
|
}
|
||||||
|
|
||||||
int lua::create_environment(State* L, int parent) {
|
int lua::create_environment(State* L, int parent) {
|
||||||
int id = nextEnvironment++;
|
int id = next_environment++;
|
||||||
|
|
||||||
// local env = {}
|
// local env = {}
|
||||||
createtable(L, 0, 1);
|
createtable(L, 0, 1);
|
||||||
|
|
@ -331,24 +343,22 @@ int lua::create_environment(State* L, int parent) {
|
||||||
setfield(L, "__index");
|
setfield(L, "__index");
|
||||||
setmetatable(L);
|
setmetatable(L);
|
||||||
|
|
||||||
// envname = env
|
store_env(L, id);
|
||||||
setglobal(L, env_name(id));
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua::restore_pack_environment(lua::State* L, const std::string& packid) {
|
int lua::restore_pack_environment(lua::State* L, const std::string& packid) {
|
||||||
if(!lua::getglobal(L, "__vc__pack_envs")) {
|
if(!requireregistry(L, PACK_ENVS_TABLE)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int id = nextEnvironment++;
|
int id = next_environment++;
|
||||||
|
|
||||||
if (lua::getfield(L, packid)) {
|
if (getfield(L, packid)) {
|
||||||
// envname = env
|
store_env(L, id);
|
||||||
setglobal(L, env_name(id));
|
pop(L);
|
||||||
lua::pop(L);
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
lua::pop(L);
|
pop(L);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -357,5 +367,5 @@ void lua::remove_environment(State* L, int id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pushnil(L);
|
pushnil(L);
|
||||||
setglobal(L, env_name(id));
|
store_env(L, id);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,21 +14,35 @@
|
||||||
namespace lua {
|
namespace lua {
|
||||||
inline std::string LAMBDAS_TABLE = "$L"; // lambdas storage
|
inline std::string LAMBDAS_TABLE = "$L"; // lambdas storage
|
||||||
inline std::string CHUNKS_TABLE = "$C"; // precompiled lua chunks
|
inline std::string CHUNKS_TABLE = "$C"; // precompiled lua chunks
|
||||||
|
inline std::string PACK_ENVS_TABLE = "$P";
|
||||||
|
inline std::string ENVS_TABLE = "$E";
|
||||||
extern std::unordered_map<std::type_index, std::string> usertypeNames;
|
extern std::unordered_map<std::type_index, std::string> usertypeNames;
|
||||||
int userdata_destructor(lua::State* L);
|
int userdata_destructor(lua::State* L);
|
||||||
|
|
||||||
std::string env_name(int env);
|
std::string env_name(int env);
|
||||||
void dump_stack(lua::State*);
|
void dump_stack(lua::State*);
|
||||||
|
|
||||||
inline bool getglobal(lua::State* L, const std::string& name) {
|
inline bool isnoneornil(lua::State* L, int idx) {
|
||||||
lua_getglobal(L, name.c_str());
|
return lua_isnoneornil(L, idx);
|
||||||
if (isnil(L, -1)) {
|
}
|
||||||
|
|
||||||
|
inline bool getfield(lua::State* L, const std::string& name, int idx = -1) {
|
||||||
|
lua_getfield(L, idx, name.c_str());
|
||||||
|
if (isnoneornil(L, -1)) {
|
||||||
pop(L);
|
pop(L);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool getglobal(lua::State* L, const std::string& name) {
|
||||||
|
return getfield(L, name, LUA_GLOBALSINDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool getregistry(lua::State* L, const std::string& name) {
|
||||||
|
return getfield(L, name, LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
|
||||||
inline int requireglobal(lua::State* L, const std::string& name) {
|
inline int requireglobal(lua::State* L, const std::string& name) {
|
||||||
if (getglobal(L, name)) {
|
if (getglobal(L, name)) {
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -37,6 +51,24 @@ namespace lua {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int requireregistry(lua::State* L, const std::string& name) {
|
||||||
|
if (getregistry(L, name)) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("registry entry " + name + " not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool getregistry(lua::State* L, const std::string& name, const std::string& key) {
|
||||||
|
requireregistry(L, name);
|
||||||
|
if (getfield(L, key)) {
|
||||||
|
lua_remove(L, -2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pop(L);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool hasglobal(lua::State* L, const std::string& name) {
|
inline bool hasglobal(lua::State* L, const std::string& name) {
|
||||||
lua_getglobal(L, name.c_str());
|
lua_getglobal(L, name.c_str());
|
||||||
if (isnil(L, -1)) {
|
if (isnil(L, -1)) {
|
||||||
|
|
@ -203,9 +235,6 @@ namespace lua {
|
||||||
inline int pushglobals(lua::State* L) {
|
inline int pushglobals(lua::State* L) {
|
||||||
return pushvalue(L, LUA_GLOBALSINDEX);
|
return pushvalue(L, LUA_GLOBALSINDEX);
|
||||||
}
|
}
|
||||||
inline bool isnoneornil(lua::State* L, int idx) {
|
|
||||||
return lua_isnoneornil(L, idx);
|
|
||||||
}
|
|
||||||
inline bool isboolean(lua::State* L, int idx) {
|
inline bool isboolean(lua::State* L, int idx) {
|
||||||
return lua_isboolean(L, idx);
|
return lua_isboolean(L, idx);
|
||||||
}
|
}
|
||||||
|
|
@ -267,6 +296,9 @@ namespace lua {
|
||||||
inline void setglobal(lua::State* L, const std::string& name) {
|
inline void setglobal(lua::State* L, const std::string& name) {
|
||||||
lua_setglobal(L, name.c_str());
|
lua_setglobal(L, name.c_str());
|
||||||
}
|
}
|
||||||
|
inline void setregistry(lua::State* L, const std::string& key) {
|
||||||
|
lua_setfield(L, LUA_REGISTRYINDEX, key.c_str());
|
||||||
|
}
|
||||||
template <class T>
|
template <class T>
|
||||||
inline T* touserdata(lua::State* L, int idx) {
|
inline T* touserdata(lua::State* L, int idx) {
|
||||||
if (void* rawptr = lua_touserdata(L, idx)) {
|
if (void* rawptr = lua_touserdata(L, idx)) {
|
||||||
|
|
@ -461,15 +493,6 @@ namespace lua {
|
||||||
|
|
||||||
[[nodiscard]] dv::value tovalue(lua::State*, int idx);
|
[[nodiscard]] dv::value tovalue(lua::State*, int idx);
|
||||||
|
|
||||||
inline bool getfield(lua::State* L, const std::string& name, int idx = -1) {
|
|
||||||
lua_getfield(L, idx, name.c_str());
|
|
||||||
if (isnoneornil(L, -1)) {
|
|
||||||
pop(L);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int requirefield(
|
inline int requirefield(
|
||||||
lua::State* L, const std::string& name, int idx = -1
|
lua::State* L, const std::string& name, int idx = -1
|
||||||
) {
|
) {
|
||||||
|
|
@ -538,7 +561,7 @@ namespace lua {
|
||||||
if (luaL_loadbuffer(L, src.c_str(), src.length(), file.c_str())) {
|
if (luaL_loadbuffer(L, src.c_str(), src.length(), file.c_str())) {
|
||||||
throw luaerror(tostring(L, -1));
|
throw luaerror(tostring(L, -1));
|
||||||
}
|
}
|
||||||
if (env && getglobal(L, env_name(env))) {
|
if (env && getregistry(L, ENVS_TABLE, env_name(env))) {
|
||||||
lua_setfenv(L, -2);
|
lua_setfenv(L, -2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -551,7 +574,46 @@ namespace lua {
|
||||||
setfield(L, name);
|
setfield(L, name);
|
||||||
pop(L, 2);
|
pop(L, 2);
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("table " + tableName + " not found");
|
throw std::runtime_error("global table " + tableName + " not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void store_in_registry(
|
||||||
|
lua::State* L, const std::string& tableName, const std::string& name
|
||||||
|
) {
|
||||||
|
if (getregistry(L, tableName)) {
|
||||||
|
pushvalue(L, -2);
|
||||||
|
setfield(L, name);
|
||||||
|
pop(L, 2);
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("table " + tableName + " not found in registry");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int get_from(
|
||||||
|
lua::State* L,
|
||||||
|
const std::string& tableName,
|
||||||
|
const std::string& name,
|
||||||
|
bool required,
|
||||||
|
int idx,
|
||||||
|
std::string_view context
|
||||||
|
) {
|
||||||
|
if (getfield(L, tableName, idx)) {
|
||||||
|
if (getfield(L, name)) {
|
||||||
|
return 1;
|
||||||
|
} else if (required) {
|
||||||
|
pop(L);
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string(context) + " table " + tableName +
|
||||||
|
" has no member " + name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pop(L);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string(context) + " table " + tableName + " not found"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -561,20 +623,20 @@ namespace lua {
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
bool required = false
|
bool required = false
|
||||||
) {
|
) {
|
||||||
if (getglobal(L, tableName)) {
|
return get_from(
|
||||||
if (getfield(L, name)) {
|
L, tableName, name, required, LUA_GLOBALSINDEX, "global"
|
||||||
return 1;
|
);
|
||||||
} else if (required) {
|
}
|
||||||
pop(L);
|
|
||||||
throw std::runtime_error(
|
inline int get_from_registry(
|
||||||
"table " + tableName + " has no member " + name
|
lua::State* L,
|
||||||
);
|
const std::string& tableName,
|
||||||
}
|
const std::string& name,
|
||||||
pop(L);
|
bool required = false
|
||||||
return 0;
|
) {
|
||||||
} else {
|
return get_from(
|
||||||
throw std::runtime_error("table " + tableName + " not found");
|
L, tableName, name, required, LUA_REGISTRYINDEX, "registry"
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
int call(lua::State*, int argc, int nresults = -1);
|
int call(lua::State*, int argc, int nresults = -1);
|
||||||
|
|
@ -607,10 +669,7 @@ namespace lua {
|
||||||
scripting::common_func create_lambda_nothrow(lua::State*);
|
scripting::common_func create_lambda_nothrow(lua::State*);
|
||||||
|
|
||||||
inline int pushenv(lua::State* L, int env) {
|
inline int pushenv(lua::State* L, int env) {
|
||||||
if (getglobal(L, env_name(env))) {
|
return getregistry(L, ENVS_TABLE, env_name(env));
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
int create_environment(lua::State*, int parent);
|
int create_environment(lua::State*, int parent);
|
||||||
int restore_pack_environment(lua::State*, const std::string& packid);
|
int restore_pack_environment(lua::State*, const std::string& packid);
|
||||||
|
|
@ -739,14 +798,14 @@ namespace lua {
|
||||||
inline void read_bytes_from_table(
|
inline void read_bytes_from_table(
|
||||||
lua::State* L, int tableIndex, std::vector<ubyte>& bytes
|
lua::State* L, int tableIndex, std::vector<ubyte>& bytes
|
||||||
) {
|
) {
|
||||||
if (!lua::istable(L, tableIndex)) {
|
if (!istable(L, tableIndex)) {
|
||||||
throw std::runtime_error("table expected");
|
throw std::runtime_error("table expected");
|
||||||
} else {
|
} else {
|
||||||
size_t size = lua::objlen(L, tableIndex);
|
size_t size = objlen(L, tableIndex);
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
lua::rawgeti(L, i + 1, tableIndex);
|
rawgeti(L, i + 1, tableIndex);
|
||||||
const int byte = lua::tointeger(L, -1);
|
const int byte = tointeger(L, -1);
|
||||||
lua::pop(L);
|
pop(L);
|
||||||
if (byte < 0 || byte > 255) {
|
if (byte < 0 || byte > 255) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"invalid byte '" + std::to_string(byte) + "'"
|
"invalid byte '" + std::to_string(byte) + "'"
|
||||||
|
|
@ -758,11 +817,11 @@ namespace lua {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int create_bytearray(lua::State* L, const void* bytes, size_t size) {
|
inline int create_bytearray(lua::State* L, const void* bytes, size_t size) {
|
||||||
lua::requireglobal(L, "Bytearray_construct");
|
requireglobal(L, "Bytearray_construct");
|
||||||
lua::pushlstring(
|
pushlstring(
|
||||||
L, std::string_view(reinterpret_cast<const char*>(bytes), size)
|
L, std::string_view(reinterpret_cast<const char*>(bytes), size)
|
||||||
);
|
);
|
||||||
return lua::call(L, 1, 1);
|
return call(L, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int create_bytearray(lua::State* L, const std::vector<ubyte>& bytes) {
|
inline int create_bytearray(lua::State* L, const std::vector<ubyte>& bytes) {
|
||||||
|
|
@ -770,12 +829,15 @@ namespace lua {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string_view bytearray_as_string(lua::State* L, int idx) {
|
inline std::string_view bytearray_as_string(lua::State* L, int idx) {
|
||||||
lua::pushvalue(L, idx);
|
if (type(L, idx) == LUA_TSTRING) {
|
||||||
lua::requireglobal(L, "Bytearray_as_string");
|
return tolstring(L, idx);
|
||||||
lua::pushvalue(L, -2);
|
}
|
||||||
lua::call(L, 1, 1);
|
pushvalue(L, idx);
|
||||||
auto view = lua::tolstring(L, -1);
|
requireglobal(L, "Bytearray_as_string");
|
||||||
lua::pop(L, 2);
|
pushvalue(L, -2);
|
||||||
|
call(L, 1, 1);
|
||||||
|
auto view = tolstring(L, -1);
|
||||||
|
pop(L, 2);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -188,11 +188,7 @@ std::unique_ptr<Process> scripting::start_app_script(const io::path& script) {
|
||||||
lua::pushstring(L, pack.id);
|
lua::pushstring(L, pack.id);
|
||||||
lua::setfield(L, "PACK_ID");
|
lua::setfield(L, "PACK_ID");
|
||||||
|
|
||||||
if(!lua::getglobal(L, "__vc__pack_envs")) {
|
lua::requireregistry(L, lua::PACK_ENVS_TABLE);
|
||||||
lua::createtable(L, 0, 0);
|
|
||||||
lua::setglobal(L, "__vc__pack_envs");
|
|
||||||
lua::pushvalue(L, -1);
|
|
||||||
}
|
|
||||||
lua::pushenv(L, id);
|
lua::pushenv(L, id);
|
||||||
lua::setfield(L, pack.id);
|
lua::setfield(L, pack.id);
|
||||||
lua::pop(L);
|
lua::pop(L);
|
||||||
|
|
@ -248,7 +244,7 @@ std::unique_ptr<Process> scripting::start_app_script(const io::path& script) {
|
||||||
|
|
||||||
void scripting::process_post_runnables() {
|
void scripting::process_post_runnables() {
|
||||||
auto L = lua::get_main_state();
|
auto L = lua::get_main_state();
|
||||||
if (lua::getglobal(L, "__process_post_runnables")) {
|
if (lua::getglobal(L, "__vc__process_post_runnables")) {
|
||||||
lua::call_nothrow(L, 0, 0);
|
lua::call_nothrow(L, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -627,6 +623,26 @@ void scripting::on_ui_close(UiDocument* layout, Inventory* inventory) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void scripting::on_scripts_loading() {
|
||||||
|
auto L = lua::get_main_state();
|
||||||
|
|
||||||
|
for (auto& pack : content_control->getAllContentPacks()) {
|
||||||
|
lua::emit_event(L, pack.id + ":.onscriptsloading", [](auto L) {
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scripting::on_content_loaded() {
|
||||||
|
auto L = lua::get_main_state();
|
||||||
|
|
||||||
|
for (auto& pack : content_control->getAllContentPacks()) {
|
||||||
|
lua::emit_event(L, pack.id + ":.oncontentloaded", [](auto L) {
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool scripting::register_event(
|
bool scripting::register_event(
|
||||||
int env, const std::string& name, const std::string& id
|
int env, const std::string& name, const std::string& id
|
||||||
) {
|
) {
|
||||||
|
|
@ -722,7 +738,7 @@ void scripting::load_entity_component(
|
||||||
std::string src = io::read_string(file);
|
std::string src = io::read_string(file);
|
||||||
logger.info() << "script (component) " << file.string();
|
logger.info() << "script (component) " << file.string();
|
||||||
lua::loadbuffer(L, *env, src, fileName);
|
lua::loadbuffer(L, *env, src, fileName);
|
||||||
lua::store_in(L, lua::CHUNKS_TABLE, name);
|
lua::store_in_registry(L, lua::CHUNKS_TABLE, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scripting::load_world_script(
|
void scripting::load_world_script(
|
||||||
|
|
@ -761,6 +777,23 @@ void scripting::load_world_script(
|
||||||
register_event(env, "on_inventory_open", prefix + ":.inventoryopen");
|
register_event(env, "on_inventory_open", prefix + ":.inventoryopen");
|
||||||
funcsset.oninventoryclosed =
|
funcsset.oninventoryclosed =
|
||||||
register_event(env, "on_inventory_closed", prefix + ":.inventoryclosed");
|
register_event(env, "on_inventory_closed", prefix + ":.inventoryclosed");
|
||||||
|
funcsset.onentityspawn =
|
||||||
|
register_event(env, "on_entity_spawn", prefix + ":.entityspawn");
|
||||||
|
funcsset.onentitydespawn =
|
||||||
|
register_event(env, "on_entity_despawn", prefix + ":.entitydespawn");
|
||||||
|
}
|
||||||
|
|
||||||
|
void scripting::load_content_script(
|
||||||
|
const scriptenv& senv,
|
||||||
|
const std::string& prefix,
|
||||||
|
const io::path& file,
|
||||||
|
const std::string& fileName
|
||||||
|
) {
|
||||||
|
int env = *senv;
|
||||||
|
lua::pop(lua::get_main_state(), load_script(env, "content", file, fileName));
|
||||||
|
|
||||||
|
register_event(env, "on_scripts_loading", prefix + ":.onscriptsloading");
|
||||||
|
register_event(env, "on_content_loaded", prefix + ":.oncontentloaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
void scripting::load_layout_script(
|
void scripting::load_layout_script(
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,12 @@ namespace scripting {
|
||||||
/// @brief Called on UI view close
|
/// @brief Called on UI view close
|
||||||
void on_ui_close(UiDocument* layout, Inventory* inventory);
|
void on_ui_close(UiDocument* layout, Inventory* inventory);
|
||||||
|
|
||||||
|
/// @brief Called on Content loading
|
||||||
|
void on_scripts_loading();
|
||||||
|
|
||||||
|
/// @brief Called on Content loading finish
|
||||||
|
void on_content_loaded();
|
||||||
|
|
||||||
/// @brief Load script associated with a Block
|
/// @brief Load script associated with a Block
|
||||||
/// @param env environment
|
/// @param env environment
|
||||||
/// @param prefix pack id
|
/// @param prefix pack id
|
||||||
|
|
@ -221,6 +227,13 @@ namespace scripting {
|
||||||
WorldFuncsSet& funcsset
|
WorldFuncsSet& funcsset
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void load_content_script(
|
||||||
|
const scriptenv& env,
|
||||||
|
const std::string& packid,
|
||||||
|
const io::path& file,
|
||||||
|
const std::string& fileName
|
||||||
|
);
|
||||||
|
|
||||||
/// @brief Load script associated with an UiDocument
|
/// @brief Load script associated with an UiDocument
|
||||||
/// @param env environment
|
/// @param env environment
|
||||||
/// @param prefix pack id
|
/// @param prefix pack id
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,18 @@
|
||||||
#include "scripting.hpp"
|
#include "scripting.hpp"
|
||||||
|
|
||||||
|
#include "debug/Logger.hpp"
|
||||||
#include "lua/lua_engine.hpp"
|
#include "lua/lua_engine.hpp"
|
||||||
#include "objects/Entities.hpp"
|
#include "objects/Entities.hpp"
|
||||||
#include "objects/EntityDef.hpp"
|
#include "objects/EntityDef.hpp"
|
||||||
#include "objects/Entity.hpp"
|
#include "objects/Entity.hpp"
|
||||||
#include "objects/Player.hpp"
|
#include "objects/Player.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
|
#include "content/Content.hpp"
|
||||||
|
#include "content/ContentPack.hpp"
|
||||||
|
|
||||||
using namespace scripting;
|
using namespace scripting;
|
||||||
|
|
||||||
|
static debug::Logger logger("scripting-entities");
|
||||||
static inline const std::string STDCOMP = "stdcomp";
|
static inline const std::string STDCOMP = "stdcomp";
|
||||||
|
|
||||||
[[nodiscard]] static scriptenv create_component_environment(
|
[[nodiscard]] static scriptenv create_component_environment(
|
||||||
|
|
@ -52,6 +56,24 @@ dv::value scripting::get_component_value(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void init_component_events(
|
||||||
|
lua::State* L, const scriptenv& env, UserComponent& component
|
||||||
|
) {
|
||||||
|
lua::pushenv(L, *env);
|
||||||
|
auto& funcsset = component.funcsset;
|
||||||
|
funcsset.on_grounded = lua::hasfield(L, "on_grounded");
|
||||||
|
funcsset.on_fall = lua::hasfield(L, "on_fall");
|
||||||
|
funcsset.on_despawn = lua::hasfield(L, "on_despawn");
|
||||||
|
funcsset.on_sensor_enter = lua::hasfield(L, "on_sensor_enter");
|
||||||
|
funcsset.on_sensor_exit = lua::hasfield(L, "on_sensor_exit");
|
||||||
|
funcsset.on_save = lua::hasfield(L, "on_save");
|
||||||
|
funcsset.on_aim_on = lua::hasfield(L, "on_aim_on");
|
||||||
|
funcsset.on_aim_off = lua::hasfield(L, "on_aim_off");
|
||||||
|
funcsset.on_attacked = lua::hasfield(L, "on_attacked");
|
||||||
|
funcsset.on_used = lua::hasfield(L, "on_used");
|
||||||
|
lua::pop(L);
|
||||||
|
}
|
||||||
|
|
||||||
static void create_component(
|
static void create_component(
|
||||||
lua::State* L,
|
lua::State* L,
|
||||||
int entityIdx,
|
int entityIdx,
|
||||||
|
|
@ -59,11 +81,20 @@ static void create_component(
|
||||||
const dv::value& args,
|
const dv::value& args,
|
||||||
const dv::value& saved
|
const dv::value& saved
|
||||||
) {
|
) {
|
||||||
|
auto parentEnv = get_root_environment();
|
||||||
|
auto prefix = ContentPack::getPrefix(component.name);
|
||||||
|
const auto& content = *scripting::content;
|
||||||
|
if (auto runtime = content.getPackRuntime(std::string(prefix))) {
|
||||||
|
parentEnv = runtime->getEnvironment();
|
||||||
|
} else {
|
||||||
|
logger.warning() << "pack environment is not available for "
|
||||||
|
<< component.name;
|
||||||
|
}
|
||||||
lua::pushvalue(L, entityIdx);
|
lua::pushvalue(L, entityIdx);
|
||||||
auto compenv = create_component_environment(
|
auto compenv = create_component_environment(
|
||||||
get_root_environment(), -1, component.name
|
std::move(parentEnv), -1, component.name
|
||||||
);
|
);
|
||||||
lua::get_from(L, lua::CHUNKS_TABLE, component.name, true);
|
lua::get_from_registry(L, lua::CHUNKS_TABLE, component.name, true);
|
||||||
lua::pushenv(L, *compenv);
|
lua::pushenv(L, *compenv);
|
||||||
|
|
||||||
if (args != nullptr) {
|
if (args != nullptr) {
|
||||||
|
|
@ -95,19 +126,8 @@ static void create_component(
|
||||||
lua::setfenv(L);
|
lua::setfenv(L);
|
||||||
lua::call_nothrow(L, 0, 0);
|
lua::call_nothrow(L, 0, 0);
|
||||||
|
|
||||||
lua::pushenv(L, *compenv);
|
init_component_events(L, compenv, component);
|
||||||
auto& funcsset = component.funcsset;
|
lua::pop(L);
|
||||||
funcsset.on_grounded = lua::hasfield(L, "on_grounded");
|
|
||||||
funcsset.on_fall = lua::hasfield(L, "on_fall");
|
|
||||||
funcsset.on_despawn = lua::hasfield(L, "on_despawn");
|
|
||||||
funcsset.on_sensor_enter = lua::hasfield(L, "on_sensor_enter");
|
|
||||||
funcsset.on_sensor_exit = lua::hasfield(L, "on_sensor_exit");
|
|
||||||
funcsset.on_save = lua::hasfield(L, "on_save");
|
|
||||||
funcsset.on_aim_on = lua::hasfield(L, "on_aim_on");
|
|
||||||
funcsset.on_aim_off = lua::hasfield(L, "on_aim_off");
|
|
||||||
funcsset.on_attacked = lua::hasfield(L, "on_attacked");
|
|
||||||
funcsset.on_used = lua::hasfield(L, "on_used");
|
|
||||||
lua::pop(L, 2);
|
|
||||||
|
|
||||||
component.env = compenv;
|
component.env = compenv;
|
||||||
}
|
}
|
||||||
|
|
@ -129,6 +149,15 @@ void scripting::on_entity_spawn(
|
||||||
for (auto& component : components) {
|
for (auto& component : components) {
|
||||||
create_component(L, -1, *component, args, saved);
|
create_component(L, -1, *component, args, saved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& [packid, pack] : content->getPacks()) {
|
||||||
|
if (pack->worldfuncsset.onentityspawn) {
|
||||||
|
lua::emit_event(L, packid + ":.entityspawn", [&](lua::State* L) {
|
||||||
|
lua::pushinteger(L, eid);
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_entity_callback(
|
static void process_entity_callback(
|
||||||
|
|
@ -170,9 +199,21 @@ void scripting::on_entity_despawn(const Entity& entity) {
|
||||||
process_entity_callback(
|
process_entity_callback(
|
||||||
entity, "on_despawn", &EntityFuncsSet::on_despawn, nullptr
|
entity, "on_despawn", &EntityFuncsSet::on_despawn, nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
auto L = lua::get_main_state();
|
auto L = lua::get_main_state();
|
||||||
|
entityid_t uid = entity.getUID();
|
||||||
|
|
||||||
|
for (auto& [packid, pack] : content->getPacks()) {
|
||||||
|
if (pack->worldfuncsset.onentitydespawn) {
|
||||||
|
lua::emit_event(L, packid + ":.entitydespawn", [&](lua::State* L) {
|
||||||
|
lua::pushinteger(L, uid);
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lua::get_from(L, "stdcomp", "remove_Entity", true);
|
lua::get_from(L, "stdcomp", "remove_Entity", true);
|
||||||
lua::pushinteger(L, entity.getUID());
|
lua::pushinteger(L, uid);
|
||||||
lua::call(L, 1, 0);
|
lua::call(L, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ static void sigterm_handler(int signum) {
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
#ifdef VC_BUILD_NAME
|
#ifdef VC_BUILD_NAME
|
||||||
logger.info() << "build: " << VC_BUILD_NAME;
|
if constexpr (VC_BUILD_NAME[0]) {
|
||||||
|
logger.info() << "build: " << VC_BUILD_NAME;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CoreParameters coreParameters;
|
CoreParameters coreParameters;
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,9 @@ std::filesystem::path platform::get_executable_path() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void platform::new_engine_instance(const std::vector<std::string>& args) {
|
void platform::new_engine_instance(
|
||||||
|
const std::vector<std::string>& args, std::filesystem::path outputFile
|
||||||
|
) {
|
||||||
auto executable = get_executable_path();
|
auto executable = get_executable_path();
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
@ -250,6 +252,24 @@ void platform::new_engine_instance(const std::vector<std::string>& args) {
|
||||||
auto commandString = toWString(ss.str());
|
auto commandString = toWString(ss.str());
|
||||||
|
|
||||||
STARTUPINFOW si = { sizeof(si) };
|
STARTUPINFOW si = { sizeof(si) };
|
||||||
|
if (!outputFile.empty()) {
|
||||||
|
si.dwFlags |= STARTF_USESTDHANDLES;
|
||||||
|
si.hStdOutput = CreateFileW(
|
||||||
|
toWString(outputFile.u8string()).data(),
|
||||||
|
GENERIC_WRITE,
|
||||||
|
FILE_SHARE_WRITE | FILE_SHARE_READ,
|
||||||
|
nullptr,
|
||||||
|
CREATE_ALWAYS,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
if (si.hStdOutput == INVALID_HANDLE_VALUE) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"CreateFileW failed with code: " +
|
||||||
|
std::to_string(GetLastError())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
PROCESS_INFORMATION pi = { 0 };
|
PROCESS_INFORMATION pi = { 0 };
|
||||||
DWORD flags = CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS;
|
DWORD flags = CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS;
|
||||||
// | CREATE_NO_WINDOW;
|
// | CREATE_NO_WINDOW;
|
||||||
|
|
@ -280,7 +300,11 @@ void platform::new_engine_instance(const std::vector<std::string>& args) {
|
||||||
for (int i = 0; i < args.size(); i++) {
|
for (int i = 0; i < args.size(); i++) {
|
||||||
ss << " " << util::quote(args[i]);
|
ss << " " << util::quote(args[i]);
|
||||||
}
|
}
|
||||||
ss << " >/dev/null &";
|
if (outputFile.empty()) {
|
||||||
|
ss << " >/dev/null &";
|
||||||
|
} else {
|
||||||
|
ss << " >" << util::quote(outputFile.u8string()) << " &";
|
||||||
|
}
|
||||||
|
|
||||||
auto command = ss.str();
|
auto command = ss.str();
|
||||||
logger.info() << command;
|
logger.info() << command;
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,9 @@ namespace platform {
|
||||||
/// @brief Get current process running executable path
|
/// @brief Get current process running executable path
|
||||||
std::filesystem::path get_executable_path();
|
std::filesystem::path get_executable_path();
|
||||||
/// @brief Run a separate engine instance with specified arguments
|
/// @brief Run a separate engine instance with specified arguments
|
||||||
void new_engine_instance(const std::vector<std::string>& args);
|
void new_engine_instance(
|
||||||
|
const std::vector<std::string>& args, std::filesystem::path outputFile
|
||||||
|
);
|
||||||
/// @brief Open URL in web browser
|
/// @brief Open URL in web browser
|
||||||
bool open_url(const std::string& url);
|
bool open_url(const std::string& url);
|
||||||
/// @brief Check if stdin has input
|
/// @brief Check if stdin has input
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue