Merge branch 'MihailRis:main' into main
This commit is contained in:
commit
bec7e59e33
2
.github/workflows/appimage.yml
vendored
2
.github/workflows/appimage.yml
vendored
@ -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
|
||||||
|
|||||||
2
.github/workflows/cmake.yml
vendored
2
.github/workflows/cmake.yml
vendored
@ -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 ../..
|
||||||
|
|
||||||
|
|||||||
215
CHANGELOG.md
215
CHANGELOG.md
@ -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)
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -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,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
|
||||||
|
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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,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)
|
|
||||||
|
|
||||||
## Разделы
|
## Разделы
|
||||||
|
|
||||||
|
|||||||
@ -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(...))
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|||||||
@ -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)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Встроенные компоненты
|
## Встроенные компоненты
|
||||||
|
|||||||
5
res/content/base/block_materials/snow.json
Normal file
5
res/content/base/block_materials/snow.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"steps-sound": "steps/snow",
|
||||||
|
"place-sound": "blocks/snow_place",
|
||||||
|
"break-sound": "blocks/snow_break"
|
||||||
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
res/content/base/sounds/blocks/snow_3.ogg
Normal file
BIN
res/content/base/sounds/blocks/snow_3.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/blocks/snow_break.ogg
Normal file
BIN
res/content/base/sounds/blocks/snow_break.ogg
Normal file
Binary file not shown.
BIN
res/content/base/sounds/blocks/snow_place.ogg
Normal file
BIN
res/content/base/sounds/blocks/snow_place.ogg
Normal file
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.
@ -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>
|
||||||
|
|||||||
@ -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)
|
||||||
@ -148,8 +149,6 @@ function submit(text)
|
|||||||
text = text:sub(2)
|
text = text:sub(2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
setup_variables()
|
|
||||||
|
|
||||||
local name
|
local name
|
||||||
for s in text:gmatch("%S+") do
|
for s in text:gmatch("%S+") do
|
||||||
@ -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)
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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() {
|
||||||
|
|||||||
@ -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();
|
||||||
|
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,6 +53,7 @@ void Panel::cropToContent() {
|
|||||||
void Panel::fullRefresh() {
|
void Panel::fullRefresh() {
|
||||||
refresh();
|
refresh();
|
||||||
cropToContent();
|
cropToContent();
|
||||||
|
reposition();
|
||||||
Container::fullRefresh();
|
Container::fullRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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");
|
||||||
@ -633,31 +654,34 @@ 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) {
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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>},
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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++) {
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
14
src/main.cpp
14
src/main.cpp
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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 {};
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user