Merge branch 'MihailRis:main' into main

This commit is contained in:
Xertis
2025-01-27 16:35:11 +03:00
committed by GitHub
69 changed files with 639 additions and 285 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
# install EnTT # install EnTT
git clone https://github.com/skypjack/entt.git git clone https://github.com/skypjack/entt.git
cd entt/build cd entt/build
cmake -DCMAKE_BUILD_TYPE=Release .. cmake -DCMAKE_BUILD_TYPE=Release -DENTT_INSTALL=on ..
sudo make install sudo make install
cd ../.. cd ../..
- name: Configure - name: Configure
+1 -1
View File
@@ -46,7 +46,7 @@ jobs:
# install EnTT # install EnTT
git clone https://github.com/skypjack/entt.git git clone https://github.com/skypjack/entt.git
cd entt/build cd entt/build
cmake -DCMAKE_BUILD_TYPE=Release .. cmake -DCMAKE_BUILD_TYPE=Release -DENTT_INSTALL=on ..
sudo make install sudo make install
cd ../.. cd ../..
+136 -79
View File
@@ -1,96 +1,153 @@
# 0.25 - 2024.12.01 # 0.26 - 2025.01.27
[Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/tree/release-0.25/doc/en/main-page.md) for 0.25 [Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/tree/release-0.26/doc/en/main-page.md) for 0.26
Table of contents: Table of contents:
- [Added](#added) - [Added](#added)
- [Changes](#changes)
- [Functions](#functions) - [Functions](#functions)
- [Fixes](#fixes) - [Fixes](#fixes)
## Added ## Added
- 3dtext - headless mode `--headless`
- blockwraps - script execution mode `--headless --script filename`
- network (http requests and sockets) - test execution mode `--headless --test filename`
- vctest console application
- libraries: - libraries:
- base64 - app
- gfx.text3d - byteutil
- gfx.blockwraps - in-game chat
- network - text markup: Markdown
- syntax-highlighting: Lua
- http post requests
- `Scripts` menu page for app scripts
- binding `hud.chat`
- user-defined console.submit
- events: - events:
- on_replaced - on_chunk_present
- on_block_replaced - on_chunk_remove
- on_player_tick - on_inventory_open
- structures 'lowering' property - on_inventory_closed
- add 'hint' property to textbox - [canvas](https://github.com/MihailRis/VoxelEngine-Cpp/pull/444) ui node
- add 'taking' and 'placing' properties to slot and slotsgrid - settings:
- add 'scroll-step' property to container - `graphics.dense-render`
- add 'line-numbers' and 'text-color' to textbox - block properties:
- modules: - `culling`
- base:util - particles properties:
- uinode property 'id' - `angle_spread`
- block.materials table - `min_angular_vel`, `max_angular_vel`
- block.properties table - bytearray support in serializers
- item.properties table - ui properties:
- add version to world info table - uinode: `cursor`
- add 'sizeSpread' particles property - textbox: `markup`, `syntax`, `text-color`
- add user properties - label: `markup`
- base pack:
- add transparent leaves render mode
- add falling leaves particles
- 'states' parameter in base:falling_block
- added/updated sounds
- nameless worlds
- SIGTERM handler
- project:
- clang Windows workflow
- engine tests
### Changes
- moved `devtools.console` binding handler to Lua
- move `key:escape` binding handler to Lua
- upgrade dead emitters garbage collection
- reserved player entity ids: `0` - none (example: dead), `-1` - auto (spawns new one)
- input.add_callback("key:name") support and add optional `owner` argument
### Functions ### Functions
- player.is_infinite_items - app.tick
- player.set_infinite_items - app.sleep
- player.is_instant_destruction - app.sleep_until
- player.set_instant_destruction - app.new_world
- player.get_name - app.open_world
- player.set_name - app.save_world
- hud.open - app.close_world
- base64.encode - app.reopen_world
- base64.decode - app.delete_world
- utf8.escape - app.config_packs
- string.escape - app.reconfig_packs
- textbox:lineAt - app.get_setting
- textbox:linePos - app.set_setting
- network.get - app.get_version
- network.get_binary - app.get_setting_info
- network.tcp_connect - app.load_content
- network.tcp_open - app.reset_content
- network.get_total_upload - app.is_content_loaded
- network.get_total_download - app.quit
- gfx.text3d.show - entity:get_player
- gfx.text3d.hide - start_coroutine
- gfx.text3d.get_text - gui.clear_markup
- gfx.text3d.set_text - gui.escape_markup
- gfx.text3d.get_pos - gui.alert
- gfx.text3d.set_pos - gui.confirm
- gfx.text3d.get_axis_x - gui.load_document
- gfx.text3d.set_axis_x - console.get
- gfx.text3d.get_axis_y - world.get_chunk_data
- gfx.text3d.set_axis_y - world.set_chunk_data
- gfx.text3d.set_rotation - world.save_chunk_data
- gfx.text3d.update_settings - world.count_chunks
- player.create
- player.delete
- player.is_suspended
- player.set_suspended
- player.is_loaded_chunks
- player.set_loading_chunks
- network.post
- table.shuffle
- table.deep_copy
- math.normalize
- math.round
- byteutil.pack
- byteutil.unpack
- file.name
- file.stem
- file.ext
- file.prefix
- hud.set_allow_pause
Methods:
- uinode:reposition
- socket:available
New overloads:
- block.get_X, block.get_Y, block.get_Z
- player.get_rot
- Bytearray:append
## Fixes ## Fixes
- [fix on_block_interact & fix segfault after engine finished](https://github.com/MihailRis/VoxelEngine-Cpp/commit/d1f92c21d0bbdf2df0eb3b31c5637bdf7110444c)
- [fix translucent blocks render](https://github.com/MihailRis/VoxelEngine-Cpp/pull/370) - [fix item.properties](https://github.com/MihailRis/VoxelEngine-Cpp/commit/92fb19ba5e2307fdbcbf5d0e55f9c0712be45f72)
- [fix blocks selection with semi-transparent blocks](https://github.com/MihailRis/VoxelEngine-Cpp/commit/171cbb48d099032d7e78c51a46c374104f96f0d1) - [fix base:bazalt durability](https://github.com/MihailRis/VoxelEngine-Cpp/commit/a036c5e383135dc0f9b086e244188d1ceb3f0bf2)
- [fix: commands repository not reset before world open](https://github.com/MihailRis/VoxelEngine-Cpp/commit/1a00a91b604399f3108aa995422d371e573e650b) - [fix camera-related bugs](https://github.com/MihailRis/VoxelEngine-Cpp/commit/0d071ab0141edbf087f3ec03505792740023c01e)
- [mip-mapping related fixes](https://github.com/MihailRis/VoxelEngine-Cpp/commit/d9277e1b31714632bd7f5f601b8362a9e7cb8819) - [fix: grabbed item is deleted on inventory close](https://github.com/MihailRis/VoxelEngine-Cpp/commit/2787f2fc5495004f6029644ed5221f3abfc0c68f)
- [fix disabled slots display](https://github.com/MihailRis/VoxelEngine-Cpp/commit/e8ee3e04b1398a3ada8445591267525304410571) - [fix block overriding](https://github.com/MihailRis/VoxelEngine-Cpp/commit/cda34e3975a42696ea31a1b0018731e746cd13bb)
- [fix attack](https://github.com/MihailRis/VoxelEngine-Cpp/commit/bc17abc8b3ee7ff9027f7e3c375ca0330bb8e7bc) - [fix faces culling when 'light-passing' is false](https://github.com/MihailRis/VoxelEngine-Cpp/commit/954724c8378da525fc7349c018e9351c5bdfdf8f)
- [fix: commands repository not reset before world open](https://github.com/MihailRis/VoxelEngine-Cpp/commit/1a00a91b604399f3108aa995422d371e573e650b) - [fix particles lighting](https://github.com/MihailRis/VoxelEngine-Cpp/commit/6be640458d6b4ae46866b342ca0f26e561ead125)
- [fix stdlib.lua](https://github.com/MihailRis/VoxelEngine-Cpp/commit/6ec33ab98c78523eaececf40f113f2323d25a33a) - [fix non-skipping particles](https://github.com/MihailRis/VoxelEngine-Cpp/pull/421/commits/f1c7317c5ab2a148e5188e091cd1aa3490dc8b4d)
- [fix file.write_bytes](https://github.com/MihailRis/VoxelEngine-Cpp/commit/0fec17a8b69ac81255b77022f3af5addf8fcc8f8) - [fix content stats](https://github.com/MihailRis/VoxelEngine-Cpp/commit/97eef3ef1900157a9648bade8e06b203b99ee6f6)
- [fix World::nextInventoryId](https://github.com/MihailRis/VoxelEngine-Cpp/commit/371fdaedcef2c163edd226160f388068b2bf5e83) - [fix byte manipulation functions](https://github.com/MihailRis/VoxelEngine-Cpp/commit/9490d1f7eacb00f56112dfdd1ea12bb9c3ca528d)
- [fix block inventory unbinding](https://github.com/MihailRis/VoxelEngine-Cpp/commit/6f6c2a916afd6b9b79221111fc72b1a86109be13) - [fix error handling in events and runnables](https://github.com/MihailRis/VoxelEngine-Cpp/commit/03a3062940ebfc4e8f0b3efc5930c71f8d07b604)
- [fix xml text escapes handling](https://github.com/MihailRis/VoxelEngine-Cpp/commit/53c54dc91d132c221ff5fea2f7e9fb4568db9a0f) - [fix small dumb legacy memory leak](https://github.com/MihailRis/VoxelEngine-Cpp/commit/4d0b9f049b79322959e4aefd95eedc665e87d087)
- [fix `\'` escape parsing](https://github.com/MihailRis/VoxelEngine-Cpp/commit/2bc6cbda2e809b14fa6cffe09161b53c1636675f) - [fix grass lighting](https://github.com/MihailRis/VoxelEngine-Cpp/commit/9d7816a286fb3a7269b5220502354720e4d2726b)
- [fix crosshair look](https://github.com/MihailRis/VoxelEngine-Cpp/commit/e034bda477c35efe96548e78ecc722966a7a2197) - [small fixes in translation.](https://github.com/MihailRis/VoxelEngine-Cpp/commit/d25452784d68be19821dc917ad15bc0a92d81bd9)
- [fix: actual block inventory size not updating on inventory-size property update](https://github.com/MihailRis/VoxelEngine-Cpp/commit/1ba5b0ce33103e539ccb199ee1cd52095e286a1f) - [fix errors handling in event handlers](https://github.com/MihailRis/VoxelEngine-Cpp/commit/f62fc5a039dca70219fb2b38f61fc53a2542adf7)
- [fix falling block hitbox](https://github.com/MihailRis/VoxelEngine-Cpp/commit/352ef6485a4b796d1cdc8dd0e00ab1a1d72a2c0a) - [fix lua stack manipulations](https://github.com/MihailRis/VoxelEngine-Cpp/commit/e7555448cf0df86995b40d67fa58de1ca78f8105)
- [fix console position](https://github.com/MihailRis/VoxelEngine-Cpp/commit/3ea213e8d3cee7be55ec39ffb18dc557dec7557b) - [fix lua::create_lambda](https://github.com/MihailRis/VoxelEngine-Cpp/commit/40cdebb175014736e35bc31ecc93ae72fb00a6e9)
- [fix: fatal error on pack removal when no world open](https://github.com/MihailRis/VoxelEngine-Cpp/commit/78d5ab02c2ba8a3d05cf5639eb10a49c9ca14ec3) - [fix some UB](https://github.com/MihailRis/VoxelEngine-Cpp/commit/b5999fe36420d116674abc353ed3dad739ac5f70)
- [fix custom model lighting](https://github.com/MihailRis/VoxelEngine-Cpp/commit/a333cadfcaeb485a30833343d55faf01b28a5c5f) - [fix rigidbody:is_enabled](https://github.com/MihailRis/VoxelEngine-Cpp/commit/2adfbdb19226b2685848131073a56b354706433d)
- [fix: emitter does not skip particles](https://github.com/MihailRis/VoxelEngine-Cpp/commit/983e516fb4ebc1f2def592f2b7f3195d968deed2) - [fix panel elements removal](https://github.com/MihailRis/VoxelEngine-Cpp/commit/c6951e09651149463528bdffbc2cba4ea41de4a4)
- [fix old custom models render](https://github.com/MihailRis/VoxelEngine-Cpp/commit/82733d38011b52a426cb74560521949c1cd43cc1) - [fix infinite block fields conversion requests](https://github.com/MihailRis/VoxelEngine-Cpp/commit/0494db91872abff500cfc153a32035ee3f2745ae)
- [fix data_buffer:put_number](https://github.com/MihailRis/VoxelEngine-Cpp/commit/e247902cc6ffdaa6beab391fcfdaea7f021ab063)
- [fix textbox horizontal scroll & fix console log width](https://github.com/MihailRis/VoxelEngine-Cpp/commit/13fde2116d095b9393c4f5804ba23071e5f56ad6)
- [fix is_array](https://github.com/MihailRis/VoxelEngine-Cpp/pull/420)
- [fix neighbour chunk update](https://github.com/MihailRis/VoxelEngine-Cpp/pull/404)
- [fix lamp material](https://github.com/MihailRis/VoxelEngine-Cpp/commit/57356e1d64d6d9d7e8d59b078543b290e998ad00)
+1 -1
View File
@@ -63,7 +63,7 @@ else()
endif() endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie -lstdc++fs") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
endif() endif()
if(WIN32) if(WIN32)
+2 -2
View File
@@ -3,7 +3,7 @@
## Latest release ## Latest release
- [Download](https://github.com/MihailRis/VoxelEngine-Cpp/releases/latest) | [Скачать](https://github.com/MihailRis/VoxelEngine-Cpp/releases/latest) - [Download](https://github.com/MihailRis/VoxelEngine-Cpp/releases/latest) | [Скачать](https://github.com/MihailRis/VoxelEngine-Cpp/releases/latest)
- [Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.25/doc/en/main-page.md) | [Документация](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.25/doc/ru/main-page.md) - [Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.26/doc/en/main-page.md) | [Документация](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.26/doc/ru/main-page.md)
## Build project in Linux ## Build project in Linux
@@ -14,7 +14,7 @@
```sh ```sh
git clone https://github.com/skypjack/entt.git git clone https://github.com/skypjack/entt.git
cd entt/build cd entt/build
cmake -DCMAKE_BUILD_TYPE=Release .. cmake -DCMAKE_BUILD_TYPE=Release -DENTT_INSTALL=on ..
sudo make install sudo make install
``` ```
+7
View File
@@ -2,6 +2,13 @@
To work with the command interpreter, use the **console** library. To work with the command interpreter, use the **console** library.
When sending a command via the standard console (core:console layout):
1. the `allow-cheats` rule is checked
2. the `player`, `pos.x|y|z`, `entity.id`, `entity.selected` variables are automatically set.
3. the command handler is called - console.submit or the default one.
The default handler calls console.execute, passing the result to the console.log call.
## Commands creation ## Commands creation
To create a console command, use the following function: To create a console command, use the following function:
+1 -3
View File
@@ -1,8 +1,6 @@
# Documentation # Documentation
Documentation for in-development version 0.26. Documentation for release 0.26.
[Documentation for stable release 0.25.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.25/doc/en/main-page.md)
## Sections ## Sections
+12 -1
View File
@@ -62,6 +62,17 @@ gui.escape_markup(
Escapes markup in text. Escapes markup in text.
```lua
gui.alert(
-- message (not automatically translated, use gui.str(...))
message: str,
-- function called on close
on_ok: function() -> nil
)
```
Displays a message box. **Non-blocking**.
```lua ```lua
gui.confirm( gui.confirm(
-- message (does not translate automatically, use gui.str(...)) -- message (does not translate automatically, use gui.str(...))
@@ -78,7 +89,7 @@ gui.confirm(
) )
``` ```
Requests confirmation from the user for an action. **Does not** stop code execution. Requests confirmation from the user for an action. **Non-blocking**.
```lua ```lua
gui.load_document( gui.load_document(
+9
View File
@@ -96,6 +96,15 @@ player.get_spawnpoint(playerid: int) -> number, number, number
Spawn point setter and getter Spawn point setter and getter
```lua
player.is_suspended(pid: int) -> bool
player.set_suspended(pid: int, suspended: bool)
```
Setter and getter for the player's suspended status.
When suspended, the entity is deleted and the player is disabled from the world simulation.
```lua ```lua
player.set_name(playerid: int, name: str) player.set_name(playerid: int, name: str)
player.get_name(playerid: int) -> str player.get_name(playerid: int) -> str
+1 -1
View File
@@ -18,7 +18,7 @@ Creates a rule. If a handler is specified, returns the id for deletion.
> Rules that have not been created can be used, but resetting via rules.reset will result in setting the value to nil. > Rules that have not been created can be used, but resetting via rules.reset will result in setting the value to nil.
```lua ```lua
rules.listen( rules.listen(
-- rule name -- rule name
name: str, name: str,
-- value change handler function -- value change handler function
+10 -1
View File
@@ -49,10 +49,11 @@ world.is_night() -> bool
world.count_chunks() -> int world.count_chunks() -> int
-- Returns the compressed chunk data to send. -- Returns the compressed chunk data to send.
-- If the chunk is not loaded, returns the saved data.
-- Currently includes: -- Currently includes:
-- 1. Voxel data (id and state) -- 1. Voxel data (id and state)
-- 2. Voxel metadata (fields) -- 2. Voxel metadata (fields)
world.get_chunk_data(x: int, z: int) -> Bytearray world.get_chunk_data(x: int, z: int) -> Bytearray or nil
-- Modifies the chunk based on the compressed data. -- Modifies the chunk based on the compressed data.
-- Returns true if the chunk exists. -- Returns true if the chunk exists.
@@ -61,4 +62,12 @@ world.set_chunk_data(
-- compressed chunk data -- compressed chunk data
data: Bytearray data: Bytearray
) -> bool ) -> bool
-- Saves chunk data to region.
-- Changes will be written to file only on world save.
world.save_chunk_data(
x: int, z: int,
-- compressed chunk data
data: Bytearray
)
``` ```
+3
View File
@@ -26,6 +26,9 @@ entity:get_uid() -> int
entity:get_component(name: str) -> component or nil entity:get_component(name: str) -> component or nil
-- Checks for the presence of a component by name -- Checks for the presence of a component by name
entity:has_component(name: str) -> bool entity:has_component(name: str) -> bool
-- Enables/disables the component
entity:set_enabled(name: str, enable: bool)
``` ```
## Built-in components ## Built-in components
+7
View File
@@ -2,6 +2,13 @@
Для работы с командным интерпретатором предоставляется библиотека **console**. Для работы с командным интерпретатором предоставляется библиотека **console**.
При отправке команды через стандартную консоль (макет core:console):
1. проверяется правило `allow-cheats`
2. автоматически устанавливаются переменные `player`, `pos.x|y|z`, `entity.id`, `entity.selected`.
3. вызывается обработчик команд - console.submit или по-умолчанию.
Обработчик по-умолчанию вызывает console.execute, передавая результат в вызов console.log.
## Создание команд ## Создание команд
Для создания команды консоли используется следующая функция: Для создания команды консоли используется следующая функция:
+1 -3
View File
@@ -1,8 +1,6 @@
# Документация # Документация
Документация разрабатываемой версии 0.26. Документация версии 0.26.
[Документация стабильной версии 0.25.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.25/doc/ru/main-page.md)
## Разделы ## Разделы
+11
View File
@@ -59,6 +59,17 @@ gui.escape_markup(
Экранирует разметку в тексте. Экранирует разметку в тексте.
```lua
gui.alert(
-- сообщение (не переводится автоматически, используйте gui.str(...))
message: str,
-- функция, вызываемая при закрытии
on_ok: function() -> nil
)
```
Выводит окно с сообщением. **Не** останавливает выполнение кода.
```lua ```lua
gui.confirm( gui.confirm(
-- сообщение (не переводится автоматически, используйте gui.str(...)) -- сообщение (не переводится автоматически, используйте gui.str(...))
+9
View File
@@ -96,6 +96,15 @@ player.get_spawnpoint(playerid: int) -> number, number, number
Сеттер и геттер точки спавна игрока Сеттер и геттер точки спавна игрока
```lua
player.is_suspended(pid: int) -> bool
player.set_suspended(pid: int, suspended: bool)
```
Сеттер и геттер статуса "заморозки" игрока.
При "заморозке" удаляется сущность, а игрок выключается из симуляции мира.
```lua ```lua
player.set_name(playerid: int, name: str) player.set_name(playerid: int, name: str)
player.get_name(playerid: int) -> str player.get_name(playerid: int) -> str
+10 -1
View File
@@ -48,10 +48,11 @@ world.is_night() -> bool
world.count_chunks() -> int world.count_chunks() -> int
-- Возвращает сжатые данные чанка для отправки. -- Возвращает сжатые данные чанка для отправки.
-- Если чанк не загружен, возвращает сохранённые данные.
-- На данный момент включает: -- На данный момент включает:
-- 1. Данные вокселей (id и состояние) -- 1. Данные вокселей (id и состояние)
-- 2. Метаданные (поля) вокселей -- 2. Метаданные (поля) вокселей
world.get_chunk_data(x: int, z: int) -> Bytearray world.get_chunk_data(x: int, z: int) -> Bytearray или nil
-- Изменяет чанк на основе сжатых данных. -- Изменяет чанк на основе сжатых данных.
-- Возвращает true если чанк существует. -- Возвращает true если чанк существует.
@@ -60,4 +61,12 @@ world.set_chunk_data(
-- сжатые данные чанка -- сжатые данные чанка
data: Bytearray data: Bytearray
) -> bool ) -> bool
-- Сохраняет данные чанка в регион.
-- Изменения будет записаны в файл только после сохранения мира.
world.save_chunk_data(
x: int, z: int,
-- сжатые данные чанка
data: Bytearray
)
``` ```
+3
View File
@@ -26,6 +26,9 @@ entity:get_uid() -> int
entity:get_component(name: str) -> компонент или nil entity:get_component(name: str) -> компонент или nil
-- Проверяет наличие компонента по имени -- Проверяет наличие компонента по имени
entity:has_component(name: str) -> bool entity:has_component(name: str) -> bool
-- Включает/выключает компонент по имени
entity:set_enabled(name: str, enable: bool)
``` ```
## Встроенные компоненты ## Встроенные компоненты
@@ -0,0 +1,5 @@
{
"steps-sound": "steps/snow",
"place-sound": "blocks/snow_place",
"break-sound": "blocks/snow_break"
}
+1
View File
@@ -2,5 +2,6 @@
"texture": "lamp", "texture": "lamp",
"emission": [15, 14, 13], "emission": [15, 14, 13],
"shadeless": true, "shadeless": true,
"material": "base:glass",
"base:durability": 0.3 "base:durability": 0.3
} }
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -12,7 +12,7 @@
</container> </container>
<container id="logContainer" pos="0,60" <container id="logContainer" pos="0,60"
size-func="unpack(vec2.add(gui.get_viewport(), {0,-100}))"> size-func="unpack(vec2.add(gui.get_viewport(), {-350,-100}))">
<textbox <textbox
id='log' id='log'
color='0' color='0'
@@ -20,7 +20,7 @@
margin='0' margin='0'
editable='false' editable='false'
multiline='true' multiline='true'
size-func="gui.get_viewport()[1],40" size-func="gui.get_viewport()[1]-350,40"
gravity="bottom-left" gravity="bottom-left"
markup="md" markup="md"
></textbox> ></textbox>
+13 -7
View File
@@ -97,11 +97,12 @@ end)
function setup_variables() function setup_variables()
local pid = hud.get_player() local pid = hud.get_player()
local x,y,z = player.get_pos(pid) local x,y,z = player.get_pos(pid)
console.set("player", pid)
console.set('pos.x', x) console.set('pos.x', x)
console.set('pos.y', y) console.set('pos.y', y)
console.set('pos.z', z) console.set('pos.z', z)
local pentity = player.get_entity(pid) local pentity = player.get_entity(pid)
if pentity ~= 0 then if pentity > 0 then
console.set('entity.id', pentity) console.set('entity.id', pentity)
end end
local sentity = player.get_selected_entity(pid) local sentity = player.get_selected_entity(pid)
@@ -149,8 +150,6 @@ function submit(text)
end end
end end
setup_variables()
local name local name
for s in text:gmatch("%S+") do for s in text:gmatch("%S+") do
name = s name = s
@@ -167,12 +166,19 @@ function submit(text)
end end
document.log.caret = -1 document.log.caret = -1
local status, result = pcall(console.execute, text)
if result then
console.log(result)
end
document.prompt.text = "" document.prompt.text = ""
document.prompt.focused = true document.prompt.focused = true
setup_variables()
if console.submit then
console.submit(text)
else
local status, result = pcall(console.execute, text)
if result then
console.log(result)
end
end
end end
function set_mode(mode) function set_mode(mode)
+6 -11
View File
@@ -7,16 +7,11 @@ local initialized = false
local max_lines = 15 local max_lines = 15
local animation_fps = 30 local animation_fps = 30
local function remove_line(line)
document[line[1]]:destruct()
time.post_runnable(function() document.root:reposition() end)
end
local function update_line(line, uptime) local function update_line(line, uptime)
local diff = uptime - line[2] local diff = uptime - line[2]
if diff > timeout then if diff > timeout then
remove_line(line) document[line[1]]:destruct()
table.insert(dead_lines, i) table.insert(dead_lines, table.index(lines, line))
elseif diff > timeout-fadeout then elseif diff > timeout-fadeout then
local opacity = (timeout - diff) / fadeout local opacity = (timeout - diff) / fadeout
document[line[1]].color = {0, 0, 0, opacity * 80} document[line[1]].color = {0, 0, 0, opacity * 80}
@@ -25,16 +20,16 @@ local function update_line(line, uptime)
end end
events.on("core:chat", function(message) events.on("core:chat", function(message)
while #lines >= max_lines do
document[lines[1][1]]:destruct()
table.remove(lines, 1)
end
local current_time = time.uptime() local current_time = time.uptime()
local id = 'l'..tostring(nextid) local id = 'l'..tostring(nextid)
document.root:add(gui.template("chat_line", {id=id})) document.root:add(gui.template("chat_line", {id=id}))
document.root:reposition() document.root:reposition()
document[id.."L"].text = message document[id.."L"].text = message
nextid = nextid + 1 nextid = nextid + 1
if #lines == max_lines then
remove_line(lines[1])
table.remove(lines, 1)
end
table.insert(lines, {id, current_time}) table.insert(lines, {id, current_time})
end) end)
+2 -2
View File
@@ -313,8 +313,8 @@ function bit_converter.bytes_to_uint16(bytes, order)
return return
bit.bor( bit.bor(
bit.lshift(bytes[1], 8), bit.lshift(bytes[2], 8),
bytes[2], 0) bytes[1], 0)
end end
function bit_converter.bytes_to_int64(bytes, order) function bit_converter.bytes_to_int64(bytes, order)
+7 -7
View File
@@ -144,31 +144,31 @@ function data_buffer:put_number(num)
if math.floor(num) ~= num then if math.floor(num) ~= num then
type = TYPE_FLOAT64 type = TYPE_FLOAT64
bytes = bit_converter.float64_to_bytes(num) bytes = bit_converter.float64_to_bytes(num, self.order)
elseif num == 0 then elseif num == 0 then
type = TYPE_ZERO type = TYPE_ZERO
bytes = { } bytes = { }
elseif num > 0 then elseif num > 0 then
if num <= MAX_UINT16 then if num <= MAX_UINT16 then
type = TYPE_UINT16 type = TYPE_UINT16
bytes = bit_converter.uint16_to_bytes(num) bytes = bit_converter.uint16_to_bytes(num, self.order)
elseif num <= MAX_UINT32 then elseif num <= MAX_UINT32 then
type = TYPE_UINT32 type = TYPE_UINT32
bytes = bit_converter.uint32_to_bytes(num) bytes = bit_converter.uint32_to_bytes(num, self.order)
elseif num <= MAX_INT64 then elseif num <= MAX_INT64 then
type = TYPE_INT64 type = TYPE_INT64
bytes = bit_converter.int64_to_bytes(num) bytes = bit_converter.int64_to_bytes(num, self.order)
end end
elseif num < 0 then elseif num < 0 then
if num >= MIN_INT16 then if num >= MIN_INT16 then
type = TYPE_SINT16 type = TYPE_SINT16
bytes = bit_converter.sint16_to_bytes(num) bytes = bit_converter.sint16_to_bytes(num, self.order)
elseif num >= MIN_INT32 then elseif num >= MIN_INT32 then
type = TYPE_SINT32 type = TYPE_SINT32
bytes = bit_converter.sint32_to_bytes(num) bytes = bit_converter.sint32_to_bytes(num, self.order)
elseif num >= MIN_INT64 then elseif num >= MIN_INT64 then
type = TYPE_INT64 type = TYPE_INT64
bytes = bit_converter.int64_to_bytes(num) bytes = bit_converter.int64_to_bytes(num, self.order)
end end
end end
+1 -1
View File
@@ -47,7 +47,7 @@ function gui_util.add_page_dispatcher(dispatcher)
table.insert(gui_util.local_dispatchers, dispatcher) table.insert(gui_util.local_dispatchers, dispatcher)
end end
function gui_util.reset_local() function gui_util.__reset_local()
gui_util.local_dispatchers = {} gui_util.local_dispatchers = {}
end end
+21 -2
View File
@@ -68,6 +68,22 @@ local Entity = {__index={
def_index=function(self) return entities.get_def(self.eid) end, def_index=function(self) return entities.get_def(self.eid) end,
def_name=function(self) return entities.def_name(entities.get_def(self.eid)) end, def_name=function(self) return entities.def_name(entities.get_def(self.eid)) end,
get_player=function(self) return entities.get_player(self.eid) end, get_player=function(self) return entities.get_player(self.eid) end,
set_enabled=function(self, name, flag)
local comp = self.components[name]
if comp then
if flag then
if comp.__disabled and comp.on_enable then
comp.on_enable()
end
comp.__disabled = nil
else
if not comp.__disabled and comp.on_disable then
comp.on_disable()
end
comp.__disabled = true
end
end
end,
}} }}
local entities = {} local entities = {}
@@ -99,7 +115,7 @@ return {
end end
for _, component in pairs(entity.components) do for _, component in pairs(entity.components) do
local callback = component.on_update local callback = component.on_update
if callback then if not component.__disabled and callback then
local result, err = pcall(callback, tps) local result, err = pcall(callback, tps)
if err then if err then
debug.error(err) debug.error(err)
@@ -113,7 +129,7 @@ return {
for _,entity in pairs(entities) do for _,entity in pairs(entities) do
for _, component in pairs(entity.components) do for _, component in pairs(entity.components) do
local callback = component.on_render local callback = component.on_render
if callback then if not component.__disabled and callback then
local result, err = pcall(callback, delta) local result, err = pcall(callback, delta)
if err then if err then
debug.error(err) debug.error(err)
@@ -132,5 +148,8 @@ return {
end end
return values return values
end end
end,
__reset = function()
entities = {}
end end
} }
+22 -7
View File
@@ -37,7 +37,10 @@ local function complete_app_lib(app)
app.tick = coroutine.yield app.tick = coroutine.yield
app.get_version = core.get_version app.get_version = core.get_version
app.get_setting_info = core.get_setting_info app.get_setting_info = core.get_setting_info
app.load_content = core.load_content app.load_content = function()
core.load_content()
app.tick()
end
app.reset_content = core.reset_content app.reset_content = core.reset_content
app.is_content_loaded = core.is_content_loaded app.is_content_loaded = core.is_content_loaded
@@ -191,8 +194,8 @@ function gui.template(name, params)
text = text:gsub("if%s*=%s*'%%{%w+}'", "if=''") text = text:gsub("if%s*=%s*'%%{%w+}'", "if=''")
text = text:gsub("if%s*=%s*\"%%{%w+}\"", "if=\"\"") text = text:gsub("if%s*=%s*\"%%{%w+}\"", "if=\"\"")
-- remove unsolved properties: attr='%{var}' -- remove unsolved properties: attr='%{var}'
text = text:gsub("%w+%s*=%s*'%%{%w+}'%s?", "") text = text:gsub("%s*%S+='%%{[^}]+}'%s*", " ")
text = text:gsub("%w+%s*=%s*\"%%{%w+}\"%s?", "") text = text:gsub('%s*%S+="%%{[^}]+}"%s*', " ")
return text return text
end end
@@ -343,8 +346,8 @@ function __vc_on_hud_open()
end) end)
end) end)
input.add_callback("key:escape", function() input.add_callback("key:escape", function()
if hud.is_paused() then if menu.page ~= "" then
hud.resume() menu:reset()
elseif hud.is_inventory_open() then elseif hud.is_inventory_open() then
hud.close_inventory() hud.close_inventory()
else else
@@ -375,7 +378,8 @@ end
function __vc_on_world_quit() function __vc_on_world_quit()
_rules.clear() _rules.clear()
gui_util:reset_local() gui_util:__reset_local()
stdcomp.__reset()
end end
local __vc_coroutines = {} local __vc_coroutines = {}
@@ -415,7 +419,18 @@ end
function start_coroutine(chunk, name) function start_coroutine(chunk, name)
local co = coroutine.create(function() local co = coroutine.create(function()
local status, error = xpcall(chunk, __vc__error) local status, error = xpcall(chunk, function(...)
gui.alert(debug.traceback(), function()
if world.is_open() then
__vc_app.close_world()
else
__vc_app.reset_content()
menu:reset()
menu.page = "main"
end
end)
return ...
end)
if not status then if not status then
debug.error(error) debug.error(error)
end end
+24 -5
View File
@@ -9,19 +9,21 @@
#include "AL/ALAudio.hpp" #include "AL/ALAudio.hpp"
#include "NoAudio.hpp" #include "NoAudio.hpp"
#include "debug/Logger.hpp" #include "debug/Logger.hpp"
#include "util/ObjectsKeeper.hpp"
static debug::Logger logger("audio"); static debug::Logger logger("audio");
namespace audio { using namespace audio;
namespace {
static speakerid_t nextId = 1; static speakerid_t nextId = 1;
static Backend* backend; static Backend* backend;
static std::unordered_map<speakerid_t, std::unique_ptr<Speaker>> speakers; static std::unordered_map<speakerid_t, std::unique_ptr<Speaker>> speakers;
static std::unordered_map<speakerid_t, std::shared_ptr<Stream>> streams; static std::unordered_map<speakerid_t, std::shared_ptr<Stream>> streams;
static std::vector<std::unique_ptr<Channel>> channels; static std::vector<std::unique_ptr<Channel>> channels;
static util::ObjectsKeeper objects_keeper {};
} }
using namespace audio;
Channel::Channel(std::string name) : name(std::move(name)) { Channel::Channel(std::string name) : name(std::move(name)) {
} }
@@ -148,7 +150,8 @@ public:
} }
}; };
void audio::initialize(bool enabled) { void audio::initialize(bool enabled, AudioSettings& settings) {
enabled = enabled && settings.enabled.get();
if (enabled) { if (enabled) {
logger.info() << "initializing ALAudio backend"; logger.info() << "initializing ALAudio backend";
backend = ALAudio::create().release(); backend = ALAudio::create().release();
@@ -160,7 +163,22 @@ void audio::initialize(bool enabled) {
logger.info() << "initializing NoAudio backend"; logger.info() << "initializing NoAudio backend";
backend = NoAudio::create().release(); backend = NoAudio::create().release();
} }
create_channel("master"); struct {
std::string name;
NumberSetting* setting;
} builtin_channels[] {
{"master", &settings.volumeMaster},
{"regular", &settings.volumeRegular},
{"music", &settings.volumeMusic},
{"ambient", &settings.volumeAmbient},
{"ui", &settings.volumeUI}
};
for (auto& channel : builtin_channels) {
create_channel(channel.name);
objects_keeper.keepAlive(channel.setting->observe([=](auto value) {
audio::get_channel(channel.name)->setVolume(value * value);
}, true));
}
} }
std::unique_ptr<PCM> audio::load_PCM(const fs::path& file, bool headerOnly) { std::unique_ptr<PCM> audio::load_PCM(const fs::path& file, bool headerOnly) {
@@ -442,4 +460,5 @@ void audio::close() {
speakers.clear(); speakers.clear();
delete backend; delete backend;
backend = nullptr; backend = nullptr;
objects_keeper.clearKeepedObjects();
} }
+2 -1
View File
@@ -6,6 +6,7 @@
#include <vector> #include <vector>
#include "typedefs.hpp" #include "typedefs.hpp"
#include "settings.hpp"
namespace fs = std::filesystem; namespace fs = std::filesystem;
@@ -357,7 +358,7 @@ namespace audio {
/// @brief Initialize audio system or use no audio mode /// @brief Initialize audio system or use no audio mode
/// @param enabled try to initialize actual audio /// @param enabled try to initialize actual audio
void initialize(bool enabled); void initialize(bool enabled, AudioSettings& settings);
/// @brief Load audio file info and PCM data /// @brief Load audio file info and PCM data
/// @param file audio file /// @param file audio file
+1
View File
@@ -27,6 +27,7 @@ inline constexpr blockid_t BLOCK_OBSTACLE = 1;
inline constexpr blockid_t BLOCK_STRUCT_AIR = 2; inline constexpr blockid_t BLOCK_STRUCT_AIR = 2;
inline constexpr itemid_t ITEM_EMPTY = 0; inline constexpr itemid_t ITEM_EMPTY = 0;
inline constexpr entityid_t ENTITY_NONE = 0; inline constexpr entityid_t ENTITY_NONE = 0;
inline constexpr entityid_t ENTITY_AUTO = std::numeric_limits<entityid_t>::max();
inline constexpr int CHUNK_W = 16; inline constexpr int CHUNK_W = 16;
inline constexpr int CHUNK_H = 256; inline constexpr int CHUNK_H = 256;
+3
View File
@@ -104,6 +104,9 @@ namespace dv {
} }
boolean_t value::asBoolean() const { boolean_t value::asBoolean() const {
if (type == value_type::none) {
return false;
}
check_type(type, value_type::boolean); check_type(type, value_type::boolean);
return val.boolean; return val.boolean;
} }
+26 -25
View File
@@ -52,15 +52,6 @@ static debug::Logger logger("engine");
namespace fs = std::filesystem; namespace fs = std::filesystem;
static void create_channel(Engine* engine, std::string name, NumberSetting& setting) {
if (name != "master") {
audio::create_channel(name);
}
engine->keepAlive(setting.observe([=](auto value) {
audio::get_channel(name)->setVolume(value*value);
}, true));
}
static std::unique_ptr<ImageData> load_icon(const fs::path& resdir) { static std::unique_ptr<ImageData> load_icon(const fs::path& resdir) {
try { try {
auto file = resdir / fs::u8path("textures/misc/icon.png"); auto file = resdir / fs::u8path("textures/misc/icon.png");
@@ -73,12 +64,23 @@ static std::unique_ptr<ImageData> load_icon(const fs::path& resdir) {
return nullptr; return nullptr;
} }
Engine::Engine(CoreParameters coreParameters) Engine::Engine() = default;
: params(std::move(coreParameters)),
settings(), static std::unique_ptr<Engine> engine;
settingsHandler({settings}),
interpreter(std::make_unique<cmd::CommandsInterpreter>()), Engine& Engine::getInstance() {
network(network::Network::create(settings.network)) { if (!engine) {
engine = std::make_unique<Engine>();
}
return *engine;
}
void Engine::initialize(CoreParameters coreParameters) {
params = std::move(coreParameters);
settingsHandler = std::make_unique<SettingsHandler>(settings);
interpreter = std::make_unique<cmd::CommandsInterpreter>();
network = network::Network::create(settings.network);
logger.info() << "engine version: " << ENGINE_VERSION_STRING; logger.info() << "engine version: " << ENGINE_VERSION_STRING;
if (params.headless) { if (params.headless) {
logger.info() << "headless mode is enabled"; logger.info() << "headless mode is enabled";
@@ -110,12 +112,7 @@ Engine::Engine(CoreParameters coreParameters)
menus::create_version_label(*this); menus::create_version_label(*this);
} }
} }
audio::initialize(settings.audio.enabled.get() && !params.headless); audio::initialize(!params.headless, settings.audio);
create_channel(this, "master", settings.audio.volumeMaster);
create_channel(this, "regular", settings.audio.volumeRegular);
create_channel(this, "music", settings.audio.volumeMusic);
create_channel(this, "ambient", settings.audio.volumeAmbient);
create_channel(this, "ui", settings.audio.volumeUI);
bool langNotSet = settings.ui.language.get() == "auto"; bool langNotSet = settings.ui.language.get() == "auto";
if (langNotSet) { if (langNotSet) {
@@ -140,7 +137,7 @@ void Engine::loadSettings() {
logger.info() << "loading settings"; logger.info() << "loading settings";
std::string text = files::read_string(settings_file); std::string text = files::read_string(settings_file);
try { try {
toml::parse(settingsHandler, settings_file.string(), text); toml::parse(*settingsHandler, settings_file.string(), text);
} catch (const parsing_error& err) { } catch (const parsing_error& err) {
logger.error() << err.errorLog(); logger.error() << err.errorLog();
throw; throw;
@@ -199,6 +196,7 @@ void Engine::updateFrontend() {
audio::update(delta); audio::update(delta);
gui->act(delta, Viewport(Window::width, Window::height)); gui->act(delta, Viewport(Window::width, Window::height));
screen->update(delta); screen->update(delta);
gui->postAct();
} }
void Engine::nextFrame() { void Engine::nextFrame() {
@@ -217,12 +215,11 @@ void Engine::renderFrame() {
Viewport viewport(Window::width, Window::height); Viewport viewport(Window::width, Window::height);
DrawContext ctx(nullptr, viewport, nullptr); DrawContext ctx(nullptr, viewport, nullptr);
gui->draw(ctx, *assets); gui->draw(ctx, *assets);
gui->postAct();
} }
void Engine::saveSettings() { void Engine::saveSettings() {
logger.info() << "saving settings"; logger.info() << "saving settings";
files::write_string(paths.getSettingsFile(), toml::stringify(settingsHandler)); files::write_string(paths.getSettingsFile(), toml::stringify(*settingsHandler));
if (!params.headless) { if (!params.headless) {
logger.info() << "saving bindings"; logger.info() << "saving bindings";
files::write_string(paths.getControlsFile(), Events::writeBindings()); files::write_string(paths.getControlsFile(), Events::writeBindings());
@@ -255,6 +252,10 @@ Engine::~Engine() {
logger.info() << "engine finished"; logger.info() << "engine finished";
} }
void Engine::terminate() {
engine.reset();
}
EngineController* Engine::getController() { EngineController* Engine::getController() {
return controller.get(); return controller.get();
} }
@@ -511,7 +512,7 @@ std::shared_ptr<Screen> Engine::getScreen() {
} }
SettingsHandler& Engine::getSettingsHandler() { SettingsHandler& Engine::getSettingsHandler() {
return settingsHandler; return *settingsHandler;
} }
network::Network& Engine::getNetwork() { network::Network& Engine::getNetwork() {
+8 -2
View File
@@ -58,9 +58,9 @@ using OnWorldOpen = std::function<void(std::unique_ptr<Level>, int64_t)>;
class Engine : public util::ObjectsKeeper { class Engine : public util::ObjectsKeeper {
CoreParameters params; CoreParameters params;
EngineSettings settings; EngineSettings settings;
SettingsHandler settingsHandler;
EnginePaths paths; EnginePaths paths;
std::unique_ptr<SettingsHandler> settingsHandler;
std::unique_ptr<Assets> assets; std::unique_ptr<Assets> assets;
std::shared_ptr<Screen> screen; std::shared_ptr<Screen> screen;
std::vector<ContentPack> contentPacks; std::vector<ContentPack> contentPacks;
@@ -82,9 +82,15 @@ class Engine : public util::ObjectsKeeper {
void updateHotkeys(); void updateHotkeys();
void loadAssets(); void loadAssets();
public: public:
Engine(CoreParameters coreParameters); Engine();
~Engine(); ~Engine();
static Engine& getInstance();
void initialize(CoreParameters coreParameters);
static void terminate();
/// @brief Start the engine /// @brief Start the engine
void run(); void run();
+3 -1
View File
@@ -117,7 +117,9 @@ void LevelScreen::initializePack(ContentPackRuntime* pack) {
} }
LevelScreen::~LevelScreen() { LevelScreen::~LevelScreen() {
saveWorldPreview(); if (!controller->getLevel()->getWorld()->isNameless()) {
saveWorldPreview();
}
scripting::on_frontend_close(); scripting::on_frontend_close();
// unblock all bindings // unblock all bindings
Events::enableBindings(); Events::enableBindings();
+3 -3
View File
@@ -9,7 +9,7 @@
#include "lighting/Lightmap.hpp" #include "lighting/Lightmap.hpp"
#include "frontend/ContentGfxCache.hpp" #include "frontend/ContentGfxCache.hpp"
const glm::vec3 BlocksRenderer::SUN_VECTOR (0.411934f, 0.863868f, -0.279161f); const glm::vec3 BlocksRenderer::SUN_VECTOR (0.2275f,0.9388f,-0.1005f);
BlocksRenderer::BlocksRenderer( BlocksRenderer::BlocksRenderer(
size_t capacity, size_t capacity,
@@ -129,7 +129,7 @@ void BlocksRenderer::faceAO(
float s = 0.5f; float s = 0.5f;
if (lights) { if (lights) {
float d = glm::dot(glm::normalize(Z), SUN_VECTOR); float d = glm::dot(glm::normalize(Z), SUN_VECTOR);
d = 0.8f + d * 0.2f; d = 0.7f + d * 0.3f;
auto axisX = glm::normalize(X); auto axisX = glm::normalize(X);
auto axisY = glm::normalize(Y); auto axisY = glm::normalize(Y);
@@ -167,7 +167,7 @@ void BlocksRenderer::face(
float s = 0.5f; float s = 0.5f;
if (lights) { if (lights) {
float d = glm::dot(glm::normalize(Z), SUN_VECTOR); float d = glm::dot(glm::normalize(Z), SUN_VECTOR);
d = 0.8f + d * 0.2f; d = 0.7f + d * 0.3f;
tint *= d; tint *= d;
} }
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint); vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint);
+1 -1
View File
@@ -202,7 +202,7 @@ void GUI::act(float delta, const Viewport& vp) {
void GUI::postAct() { void GUI::postAct() {
while (!postRunnables.empty()) { while (!postRunnables.empty()) {
runnable callback = postRunnables.back(); runnable callback = postRunnables.front();
postRunnables.pop(); postRunnables.pop();
callback(); callback();
} }
+1
View File
@@ -53,6 +53,7 @@ void Panel::cropToContent() {
void Panel::fullRefresh() { void Panel::fullRefresh() {
refresh(); refresh();
cropToContent(); cropToContent();
reposition();
Container::fullRefresh(); Container::fullRefresh();
} }
+1 -1
View File
@@ -826,7 +826,7 @@ void TextBox::setCaret(size_t position) {
scrolled(-glm::ceil(offset/static_cast<double>(scrollStep)+0.5f)); scrolled(-glm::ceil(offset/static_cast<double>(scrollStep)+0.5f));
} }
uint lcaret = caret - label->getTextLineOffset(line); uint lcaret = caret - label->getTextLineOffset(line);
int realoffset = font->calcWidth(input, lcaret)-int(textOffset)+2; int realoffset = font->calcWidth(input, lcaret)-int(textOffset) - padding.x;
if (realoffset-width > 0) { if (realoffset-width > 0) {
setTextOffset(textOffset + realoffset-width); setTextOffset(textOffset + realoffset-width);
} else if (realoffset < 0) { } else if (realoffset < 0) {
+10 -9
View File
@@ -34,13 +34,14 @@ void guiutil::alert(
auto panel = std::make_shared<Panel>(glm::vec2(500, 300), glm::vec4(4.0f), 4.0f); auto panel = std::make_shared<Panel>(glm::vec2(500, 300), glm::vec4(4.0f), 4.0f);
panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f)); panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f));
auto menu = engine.getGUI()->getMenu(); auto menuPtr = engine.getGUI()->getMenu();
runnable on_hidden_final = [on_hidden, menu, &engine]() { auto& menu = *menuPtr;
menu->removePage("<alert>"); runnable on_hidden_final = [on_hidden, &menu, &engine]() {
menu.removePage("<alert>");
if (on_hidden) { if (on_hidden) {
on_hidden(); on_hidden();
} else { } else {
menu->back(); menu.back();
} }
}; };
@@ -50,21 +51,21 @@ void guiutil::alert(
panel->add(label); panel->add(label);
panel->add(std::make_shared<Button>( panel->add(std::make_shared<Button>(
langs::get(L"Ok"), glm::vec4(10.f), langs::get(L"Ok"), glm::vec4(10.f),
[=](GUI*) { [on_hidden_final](GUI*) {
on_hidden_final(); on_hidden_final();
} }
)); ));
panel->refresh(); panel->refresh();
panel->keepAlive(Events::keyCallbacks[keycode::ENTER].add([=](){ panel->keepAlive(Events::keyCallbacks[keycode::ENTER].add([on_hidden_final](){
on_hidden_final(); on_hidden_final();
return true; return true;
})); }));
panel->keepAlive(Events::keyCallbacks[keycode::ESCAPE].add([=](){ panel->keepAlive(Events::keyCallbacks[keycode::ESCAPE].add([on_hidden_final](){
on_hidden_final(); on_hidden_final();
return true; return true;
})); }));
menu->addPage("<alert>", panel, true); menu.addPage("<alert>", panel, true);
menu->setPage("<alert>"); menu.setPage("<alert>");
} }
void guiutil::confirm( void guiutil::confirm(
+80 -56
View File
@@ -82,8 +82,8 @@ static onaction create_action(
return [callback](GUI*) {callback();}; return [callback](GUI*) {callback();};
} }
/* Read basic UINode properties */ /// @brief Read basic UINode properties
static void _readUINode( static void read_uinode(
const UiXmlReader& reader, const xml::xmlelement& element, UINode& node const UiXmlReader& reader, const xml::xmlelement& element, UINode& node
) { ) {
if (element.has("id")) { if (element.has("id")) {
@@ -177,8 +177,8 @@ static void _readUINode(
} }
} }
static void _readContainer(UiXmlReader& reader, const xml::xmlelement& element, Container& container) { static void read_container_impl(UiXmlReader& reader, const xml::xmlelement& element, Container& container) {
_readUINode(reader, element, container); read_uinode(reader, element, container);
if (element.has("scrollable")) { if (element.has("scrollable")) {
container.setScrollable(element.attr("scrollable").asBool()); container.setScrollable(element.attr("scrollable").asBool());
@@ -197,17 +197,22 @@ static void _readContainer(UiXmlReader& reader, const xml::xmlelement& element,
} }
void UiXmlReader::readUINode(UiXmlReader& reader, const xml::xmlelement& element, Container& container) { void UiXmlReader::readUINode(UiXmlReader& reader, const xml::xmlelement& element, Container& container) {
_readContainer(reader, element, container); read_container_impl(reader, element, container);
} }
void UiXmlReader::readUINode( void UiXmlReader::readUINode(
const UiXmlReader& reader, const xml::xmlelement& element, UINode& node const UiXmlReader& reader, const xml::xmlelement& element, UINode& node
) { ) {
_readUINode(reader, element, node); read_uinode(reader, element, node);
} }
static void _readPanel(UiXmlReader& reader, const xml::xmlelement& element, Panel& panel, bool subnodes=true) { static void read_panel_impl(
_readUINode(reader, element, panel); UiXmlReader& reader,
const xml::xmlelement& element,
Panel& panel,
bool subnodes = true
) {
read_uinode(reader, element, panel);
if (element.has("padding")) { if (element.has("padding")) {
glm::vec4 padding = element.attr("padding").asVec4(); glm::vec4 padding = element.attr("padding").asVec4();
@@ -245,7 +250,9 @@ static void _readPanel(UiXmlReader& reader, const xml::xmlelement& element, Pane
} }
} }
static std::wstring readAndProcessInnerText(const xml::xmlelement& element, const std::string& context) { static std::wstring parse_inner_text(
const xml::xmlelement& element, const std::string& context
) {
std::wstring text = L""; std::wstring text = L"";
if (element.size() == 1) { if (element.size() == 1) {
std::string source = element.sub(0).attr("#").getText(); std::string source = element.sub(0).attr("#").getText();
@@ -265,9 +272,9 @@ static std::wstring readAndProcessInnerText(const xml::xmlelement& element, cons
static std::shared_ptr<UINode> readLabel( static std::shared_ptr<UINode> readLabel(
const UiXmlReader& reader, const xml::xmlelement& element const UiXmlReader& reader, const xml::xmlelement& element
) { ) {
std::wstring text = readAndProcessInnerText(element, reader.getContext()); std::wstring text = parse_inner_text(element, reader.getContext());
auto label = std::make_shared<Label>(text); auto label = std::make_shared<Label>(text);
_readUINode(reader, element, *label); read_uinode(reader, element, *label);
if (element.has("valign")) { if (element.has("valign")) {
label->setVerticalAlign( label->setVerticalAlign(
align_from_string(element.attr("valign").getText(), label->getVerticalAlign()) align_from_string(element.attr("valign").getText(), label->getVerticalAlign())
@@ -298,20 +305,26 @@ static std::shared_ptr<UINode> readLabel(
return label; return label;
} }
static std::shared_ptr<UINode> readContainer(UiXmlReader& reader, const xml::xmlelement& element) { static std::shared_ptr<UINode> read_container(
UiXmlReader& reader, const xml::xmlelement& element
) {
auto container = std::make_shared<Container>(glm::vec2()); auto container = std::make_shared<Container>(glm::vec2());
_readContainer(reader, element, *container); read_container_impl(reader, element, *container);
return container; return container;
} }
static std::shared_ptr<UINode> readPanel(UiXmlReader& reader, const xml::xmlelement& element) { static std::shared_ptr<UINode> read_panel(
UiXmlReader& reader, const xml::xmlelement& element
) {
float interval = element.attr("interval", "2").asFloat(); float interval = element.attr("interval", "2").asFloat();
auto panel = std::make_shared<Panel>(glm::vec2(), glm::vec4(), interval); auto panel = std::make_shared<Panel>(glm::vec2(), glm::vec4(), interval);
_readPanel(reader, element, *panel); read_panel_impl(reader, element, *panel);
return panel; return panel;
} }
static std::shared_ptr<UINode> readButton(UiXmlReader& reader, const xml::xmlelement& element) { static std::shared_ptr<UINode> read_button(
UiXmlReader& reader, const xml::xmlelement& element
) {
glm::vec4 padding = element.attr("padding", "10").asVec4(); glm::vec4 padding = element.attr("padding", "10").asVec4();
std::shared_ptr<Button> button; std::shared_ptr<Button> button;
@@ -323,11 +336,11 @@ static std::shared_ptr<UINode> readButton(UiXmlReader& reader, const xml::xmlele
} else { } else {
button = std::make_shared<Button>(L"", padding, nullptr); button = std::make_shared<Button>(L"", padding, nullptr);
} }
_readPanel(reader, element, *button, false); read_panel_impl(reader, element, *button, false);
} else { } else {
std::wstring text = readAndProcessInnerText(element, reader.getContext()); std::wstring text = parse_inner_text(element, reader.getContext());
button = std::make_shared<Button>(text, padding, nullptr); button = std::make_shared<Button>(text, padding, nullptr);
_readPanel(reader, element, *button, true); read_panel_impl(reader, element, *button, true);
} }
if (element.has("text-align")) { if (element.has("text-align")) {
button->setTextAlign(align_from_string( button->setTextAlign(align_from_string(
@@ -337,11 +350,13 @@ static std::shared_ptr<UINode> readButton(UiXmlReader& reader, const xml::xmlele
return button; return button;
} }
static std::shared_ptr<UINode> readCheckBox(UiXmlReader& reader, const xml::xmlelement& element) { static std::shared_ptr<UINode> read_check_box(
auto text = readAndProcessInnerText(element, reader.getContext()); UiXmlReader& reader, const xml::xmlelement& element
) {
auto text = parse_inner_text(element, reader.getContext());
bool checked = element.attr("checked", "false").asBool(); bool checked = element.attr("checked", "false").asBool();
auto checkbox = std::make_shared<FullCheckBox>(text, glm::vec2(32), checked); auto checkbox = std::make_shared<FullCheckBox>(text, glm::vec2(32), checked);
_readPanel(reader, element, *checkbox); read_panel_impl(reader, element, *checkbox);
if (element.has("consumer")) { if (element.has("consumer")) {
checkbox->setConsumer(scripting::create_bool_consumer( checkbox->setConsumer(scripting::create_bool_consumer(
@@ -361,14 +376,16 @@ static std::shared_ptr<UINode> readCheckBox(UiXmlReader& reader, const xml::xmle
return checkbox; return checkbox;
} }
static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, const xml::xmlelement& element) { static std::shared_ptr<UINode> read_text_box(
UiXmlReader& reader, const xml::xmlelement& element
) {
auto placeholder = util::str2wstr_utf8(element.attr("placeholder", "").getText()); auto placeholder = util::str2wstr_utf8(element.attr("placeholder", "").getText());
auto hint = util::str2wstr_utf8(element.attr("hint", "").getText()); auto hint = util::str2wstr_utf8(element.attr("hint", "").getText());
auto text = readAndProcessInnerText(element, reader.getContext()); auto text = parse_inner_text(element, reader.getContext());
auto textbox = std::make_shared<TextBox>(placeholder, glm::vec4(0.0f)); auto textbox = std::make_shared<TextBox>(placeholder, glm::vec4(0.0f));
textbox->setHint(hint); textbox->setHint(hint);
_readContainer(reader, element, *textbox); read_container_impl(reader, element, *textbox);
if (element.has("padding")) { if (element.has("padding")) {
glm::vec4 padding = element.attr("padding").asVec4(); glm::vec4 padding = element.attr("padding").asVec4();
textbox->setPadding(padding); textbox->setPadding(padding);
@@ -447,16 +464,16 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, const xml::xmlel
return textbox; return textbox;
} }
static std::shared_ptr<UINode> readImage( static std::shared_ptr<UINode> read_image(
const UiXmlReader& reader, const xml::xmlelement& element const UiXmlReader& reader, const xml::xmlelement& element
) { ) {
std::string src = element.attr("src", "").getText(); std::string src = element.attr("src", "").getText();
auto image = std::make_shared<Image>(src); auto image = std::make_shared<Image>(src);
_readUINode(reader, element, *image); read_uinode(reader, element, *image);
return image; return image;
} }
static std::shared_ptr<UINode> readCanvas( static std::shared_ptr<UINode> read_canvas(
const UiXmlReader& reader, const xml::xmlelement& element const UiXmlReader& reader, const xml::xmlelement& element
) { ) {
auto size = glm::uvec2{32, 32}; auto size = glm::uvec2{32, 32};
@@ -464,11 +481,11 @@ static std::shared_ptr<UINode> readCanvas(
size = element.attr("size").asVec2(); size = element.attr("size").asVec2();
} }
auto image = std::make_shared<Canvas>(ImageFormat::rgba8888, size); auto image = std::make_shared<Canvas>(ImageFormat::rgba8888, size);
_readUINode(reader, element, *image); read_uinode(reader, element, *image);
return image; return image;
} }
static std::shared_ptr<UINode> readTrackBar( static std::shared_ptr<UINode> read_track_bar(
const UiXmlReader& reader, const xml::xmlelement& element const UiXmlReader& reader, const xml::xmlelement& element
) { ) {
const auto& env = reader.getEnvironment(); const auto& env = reader.getEnvironment();
@@ -479,7 +496,7 @@ static std::shared_ptr<UINode> readTrackBar(
float step = element.attr("step", "1.0").asFloat(); float step = element.attr("step", "1.0").asFloat();
int trackWidth = element.attr("track-width", "12").asInt(); int trackWidth = element.attr("track-width", "12").asInt();
auto bar = std::make_shared<TrackBar>(minv, maxv, def, step, trackWidth); auto bar = std::make_shared<TrackBar>(minv, maxv, def, step, trackWidth);
_readUINode(reader, element, *bar); read_uinode(reader, element, *bar);
if (element.has("consumer")) { if (element.has("consumer")) {
bar->setConsumer(scripting::create_number_consumer( bar->setConsumer(scripting::create_number_consumer(
env, element.attr("consumer").getText(), file)); env, element.attr("consumer").getText(), file));
@@ -501,7 +518,9 @@ static std::shared_ptr<UINode> readTrackBar(
return bar; return bar;
} }
static std::shared_ptr<UINode> readInputBindBox(UiXmlReader& reader, const xml::xmlelement& element) { static std::shared_ptr<UINode> read_input_bind_box(
UiXmlReader& reader, const xml::xmlelement& element
) {
auto bindname = element.attr("binding").getText(); auto bindname = element.attr("binding").getText();
auto found = Events::bindings.find(bindname); auto found = Events::bindings.find(bindname);
if (found == Events::bindings.end()) { if (found == Events::bindings.end()) {
@@ -509,12 +528,12 @@ static std::shared_ptr<UINode> readInputBindBox(UiXmlReader& reader, const xml::
} }
glm::vec4 padding = element.attr("padding", "6").asVec4(); glm::vec4 padding = element.attr("padding", "6").asVec4();
auto bindbox = std::make_shared<InputBindBox>(found->second, padding); auto bindbox = std::make_shared<InputBindBox>(found->second, padding);
_readPanel(reader, element, *bindbox); read_panel_impl(reader, element, *bindbox);
return bindbox; return bindbox;
} }
static slotcallback readSlotFunc( static slotcallback read_slot_func(
InventoryView* view, InventoryView* view,
const UiXmlReader& reader, const UiXmlReader& reader,
const xml::xmlelement& element, const xml::xmlelement& element,
@@ -542,13 +561,13 @@ static void readSlot(
layout.position = element.attr("pos").asVec2(); layout.position = element.attr("pos").asVec2();
} }
if (element.has("updatefunc")) { if (element.has("updatefunc")) {
layout.updateFunc = readSlotFunc(view, reader, element, "updatefunc"); layout.updateFunc = read_slot_func(view, reader, element, "updatefunc");
} }
if (element.has("sharefunc")) { if (element.has("sharefunc")) {
layout.shareFunc = readSlotFunc(view, reader, element, "sharefunc"); layout.shareFunc = read_slot_func(view, reader, element, "sharefunc");
} }
if (element.has("onrightclick")) { if (element.has("onrightclick")) {
layout.rightClick = readSlotFunc(view, reader, element, "onrightclick"); layout.rightClick = read_slot_func(view, reader, element, "onrightclick");
} }
layout.taking = taking; layout.taking = taking;
layout.placing = placing; layout.placing = placing;
@@ -588,13 +607,13 @@ static void readSlotsGrid(
layout.position = element.attr("pos").asVec2(); layout.position = element.attr("pos").asVec2();
} }
if (element.has("updatefunc")) { if (element.has("updatefunc")) {
layout.updateFunc = readSlotFunc(view, reader, element, "updatefunc"); layout.updateFunc = read_slot_func(view, reader, element, "updatefunc");
} }
if (element.has("sharefunc")) { if (element.has("sharefunc")) {
layout.shareFunc = readSlotFunc(view, reader, element, "sharefunc"); layout.shareFunc = read_slot_func(view, reader, element, "sharefunc");
} }
if (element.has("onrightclick")) { if (element.has("onrightclick")) {
layout.rightClick = readSlotFunc(view, reader, element, "onrightclick"); layout.rightClick = read_slot_func(view, reader, element, "onrightclick");
} }
layout.padding = padding; layout.padding = padding;
layout.taking = taking; layout.taking = taking;
@@ -618,7 +637,9 @@ static void readSlotsGrid(
} }
} }
static std::shared_ptr<UINode> readInventory(UiXmlReader& reader, const xml::xmlelement& element) { static std::shared_ptr<UINode> read_inventory(
UiXmlReader& reader, const xml::xmlelement& element
) {
auto view = std::make_shared<InventoryView>(); auto view = std::make_shared<InventoryView>();
view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f)); // todo: fixme view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f)); // todo: fixme
reader.addIgnore("slot"); reader.addIgnore("slot");
@@ -635,29 +656,32 @@ static std::shared_ptr<UINode> readInventory(UiXmlReader& reader, const xml::xml
return view; return view;
} }
static std::shared_ptr<UINode> readPageBox(UiXmlReader& reader, const xml::xmlelement& element) { static std::shared_ptr<UINode> read_page_box(
UiXmlReader& reader, const xml::xmlelement& element
) {
auto menu = std::make_shared<Menu>(); auto menu = std::make_shared<Menu>();
// FIXME menu->setPageLoader(
menu->setPageLoader(scripting::engine->getGUI()->getMenu()->getPageLoader()); Engine::getInstance().getGUI()->getMenu()->getPageLoader()
_readContainer(reader, element, *menu); );
read_container_impl(reader, element, *menu);
return menu; return menu;
} }
UiXmlReader::UiXmlReader(const scriptenv& env) : env(env) { UiXmlReader::UiXmlReader(const scriptenv& env) : env(env) {
contextStack.emplace(""); contextStack.emplace("");
add("image", readImage); add("image", read_image);
add("canvas", readCanvas); add("canvas", read_canvas);
add("label", readLabel); add("label", readLabel);
add("panel", readPanel); add("panel", read_panel);
add("button", readButton); add("button", read_button);
add("textbox", readTextBox); add("textbox", read_text_box);
add("pagebox", readPageBox); add("pagebox", read_page_box);
add("checkbox", readCheckBox); add("checkbox", read_check_box);
add("trackbar", readTrackBar); add("trackbar", read_track_bar);
add("container", readContainer); add("container", read_container);
add("bindbox", readInputBindBox); add("bindbox", read_input_bind_box);
add("inventory", readInventory); add("inventory", read_inventory);
} }
void UiXmlReader::add(const std::string& tag, uinode_reader reader) { void UiXmlReader::add(const std::string& tag, uinode_reader reader) {
+4 -3
View File
@@ -46,9 +46,10 @@ static glm::vec4 parse_color(const std::basic_string_view<CharT>& color_code) {
template <typename CharT> template <typename CharT>
static inline void apply_color( static inline void apply_color(
const std::basic_string_view<CharT>& color_code, FontStylesScheme& styles const std::basic_string_view<CharT>& color_code,
FontStylesScheme& styles,
FontStyle& style
) { ) {
FontStyle style = styles.palette.back();
style.color = parse_color(color_code); style.color = parse_color(color_code);
styles.palette.push_back(style); styles.palette.push_back(style);
} }
@@ -116,7 +117,7 @@ Result<CharT> process_markdown(
} }
} else if (first == '[' && pos + 9 <= source.size() && source[pos + 1] == '#' && source[pos + 8] == ']') { } else if (first == '[' && pos + 9 <= source.size() && source[pos + 1] == '#' && source[pos + 8] == ']') {
std::basic_string_view<CharT> color_code = source.substr(pos + 1, 8); std::basic_string_view<CharT> color_code = source.substr(pos + 1, 8);
apply_color(color_code, styles); apply_color(color_code, styles, style);
if (!eraseMarkdown) { if (!eraseMarkdown) {
for (int i = 0; i < 9; ++i) { for (int i = 0; i < 9; ++i) {
emit_md(source[pos + i], styles, ss); emit_md(source[pos + i], styles, ss);
+5
View File
@@ -4,6 +4,7 @@
#include "typedefs.hpp" #include "typedefs.hpp"
#include <memory> #include <memory>
#include <cstring>
inline constexpr int LIGHTMAP_DATA_LEN = CHUNK_VOL/2; inline constexpr int LIGHTMAP_DATA_LEN = CHUNK_VOL/2;
@@ -17,6 +18,10 @@ public:
void set(const light_t* map); void set(const light_t* map);
void clear() {
std::memset(map, 0, sizeof(map));
}
inline unsigned short get(int x, int y, int z) const { inline unsigned short get(int x, int y, int z) const {
return (map[y*CHUNK_D*CHUNK_W+z*CHUNK_W+x]); return (map[y*CHUNK_D*CHUNK_W+z*CHUNK_W+x]);
} }
@@ -43,6 +43,11 @@ static int l_execute(lua::State* L) {
} }
} }
static int l_get(lua::State* L) {
auto name = lua::require_string(L, 1);
return lua::pushvalue(L, (*engine->getCommandsInterpreter())[name]);
}
static int l_set(lua::State* L) { static int l_set(lua::State* L) {
auto name = lua::require_string(L, 1); auto name = lua::require_string(L, 1);
auto value = lua::tovalue(L, 2); auto value = lua::tovalue(L, 2);
@@ -119,6 +124,7 @@ static int l_get_command_info(lua::State* L) {
const luaL_Reg consolelib[] = { const luaL_Reg consolelib[] = {
{"add_command", lua::wrap<l_add_command>}, {"add_command", lua::wrap<l_add_command>},
{"execute", lua::wrap<l_execute>}, {"execute", lua::wrap<l_execute>},
{"get", lua::wrap<l_get>},
{"set", lua::wrap<l_set>}, {"set", lua::wrap<l_set>},
{"get_commands_list", lua::wrap<l_get_commands_list>}, {"get_commands_list", lua::wrap<l_get_commands_list>},
{"get_command_info", lua::wrap<l_get_command_info>}, {"get_command_info", lua::wrap<l_get_command_info>},
+7 -1
View File
@@ -148,7 +148,13 @@ static int l_reconfig_packs(lua::State* L) {
lua::pop(L); lua::pop(L);
} }
auto engineController = engine->getController(); auto engineController = engine->getController();
engineController->reconfigPacks(controller, addPacks, remPacks); try {
engineController->reconfigPacks(controller, addPacks, remPacks);
} catch (const contentpack_error& err) {
throw std::runtime_error(
std::string(err.what()) + " [" + err.getPackId() + " ]"
);
}
return 0; return 0;
} }
+7 -1
View File
@@ -231,7 +231,13 @@ static int l_pack_assemble(lua::State* L) {
} }
auto manager = engine->createPacksManager(worldFolder); auto manager = engine->createPacksManager(worldFolder);
manager.scan(); manager.scan();
ids = std::move(manager.assemble(ids)); try {
ids = std::move(manager.assemble(ids));
} catch (const contentpack_error& err) {
throw std::runtime_error(
std::string(err.what()) + " [" + err.getPackId() + "]"
);
}
lua::createtable(L, ids.size(), 0); lua::createtable(L, ids.size(), 0);
for (size_t i = 0; i < ids.size(); i++) { for (size_t i = 0; i < ids.size(); i++) {
+3 -1
View File
@@ -229,7 +229,9 @@ static int l_set_entity(lua::State* L) {
if (player == nullptr) { if (player == nullptr) {
return 0; return 0;
} }
if (auto entity = get_entity(L, 2)) { if (lua::isnumber(L, 2)) {
player->setEntity(lua::tointeger(L, 2));
} else if (auto entity = get_entity(L, 2)) {
player->setEntity(entity->getUID()); player->setEntity(entity->getUID());
} }
return 0; return 0;
+38 -7
View File
@@ -6,6 +6,7 @@
#include "assets/AssetsLoader.hpp" #include "assets/AssetsLoader.hpp"
#include "coders/json.hpp" #include "coders/json.hpp"
#include "engine/Engine.hpp" #include "engine/Engine.hpp"
#include "files/WorldFiles.hpp"
#include "files/engine_paths.hpp" #include "files/engine_paths.hpp"
#include "files/files.hpp" #include "files/files.hpp"
#include "lighting/Lighting.hpp" #include "lighting/Lighting.hpp"
@@ -54,7 +55,7 @@ static int l_get_list(lua::State* L) {
auto assets = engine->getAssets(); auto assets = engine->getAssets();
std::string icon = "world#" + name + ".icon"; std::string icon = "world#" + name + ".icon";
if (!AssetsLoader::loadExternalTexture( if (!engine->isHeadless() && !AssetsLoader::loadExternalTexture(
assets, assets,
icon, icon,
{worlds[i] / fs::path("icon.png"), {worlds[i] / fs::path("icon.png"),
@@ -125,11 +126,21 @@ static int l_get_chunk_data(lua::State* L) {
int x = static_cast<int>(lua::tointeger(L, 1)); int x = static_cast<int>(lua::tointeger(L, 1));
int z = static_cast<int>(lua::tointeger(L, 2)); int z = static_cast<int>(lua::tointeger(L, 2));
const auto& chunk = level->chunks->getChunk(x, z); const auto& chunk = level->chunks->getChunk(x, z);
std::vector<ubyte> chunkData;
if (chunk == nullptr) { if (chunk == nullptr) {
lua::pushnil(L); auto& regions = level->getWorld()->wfile->getRegions();
return 0; auto voxelData = regions.getVoxels(x, z);
if (voxelData == nullptr) {
return 0;
}
static util::Buffer<ubyte> rleBuffer(CHUNK_DATA_LEN * 2);
auto metadata = regions.getBlocksData(x, z);
chunkData =
compressed_chunks::encode(voxelData.get(), metadata, rleBuffer);
} else {
chunkData = compressed_chunks::encode(*chunk);
} }
auto chunkData = compressed_chunks::encode(*chunk);
return lua::newuserdata<lua::LuaBytearray>(L, std::move(chunkData)); return lua::newuserdata<lua::LuaBytearray>(L, std::move(chunkData));
} }
@@ -137,12 +148,12 @@ static void integrate_chunk_client(Chunk& chunk) {
int x = chunk.x; int x = chunk.x;
int z = chunk.z; int z = chunk.z;
auto chunksController = controller->getChunksController(); auto chunksController = controller->getChunksController();
Lighting& lighting = *chunksController->lighting; Lighting& lighting = *chunksController->lighting;
chunk.flags.loadedLights = false; chunk.flags.loadedLights = false;
chunk.flags.lighted = false; chunk.flags.lighted = false;
chunk.lightmap.clear();
Lighting::prebuildSkyLight(chunk, *indices); Lighting::prebuildSkyLight(chunk, *indices);
lighting.onChunkLoaded(x, z, true);
for (int lz = -1; lz <= 1; lz++) { for (int lz = -1; lz <= 1; lz++) {
for (int lx = -1; lx <= 1; lx++) { for (int lx = -1; lx <= 1; lx++) {
@@ -151,16 +162,20 @@ static void integrate_chunk_client(Chunk& chunk) {
} }
if (auto other = level->chunks->getChunk(x + lx, z + lz)) { if (auto other = level->chunks->getChunk(x + lx, z + lz)) {
other->flags.modified = true; other->flags.modified = true;
lighting.onChunkLoaded(x - 1, z, true);
} }
} }
} }
} }
static int l_set_chunk_data(lua::State* L) { static int l_set_chunk_data(lua::State* L) {
if (level == nullptr) {
throw std::runtime_error("no open world");
}
int x = static_cast<int>(lua::tointeger(L, 1)); int x = static_cast<int>(lua::tointeger(L, 1));
int z = static_cast<int>(lua::tointeger(L, 2)); int z = static_cast<int>(lua::tointeger(L, 2));
auto buffer = lua::require_bytearray(L, 3); auto buffer = lua::require_bytearray(L, 3);
auto chunk = level->chunks->getChunk(x, z); auto chunk = level->chunks->getChunk(x, z);
if (chunk == nullptr) { if (chunk == nullptr) {
return lua::pushboolean(L, false); return lua::pushboolean(L, false);
@@ -175,6 +190,21 @@ static int l_set_chunk_data(lua::State* L) {
return lua::pushboolean(L, true); return lua::pushboolean(L, true);
} }
static int l_save_chunk_data(lua::State* L) {
if (level == nullptr) {
throw std::runtime_error("no open world");
}
int x = static_cast<int>(lua::tointeger(L, 1));
int z = static_cast<int>(lua::tointeger(L, 2));
auto buffer = lua::require_bytearray(L, 3);
compressed_chunks::save(
x, z, std::move(buffer), level->getWorld()->wfile->getRegions()
);
return 0;
}
static int l_count_chunks(lua::State* L) { static int l_count_chunks(lua::State* L) {
if (level == nullptr) { if (level == nullptr) {
return 0; return 0;
@@ -197,6 +227,7 @@ const luaL_Reg worldlib[] = {
{"exists", lua::wrap<l_exists>}, {"exists", lua::wrap<l_exists>},
{"get_chunk_data", lua::wrap<l_get_chunk_data>}, {"get_chunk_data", lua::wrap<l_get_chunk_data>},
{"set_chunk_data", lua::wrap<l_set_chunk_data>}, {"set_chunk_data", lua::wrap<l_set_chunk_data>},
{"save_chunk_data", lua::wrap<l_save_chunk_data>},
{"count_chunks", lua::wrap<l_count_chunks>}, {"count_chunks", lua::wrap<l_count_chunks>},
{NULL, NULL} {NULL, NULL}
}; };
+3
View File
@@ -22,6 +22,9 @@ namespace lua {
inline void pop(lua::State* L, int n = 1) { inline void pop(lua::State* L, int n = 1) {
#ifndef NDEBUG #ifndef NDEBUG
if (n < 0) {
abort();
}
if (lua_gettop(L) < n) { if (lua_gettop(L) < n) {
abort(); abort();
} }
+12 -5
View File
@@ -86,7 +86,10 @@ public:
} }
void update() override { void update() override {
if (lua::getglobal(L, "__vc_resume_coroutine")) { if (id == 0) {
return;
}
if (lua::requireglobal(L, "__vc_resume_coroutine")) {
lua::pushinteger(L, id); lua::pushinteger(L, id);
if (lua::call(L, 1)) { if (lua::call(L, 1)) {
alive = lua::toboolean(L, -1); alive = lua::toboolean(L, -1);
@@ -102,10 +105,10 @@ public:
} }
void terminate() override { void terminate() override {
if (lua::getglobal(L, "__vc_stop_coroutine")) { lua::requireglobal(L, "__vc_stop_coroutine");
lua::pushinteger(L, id); lua::pushinteger(L, id);
lua::pop(L, lua::call(L, 1)); lua::pop(L, lua::call(L, 1));
} id = 0;
} }
}; };
@@ -614,6 +617,10 @@ static void process_entity_callback(
) { ) {
auto L = lua::get_main_state(); auto L = lua::get_main_state();
lua::pushenv(L, *env); lua::pushenv(L, *env);
if (lua::hasfield(L, "__disabled")) {
lua::pop(L);
return;
}
if (lua::getfield(L, name)) { if (lua::getfield(L, name)) {
if (args) { if (args) {
lua::call_nothrow(L, args(L), 0); lua::call_nothrow(L, args(L), 0);
+11 -1
View File
@@ -3,11 +3,16 @@
#include "util/command_line.hpp" #include "util/command_line.hpp"
#include "debug/Logger.hpp" #include "debug/Logger.hpp"
#include <csignal>
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
static debug::Logger logger("main"); static debug::Logger logger("main");
static void sigterm_handler(int signum) {
Engine::getInstance().quit();
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
CoreParameters coreParameters; CoreParameters coreParameters;
try { try {
@@ -18,11 +23,15 @@ int main(int argc, char** argv) {
std::cerr << err.what() << std::endl; std::cerr << err.what() << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
std::signal(SIGTERM, sigterm_handler);
debug::Logger::init(coreParameters.userFolder.string()+"/latest.log"); debug::Logger::init(coreParameters.userFolder.string()+"/latest.log");
platform::configure_encoding(); platform::configure_encoding();
auto& engine = Engine::getInstance();
try { try {
Engine(std::move(coreParameters)).run(); engine.initialize(std::move(coreParameters));
engine.run();
} catch (const initialize_error& err) { } catch (const initialize_error& err) {
logger.error() << "could not to initialize engine\n" << err.what(); logger.error() << "could not to initialize engine\n" << err.what();
} }
@@ -33,5 +42,6 @@ int main(int argc, char** argv) {
throw; throw;
} }
#endif #endif
Engine::terminate();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
+3 -3
View File
@@ -62,7 +62,7 @@ Player::Player(
Player::~Player() = default; Player::~Player() = default;
void Player::updateEntity() { void Player::updateEntity() {
if (eid == 0) { if (eid == ENTITY_AUTO) {
auto& def = level.content.entities.require("base:player"); auto& def = level.content.entities.require("base:player");
eid = level.entities->spawn(def, getPosition()); eid = level.entities->spawn(def, getPosition());
if (auto entity = level.entities->get(eid)) { if (auto entity = level.entities->get(eid)) {
@@ -73,10 +73,10 @@ void Player::updateEntity() {
if (auto entity = level.entities->get(eid)) { if (auto entity = level.entities->get(eid)) {
entity->setPlayer(id); entity->setPlayer(id);
} }
} else if (chunks->getChunkByVoxel(position)) { } else if (chunks->getChunkByVoxel(position) && eid != ENTITY_NONE) {
logger.error() << "player entity despawned or deleted; " logger.error() << "player entity despawned or deleted; "
"will be respawned"; "will be respawned";
eid = 0; eid = ENTITY_AUTO;
} }
} }
+1 -1
View File
@@ -54,7 +54,7 @@ class Player : public Serializable {
bool infiniteItems = true; bool infiniteItems = true;
bool instantDestruction = true; bool instantDestruction = true;
bool loadingChunks = true; bool loadingChunks = true;
entityid_t eid; entityid_t eid = ENTITY_AUTO;
entityid_t selectedEid = 0; entityid_t selectedEid = 0;
glm::vec3 rotation {}; glm::vec3 rotation {};
+2 -2
View File
@@ -37,7 +37,7 @@ Player* Players::create(int64_t id) {
glm::vec3(0, DEF_PLAYER_Y, 0), glm::vec3(0, DEF_PLAYER_Y, 0),
DEF_PLAYER_SPEED, DEF_PLAYER_SPEED,
level.inventories->create(DEF_PLAYER_INVENTORY_SIZE), level.inventories->create(DEF_PLAYER_INVENTORY_SIZE),
0 ENTITY_AUTO
); );
auto player = playerPtr.get(); auto player = playerPtr.get();
add(std::move(playerPtr)); add(std::move(playerPtr));
@@ -92,7 +92,7 @@ void Players::deserialize(const dv::value& src) {
glm::vec3(0, DEF_PLAYER_Y, 0), glm::vec3(0, DEF_PLAYER_Y, 0),
DEF_PLAYER_SPEED, DEF_PLAYER_SPEED,
level.inventories->create(DEF_PLAYER_INVENTORY_SIZE), level.inventories->create(DEF_PLAYER_INVENTORY_SIZE),
0 ENTITY_AUTO
); );
auto player = playerPtr.get(); auto player = playerPtr.get();
player->deserialize(playerMap); player->deserialize(playerMap);
+1
View File
@@ -14,6 +14,7 @@
#include "maths/voxmaths.hpp" #include "maths/voxmaths.hpp"
#include <set> #include <set>
#include <algorithm>
#include <stdint.h> #include <stdint.h>
#include <stdexcept> #include <stdexcept>
#include <glm/glm.hpp> #include <glm/glm.hpp>
+54 -18
View File
@@ -2,27 +2,24 @@
#include "coders/rle.hpp" #include "coders/rle.hpp"
#include "coders/gzip.hpp" #include "coders/gzip.hpp"
#include "coders/byte_utils.hpp"
#include "voxels/Chunk.hpp" #include "files/WorldFiles.hpp"
inline constexpr int HAS_VOXELS = 0x1; inline constexpr int HAS_VOXELS = 0x1;
inline constexpr int HAS_METADATA = 0x2; inline constexpr int HAS_METADATA = 0x2;
std::vector<ubyte> compressed_chunks::encode(const Chunk& chunk) { std::vector<ubyte> compressed_chunks::encode(
auto data = chunk.encode(); const ubyte* data,
const BlocksMetadata& metadata,
/// world.get_chunk_data is only available in the main Lua state util::Buffer<ubyte>& rleBuffer
static util::Buffer<ubyte> rleBuffer; ) {
if (rleBuffer.size() < CHUNK_DATA_LEN * 2) {
rleBuffer = util::Buffer<ubyte>(CHUNK_DATA_LEN * 2);
}
size_t rleCompressedSize = size_t rleCompressedSize =
extrle::encode16(data.get(), CHUNK_DATA_LEN, rleBuffer.data()); extrle::encode16(data, CHUNK_DATA_LEN, rleBuffer.data());
const auto gzipCompressedData = gzip::compress( const auto gzipCompressedData = gzip::compress(
rleBuffer.data(), rleCompressedSize rleBuffer.data(), rleCompressedSize
); );
auto metadataBytes = chunk.blocksMetadata.serialize(); auto metadataBytes = metadata.serialize();
ByteBuilder builder(2 + 8 + gzipCompressedData.size() + metadataBytes.size()); ByteBuilder builder(2 + 8 + gzipCompressedData.size() + metadataBytes.size());
builder.put(HAS_VOXELS | HAS_METADATA); // flags builder.put(HAS_VOXELS | HAS_METADATA); // flags
@@ -34,6 +31,23 @@ std::vector<ubyte> compressed_chunks::encode(const Chunk& chunk) {
return builder.build(); return builder.build();
} }
std::vector<ubyte> compressed_chunks::encode(const Chunk& chunk) {
auto data = chunk.encode();
/// world.get_chunk_data is only available in the main Lua state
static util::Buffer<ubyte> rleBuffer(CHUNK_DATA_LEN * 2);
return encode(data.get(), chunk.blocksMetadata, rleBuffer);
}
static void read_voxel_data(ByteReader& reader, util::Buffer<ubyte>& dst) {
size_t gzipCompressedSize = reader.getInt32();
auto rleData = gzip::decompress(reader.pointer(), gzipCompressedSize);
reader.skip(gzipCompressedSize);
extrle::decode16(rleData.data(), rleData.size(), dst.data());
}
void compressed_chunks::decode(Chunk& chunk, const ubyte* src, size_t size) { void compressed_chunks::decode(Chunk& chunk, const ubyte* src, size_t size) {
ByteReader reader(src, size); ByteReader reader(src, size);
@@ -41,14 +55,9 @@ void compressed_chunks::decode(Chunk& chunk, const ubyte* src, size_t size) {
reader.skip(1); // reserved byte reader.skip(1); // reserved byte
if (flags & HAS_VOXELS) { if (flags & HAS_VOXELS) {
size_t gzipCompressedSize = reader.getInt32();
auto rleData = gzip::decompress(reader.pointer(), gzipCompressedSize);
reader.skip(gzipCompressedSize);
/// world.get_chunk_data is only available in the main Lua state /// world.get_chunk_data is only available in the main Lua state
static util::Buffer<ubyte> voxelData (CHUNK_DATA_LEN); static util::Buffer<ubyte> voxelData (CHUNK_DATA_LEN);
extrle::decode16(rleData.data(), rleData.size(), voxelData.data()); read_voxel_data(reader, voxelData);
chunk.decode(voxelData.data()); chunk.decode(voxelData.data());
chunk.updateHeights(); chunk.updateHeights();
} }
@@ -59,3 +68,30 @@ void compressed_chunks::decode(Chunk& chunk, const ubyte* src, size_t size) {
} }
chunk.setModifiedAndUnsaved(); chunk.setModifiedAndUnsaved();
} }
void compressed_chunks::save(
int x, int z, std::vector<ubyte> bytes, WorldRegions& regions
) {
ByteReader reader(bytes.data(), bytes.size());
ubyte flags = reader.get();
reader.skip(1); // reserved byte
if (flags & HAS_VOXELS) {
util::Buffer<ubyte> voxelData (CHUNK_DATA_LEN);
read_voxel_data(reader, voxelData);
regions.put(
x, z, REGION_LAYER_VOXELS, voxelData.release(), CHUNK_DATA_LEN
);
}
if (flags & HAS_METADATA) {
size_t metadataSize = reader.getInt32();
regions.put(
x,
z,
REGION_LAYER_BLOCKS_DATA,
util::Buffer<ubyte>(reader.pointer(), metadataSize).release(),
metadataSize
);
reader.skip(metadataSize);
}
}
+9 -1
View File
@@ -1,12 +1,20 @@
#pragma once #pragma once
#include "typedefs.hpp" #include "typedefs.hpp"
#include "Chunk.hpp"
#include "coders/byte_utils.hpp"
#include <vector> #include <vector>
class Chunk; class WorldRegions;
namespace compressed_chunks { namespace compressed_chunks {
std::vector<ubyte> encode(
const ubyte* voxelData,
const BlocksMetadata& metadata,
util::Buffer<ubyte>& rleBuffer
);
std::vector<ubyte> encode(const Chunk& chunk); std::vector<ubyte> encode(const Chunk& chunk);
void decode(Chunk& chunk, const ubyte* src, size_t size); void decode(Chunk& chunk, const ubyte* src, size_t size);
void save(int x, int z, std::vector<ubyte> bytes, WorldRegions& regions);
} }
+2 -1
View File
@@ -133,11 +133,12 @@ static inline const Biome* choose_biome(
score += glm::abs((params[i] - biome.parameters[i].value) / score += glm::abs((params[i] - biome.parameters[i].value) /
biome.parameters[i].weight); biome.parameters[i].weight);
} }
if (score < chosenScore) { if (score < chosenScore || std::isinf(chosenScore)) {
chosenScore = score; chosenScore = score;
chosenBiome = &biome; chosenBiome = &biome;
} }
} }
assert(chosenBiome != nullptr);
return chosenBiome; return chosenBiome;
} }
+1 -1
View File
@@ -35,7 +35,7 @@ else()
endif() endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie -lstdc++fs") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
endif() endif()
target_include_directories( target_include_directories(