Merge branch 'headless-mode' into Fix-usage-vcpkg-for-windows-and-add-cmake-preset-for-vscode
This commit is contained in:
@@ -0,0 +1,50 @@
|
|||||||
|
debug.log("check initial state")
|
||||||
|
assert(file.exists("config:"))
|
||||||
|
|
||||||
|
debug.log("write text file")
|
||||||
|
assert(file.write("config:text.txt", "example, пример"))
|
||||||
|
assert(file.exists("config:text.txt"))
|
||||||
|
|
||||||
|
debug.log("read text file")
|
||||||
|
assert(file.read("config:text.txt") == "example, пример")
|
||||||
|
|
||||||
|
debug.log("delete file")
|
||||||
|
file.remove("config:text.txt")
|
||||||
|
assert(not file.exists("config:text.txt"))
|
||||||
|
|
||||||
|
debug.log("create directory")
|
||||||
|
file.mkdir("config:dir")
|
||||||
|
assert(file.isdir("config:dir"))
|
||||||
|
|
||||||
|
debug.log("remove directory")
|
||||||
|
file.remove("config:dir")
|
||||||
|
|
||||||
|
debug.log("create directories")
|
||||||
|
file.mkdirs("config:dir/subdir/other")
|
||||||
|
assert(file.isdir("config:dir/subdir/other"))
|
||||||
|
|
||||||
|
debug.log("remove tree")
|
||||||
|
file.remove_tree("config:dir")
|
||||||
|
assert(not file.isdir("config:dir"))
|
||||||
|
|
||||||
|
debug.log("write binary file")
|
||||||
|
local bytes = {0xDE, 0xAD, 0xC0, 0xDE}
|
||||||
|
file.write_bytes("config:binary", bytes)
|
||||||
|
assert(file.exists("config:binary"))
|
||||||
|
|
||||||
|
debug.log("read binary file")
|
||||||
|
local rbytes = file.read_bytes("config:binary")
|
||||||
|
assert(#rbytes == #bytes)
|
||||||
|
for i, b in ipairs(bytes) do
|
||||||
|
assert(rbytes[i] == b)
|
||||||
|
end
|
||||||
|
|
||||||
|
debug.log("delete file")
|
||||||
|
file.remove("config:binary")
|
||||||
|
assert(not file.exists("config:binary"))
|
||||||
|
|
||||||
|
debug.log("checking entry points for writeability")
|
||||||
|
assert(file.is_writeable("config:"))
|
||||||
|
assert(file.is_writeable("export:"))
|
||||||
|
assert(not file.is_writeable("user:"))
|
||||||
|
assert(not file.is_writeable("res:"))
|
||||||
@@ -81,6 +81,13 @@ Turns off block model shading
|
|||||||
|
|
||||||
Determines the presence of the vertex AO effect. Turned-on by default.
|
Determines the presence of the vertex AO effect. Turned-on by default.
|
||||||
|
|
||||||
|
### *culling*
|
||||||
|
|
||||||
|
Face culling mode:
|
||||||
|
- **default** - normal face culling
|
||||||
|
- **optional** - face culling among blocks of the same rendering group can be disabled via the `graphics.dense-render` setting.
|
||||||
|
- **disabled** - face culling among blocks of the same rendering group disabled.
|
||||||
|
|
||||||
## Physics
|
## Physics
|
||||||
|
|
||||||
### *obstacle*
|
### *obstacle*
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ Particles are a table, all fields of which are optional.
|
|||||||
| acceleration | Particles acceleration. | {0, -16, 0} |
|
| acceleration | Particles acceleration. | {0, -16, 0} |
|
||||||
| explosion | Force of particles explosion on spawn. | {2, 2, 2} |
|
| explosion | Force of particles explosion on spawn. | {2, 2, 2} |
|
||||||
| size | Size of particles. | {0.1, 0.1, 0.1} |
|
| size | Size of particles. | {0.1, 0.1, 0.1} |
|
||||||
|
| size_spread | Maximum particle size spread over time. | 0.2 |
|
||||||
|
| angle_spread | Maximum initial rotation angle spread (0 to 1) | 0.0 |
|
||||||
|
| min_angular_vel | Minimum angular velocity (radians per sec). Non-negative. | 0.0 |
|
||||||
|
| max_angular_vel | Maximum angular velocity (radians per sec). Non-negative. | 0.0 |
|
||||||
| spawn_shape | Shape of particle spawn area. (ball/sphere/box) | ball |
|
| spawn_shape | Shape of particle spawn area. (ball/sphere/box) | ball |
|
||||||
| spawn_spread | Size of particle spawn area. | {0, 0, 0} |
|
| spawn_spread | Size of particle spawn area. | {0, 0, 0} |
|
||||||
| random_sub_uv | Size of random texture subregion (1 - entire texture will be used). | 1.0 |
|
| random_sub_uv | Size of random texture subregion (1 - entire texture will be used). | 1.0 |
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ file.read_bytes(path: str) -> array of integers
|
|||||||
|
|
||||||
Read file into bytes array.
|
Read file into bytes array.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
file.is_writeable(path: str) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Checks if the specified path is writable.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
file.write(path: str, text: str) -> nil
|
file.write(path: str, text: str) -> nil
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -32,6 +32,21 @@ inventory.size(invid: int) -> int
|
|||||||
-- Returns remaining count if could not to add fully.
|
-- Returns remaining count if could not to add fully.
|
||||||
inventory.add(invid: int, itemid: int, count: int) -> int
|
inventory.add(invid: int, itemid: int, count: int) -> int
|
||||||
|
|
||||||
|
-- Returns the index of the first matching slot in the given range.
|
||||||
|
-- If no matching slot was found, returns nil
|
||||||
|
inventory.find_by_item(
|
||||||
|
-- inventory id
|
||||||
|
invid: int,
|
||||||
|
-- item id
|
||||||
|
itemid: int,
|
||||||
|
-- [optional] index of the slot range start (from 0)
|
||||||
|
range_begin: int,
|
||||||
|
-- [optional] index of the slot range end (from 0)
|
||||||
|
range_end: int,
|
||||||
|
-- [optional] minimum item count in the slot
|
||||||
|
min_count: int = 1
|
||||||
|
) -> int
|
||||||
|
|
||||||
-- Returns block inventory ID or 0.
|
-- Returns block inventory ID or 0.
|
||||||
inventory.get_block(x: int, y: int, z: int) -> int
|
inventory.get_block(x: int, y: int, z: int) -> int
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,13 @@ player.set_instant_destruction(playerid: int, bool)
|
|||||||
|
|
||||||
Getter and setter for instant destruction of blocks when the `player.destroy` binding is activated.
|
Getter and setter for instant destruction of blocks when the `player.destroy` binding is activated.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
player.is_loading_chunks(playerid: int) -> bool
|
||||||
|
player.set_loading_chunks(playerid: int, bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
Getter and setter of the property that determines whether the player is loading chunks.
|
||||||
|
|
||||||
``` lua
|
``` lua
|
||||||
player.set_spawnpoint(playerid: int, x: number, y: number, z: number)
|
player.set_spawnpoint(playerid: int, x: number, y: number, z: number)
|
||||||
player.get_spawnpoint(playerid: int) -> number, number, number
|
player.get_spawnpoint(playerid: int) -> number, number, number
|
||||||
@@ -84,6 +91,12 @@ player.get_name(playerid: int) -> str
|
|||||||
|
|
||||||
Player name setter and getter
|
Player name setter and getter
|
||||||
|
|
||||||
|
```lua
|
||||||
|
player.set_selected_slot(playerid: int, slotid: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Sets the selected slot index
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
player.get_selected_block(playerid: int) -> x,y,z
|
player.get_selected_block(playerid: int) -> x,y,z
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
* [Small structures placement](#small-structures-placement)
|
* [Small structures placement](#small-structures-placement)
|
||||||
* [Wide structures placement](#wide-structures-placement)
|
* [Wide structures placement](#wide-structures-placement)
|
||||||
- [Structural air](#structural-air)
|
- [Structural air](#structural-air)
|
||||||
|
- [Generator 'Demo' (base:demo)](#generator-demo-basedemo)
|
||||||
|
|
||||||
## Basic concepts
|
## Basic concepts
|
||||||
|
|
||||||
@@ -473,3 +474,24 @@ function place_structures_wide(
|
|||||||
`core:struct_air` - a block that should be used in chunks to mark empty space that should not be filled with blocks when generated in the world.
|
`core:struct_air` - a block that should be used in chunks to mark empty space that should not be filled with blocks when generated in the world.
|
||||||
|
|
||||||
<image src="../../res/textures/blocks/struct_air.png" width="128px" height="128px" style="image-rendering: pixelated">
|
<image src="../../res/textures/blocks/struct_air.png" width="128px" height="128px" style="image-rendering: pixelated">
|
||||||
|
|
||||||
|
# Generator 'Demo' (base:demo)
|
||||||
|
|
||||||
|
## Adding new ore
|
||||||
|
|
||||||
|
To add a new ore in your pack:
|
||||||
|
1. In the `generators` folder, create a `demo.files` folder (you don't need to create demo.toml).
|
||||||
|
|
||||||
|
2. In the created folder, create a fragments folder and place the ore fragment file in it.
|
||||||
|
3. In `demo.files`, create a structures.toml file:
|
||||||
|
```toml
|
||||||
|
fragment_name = {}
|
||||||
|
```
|
||||||
|
4. Also in `demo.files`, create an ores.json file:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"struct": "fragment_name", "rarity": rarity}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
The higher the rarity value, the less ore generation chance.
|
||||||
|
You can rely on the rarity of coal ore: 4400.
|
||||||
|
|||||||
@@ -82,7 +82,6 @@
|
|||||||
|
|
||||||
При значении `true` блок не препятствует прохождению вертикального луча солнечного света.
|
При значении `true` блок не препятствует прохождению вертикального луча солнечного света.
|
||||||
|
|
||||||
|
|
||||||
### Без освещения - *shadeless*
|
### Без освещения - *shadeless*
|
||||||
|
|
||||||
Выключает освещение на модели блока.
|
Выключает освещение на модели блока.
|
||||||
@@ -91,6 +90,13 @@
|
|||||||
|
|
||||||
Определяет наличие эффекта вершинного AO. Включен по-умолчанию.
|
Определяет наличие эффекта вершинного AO. Включен по-умолчанию.
|
||||||
|
|
||||||
|
### Отсечение - *culling*
|
||||||
|
|
||||||
|
Режим отсечения граней:
|
||||||
|
- **default** - обычное отсечение граней
|
||||||
|
- **optional** - отсечение граней среди блоков одной группы отрисовки можно отключить через настройку `graphics.dense-render` (Плотный рендер блоков).
|
||||||
|
- **disabled** - отсечение граней среди блоков одной группы отрисовки отключено.
|
||||||
|
|
||||||
## Физика
|
## Физика
|
||||||
|
|
||||||
### Препятствие - *obstacle*
|
### Препятствие - *obstacle*
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
| explosion | Сила разлёта частиц при спавне. | {2, 2, 2} |
|
| explosion | Сила разлёта частиц при спавне. | {2, 2, 2} |
|
||||||
| size | Размер частиц. | {0.1, 0.1, 0.1} |
|
| size | Размер частиц. | {0.1, 0.1, 0.1} |
|
||||||
| size_spread | Максимальное отклонение времени размера частиц. | 0.2 |
|
| size_spread | Максимальное отклонение времени размера частиц. | 0.2 |
|
||||||
|
| angle_spread | Максимальное отклонение начального угла поворота (от 0 до 1) | 0.0 |
|
||||||
|
| min_angular_vel | Минимальная угловая скорость (радианы в сек.). Неотрицательное. | 0.0 |
|
||||||
|
| max_angular_vel | Максимальная угловая скорость (радианы в сек.). Неотрицательное. | 0.0 |
|
||||||
| spawn_shape | Форма области спавна частиц. (ball/sphere/box) | ball |
|
| spawn_shape | Форма области спавна частиц. (ball/sphere/box) | ball |
|
||||||
| spawn_spread | Размер области спавна частиц. | {0, 0, 0} |
|
| spawn_spread | Размер области спавна частиц. | {0, 0, 0} |
|
||||||
| random_sub_uv | Размер случайного подрегиона текстуры (1 - будет использована вся текстура). | 1.0 |
|
| random_sub_uv | Размер случайного подрегиона текстуры (1 - будет использована вся текстура). | 1.0 |
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ file.read_bytes(путь: str) -> array of integers
|
|||||||
|
|
||||||
Читает файл в массив байт.
|
Читает файл в массив байт.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
file.is_writeable(путь: str) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверяет, доступно ли право записи по указанному пути.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
file.write(путь: str, текст: str) -> nil
|
file.write(путь: str, текст: str) -> nil
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -38,6 +38,21 @@ inventory.add(
|
|||||||
count: int
|
count: int
|
||||||
) -> int
|
) -> int
|
||||||
|
|
||||||
|
-- Возвращает индекс первого подходящего под критерии слота в заданном диапазоне.
|
||||||
|
-- Если подходящий слот не был найден, возвращает nil
|
||||||
|
inventory.find_by_item(
|
||||||
|
-- id инвентаря
|
||||||
|
invid: int,
|
||||||
|
-- id предмета
|
||||||
|
itemid: int,
|
||||||
|
-- [опционально] индекс начала диапазона слотов (c 0)
|
||||||
|
range_begin: int,
|
||||||
|
-- [опционально] индекс конца диапазона слотов (c 0)
|
||||||
|
range_end: int,
|
||||||
|
-- [опционально] минимальное количество предмета в слоте
|
||||||
|
min_count: int = 1
|
||||||
|
) -> int
|
||||||
|
|
||||||
-- Функция возвращает id инвентаря блока.
|
-- Функция возвращает id инвентаря блока.
|
||||||
-- Если блок не может иметь инвентарь - возвращает 0.
|
-- Если блок не может иметь инвентарь - возвращает 0.
|
||||||
inventory.get_block(x: int, y: int, z: int) -> int
|
inventory.get_block(x: int, y: int, z: int) -> int
|
||||||
|
|||||||
@@ -70,6 +70,13 @@ player.set_instant_destruction(playerid: int, bool)
|
|||||||
|
|
||||||
Геттер и сеттер мнгновенного разрушения блоков при активации привязки `player.destroy`.
|
Геттер и сеттер мнгновенного разрушения блоков при активации привязки `player.destroy`.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
player.is_loading_chunks(playerid: int) -> bool
|
||||||
|
player.set_loading_chunks(playerid: int, bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
Геттер и сеттер свойства, определяющего, прогружает ли игрок чанки вокруг.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
player.set_spawnpoint(playerid: int, x: number, y: number, z: number)
|
player.set_spawnpoint(playerid: int, x: number, y: number, z: number)
|
||||||
player.get_spawnpoint(playerid: int) -> number, number, number
|
player.get_spawnpoint(playerid: int) -> number, number, number
|
||||||
@@ -84,6 +91,12 @@ player.get_name(playerid: int) -> str
|
|||||||
|
|
||||||
Сеттер и геттер имени игрока
|
Сеттер и геттер имени игрока
|
||||||
|
|
||||||
|
```lua
|
||||||
|
player.set_selected_slot(playerid: int, slotid: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Устанавливает индекс выбранного слота
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
player.get_selected_block(playerid: int) -> x,y,z
|
player.get_selected_block(playerid: int) -> x,y,z
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ table.remove_value(t: table, x: object)
|
|||||||
|
|
||||||
Удаляет элемент **x** из **t**.
|
Удаляет элемент **x** из **t**.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
table.shuffle(t: table) -> table
|
||||||
|
```
|
||||||
|
|
||||||
|
Перемешивает значения в таблице.
|
||||||
|
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
table.tostring(t: table) -> string
|
table.tostring(t: table) -> string
|
||||||
```
|
```
|
||||||
@@ -146,6 +153,18 @@ math.rand(low, high)
|
|||||||
|
|
||||||
Возвращает случайное дробное число в диапазоне от **low** до **high**.
|
Возвращает случайное дробное число в диапазоне от **low** до **high**.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
math.normalize(num: number, [опционально] conf: num) -> number
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает нормализованное значение num относительно conf.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
math.round(num: number, [опционально] places: num) -> number
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает округлённое значение num до указанного количества знаков после запятой places.
|
||||||
|
|
||||||
## Дополнительные глобальные функции
|
## Дополнительные глобальные функции
|
||||||
|
|
||||||
В этом же скрипте также определены и другие глобальные функции которые доступны для использования. Ниже их список
|
В этом же скрипте также определены и другие глобальные функции которые доступны для использования. Ниже их список
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
* [Расстановка малых структур](#расстановка-малых-структур)
|
* [Расстановка малых структур](#расстановка-малых-структур)
|
||||||
* [Расстановка 'широких' структур](#расстановка-широких-структур)
|
* [Расстановка 'широких' структур](#расстановка-широких-структур)
|
||||||
- [Структурный воздух](#структурный-воздух)
|
- [Структурный воздух](#структурный-воздух)
|
||||||
|
- [Генератор 'Demo' (base:demo)](#генератор-demo-basedemo)
|
||||||
|
|
||||||
## Основные понятия
|
## Основные понятия
|
||||||
|
|
||||||
@@ -478,3 +479,23 @@ function place_structures_wide(
|
|||||||
`core:struct_air` - блок, которые следует использовать в фрагментах для обозначения пустого пространства, которое не должно заполняться блоками при генерации в мире.
|
`core:struct_air` - блок, которые следует использовать в фрагментах для обозначения пустого пространства, которое не должно заполняться блоками при генерации в мире.
|
||||||
|
|
||||||
<image src="../../res/textures/blocks/struct_air.png" width="128px" height="128px" style="image-rendering: pixelated">
|
<image src="../../res/textures/blocks/struct_air.png" width="128px" height="128px" style="image-rendering: pixelated">
|
||||||
|
|
||||||
|
# Генератор 'Demo' (base:demo)
|
||||||
|
|
||||||
|
## Добавление новой руды
|
||||||
|
|
||||||
|
Чтобы добавить новую руду из своего пака:
|
||||||
|
1. В папке `generators` создайте папку `demo.files` (demo.toml создавать не нужно).
|
||||||
|
2. В созданной папке создайте папку fragments и поместите в неё файл фрагмента руды.
|
||||||
|
3. В `demo.files` создайте файл structures.toml:
|
||||||
|
```toml
|
||||||
|
имя_фрагмента = {}
|
||||||
|
```
|
||||||
|
4. Также в `demo.files` создайте файл ores.json:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"struct": "имя_фрагмента", "rarity": редкость}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
Чем выше значение редкости, тем меньше вероятность генерации руды.
|
||||||
|
Опираться можно на редкость угольной руды: 4400.
|
||||||
|
|||||||
@@ -1,5 +1,26 @@
|
|||||||
{
|
{
|
||||||
"texture": "leaves",
|
"texture": "leaves",
|
||||||
"material": "base:grass",
|
"material": "base:grass",
|
||||||
|
"draw-group": 5,
|
||||||
|
"culling": "optional",
|
||||||
|
"particles": {
|
||||||
|
"lifetime": 4.0,
|
||||||
|
"spawn_interval": 1000.0,
|
||||||
|
"acceleration": [0, -0.1, 0],
|
||||||
|
"velocity": [0.2, -2.5, 0.3],
|
||||||
|
"explosion": [0, 0, 0],
|
||||||
|
"collision": false,
|
||||||
|
"size": [0.3, 0.3, 0.3],
|
||||||
|
"size_spread": 0.2,
|
||||||
|
"spawn_shape": "box",
|
||||||
|
"spawn_spread": [0.2, 0.2, 0.2],
|
||||||
|
"angle_spread": 1.0,
|
||||||
|
"min_angular_vel": 0.5,
|
||||||
|
"max_angular_vel": 2.0,
|
||||||
|
"lighting": true,
|
||||||
|
"frames": [
|
||||||
|
"particles:leaf_0"
|
||||||
|
]
|
||||||
|
},
|
||||||
"base:durability": 0.7
|
"base:durability": 0.7
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 899 B |
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
@@ -41,4 +41,5 @@ function on_open()
|
|||||||
create_setting("graphics.fog-curve", "Fog Curve", 0.1)
|
create_setting("graphics.fog-curve", "Fog Curve", 0.1)
|
||||||
create_setting("graphics.gamma", "Gamma", 0.05, "", "graphics.gamma.tooltip")
|
create_setting("graphics.gamma", "Gamma", 0.05, "", "graphics.gamma.tooltip")
|
||||||
create_checkbox("graphics.backlight", "Backlight", "graphics.backlight.tooltip")
|
create_checkbox("graphics.backlight", "Backlight", "graphics.backlight.tooltip")
|
||||||
|
create_checkbox("graphics.dense-render", "Dense blocks render", "graphics.dense-render.tooltip")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -72,9 +72,14 @@ function data_buffer:put_byte(byte)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function data_buffer:put_bytes(bytes)
|
function data_buffer:put_bytes(bytes)
|
||||||
for i = 1, #bytes do
|
if type(self.bytes) == 'table' then
|
||||||
self:put_byte(bytes[i])
|
for i = 1, #bytes do
|
||||||
end
|
self:put_byte(bytes[i])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.bytes:insert(self.pos, bytes)
|
||||||
|
self.pos = self.pos + #bytes
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function data_buffer:put_single(single)
|
function data_buffer:put_single(single)
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
function on_hud_open()
|
||||||
|
input.add_callback("player.pick", function ()
|
||||||
|
if hud.is_paused() or hud.is_inventory_open() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local pid = hud.get_player()
|
||||||
|
local x, y, z = player.get_selected_block(pid)
|
||||||
|
if x == nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local id = block.get_picking_item(block.get(x, y, z))
|
||||||
|
local inv, cur_slot = player.get_inventory(pid)
|
||||||
|
local slot = inventory.find_by_item(inv, id, 0, 9)
|
||||||
|
if slot then
|
||||||
|
player.set_selected_slot(pid, slot)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not rules.get("allow-content-access") then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
slot = inventory.find_by_item(inv, 0, 0, 9)
|
||||||
|
if slot then
|
||||||
|
cur_slot = slot
|
||||||
|
end
|
||||||
|
player.set_selected_slot(pid, cur_slot)
|
||||||
|
inventory.set(inv, cur_slot, id, 1)
|
||||||
|
end)
|
||||||
|
|
||||||
|
input.add_callback("player.noclip", function ()
|
||||||
|
if hud.is_paused() or hud.is_inventory_open() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local pid = hud.get_player()
|
||||||
|
if player.is_noclip(pid) then
|
||||||
|
player.set_flight(pid, false)
|
||||||
|
player.set_noclip(pid, false)
|
||||||
|
else
|
||||||
|
player.set_flight(pid, true)
|
||||||
|
player.set_noclip(pid, true)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
input.add_callback("player.flight", function ()
|
||||||
|
if hud.is_paused() or hud.is_inventory_open() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local pid = hud.get_player()
|
||||||
|
if player.is_noclip(pid) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if player.is_flight(pid) then
|
||||||
|
player.set_flight(pid, false)
|
||||||
|
else
|
||||||
|
player.set_flight(pid, true)
|
||||||
|
player.set_vel(pid, 0, 1, 0)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
@@ -320,7 +320,6 @@ function __vc_on_hud_open()
|
|||||||
|
|
||||||
_rules.create("allow-content-access", hud._is_content_access(), function(value)
|
_rules.create("allow-content-access", hud._is_content_access(), function(value)
|
||||||
hud._set_content_access(value)
|
hud._set_content_access(value)
|
||||||
input.set_enabled("player.pick", value)
|
|
||||||
end)
|
end)
|
||||||
_rules.create("allow-flight", true, function(value)
|
_rules.create("allow-flight", true, function(value)
|
||||||
input.set_enabled("player.flight", value)
|
input.set_enabled("player.flight", value)
|
||||||
|
|||||||
+23
-1
@@ -1,6 +1,6 @@
|
|||||||
-- Check if given table is an array
|
-- Check if given table is an array
|
||||||
function is_array(x)
|
function is_array(x)
|
||||||
if #t > 0 then
|
if #x > 0 then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
for k, v in pairs(x) do
|
for k, v in pairs(x) do
|
||||||
@@ -51,6 +51,19 @@ function math.rand(low, high)
|
|||||||
return low + (high - low) * math.random()
|
return low + (high - low) * math.random()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function math.normalize(num, conf)
|
||||||
|
conf = conf or 1
|
||||||
|
|
||||||
|
return (num / conf) % 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function math.round(num, places)
|
||||||
|
places = places or 0
|
||||||
|
|
||||||
|
local mult = 10 ^ places
|
||||||
|
return math.floor(num * mult + 0.5) / mult
|
||||||
|
end
|
||||||
|
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
function table.copy(t)
|
function table.copy(t)
|
||||||
@@ -91,6 +104,15 @@ function table.random(t)
|
|||||||
return t[math.random(1, #t)]
|
return t[math.random(1, #t)]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function table.shuffle(t)
|
||||||
|
for i = #t, 2, -1 do
|
||||||
|
local j = math.random(i)
|
||||||
|
t[i], t[j] = t[j], t[i]
|
||||||
|
end
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
local pattern_escape_replacements = {
|
local pattern_escape_replacements = {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ devtools.traceback=Traceback (most recent call first)
|
|||||||
# Tooltips
|
# Tooltips
|
||||||
graphics.gamma.tooltip=Lighting brightness curve
|
graphics.gamma.tooltip=Lighting brightness curve
|
||||||
graphics.backlight.tooltip=Backlight to prevent total darkness
|
graphics.backlight.tooltip=Backlight to prevent total darkness
|
||||||
|
graphics.dense-render.tooltip=Enables transparency in blocks like leaves
|
||||||
|
|
||||||
# settings
|
# settings
|
||||||
settings.Controls Search Mode=Search by attached button name
|
settings.Controls Search Mode=Search by attached button name
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ pack.remove-confirm=Удалить весь поставляемый паком/
|
|||||||
# Подсказки
|
# Подсказки
|
||||||
graphics.gamma.tooltip=Кривая яркости освещения
|
graphics.gamma.tooltip=Кривая яркости освещения
|
||||||
graphics.backlight.tooltip=Подсветка, предотвращающая полную темноту
|
graphics.backlight.tooltip=Подсветка, предотвращающая полную темноту
|
||||||
|
graphics.dense-render.tooltip=Включает прозрачность блоков, таких как листья.
|
||||||
|
|
||||||
# Меню
|
# Меню
|
||||||
menu.Apply=Применить
|
menu.Apply=Применить
|
||||||
@@ -67,6 +68,7 @@ world.delete-confirm=Удалить мир безвозвратно?
|
|||||||
# Настройки
|
# Настройки
|
||||||
settings.Ambient=Фон
|
settings.Ambient=Фон
|
||||||
settings.Backlight=Подсветка
|
settings.Backlight=Подсветка
|
||||||
|
settings.Dense blocks render=Плотный рендер блоков
|
||||||
settings.Camera Shaking=Тряска Камеры
|
settings.Camera Shaking=Тряска Камеры
|
||||||
settings.Camera Inertia=Инерция Камеры
|
settings.Camera Inertia=Инерция Камеры
|
||||||
settings.Camera FOV Effects=Эффекты поля зрения
|
settings.Camera FOV Effects=Эффекты поля зрения
|
||||||
|
|||||||
@@ -239,10 +239,18 @@ void ContentLoader::loadBlock(
|
|||||||
}
|
}
|
||||||
def.model = *model;
|
def.model = *model;
|
||||||
} else if (!modelTypeName.empty()) {
|
} else if (!modelTypeName.empty()) {
|
||||||
logger.error() << "unknown model " << modelTypeName;
|
logger.error() << "unknown model: " << modelTypeName;
|
||||||
def.model = BlockModel::none;
|
def.model = BlockModel::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string cullingModeName = to_string(def.culling);
|
||||||
|
root.at("culling").get(cullingModeName);
|
||||||
|
if (auto mode = CullingMode_from(cullingModeName)) {
|
||||||
|
def.culling = *mode;
|
||||||
|
} else {
|
||||||
|
logger.error() << "unknown culling mode: " << cullingModeName;
|
||||||
|
}
|
||||||
|
|
||||||
root.at("material").get(def.material);
|
root.at("material").get(def.material);
|
||||||
|
|
||||||
// rotation profile
|
// rotation profile
|
||||||
|
|||||||
@@ -95,12 +95,13 @@ struct ContentPackStats {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct world_funcs_set {
|
struct WorldFuncsSet {
|
||||||
bool onblockplaced : 1;
|
bool onblockplaced;
|
||||||
bool onblockreplaced : 1;
|
bool onblockreplaced;
|
||||||
bool onblockbroken : 1;
|
bool onblockbreaking;
|
||||||
bool onblockinteract : 1;
|
bool onblockbroken;
|
||||||
bool onplayertick : 1;
|
bool onblockinteract;
|
||||||
|
bool onplayertick;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContentPackRuntime {
|
class ContentPackRuntime {
|
||||||
@@ -108,7 +109,7 @@ class ContentPackRuntime {
|
|||||||
ContentPackStats stats {};
|
ContentPackStats stats {};
|
||||||
scriptenv env;
|
scriptenv env;
|
||||||
public:
|
public:
|
||||||
world_funcs_set worldfuncsset {};
|
WorldFuncsSet worldfuncsset {};
|
||||||
|
|
||||||
ContentPackRuntime(ContentPack info, scriptenv env);
|
ContentPackRuntime(ContentPack info, scriptenv env);
|
||||||
~ContentPackRuntime();
|
~ContentPackRuntime();
|
||||||
|
|||||||
@@ -21,12 +21,9 @@ inline const std::string BIND_MOVE_CROUCH = "movement.crouch";
|
|||||||
inline const std::string BIND_MOVE_CHEAT = "movement.cheat";
|
inline const std::string BIND_MOVE_CHEAT = "movement.cheat";
|
||||||
inline const std::string BIND_CAM_ZOOM = "camera.zoom";
|
inline const std::string BIND_CAM_ZOOM = "camera.zoom";
|
||||||
inline const std::string BIND_CAM_MODE = "camera.mode";
|
inline const std::string BIND_CAM_MODE = "camera.mode";
|
||||||
inline const std::string BIND_PLAYER_NOCLIP = "player.noclip";
|
|
||||||
inline const std::string BIND_PLAYER_FLIGHT = "player.flight";
|
|
||||||
inline const std::string BIND_PLAYER_ATTACK = "player.attack";
|
inline const std::string BIND_PLAYER_ATTACK = "player.attack";
|
||||||
inline const std::string BIND_PLAYER_DESTROY = "player.destroy";
|
inline const std::string BIND_PLAYER_DESTROY = "player.destroy";
|
||||||
inline const std::string BIND_PLAYER_BUILD = "player.build";
|
inline const std::string BIND_PLAYER_BUILD = "player.build";
|
||||||
inline const std::string BIND_PLAYER_PICK = "player.pick";
|
|
||||||
inline const std::string BIND_PLAYER_FAST_INTERACTOIN =
|
inline const std::string BIND_PLAYER_FAST_INTERACTOIN =
|
||||||
"player.fast_interaction";
|
"player.fast_interaction";
|
||||||
inline const std::string BIND_HUD_INVENTORY = "hud.inventory";
|
inline const std::string BIND_HUD_INVENTORY = "hud.inventory";
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ Engine::Engine(CoreParameters coreParameters)
|
|||||||
paths.setResourcesFolder(params.resFolder);
|
paths.setResourcesFolder(params.resFolder);
|
||||||
paths.setUserFilesFolder(params.userFolder);
|
paths.setUserFilesFolder(params.userFolder);
|
||||||
paths.prepare();
|
paths.prepare();
|
||||||
|
if (!params.scriptFile.empty()) {
|
||||||
|
paths.setScriptFolder(params.scriptFile.parent_path());
|
||||||
|
}
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
auto resdir = paths.getResourcesFolder();
|
auto resdir = paths.getResourcesFolder();
|
||||||
|
|||||||
@@ -169,6 +169,10 @@ void EnginePaths::setResourcesFolder(std::filesystem::path folder) {
|
|||||||
this->resourcesFolder = std::move(folder);
|
this->resourcesFolder = std::move(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EnginePaths::setScriptFolder(std::filesystem::path folder) {
|
||||||
|
this->scriptFolder = std::move(folder);
|
||||||
|
}
|
||||||
|
|
||||||
void EnginePaths::setCurrentWorldFolder(std::filesystem::path folder) {
|
void EnginePaths::setCurrentWorldFolder(std::filesystem::path folder) {
|
||||||
this->currentWorldFolder = std::move(folder);
|
this->currentWorldFolder = std::move(folder);
|
||||||
}
|
}
|
||||||
@@ -211,7 +215,9 @@ std::filesystem::path EnginePaths::resolve(
|
|||||||
if (prefix == "export") {
|
if (prefix == "export") {
|
||||||
return userFilesFolder / EXPORT_FOLDER / fs::u8path(filename);
|
return userFilesFolder / EXPORT_FOLDER / fs::u8path(filename);
|
||||||
}
|
}
|
||||||
|
if (prefix == "script" && scriptFolder) {
|
||||||
|
return scriptFolder.value() / fs::u8path(filename);
|
||||||
|
}
|
||||||
if (contentPacks) {
|
if (contentPacks) {
|
||||||
for (auto& pack : *contentPacks) {
|
for (auto& pack : *contentPacks) {
|
||||||
if (pack.id == prefix) {
|
if (pack.id == prefix) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
@@ -26,6 +27,8 @@ public:
|
|||||||
void setResourcesFolder(std::filesystem::path folder);
|
void setResourcesFolder(std::filesystem::path folder);
|
||||||
std::filesystem::path getResourcesFolder() const;
|
std::filesystem::path getResourcesFolder() const;
|
||||||
|
|
||||||
|
void setScriptFolder(std::filesystem::path folder);
|
||||||
|
|
||||||
std::filesystem::path getWorldFolderByName(const std::string& name);
|
std::filesystem::path getWorldFolderByName(const std::string& name);
|
||||||
std::filesystem::path getWorldsFolder() const;
|
std::filesystem::path getWorldsFolder() const;
|
||||||
std::filesystem::path getConfigFolder() const;
|
std::filesystem::path getConfigFolder() const;
|
||||||
@@ -51,6 +54,7 @@ private:
|
|||||||
std::filesystem::path userFilesFolder {"."};
|
std::filesystem::path userFilesFolder {"."};
|
||||||
std::filesystem::path resourcesFolder {"res"};
|
std::filesystem::path resourcesFolder {"res"};
|
||||||
std::filesystem::path currentWorldFolder;
|
std::filesystem::path currentWorldFolder;
|
||||||
|
std::optional<std::filesystem::path> scriptFolder;
|
||||||
std::vector<ContentPack>* contentPacks = nullptr;
|
std::vector<ContentPack>* contentPacks = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -68,10 +68,12 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
|||||||
builder.section("graphics");
|
builder.section("graphics");
|
||||||
builder.add("fog-curve", &settings.graphics.fogCurve);
|
builder.add("fog-curve", &settings.graphics.fogCurve);
|
||||||
builder.add("backlight", &settings.graphics.backlight);
|
builder.add("backlight", &settings.graphics.backlight);
|
||||||
|
builder.add("dense-render", &settings.graphics.denseRender);
|
||||||
builder.add("gamma", &settings.graphics.gamma);
|
builder.add("gamma", &settings.graphics.gamma);
|
||||||
builder.add("frustum-culling", &settings.graphics.frustumCulling);
|
builder.add("frustum-culling", &settings.graphics.frustumCulling);
|
||||||
builder.add("skybox-resolution", &settings.graphics.skyboxResolution);
|
builder.add("skybox-resolution", &settings.graphics.skyboxResolution);
|
||||||
builder.add("chunk-max-vertices", &settings.graphics.chunkMaxVertices);
|
builder.add("chunk-max-vertices", &settings.graphics.chunkMaxVertices);
|
||||||
|
builder.add("chunk-max-vertices-dense", &settings.graphics.chunkMaxVerticesDense);
|
||||||
builder.add("chunk-max-renderers", &settings.graphics.chunkMaxRenderers);
|
builder.add("chunk-max-renderers", &settings.graphics.chunkMaxRenderers);
|
||||||
|
|
||||||
builder.section("ui");
|
builder.section("ui");
|
||||||
|
|||||||
@@ -6,53 +6,71 @@
|
|||||||
#include "assets/Assets.hpp"
|
#include "assets/Assets.hpp"
|
||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
#include "content/ContentPack.hpp"
|
#include "content/ContentPack.hpp"
|
||||||
#include "core_defs.hpp"
|
|
||||||
#include "graphics/core/Atlas.hpp"
|
#include "graphics/core/Atlas.hpp"
|
||||||
#include "maths/UVRegion.hpp"
|
#include "maths/UVRegion.hpp"
|
||||||
#include "voxels/Block.hpp"
|
#include "voxels/Block.hpp"
|
||||||
|
#include "core_defs.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
ContentGfxCache::ContentGfxCache(const Content* content, const Assets& assets)
|
|
||||||
: content(content) {
|
ContentGfxCache::ContentGfxCache(
|
||||||
auto indices = content->getIndices();
|
const Content& content,
|
||||||
|
const Assets& assets,
|
||||||
|
const GraphicsSettings& settings
|
||||||
|
)
|
||||||
|
: content(content), assets(assets), settings(settings) {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContentGfxCache::refresh(const Block& def, const Atlas& atlas) {
|
||||||
|
for (uint side = 0; side < 6; side++) {
|
||||||
|
std::string tex = def.textureFaces[side];
|
||||||
|
if (def.culling == CullingMode::OPTIONAL &&
|
||||||
|
!settings.denseRender.get() && atlas.has(tex + "_opaque")) {
|
||||||
|
tex = tex + "_opaque";
|
||||||
|
}
|
||||||
|
if (atlas.has(tex)) {
|
||||||
|
sideregions[def.rt.id * 6 + side] = atlas.get(tex);
|
||||||
|
} else if (atlas.has(TEXTURE_NOTFOUND)) {
|
||||||
|
sideregions[def.rt.id * 6 + side] = atlas.get(TEXTURE_NOTFOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (def.model == BlockModel::custom) {
|
||||||
|
auto model = assets.require<model::Model>(def.modelName);
|
||||||
|
// temporary dirty fix tbh
|
||||||
|
if (def.modelName.find(':') == std::string::npos) {
|
||||||
|
for (auto& mesh : model.meshes) {
|
||||||
|
size_t pos = mesh.texture.find(':');
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (auto region = atlas.getIf(mesh.texture.substr(pos+1))) {
|
||||||
|
for (auto& vertex : mesh.vertices) {
|
||||||
|
vertex.uv = region->apply(vertex.uv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
models[def.rt.id] = std::move(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContentGfxCache::refresh() {
|
||||||
|
auto indices = content.getIndices();
|
||||||
sideregions = std::make_unique<UVRegion[]>(indices->blocks.count() * 6);
|
sideregions = std::make_unique<UVRegion[]>(indices->blocks.count() * 6);
|
||||||
const auto& atlas = assets.require<Atlas>("blocks");
|
const auto& atlas = assets.require<Atlas>("blocks");
|
||||||
|
|
||||||
const auto& blocks = indices->blocks.getIterable();
|
const auto& blocks = indices->blocks.getIterable();
|
||||||
for (blockid_t i = 0; i < blocks.size(); i++) {
|
for (blockid_t i = 0; i < blocks.size(); i++) {
|
||||||
auto def = blocks[i];
|
auto def = blocks[i];
|
||||||
for (uint side = 0; side < 6; side++) {
|
refresh(*def, atlas);
|
||||||
const std::string& tex = def->textureFaces[side];
|
|
||||||
if (atlas.has(tex)) {
|
|
||||||
sideregions[i * 6 + side] = atlas.get(tex);
|
|
||||||
} else if (atlas.has(TEXTURE_NOTFOUND)) {
|
|
||||||
sideregions[i * 6 + side] = atlas.get(TEXTURE_NOTFOUND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (def->model == BlockModel::custom) {
|
|
||||||
auto model = assets.require<model::Model>(def->modelName);
|
|
||||||
// temporary dirty fix tbh
|
|
||||||
if (def->modelName.find(':') == std::string::npos) {
|
|
||||||
for (auto& mesh : model.meshes) {
|
|
||||||
size_t pos = mesh.texture.find(':');
|
|
||||||
if (pos == std::string::npos) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (auto region = atlas.getIf(mesh.texture.substr(pos+1))) {
|
|
||||||
for (auto& vertex : mesh.vertices) {
|
|
||||||
vertex.uv = region->apply(vertex.uv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
models[def->rt.id] = std::move(model);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentGfxCache::~ContentGfxCache() = default;
|
ContentGfxCache::~ContentGfxCache() = default;
|
||||||
|
|
||||||
const Content* ContentGfxCache::getContent() const {
|
const Content* ContentGfxCache::getContent() const {
|
||||||
return content;
|
return &content;
|
||||||
}
|
}
|
||||||
|
|
||||||
const model::Model& ContentGfxCache::getModel(blockid_t id) const {
|
const model::Model& ContentGfxCache::getModel(blockid_t id) const {
|
||||||
|
|||||||
@@ -10,19 +10,29 @@
|
|||||||
|
|
||||||
class Content;
|
class Content;
|
||||||
class Assets;
|
class Assets;
|
||||||
|
class Atlas;
|
||||||
|
class Block;
|
||||||
struct UVRegion;
|
struct UVRegion;
|
||||||
|
struct GraphicsSettings;
|
||||||
|
|
||||||
namespace model {
|
namespace model {
|
||||||
struct Model;
|
struct Model;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ContentGfxCache {
|
class ContentGfxCache {
|
||||||
const Content* content;
|
const Content& content;
|
||||||
|
const Assets& assets;
|
||||||
|
const GraphicsSettings& settings;
|
||||||
|
|
||||||
// array of block sides uv regions (6 per block)
|
// array of block sides uv regions (6 per block)
|
||||||
std::unique_ptr<UVRegion[]> sideregions;
|
std::unique_ptr<UVRegion[]> sideregions;
|
||||||
std::unordered_map<blockid_t, model::Model> models;
|
std::unordered_map<blockid_t, model::Model> models;
|
||||||
public:
|
public:
|
||||||
ContentGfxCache(const Content* content, const Assets& assets);
|
ContentGfxCache(
|
||||||
|
const Content& content,
|
||||||
|
const Assets& assets,
|
||||||
|
const GraphicsSettings& settings
|
||||||
|
);
|
||||||
~ContentGfxCache();
|
~ContentGfxCache();
|
||||||
|
|
||||||
inline const UVRegion& getRegion(blockid_t id, int side) const {
|
inline const UVRegion& getRegion(blockid_t id, int side) const {
|
||||||
@@ -32,4 +42,8 @@ public:
|
|||||||
const model::Model& getModel(blockid_t id) const;
|
const model::Model& getModel(blockid_t id) const;
|
||||||
|
|
||||||
const Content* getContent() const;
|
const Content* getContent() const;
|
||||||
|
|
||||||
|
void refresh(const Block& block, const Atlas& atlas);
|
||||||
|
|
||||||
|
void refresh();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,12 +14,17 @@
|
|||||||
#include "world/Level.hpp"
|
#include "world/Level.hpp"
|
||||||
|
|
||||||
LevelFrontend::LevelFrontend(
|
LevelFrontend::LevelFrontend(
|
||||||
Player* currentPlayer, LevelController* controller, Assets& assets
|
Player* currentPlayer,
|
||||||
) : level(*controller->getLevel()),
|
LevelController* controller,
|
||||||
controller(controller),
|
Assets& assets,
|
||||||
assets(assets),
|
const EngineSettings& settings
|
||||||
contentCache(std::make_unique<ContentGfxCache>(level.content, assets))
|
)
|
||||||
{
|
: level(*controller->getLevel()),
|
||||||
|
controller(controller),
|
||||||
|
assets(assets),
|
||||||
|
contentCache(std::make_unique<ContentGfxCache>(
|
||||||
|
*level.content, assets, settings.graphics
|
||||||
|
)) {
|
||||||
assets.store(
|
assets.store(
|
||||||
BlocksPreview::build(
|
BlocksPreview::build(
|
||||||
*contentCache, assets, *level.content->getIndices()
|
*contentCache, assets, *level.content->getIndices()
|
||||||
@@ -98,6 +103,10 @@ const Assets& LevelFrontend::getAssets() const {
|
|||||||
return assets;
|
return assets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContentGfxCache& LevelFrontend::getContentGfxCache() {
|
||||||
|
return *contentCache;
|
||||||
|
}
|
||||||
|
|
||||||
const ContentGfxCache& LevelFrontend::getContentGfxCache() const {
|
const ContentGfxCache& LevelFrontend::getContentGfxCache() const {
|
||||||
return *contentCache;
|
return *contentCache;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ class Assets;
|
|||||||
class Player;
|
class Player;
|
||||||
class ContentGfxCache;
|
class ContentGfxCache;
|
||||||
class LevelController;
|
class LevelController;
|
||||||
|
struct EngineSettings;
|
||||||
|
|
||||||
class LevelFrontend {
|
class LevelFrontend {
|
||||||
Level& level;
|
Level& level;
|
||||||
@@ -14,12 +15,18 @@ class LevelFrontend {
|
|||||||
const Assets& assets;
|
const Assets& assets;
|
||||||
std::unique_ptr<ContentGfxCache> contentCache;
|
std::unique_ptr<ContentGfxCache> contentCache;
|
||||||
public:
|
public:
|
||||||
LevelFrontend(Player* currentPlayer, LevelController* controller, Assets& assets);
|
LevelFrontend(
|
||||||
|
Player* currentPlayer,
|
||||||
|
LevelController* controller,
|
||||||
|
Assets& assets,
|
||||||
|
const EngineSettings& settings
|
||||||
|
);
|
||||||
~LevelFrontend();
|
~LevelFrontend();
|
||||||
|
|
||||||
Level& getLevel();
|
Level& getLevel();
|
||||||
const Level& getLevel() const;
|
const Level& getLevel() const;
|
||||||
const Assets& getAssets() const;
|
const Assets& getAssets() const;
|
||||||
const ContentGfxCache& getContentGfxCache() const;
|
const ContentGfxCache& getContentGfxCache() const;
|
||||||
|
ContentGfxCache& getContentGfxCache();
|
||||||
LevelController* getController() const;
|
LevelController* getController() const;
|
||||||
};
|
};
|
||||||
|
|||||||
+28
-24
@@ -154,7 +154,7 @@ static constexpr uint WORLDGEN_IMG_SIZE = 128U;
|
|||||||
Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
|
Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
|
||||||
: engine(engine),
|
: engine(engine),
|
||||||
assets(*engine.getAssets()),
|
assets(*engine.getAssets()),
|
||||||
gui(engine.getGUI()),
|
gui(*engine.getGUI()),
|
||||||
frontend(frontend),
|
frontend(frontend),
|
||||||
player(player),
|
player(player),
|
||||||
debugImgWorldGen(std::make_unique<ImageData>(
|
debugImgWorldGen(std::make_unique<ImageData>(
|
||||||
@@ -183,11 +183,11 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
|
|||||||
engine, frontend.getLevel(), player, allowDebugCheats
|
engine, frontend.getLevel(), player, allowDebugCheats
|
||||||
);
|
);
|
||||||
debugPanel->setZIndex(2);
|
debugPanel->setZIndex(2);
|
||||||
gui->add(debugPanel);
|
gui.add(debugPanel);
|
||||||
|
|
||||||
gui->add(darkOverlay);
|
gui.add(darkOverlay);
|
||||||
gui->add(hotbarView);
|
gui.add(hotbarView);
|
||||||
gui->add(contentAccessPanel);
|
gui.add(contentAccessPanel);
|
||||||
|
|
||||||
auto dplotter = std::make_shared<Plotter>(350, 250, 2000, 16);
|
auto dplotter = std::make_shared<Plotter>(350, 250, 2000, 16);
|
||||||
dplotter->setGravity(Gravity::bottom_right);
|
dplotter->setGravity(Gravity::bottom_right);
|
||||||
@@ -208,10 +208,10 @@ Hud::~Hud() {
|
|||||||
for (auto& element : elements) {
|
for (auto& element : elements) {
|
||||||
onRemove(element);
|
onRemove(element);
|
||||||
}
|
}
|
||||||
gui->remove(hotbarView);
|
gui.remove(hotbarView);
|
||||||
gui->remove(darkOverlay);
|
gui.remove(darkOverlay);
|
||||||
gui->remove(contentAccessPanel);
|
gui.remove(contentAccessPanel);
|
||||||
gui->remove(debugPanel);
|
gui.remove(debugPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Remove all elements marked as removed
|
/// @brief Remove all elements marked as removed
|
||||||
@@ -322,9 +322,9 @@ void Hud::updateWorldGenDebugVisualization() {
|
|||||||
void Hud::update(bool visible) {
|
void Hud::update(bool visible) {
|
||||||
const auto& level = frontend.getLevel();
|
const auto& level = frontend.getLevel();
|
||||||
const auto& chunks = *player.chunks;
|
const auto& chunks = *player.chunks;
|
||||||
auto menu = gui->getMenu();
|
const auto& menu = gui.getMenu();
|
||||||
|
|
||||||
debugPanel->setVisible(player.debug && visible);
|
debugPanel->setVisible(debug && visible);
|
||||||
|
|
||||||
if (!visible && inventoryOpen) {
|
if (!visible && inventoryOpen) {
|
||||||
closeInventory();
|
closeInventory();
|
||||||
@@ -333,7 +333,7 @@ void Hud::update(bool visible) {
|
|||||||
setPause(false);
|
setPause(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gui->isFocusCaught()) {
|
if (!gui.isFocusCaught()) {
|
||||||
processInput(visible);
|
processInput(visible);
|
||||||
}
|
}
|
||||||
if ((pause || inventoryOpen) == Events::_cursor_locked) {
|
if ((pause || inventoryOpen) == Events::_cursor_locked) {
|
||||||
@@ -359,7 +359,7 @@ void Hud::update(bool visible) {
|
|||||||
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
for (auto& element : elements) {
|
for (auto& element : elements) {
|
||||||
element.update(pause, inventoryOpen, player.debug);
|
element.update(pause, inventoryOpen, debug);
|
||||||
if (element.isRemoved()) {
|
if (element.isRemoved()) {
|
||||||
onRemove(element);
|
onRemove(element);
|
||||||
}
|
}
|
||||||
@@ -367,8 +367,8 @@ void Hud::update(bool visible) {
|
|||||||
}
|
}
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
debugMinimap->setVisible(player.debug && showGeneratorMinimap);
|
debugMinimap->setVisible(debug && showGeneratorMinimap);
|
||||||
if (player.debug && showGeneratorMinimap) {
|
if (debug && showGeneratorMinimap) {
|
||||||
updateWorldGenDebugVisualization();
|
updateWorldGenDebugVisualization();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -460,7 +460,7 @@ void Hud::showExchangeSlot() {
|
|||||||
exchangeSlot->setColor(glm::vec4());
|
exchangeSlot->setColor(glm::vec4());
|
||||||
exchangeSlot->setInteractive(false);
|
exchangeSlot->setInteractive(false);
|
||||||
exchangeSlot->setZIndex(1);
|
exchangeSlot->setZIndex(1);
|
||||||
gui->store(SlotView::EXCHANGE_SLOT_NAME, exchangeSlot);
|
gui.store(SlotView::EXCHANGE_SLOT_NAME, exchangeSlot);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,7 +494,7 @@ void Hud::openPermanent(UiDocument* doc) {
|
|||||||
|
|
||||||
void Hud::dropExchangeSlot() {
|
void Hud::dropExchangeSlot() {
|
||||||
auto slotView = std::dynamic_pointer_cast<SlotView>(
|
auto slotView = std::dynamic_pointer_cast<SlotView>(
|
||||||
gui->get(SlotView::EXCHANGE_SLOT_NAME)
|
gui.get(SlotView::EXCHANGE_SLOT_NAME)
|
||||||
);
|
);
|
||||||
if (slotView == nullptr) {
|
if (slotView == nullptr) {
|
||||||
return;
|
return;
|
||||||
@@ -518,7 +518,7 @@ void Hud::dropExchangeSlot() {
|
|||||||
|
|
||||||
void Hud::closeInventory() {
|
void Hud::closeInventory() {
|
||||||
dropExchangeSlot();
|
dropExchangeSlot();
|
||||||
gui->remove(SlotView::EXCHANGE_SLOT_NAME);
|
gui.remove(SlotView::EXCHANGE_SLOT_NAME);
|
||||||
exchangeSlot = nullptr;
|
exchangeSlot = nullptr;
|
||||||
exchangeSlotInv = nullptr;
|
exchangeSlotInv = nullptr;
|
||||||
inventoryOpen = false;
|
inventoryOpen = false;
|
||||||
@@ -536,7 +536,7 @@ void Hud::closeInventory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Hud::add(const HudElement& element, const dv::value& argsArray) {
|
void Hud::add(const HudElement& element, const dv::value& argsArray) {
|
||||||
gui->add(element.getNode());
|
gui.add(element.getNode());
|
||||||
auto document = element.getDocument();
|
auto document = element.getDocument();
|
||||||
if (document) {
|
if (document) {
|
||||||
auto invview = std::dynamic_pointer_cast<InventoryView>(element.getNode());
|
auto invview = std::dynamic_pointer_cast<InventoryView>(element.getNode());
|
||||||
@@ -572,7 +572,7 @@ void Hud::onRemove(const HudElement& element) {
|
|||||||
invview->unbind();
|
invview->unbind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gui->remove(element.getNode());
|
gui.remove(element.getNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hud::remove(const std::shared_ptr<UINode>& node) {
|
void Hud::remove(const std::shared_ptr<UINode>& node) {
|
||||||
@@ -585,6 +585,10 @@ void Hud::remove(const std::shared_ptr<UINode>& node) {
|
|||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Hud::setDebug(bool flag) {
|
||||||
|
debug = flag;
|
||||||
|
}
|
||||||
|
|
||||||
void Hud::draw(const DrawContext& ctx){
|
void Hud::draw(const DrawContext& ctx){
|
||||||
const Viewport& viewport = ctx.getViewport();
|
const Viewport& viewport = ctx.getViewport();
|
||||||
const uint width = viewport.getWidth();
|
const uint width = viewport.getWidth();
|
||||||
@@ -602,7 +606,7 @@ void Hud::draw(const DrawContext& ctx){
|
|||||||
uishader.uniformMatrix("u_projview", uicamera->getProjView());
|
uishader.uniformMatrix("u_projview", uicamera->getProjView());
|
||||||
|
|
||||||
// Crosshair
|
// Crosshair
|
||||||
if (!pause && !inventoryOpen && !player.debug) {
|
if (!pause && !inventoryOpen && !debug) {
|
||||||
DrawContext chctx = ctx.sub(batch);
|
DrawContext chctx = ctx.sub(batch);
|
||||||
chctx.setBlendMode(BlendMode::inversion);
|
chctx.setBlendMode(BlendMode::inversion);
|
||||||
auto texture = assets.get<Texture>("gui/crosshair");
|
auto texture = assets.get<Texture>("gui/crosshair");
|
||||||
@@ -681,7 +685,7 @@ void Hud::setPause(bool pause) {
|
|||||||
closeInventory();
|
closeInventory();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto menu = gui->getMenu();
|
const auto& menu = gui.getMenu();
|
||||||
if (pause) {
|
if (pause) {
|
||||||
menu->setPage("pause");
|
menu->setPage("pause");
|
||||||
} else {
|
} else {
|
||||||
@@ -713,10 +717,10 @@ void Hud::setContentAccess(bool flag) {
|
|||||||
void Hud::setDebugCheats(bool flag) {
|
void Hud::setDebugCheats(bool flag) {
|
||||||
allowDebugCheats = flag;
|
allowDebugCheats = flag;
|
||||||
|
|
||||||
gui->remove(debugPanel);
|
gui.remove(debugPanel);
|
||||||
debugPanel = create_debug_panel(
|
debugPanel = create_debug_panel(
|
||||||
engine, frontend.getLevel(), player, allowDebugCheats
|
engine, frontend.getLevel(), player, allowDebugCheats
|
||||||
);
|
);
|
||||||
debugPanel->setZIndex(2);
|
debugPanel->setZIndex(2);
|
||||||
gui->add(debugPanel);
|
gui.add(debugPanel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class Hud : public util::ObjectsKeeper {
|
|||||||
Engine& engine;
|
Engine& engine;
|
||||||
Assets& assets;
|
Assets& assets;
|
||||||
std::unique_ptr<Camera> uicamera;
|
std::unique_ptr<Camera> uicamera;
|
||||||
gui::GUI* gui;
|
gui::GUI& gui;
|
||||||
LevelFrontend& frontend;
|
LevelFrontend& frontend;
|
||||||
Player& player;
|
Player& player;
|
||||||
|
|
||||||
@@ -113,6 +113,7 @@ class Hud : public util::ObjectsKeeper {
|
|||||||
bool showContentPanel = true;
|
bool showContentPanel = true;
|
||||||
/// @brief Provide cheat controllers to the debug panel
|
/// @brief Provide cheat controllers to the debug panel
|
||||||
bool allowDebugCheats = true;
|
bool allowDebugCheats = true;
|
||||||
|
bool debug = false;
|
||||||
/// @brief UI element will be dynamicly positioned near to inventory or in screen center
|
/// @brief UI element will be dynamicly positioned near to inventory or in screen center
|
||||||
std::shared_ptr<gui::UINode> secondUI;
|
std::shared_ptr<gui::UINode> secondUI;
|
||||||
|
|
||||||
@@ -193,6 +194,8 @@ public:
|
|||||||
void onRemove(const HudElement& element);
|
void onRemove(const HudElement& element);
|
||||||
void remove(const std::shared_ptr<gui::UINode>& node);
|
void remove(const std::shared_ptr<gui::UINode>& node);
|
||||||
|
|
||||||
|
void setDebug(bool flag);
|
||||||
|
|
||||||
Player* getPlayer() const;
|
Player* getPlayer() const;
|
||||||
|
|
||||||
std::shared_ptr<Inventory> getBlockInventory();
|
std::shared_ptr<Inventory> getBlockInventory();
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#include "graphics/render/WorldRenderer.hpp"
|
#include "graphics/render/WorldRenderer.hpp"
|
||||||
#include "graphics/ui/GUI.hpp"
|
#include "graphics/ui/GUI.hpp"
|
||||||
#include "graphics/ui/elements/Menu.hpp"
|
#include "graphics/ui/elements/Menu.hpp"
|
||||||
|
#include "graphics/ui/GUI.hpp"
|
||||||
|
#include "frontend/ContentGfxCache.hpp"
|
||||||
#include "logic/LevelController.hpp"
|
#include "logic/LevelController.hpp"
|
||||||
#include "logic/PlayerController.hpp"
|
#include "logic/PlayerController.hpp"
|
||||||
#include "logic/scripting/scripting.hpp"
|
#include "logic/scripting/scripting.hpp"
|
||||||
@@ -55,7 +57,7 @@ LevelScreen::LevelScreen(Engine& engine, std::unique_ptr<Level> levelPtr)
|
|||||||
);
|
);
|
||||||
|
|
||||||
frontend = std::make_unique<LevelFrontend>(
|
frontend = std::make_unique<LevelFrontend>(
|
||||||
player, controller.get(), assets
|
player, controller.get(), assets, settings
|
||||||
);
|
);
|
||||||
worldRenderer = std::make_unique<WorldRenderer>(
|
worldRenderer = std::make_unique<WorldRenderer>(
|
||||||
engine, *frontend, *player
|
engine, *frontend, *player
|
||||||
@@ -70,6 +72,11 @@ LevelScreen::LevelScreen(Engine& engine, std::unique_ptr<Level> levelPtr)
|
|||||||
player->chunks->saveAndClear();
|
player->chunks->saveAndClear();
|
||||||
worldRenderer->clear();
|
worldRenderer->clear();
|
||||||
}));
|
}));
|
||||||
|
keepAlive(settings.graphics.denseRender.observe([=](bool) {
|
||||||
|
player->chunks->saveAndClear();
|
||||||
|
worldRenderer->clear();
|
||||||
|
frontend->getContentGfxCache().refresh();
|
||||||
|
}));
|
||||||
keepAlive(settings.camera.fov.observe([=](double value) {
|
keepAlive(settings.camera.fov.observe([=](double value) {
|
||||||
player->fpCamera->setFov(glm::radians(value));
|
player->fpCamera->setFov(glm::radians(value));
|
||||||
}));
|
}));
|
||||||
@@ -150,7 +157,9 @@ void LevelScreen::updateHotkeys() {
|
|||||||
hudVisible = !hudVisible;
|
hudVisible = !hudVisible;
|
||||||
}
|
}
|
||||||
if (Events::jpressed(keycode::F3)) {
|
if (Events::jpressed(keycode::F3)) {
|
||||||
player->debug = !player->debug;
|
debug = !debug;
|
||||||
|
hud->setDebug(debug);
|
||||||
|
worldRenderer->setDebug(debug);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class LevelScreen : public Screen {
|
|||||||
void saveWorldPreview();
|
void saveWorldPreview();
|
||||||
|
|
||||||
bool hudVisible = true;
|
bool hudVisible = true;
|
||||||
|
bool debug = false;
|
||||||
void updateHotkeys();
|
void updateHotkeys();
|
||||||
void initializeContent();
|
void initializeContent();
|
||||||
void initializePack(ContentPackRuntime* pack);
|
void initializePack(ContentPackRuntime* pack);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ GLTexture::GLTexture(const ubyte* data, uint width, uint height, ImageFormat ima
|
|||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,6 @@
|
|||||||
#include "voxels/Chunks.hpp"
|
#include "voxels/Chunks.hpp"
|
||||||
#include "lighting/Lightmap.hpp"
|
#include "lighting/Lightmap.hpp"
|
||||||
#include "frontend/ContentGfxCache.hpp"
|
#include "frontend/ContentGfxCache.hpp"
|
||||||
#include "settings.hpp"
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
const glm::vec3 BlocksRenderer::SUN_VECTOR (0.411934f, 0.863868f, -0.279161f);
|
const glm::vec3 BlocksRenderer::SUN_VECTOR (0.411934f, 0.863868f, -0.279161f);
|
||||||
|
|
||||||
@@ -342,41 +339,41 @@ void BlocksRenderer::blockCube(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ao) {
|
if (ao) {
|
||||||
if (isOpen(coord + Z, group)) {
|
if (isOpen(coord + Z, block)) {
|
||||||
faceAO(coord, X, Y, Z, texfaces[5], lights);
|
faceAO(coord, X, Y, Z, texfaces[5], lights);
|
||||||
}
|
}
|
||||||
if (isOpen(coord - Z, group)) {
|
if (isOpen(coord - Z, block)) {
|
||||||
faceAO(coord, -X, Y, -Z, texfaces[4], lights);
|
faceAO(coord, -X, Y, -Z, texfaces[4], lights);
|
||||||
}
|
}
|
||||||
if (isOpen(coord + Y, group)) {
|
if (isOpen(coord + Y, block)) {
|
||||||
faceAO(coord, X, -Z, Y, texfaces[3], lights);
|
faceAO(coord, X, -Z, Y, texfaces[3], lights);
|
||||||
}
|
}
|
||||||
if (isOpen(coord - Y, group)) {
|
if (isOpen(coord - Y, block)) {
|
||||||
faceAO(coord, X, Z, -Y, texfaces[2], lights);
|
faceAO(coord, X, Z, -Y, texfaces[2], lights);
|
||||||
}
|
}
|
||||||
if (isOpen(coord + X, group)) {
|
if (isOpen(coord + X, block)) {
|
||||||
faceAO(coord, -Z, Y, X, texfaces[1], lights);
|
faceAO(coord, -Z, Y, X, texfaces[1], lights);
|
||||||
}
|
}
|
||||||
if (isOpen(coord - X, group)) {
|
if (isOpen(coord - X, block)) {
|
||||||
faceAO(coord, Z, Y, -X, texfaces[0], lights);
|
faceAO(coord, Z, Y, -X, texfaces[0], lights);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isOpen(coord + Z, group)) {
|
if (isOpen(coord + Z, block)) {
|
||||||
face(coord, X, Y, Z, texfaces[5], pickLight(coord + Z), lights);
|
face(coord, X, Y, Z, texfaces[5], pickLight(coord + Z), lights);
|
||||||
}
|
}
|
||||||
if (isOpen(coord - Z, group)) {
|
if (isOpen(coord - Z, block)) {
|
||||||
face(coord, -X, Y, -Z, texfaces[4], pickLight(coord - Z), lights);
|
face(coord, -X, Y, -Z, texfaces[4], pickLight(coord - Z), lights);
|
||||||
}
|
}
|
||||||
if (isOpen(coord + Y, group)) {
|
if (isOpen(coord + Y, block)) {
|
||||||
face(coord, X, -Z, Y, texfaces[3], pickLight(coord + Y), lights);
|
face(coord, X, -Z, Y, texfaces[3], pickLight(coord + Y), lights);
|
||||||
}
|
}
|
||||||
if (isOpen(coord - Y, group)) {
|
if (isOpen(coord - Y, block)) {
|
||||||
face(coord, X, Z, -Y, texfaces[2], pickLight(coord - Y), lights);
|
face(coord, X, Z, -Y, texfaces[2], pickLight(coord - Y), lights);
|
||||||
}
|
}
|
||||||
if (isOpen(coord + X, group)) {
|
if (isOpen(coord + X, block)) {
|
||||||
face(coord, -Z, Y, X, texfaces[1], pickLight(coord + X), lights);
|
face(coord, -Z, Y, X, texfaces[1], pickLight(coord + X), lights);
|
||||||
}
|
}
|
||||||
if (isOpen(coord - X, group)) {
|
if (isOpen(coord - X, block)) {
|
||||||
face(coord, Z, Y, -X, texfaces[0], pickLight(coord - X), lights);
|
face(coord, Z, Y, -X, texfaces[0], pickLight(coord - X), lights);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "graphics/core/MeshData.hpp"
|
#include "graphics/core/MeshData.hpp"
|
||||||
#include "maths/util.hpp"
|
#include "maths/util.hpp"
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
class Content;
|
class Content;
|
||||||
class Mesh;
|
class Mesh;
|
||||||
@@ -22,7 +23,6 @@ class Chunks;
|
|||||||
class VoxelsVolume;
|
class VoxelsVolume;
|
||||||
class Chunks;
|
class Chunks;
|
||||||
class ContentGfxCache;
|
class ContentGfxCache;
|
||||||
struct EngineSettings;
|
|
||||||
struct UVRegion;
|
struct UVRegion;
|
||||||
|
|
||||||
class BlocksRenderer {
|
class BlocksRenderer {
|
||||||
@@ -118,7 +118,7 @@ class BlocksRenderer {
|
|||||||
bool isOpenForLight(int x, int y, int z) const;
|
bool isOpenForLight(int x, int y, int z) const;
|
||||||
|
|
||||||
// Does block allow to see other blocks sides (is it transparent)
|
// Does block allow to see other blocks sides (is it transparent)
|
||||||
inline bool isOpen(const glm::ivec3& pos, ubyte group) const {
|
inline bool isOpen(const glm::ivec3& pos, const Block& def) const {
|
||||||
auto id = voxelsBuffer->pickBlockId(
|
auto id = voxelsBuffer->pickBlockId(
|
||||||
chunk->x * CHUNK_W + pos.x, pos.y, chunk->z * CHUNK_D + pos.z
|
chunk->x * CHUNK_W + pos.x, pos.y, chunk->z * CHUNK_D + pos.z
|
||||||
);
|
);
|
||||||
@@ -126,7 +126,13 @@ class BlocksRenderer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto& block = *blockDefsCache[id];
|
const auto& block = *blockDefsCache[id];
|
||||||
if ((block.drawGroup != group && block.lightPassing) || !block.rt.solid) {
|
if (((block.drawGroup != def.drawGroup) && block.drawGroup) || !block.rt.solid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((def.culling == CullingMode::DISABLED ||
|
||||||
|
(def.culling == CullingMode::OPTIONAL &&
|
||||||
|
settings.graphics.denseRender.get())) &&
|
||||||
|
id == def.rt.id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return !id;
|
return !id;
|
||||||
|
|||||||
@@ -28,11 +28,18 @@ public:
|
|||||||
const Chunks& chunks,
|
const Chunks& chunks,
|
||||||
const ContentGfxCache& cache,
|
const ContentGfxCache& cache,
|
||||||
const EngineSettings& settings
|
const EngineSettings& settings
|
||||||
) : level(level),
|
)
|
||||||
chunks(chunks),
|
: level(level),
|
||||||
renderer(settings.graphics.chunkMaxVertices.get(),
|
chunks(chunks),
|
||||||
*level.content, cache, settings)
|
renderer(
|
||||||
{}
|
settings.graphics.denseRender.get()
|
||||||
|
? settings.graphics.chunkMaxVerticesDense.get()
|
||||||
|
: settings.graphics.chunkMaxVertices.get(),
|
||||||
|
*level.content,
|
||||||
|
cache,
|
||||||
|
settings
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
RendererResult operator()(const std::shared_ptr<Chunk>& chunk) override {
|
RendererResult operator()(const std::shared_ptr<Chunk>& chunk) override {
|
||||||
renderer.build(chunk.get(), &chunks);
|
renderer.build(chunk.get(), &chunks);
|
||||||
|
|||||||
@@ -104,9 +104,8 @@ void Decorator::update(
|
|||||||
|
|
||||||
void Decorator::update(float delta, const Camera& camera) {
|
void Decorator::update(float delta, const Camera& camera) {
|
||||||
glm::ivec3 pos = camera.position;
|
glm::ivec3 pos = camera.position;
|
||||||
pos -= glm::ivec3(UPDATE_AREA_DIAMETER / 2);
|
|
||||||
for (int i = 0; i < ITERATIONS; i++) {
|
for (int i = 0; i < ITERATIONS; i++) {
|
||||||
update(delta, pos, camera.position);
|
update(delta, pos - glm::ivec3(UPDATE_AREA_DIAMETER / 2), pos);
|
||||||
}
|
}
|
||||||
const auto& chunks = *player.chunks;
|
const auto& chunks = *player.chunks;
|
||||||
const auto& indices = *level.content->getIndices();
|
const auto& indices = *level.content->getIndices();
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class Chunks;
|
|||||||
class Camera;
|
class Camera;
|
||||||
class Assets;
|
class Assets;
|
||||||
class Player;
|
class Player;
|
||||||
struct Block;
|
class Block;
|
||||||
class Engine;
|
class Engine;
|
||||||
class LevelController;
|
class LevelController;
|
||||||
class WorldRenderer;
|
class WorldRenderer;
|
||||||
|
|||||||
@@ -19,12 +19,13 @@ Emitter::Emitter(
|
|||||||
)
|
)
|
||||||
: level(level),
|
: level(level),
|
||||||
origin(std::move(origin)),
|
origin(std::move(origin)),
|
||||||
prototype({this, 0, glm::vec3(), preset.velocity, preset.lifetime, region}),
|
prototype({this, 0, {}, preset.velocity, preset.lifetime, region}),
|
||||||
texture(texture),
|
texture(texture),
|
||||||
count(count),
|
count(count),
|
||||||
preset(std::move(preset)) {
|
preset(std::move(preset)) {
|
||||||
|
random.setSeed(reinterpret_cast<ptrdiff_t>(this));
|
||||||
this->prototype.emitter = this;
|
this->prototype.emitter = this;
|
||||||
timer = preset.spawnInterval;
|
timer = preset.spawnInterval * random.randFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Texture* Emitter::getTexture() const {
|
const Texture* Emitter::getTexture() const {
|
||||||
@@ -76,6 +77,10 @@ void Emitter::update(
|
|||||||
count = std::max(0, count - skipped);
|
count = std::max(0, count - skipped);
|
||||||
timer -= skipped * spawnInterval;
|
timer -= skipped * spawnInterval;
|
||||||
}
|
}
|
||||||
|
if (count < 0) {
|
||||||
|
int skipped = timer / spawnInterval;
|
||||||
|
timer -= skipped * spawnInterval;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (count && timer > spawnInterval) {
|
while (count && timer > spawnInterval) {
|
||||||
@@ -83,6 +88,15 @@ void Emitter::update(
|
|||||||
Particle particle = prototype;
|
Particle particle = prototype;
|
||||||
particle.emitter = this;
|
particle.emitter = this;
|
||||||
particle.random = random.rand32();
|
particle.random = random.rand32();
|
||||||
|
if (glm::abs(preset.angleSpread) >= 0.005f) {
|
||||||
|
particle.angle =
|
||||||
|
random.randFloat() * preset.angleSpread * glm::pi<float>() * 2;
|
||||||
|
}
|
||||||
|
particle.angularVelocity =
|
||||||
|
(preset.minAngularVelocity +
|
||||||
|
random.randFloat() *
|
||||||
|
(preset.maxAngularVelocity - preset.minAngularVelocity)) *
|
||||||
|
((random.rand() % 2) * 2 - 1);
|
||||||
|
|
||||||
glm::vec3 spawnOffset = generate_coord(preset.spawnShape);
|
glm::vec3 spawnOffset = generate_coord(preset.spawnShape);
|
||||||
spawnOffset *= preset.spawnSpread;
|
spawnOffset *= preset.spawnSpread;
|
||||||
@@ -103,6 +117,7 @@ void Emitter::update(
|
|||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
count--;
|
count--;
|
||||||
}
|
}
|
||||||
|
refCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +129,10 @@ bool Emitter::isDead() const {
|
|||||||
return count == 0;
|
return count == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Emitter::isReferred() const {
|
||||||
|
return refCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
const EmitterOrigin& Emitter::getOrigin() const {
|
const EmitterOrigin& Emitter::getOrigin() const {
|
||||||
return origin;
|
return origin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ struct Particle {
|
|||||||
float lifetime;
|
float lifetime;
|
||||||
/// @brief UV region
|
/// @brief UV region
|
||||||
UVRegion region;
|
UVRegion region;
|
||||||
|
/// @brief Current rotation angle
|
||||||
|
float angle;
|
||||||
|
/// @brief Angular velocity
|
||||||
|
float angularVelocity;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Texture;
|
class Texture;
|
||||||
@@ -39,7 +43,7 @@ class Emitter {
|
|||||||
EmitterOrigin origin;
|
EmitterOrigin origin;
|
||||||
/// @brief Particle prototype
|
/// @brief Particle prototype
|
||||||
Particle prototype;
|
Particle prototype;
|
||||||
/// @brief Particle
|
/// @brief Particle texture
|
||||||
const Texture* texture;
|
const Texture* texture;
|
||||||
/// @brief Number of particles should be spawned before emitter deactivation.
|
/// @brief Number of particles should be spawned before emitter deactivation.
|
||||||
/// -1 is infinite.
|
/// -1 is infinite.
|
||||||
@@ -50,6 +54,9 @@ class Emitter {
|
|||||||
|
|
||||||
util::PseudoRandom random;
|
util::PseudoRandom random;
|
||||||
public:
|
public:
|
||||||
|
/// @brief Number of references (alive particles)
|
||||||
|
int refCount = 0;
|
||||||
|
/// @brief Particle settings
|
||||||
ParticlesPreset preset;
|
ParticlesPreset preset;
|
||||||
|
|
||||||
Emitter(
|
Emitter(
|
||||||
@@ -82,6 +89,9 @@ public:
|
|||||||
/// @return true if the emitter has spawned all particles
|
/// @return true if the emitter has spawned all particles
|
||||||
bool isDead() const;
|
bool isDead() const;
|
||||||
|
|
||||||
|
/// @return true if there is at least one alive referring particle left
|
||||||
|
bool isReferred() const;
|
||||||
|
|
||||||
const EmitterOrigin& getOrigin() const;
|
const EmitterOrigin& getOrigin() const;
|
||||||
|
|
||||||
void setOrigin(const EmitterOrigin& origin);
|
void setOrigin(const EmitterOrigin& origin);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
struct ItemDef;
|
struct ItemDef;
|
||||||
class Assets;
|
class Assets;
|
||||||
class Content;
|
class Content;
|
||||||
struct Block;
|
class Block;
|
||||||
|
|
||||||
class ModelsGenerator {
|
class ModelsGenerator {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -36,12 +36,14 @@ static inline void update_particle(
|
|||||||
const auto& preset = particle.emitter->preset;
|
const auto& preset = particle.emitter->preset;
|
||||||
auto& pos = particle.position;
|
auto& pos = particle.position;
|
||||||
auto& vel = particle.velocity;
|
auto& vel = particle.velocity;
|
||||||
|
auto& angle = particle.angle;
|
||||||
|
|
||||||
vel += delta * preset.acceleration;
|
vel += delta * preset.acceleration;
|
||||||
if (preset.collision && chunks.isObstacleAt(pos + vel * delta)) {
|
if (preset.collision && chunks.isObstacleAt(pos + vel * delta)) {
|
||||||
vel *= 0.0f;
|
vel *= 0.0f;
|
||||||
}
|
}
|
||||||
pos += vel * delta;
|
pos += vel * delta;
|
||||||
|
angle += particle.angularVelocity * delta;
|
||||||
particle.lifetime -= delta;
|
particle.lifetime -= delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +67,8 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) {
|
|||||||
auto iter = vec.begin();
|
auto iter = vec.begin();
|
||||||
while (iter != vec.end()) {
|
while (iter != vec.end()) {
|
||||||
auto& particle = *iter;
|
auto& particle = *iter;
|
||||||
auto& preset = particle.emitter->preset;
|
auto& emitter = *particle.emitter;
|
||||||
|
auto& preset = emitter.preset;
|
||||||
|
|
||||||
if (!preset.frames.empty()) {
|
if (!preset.frames.empty()) {
|
||||||
float time = preset.lifetime - particle.lifetime;
|
float time = preset.lifetime - particle.lifetime;
|
||||||
@@ -86,19 +89,52 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) {
|
|||||||
}
|
}
|
||||||
update_particle(particle, delta, chunks);
|
update_particle(particle, delta, chunks);
|
||||||
|
|
||||||
|
float scale = 1.0f + ((particle.random ^ 2628172) % 1000) *
|
||||||
|
0.001f * preset.sizeSpread;
|
||||||
|
|
||||||
glm::vec4 light(1, 1, 1, 0);
|
glm::vec4 light(1, 1, 1, 0);
|
||||||
if (preset.lighting) {
|
if (preset.lighting) {
|
||||||
light = MainBatch::sampleLight(
|
light = MainBatch::sampleLight(
|
||||||
particle.position, chunks, backlight
|
particle.position,
|
||||||
|
chunks,
|
||||||
|
backlight
|
||||||
);
|
);
|
||||||
|
auto size = glm::max(glm::vec3(0.5f), preset.size * scale);
|
||||||
|
for (int x = -1; x <= 1; x++) {
|
||||||
|
for (int y = -1; y <= 1; y++) {
|
||||||
|
for (int z = -1; z <= 1; z++) {
|
||||||
|
light = glm::max(
|
||||||
|
light,
|
||||||
|
MainBatch::sampleLight(
|
||||||
|
particle.position -
|
||||||
|
size * glm::vec3(x, y, z),
|
||||||
|
chunks,
|
||||||
|
backlight
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
light *= 0.9f + (particle.random % 100) * 0.001f;
|
light *= 0.9f + (particle.random % 100) * 0.001f;
|
||||||
}
|
}
|
||||||
float scale = 1.0f + ((particle.random ^ 2628172) % 1000) *
|
|
||||||
0.001f * preset.sizeSpread;
|
|
||||||
|
glm::vec3 localRight = right;
|
||||||
|
glm::vec3 localUp = preset.globalUpVector ? glm::vec3(0, 1, 0) : up;
|
||||||
|
float angle = particle.angle;
|
||||||
|
if (glm::abs(angle) >= 0.005f) {
|
||||||
|
glm::vec3 rotatedRight(glm::cos(angle), -glm::sin(angle), 0.0f);
|
||||||
|
glm::vec3 rotatedUp(glm::sin(angle), glm::cos(angle), 0.0f);
|
||||||
|
|
||||||
|
localRight = right * rotatedRight.x + localUp * rotatedRight.y +
|
||||||
|
camera.front * rotatedRight.z;
|
||||||
|
localUp = right * rotatedUp.x + localUp * rotatedUp.y +
|
||||||
|
camera.front * rotatedUp.z;
|
||||||
|
}
|
||||||
batch->quad(
|
batch->quad(
|
||||||
particle.position,
|
particle.position,
|
||||||
right,
|
localRight,
|
||||||
preset.globalUpVector ? glm::vec3(0, 1, 0) : up,
|
localUp,
|
||||||
preset.size * scale,
|
preset.size * scale,
|
||||||
light,
|
light,
|
||||||
glm::vec3(1.0f),
|
glm::vec3(1.0f),
|
||||||
@@ -106,6 +142,7 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) {
|
|||||||
);
|
);
|
||||||
if (particle.lifetime <= 0.0f) {
|
if (particle.lifetime <= 0.0f) {
|
||||||
iter = vec.erase(iter);
|
iter = vec.erase(iter);
|
||||||
|
emitter.refCount--;
|
||||||
} else {
|
} else {
|
||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
@@ -128,19 +165,15 @@ void ParticlesRenderer::render(const Camera& camera, float delta) {
|
|||||||
auto iter = emitters.begin();
|
auto iter = emitters.begin();
|
||||||
while (iter != emitters.end()) {
|
while (iter != emitters.end()) {
|
||||||
auto& emitter = *iter->second;
|
auto& emitter = *iter->second;
|
||||||
|
if (emitter.isDead() && !emitter.isReferred()) {
|
||||||
|
// destruct Emitter only when there is no particles spawned by it
|
||||||
|
iter = emitters.erase(iter);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
auto texture = emitter.getTexture();
|
auto texture = emitter.getTexture();
|
||||||
const auto& found = particles.find(texture);
|
const auto& found = particles.find(texture);
|
||||||
std::vector<Particle>* vec;
|
std::vector<Particle>* vec;
|
||||||
if (found == particles.end()) {
|
vec = &particles[texture];
|
||||||
if (emitter.isDead()) {
|
|
||||||
// destruct Emitter only when there is no particles spawned by it
|
|
||||||
iter = emitters.erase(iter);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
vec = &particles[texture];
|
|
||||||
} else {
|
|
||||||
vec = &found->second;
|
|
||||||
}
|
|
||||||
emitter.update(delta, camera.position, *vec);
|
emitter.update(delta, camera.position, *vec);
|
||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ void WorldRenderer::renderBlockSelection() {
|
|||||||
lineBatch->box(
|
lineBatch->box(
|
||||||
center, size + glm::vec3(0.01), glm::vec4(0.f, 0.f, 0.f, 0.5f)
|
center, size + glm::vec3(0.01), glm::vec4(0.f, 0.f, 0.f, 0.5f)
|
||||||
);
|
);
|
||||||
if (player.debug) {
|
if (debug) {
|
||||||
lineBatch->line(
|
lineBatch->line(
|
||||||
point, point + norm * 0.5f, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f)
|
point, point + norm * 0.5f, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f)
|
||||||
);
|
);
|
||||||
@@ -228,7 +228,7 @@ void WorldRenderer::renderLines(
|
|||||||
if (player.selection.vox.id != BLOCK_VOID) {
|
if (player.selection.vox.id != BLOCK_VOID) {
|
||||||
renderBlockSelection();
|
renderBlockSelection();
|
||||||
}
|
}
|
||||||
if (player.debug && showEntitiesDebug) {
|
if (debug && showEntitiesDebug) {
|
||||||
auto ctx = pctx.sub(lineBatch.get());
|
auto ctx = pctx.sub(lineBatch.get());
|
||||||
bool culling = engine.getSettings().graphics.frustumCulling.get();
|
bool culling = engine.getSettings().graphics.frustumCulling.get();
|
||||||
level.entities->renderDebug(
|
level.entities->renderDebug(
|
||||||
@@ -337,7 +337,7 @@ void WorldRenderer::draw(
|
|||||||
renderLevel(ctx, camera, settings, delta, pause, hudVisible);
|
renderLevel(ctx, camera, settings, delta, pause, hudVisible);
|
||||||
// Debug lines
|
// Debug lines
|
||||||
if (hudVisible) {
|
if (hudVisible) {
|
||||||
if (player.debug) {
|
if (debug) {
|
||||||
guides->renderDebugLines(
|
guides->renderDebugLines(
|
||||||
ctx, camera, *lineBatch, linesShader, showChunkBorders
|
ctx, camera, *lineBatch, linesShader, showChunkBorders
|
||||||
);
|
);
|
||||||
@@ -410,3 +410,7 @@ void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) {
|
|||||||
void WorldRenderer::clear() {
|
void WorldRenderer::clear() {
|
||||||
chunks->clear();
|
chunks->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldRenderer::setDebug(bool flag) {
|
||||||
|
debug = flag;
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class WorldRenderer {
|
|||||||
std::unique_ptr<ModelBatch> modelBatch;
|
std::unique_ptr<ModelBatch> modelBatch;
|
||||||
|
|
||||||
float timer = 0.0f;
|
float timer = 0.0f;
|
||||||
|
bool debug = false;
|
||||||
|
|
||||||
/// @brief Render block selection lines
|
/// @brief Render block selection lines
|
||||||
void renderBlockSelection();
|
void renderBlockSelection();
|
||||||
@@ -100,4 +101,6 @@ public:
|
|||||||
);
|
);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
void setDebug(bool flag);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,10 +23,13 @@ size_t Inventory::findEmptySlot(size_t begin, size_t end) const {
|
|||||||
return npos;
|
return npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Inventory::findSlotByItem(itemid_t id, size_t begin, size_t end) {
|
size_t Inventory::findSlotByItem(
|
||||||
|
itemid_t id, size_t begin, size_t end, size_t minCount
|
||||||
|
) {
|
||||||
end = std::min(slots.size(), end);
|
end = std::min(slots.size(), end);
|
||||||
for (size_t i = begin; i < end; i++) {
|
for (size_t i = begin; i < end; i++) {
|
||||||
if (slots[i].getItemId() == id) {
|
const auto& stack = slots[i];
|
||||||
|
if (stack.getItemId() == id && stack.getCount() >= minCount) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ public:
|
|||||||
|
|
||||||
ItemStack& getSlot(size_t index);
|
ItemStack& getSlot(size_t index);
|
||||||
size_t findEmptySlot(size_t begin = 0, size_t end = -1) const;
|
size_t findEmptySlot(size_t begin = 0, size_t end = -1) const;
|
||||||
size_t findSlotByItem(itemid_t id, size_t begin = 0, size_t end = -1);
|
size_t findSlotByItem(
|
||||||
|
itemid_t id, size_t begin = 0, size_t end = -1, size_t minCount = 1
|
||||||
|
);
|
||||||
|
|
||||||
inline size_t size() const {
|
inline size_t size() const {
|
||||||
return slots.size();
|
return slots.size();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "data/dv.hpp"
|
#include "data/dv.hpp"
|
||||||
#include "typedefs.hpp"
|
#include "typedefs.hpp"
|
||||||
|
|
||||||
struct item_funcs_set {
|
struct ItemFuncsSet {
|
||||||
bool init : 1;
|
bool init : 1;
|
||||||
bool on_use : 1;
|
bool on_use : 1;
|
||||||
bool on_use_on_block : 1;
|
bool on_use_on_block : 1;
|
||||||
@@ -43,7 +43,7 @@ struct ItemDef {
|
|||||||
struct {
|
struct {
|
||||||
itemid_t id;
|
itemid_t id;
|
||||||
blockid_t placingBlock;
|
blockid_t placingBlock;
|
||||||
item_funcs_set funcsset {};
|
ItemFuncsSet funcsset {};
|
||||||
bool emissive = false;
|
bool emissive = false;
|
||||||
} rt {};
|
} rt {};
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,10 @@ void ChunksController::update(
|
|||||||
int centerX = floordiv<CHUNK_W>(position.x);
|
int centerX = floordiv<CHUNK_W>(position.x);
|
||||||
int centerY = floordiv<CHUNK_D>(position.z);
|
int centerY = floordiv<CHUNK_D>(position.z);
|
||||||
|
|
||||||
generator->update(centerX, centerY, loadDistance);
|
if (player.isLoadingChunks()) {
|
||||||
|
/// FIXME: one generator for multiple players
|
||||||
|
generator->update(centerX, centerY, loadDistance);
|
||||||
|
}
|
||||||
|
|
||||||
int64_t mcstotal = 0;
|
int64_t mcstotal = 0;
|
||||||
|
|
||||||
@@ -121,6 +124,12 @@ bool ChunksController::buildLights(const Player& player, const std::shared_ptr<C
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ChunksController::createChunk(const Player& player, int x, int z) const {
|
void ChunksController::createChunk(const Player& player, int x, int z) const {
|
||||||
|
if (!player.isLoadingChunks()) {
|
||||||
|
if (auto chunk = level.chunks->fetch(x, z)) {
|
||||||
|
player.chunks->putChunk(chunk);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto chunk = level.chunks->create(x, z);
|
auto chunk = level.chunks->create(x, z);
|
||||||
player.chunks->putChunk(chunk);
|
player.chunks->putChunk(chunk);
|
||||||
auto& chunkFlags = chunk->flags;
|
auto& chunkFlags = chunk->flags;
|
||||||
|
|||||||
@@ -47,9 +47,7 @@ LevelController::LevelController(
|
|||||||
);
|
);
|
||||||
chunks->update(16, 1, 0, *player);
|
chunks->update(16, 1, 0, *player);
|
||||||
if (player->chunks->get(
|
if (player->chunks->get(
|
||||||
std::floor(position.x),
|
std::floor(position.x), 0, std::floor(position.z)
|
||||||
std::floor(position.y),
|
|
||||||
std::floor(position.z)
|
|
||||||
)) {
|
)) {
|
||||||
confirmed++;
|
confirmed++;
|
||||||
}
|
}
|
||||||
@@ -83,7 +81,7 @@ void LevelController::update(float delta, bool pause) {
|
|||||||
playerTickClock.getPart()) {
|
playerTickClock.getPart()) {
|
||||||
|
|
||||||
const auto& position = player->getPosition();
|
const auto& position = player->getPosition();
|
||||||
if (!player->chunks->get(
|
if (player->chunks->get(
|
||||||
std::floor(position.x),
|
std::floor(position.x),
|
||||||
std::floor(position.y),
|
std::floor(position.y),
|
||||||
std::floor(position.z)
|
std::floor(position.z)
|
||||||
|
|||||||
@@ -288,8 +288,6 @@ void PlayerController::updateKeyboard() {
|
|||||||
input.jump = Events::active(BIND_MOVE_JUMP);
|
input.jump = Events::active(BIND_MOVE_JUMP);
|
||||||
input.zoom = Events::active(BIND_CAM_ZOOM);
|
input.zoom = Events::active(BIND_CAM_ZOOM);
|
||||||
input.cameraMode = Events::jactive(BIND_CAM_MODE);
|
input.cameraMode = Events::jactive(BIND_CAM_MODE);
|
||||||
input.noclip = Events::jactive(BIND_PLAYER_NOCLIP);
|
|
||||||
input.flight = Events::jactive(BIND_PLAYER_FLIGHT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerController::resetKeyboard() {
|
void PlayerController::resetKeyboard() {
|
||||||
@@ -341,28 +339,6 @@ static int determine_rotation(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pick_block(
|
|
||||||
ContentIndices* indices,
|
|
||||||
const Block& block,
|
|
||||||
Player& player,
|
|
||||||
int x,
|
|
||||||
int y,
|
|
||||||
int z
|
|
||||||
) {
|
|
||||||
itemid_t id = block.rt.pickingItem;
|
|
||||||
auto inventory = player.getInventory();
|
|
||||||
size_t slotid = inventory->findSlotByItem(id, 0, 10);
|
|
||||||
if (slotid == Inventory::npos) {
|
|
||||||
slotid = player.getChosenSlot();
|
|
||||||
} else {
|
|
||||||
player.setChosenSlot(slotid);
|
|
||||||
}
|
|
||||||
ItemStack& stack = inventory->getSlot(slotid);
|
|
||||||
if (stack.getItemId() != id) {
|
|
||||||
stack.set(ItemStack(id, 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
voxel* PlayerController::updateSelection(float maxDistance) {
|
voxel* PlayerController::updateSelection(float maxDistance) {
|
||||||
auto indices = level.content->getIndices();
|
auto indices = level.content->getIndices();
|
||||||
auto& chunks = *player.chunks;
|
auto& chunks = *player.chunks;
|
||||||
@@ -544,6 +520,7 @@ void PlayerController::updateInteraction(float delta) {
|
|||||||
}
|
}
|
||||||
auto& target = indices->blocks.require(vox->id);
|
auto& target = indices->blocks.require(vox->id);
|
||||||
if (lclick) {
|
if (lclick) {
|
||||||
|
scripting::on_block_breaking(&player, target, iend);
|
||||||
if (player.isInstantDestruction() && target.breakable) {
|
if (player.isInstantDestruction() && target.breakable) {
|
||||||
blocksController.breakBlock(
|
blocksController.breakBlock(
|
||||||
&player, target, iend.x, iend.y, iend.z
|
&player, target, iend.x, iend.y, iend.z
|
||||||
@@ -567,10 +544,6 @@ void PlayerController::updateInteraction(float delta) {
|
|||||||
if (def && rclick) {
|
if (def && rclick) {
|
||||||
processRightClick(*def, target);
|
processRightClick(*def, target);
|
||||||
}
|
}
|
||||||
if (Events::jactive(BIND_PLAYER_PICK)) {
|
|
||||||
auto coord = selection.actualPosition;
|
|
||||||
pick_block(indices, target, player, coord.x, coord.y, coord.z);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Player* PlayerController::getPlayer() {
|
Player* PlayerController::getPlayer() {
|
||||||
|
|||||||
@@ -57,12 +57,7 @@ static fs::path get_writeable_path(lua::State* L) {
|
|||||||
fs::path path = resolve_path(rawpath);
|
fs::path path = resolve_path(rawpath);
|
||||||
auto entryPoint = rawpath.substr(0, rawpath.find(':'));
|
auto entryPoint = rawpath.substr(0, rawpath.find(':'));
|
||||||
if (writeable_entry_points.find(entryPoint) == writeable_entry_points.end()) {
|
if (writeable_entry_points.find(entryPoint) == writeable_entry_points.end()) {
|
||||||
if (lua::getglobal(L, "__vc_warning")) {
|
throw std::runtime_error("access denied");
|
||||||
lua::pushstring(L, "writing to read-only entry point");
|
|
||||||
lua::pushstring(L, entryPoint);
|
|
||||||
lua::pushinteger(L, 1);
|
|
||||||
lua::call_nothrow(L, 3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
@@ -149,27 +144,6 @@ static int l_read_bytes(lua::State* L) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_bytes_from_table(
|
|
||||||
lua::State* L, int tableIndex, std::vector<ubyte>& bytes
|
|
||||||
) {
|
|
||||||
if (!lua::istable(L, tableIndex)) {
|
|
||||||
throw std::runtime_error("table expected");
|
|
||||||
} else {
|
|
||||||
size_t size = lua::objlen(L, tableIndex);
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
lua::rawgeti(L, i + 1, tableIndex);
|
|
||||||
const int byte = lua::tointeger(L, -1);
|
|
||||||
lua::pop(L);
|
|
||||||
if (byte < 0 || byte > 255) {
|
|
||||||
throw std::runtime_error(
|
|
||||||
"invalid byte '" + std::to_string(byte) + "'"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
bytes.push_back(byte);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int l_write_bytes(lua::State* L) {
|
static int l_write_bytes(lua::State* L) {
|
||||||
fs::path path = get_writeable_path(L);
|
fs::path path = get_writeable_path(L);
|
||||||
|
|
||||||
@@ -181,7 +155,7 @@ static int l_write_bytes(lua::State* L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ubyte> bytes;
|
std::vector<ubyte> bytes;
|
||||||
read_bytes_from_table(L, 2, bytes);
|
lua::read_bytes_from_table(L, 2, bytes);
|
||||||
return lua::pushboolean(
|
return lua::pushboolean(
|
||||||
L, files::write_bytes(path, bytes.data(), bytes.size())
|
L, files::write_bytes(path, bytes.data(), bytes.size())
|
||||||
);
|
);
|
||||||
@@ -223,7 +197,7 @@ static int l_list(lua::State* L) {
|
|||||||
static int l_gzip_compress(lua::State* L) {
|
static int l_gzip_compress(lua::State* L) {
|
||||||
std::vector<ubyte> bytes;
|
std::vector<ubyte> bytes;
|
||||||
|
|
||||||
read_bytes_from_table(L, 1, bytes);
|
lua::read_bytes_from_table(L, 1, bytes);
|
||||||
auto compressed_bytes = gzip::compress(bytes.data(), bytes.size());
|
auto compressed_bytes = gzip::compress(bytes.data(), bytes.size());
|
||||||
int newTable = lua::gettop(L);
|
int newTable = lua::gettop(L);
|
||||||
|
|
||||||
@@ -237,7 +211,7 @@ static int l_gzip_compress(lua::State* L) {
|
|||||||
static int l_gzip_decompress(lua::State* L) {
|
static int l_gzip_decompress(lua::State* L) {
|
||||||
std::vector<ubyte> bytes;
|
std::vector<ubyte> bytes;
|
||||||
|
|
||||||
read_bytes_from_table(L, 1, bytes);
|
lua::read_bytes_from_table(L, 1, bytes);
|
||||||
auto decompressed_bytes = gzip::decompress(bytes.data(), bytes.size());
|
auto decompressed_bytes = gzip::decompress(bytes.data(), bytes.size());
|
||||||
int newTable = lua::gettop(L);
|
int newTable = lua::gettop(L);
|
||||||
|
|
||||||
@@ -264,6 +238,16 @@ static int l_read_combined_object(lua::State* L) {
|
|||||||
return lua::pushvalue(L, engine->getResPaths()->readCombinedObject(path));
|
return lua::pushvalue(L, engine->getResPaths()->readCombinedObject(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_is_writeable(lua::State* L) {
|
||||||
|
std::string rawpath = lua::require_string(L, 1);
|
||||||
|
fs::path path = resolve_path(rawpath);
|
||||||
|
auto entryPoint = rawpath.substr(0, rawpath.find(':'));
|
||||||
|
if (writeable_entry_points.find(entryPoint) == writeable_entry_points.end()) {
|
||||||
|
return lua::pushboolean(L, false);
|
||||||
|
}
|
||||||
|
return lua::pushboolean(L, true);
|
||||||
|
}
|
||||||
|
|
||||||
const luaL_Reg filelib[] = {
|
const luaL_Reg filelib[] = {
|
||||||
{"exists", lua::wrap<l_exists>},
|
{"exists", lua::wrap<l_exists>},
|
||||||
{"find", lua::wrap<l_find>},
|
{"find", lua::wrap<l_find>},
|
||||||
@@ -284,4 +268,5 @@ const luaL_Reg filelib[] = {
|
|||||||
{"gzip_decompress", lua::wrap<l_gzip_decompress>},
|
{"gzip_decompress", lua::wrap<l_gzip_decompress>},
|
||||||
{"read_combined_list", lua::wrap<l_read_combined_list>},
|
{"read_combined_list", lua::wrap<l_read_combined_list>},
|
||||||
{"read_combined_object", lua::wrap<l_read_combined_object>},
|
{"read_combined_object", lua::wrap<l_read_combined_object>},
|
||||||
|
{"is_writeable", lua::wrap<l_is_writeable>},
|
||||||
{NULL, NULL}};
|
{NULL, NULL}};
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ static void validate_itemid(itemid_t id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<Inventory> get_inventory(int64_t id) {
|
static Inventory& get_inventory(int64_t id) {
|
||||||
auto inv = level->inventories->get(id);
|
auto inv = level->inventories->get(id);
|
||||||
if (inv == nullptr) {
|
if (inv == nullptr) {
|
||||||
throw std::runtime_error("inventory not found: " + std::to_string(id));
|
throw std::runtime_error("inventory not found: " + std::to_string(id));
|
||||||
}
|
}
|
||||||
return inv;
|
return *inv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<Inventory> get_inventory(int64_t id, int arg) {
|
static Inventory& get_inventory(int64_t id, int arg) {
|
||||||
auto inv = level->inventories->get(id);
|
auto inv = level->inventories->get(id);
|
||||||
if (inv == nullptr) {
|
if (inv == nullptr) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
@@ -29,62 +29,62 @@ static std::shared_ptr<Inventory> get_inventory(int64_t id, int arg) {
|
|||||||
std::to_string(arg)
|
std::to_string(arg)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return inv;
|
return *inv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void validate_slotid(int slotid, Inventory* inv) {
|
static void validate_slotid(int slotid, const Inventory& inv) {
|
||||||
if (static_cast<size_t>(slotid) >= inv->size()) {
|
if (static_cast<size_t>(slotid) >= inv.size()) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"slot index is out of range [0..inventory.size(invid)]"
|
"slot index is out of range [0..inventory.size(invid)]"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_inventory_get(lua::State* L) {
|
static int l_get(lua::State* L) {
|
||||||
auto invid = lua::tointeger(L, 1);
|
auto invid = lua::tointeger(L, 1);
|
||||||
auto slotid = lua::tointeger(L, 2);
|
auto slotid = lua::tointeger(L, 2);
|
||||||
auto inv = get_inventory(invid);
|
auto inv = get_inventory(invid);
|
||||||
validate_slotid(slotid, inv.get());
|
validate_slotid(slotid, inv);
|
||||||
const ItemStack& item = inv->getSlot(slotid);
|
const ItemStack& item = inv.getSlot(slotid);
|
||||||
lua::pushinteger(L, item.getItemId());
|
lua::pushinteger(L, item.getItemId());
|
||||||
lua::pushinteger(L, item.getCount());
|
lua::pushinteger(L, item.getCount());
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_inventory_set(lua::State* L) {
|
static int l_set(lua::State* L) {
|
||||||
auto invid = lua::tointeger(L, 1);
|
auto invid = lua::tointeger(L, 1);
|
||||||
auto slotid = lua::tointeger(L, 2);
|
auto slotid = lua::tointeger(L, 2);
|
||||||
auto itemid = lua::tointeger(L, 3);
|
auto itemid = lua::tointeger(L, 3);
|
||||||
auto count = lua::tointeger(L, 4);
|
auto count = lua::tointeger(L, 4);
|
||||||
validate_itemid(itemid);
|
validate_itemid(itemid);
|
||||||
|
|
||||||
auto inv = get_inventory(invid);
|
auto& inv = get_inventory(invid);
|
||||||
|
|
||||||
validate_slotid(slotid, inv.get());
|
validate_slotid(slotid, inv);
|
||||||
ItemStack& item = inv->getSlot(slotid);
|
ItemStack& item = inv.getSlot(slotid);
|
||||||
item.set(ItemStack(itemid, count));
|
item.set(ItemStack(itemid, count));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_inventory_size(lua::State* L) {
|
static int l_size(lua::State* L) {
|
||||||
auto invid = lua::tointeger(L, 1);
|
auto invid = lua::tointeger(L, 1);
|
||||||
auto inv = get_inventory(invid);
|
auto& inv = get_inventory(invid);
|
||||||
return lua::pushinteger(L, inv->size());
|
return lua::pushinteger(L, inv.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_inventory_add(lua::State* L) {
|
static int l_add(lua::State* L) {
|
||||||
auto invid = lua::tointeger(L, 1);
|
auto invid = lua::tointeger(L, 1);
|
||||||
auto itemid = lua::tointeger(L, 2);
|
auto itemid = lua::tointeger(L, 2);
|
||||||
auto count = lua::tointeger(L, 3);
|
auto count = lua::tointeger(L, 3);
|
||||||
validate_itemid(itemid);
|
validate_itemid(itemid);
|
||||||
|
|
||||||
auto inv = get_inventory(invid);
|
auto& inv = get_inventory(invid);
|
||||||
ItemStack item(itemid, count);
|
ItemStack item(itemid, count);
|
||||||
inv->move(item, indices);
|
inv.move(item, indices);
|
||||||
return lua::pushinteger(L, item.getCount());
|
return lua::pushinteger(L, item.getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_inventory_get_block(lua::State* L) {
|
static int l_get_block(lua::State* L) {
|
||||||
auto x = lua::tointeger(L, 1);
|
auto x = lua::tointeger(L, 1);
|
||||||
auto y = lua::tointeger(L, 2);
|
auto y = lua::tointeger(L, 2);
|
||||||
auto z = lua::tointeger(L, 3);
|
auto z = lua::tointeger(L, 3);
|
||||||
@@ -92,7 +92,7 @@ static int l_inventory_get_block(lua::State* L) {
|
|||||||
return lua::pushinteger(L, id);
|
return lua::pushinteger(L, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_inventory_bind_block(lua::State* L) {
|
static int l_bind_block(lua::State* L) {
|
||||||
auto id = lua::tointeger(L, 1);
|
auto id = lua::tointeger(L, 1);
|
||||||
auto x = lua::tointeger(L, 2);
|
auto x = lua::tointeger(L, 2);
|
||||||
auto y = lua::tointeger(L, 3);
|
auto y = lua::tointeger(L, 3);
|
||||||
@@ -101,7 +101,7 @@ static int l_inventory_bind_block(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_inventory_unbind_block(lua::State* L) {
|
static int l_unbind_block(lua::State* L) {
|
||||||
auto x = lua::tointeger(L, 1);
|
auto x = lua::tointeger(L, 1);
|
||||||
auto y = lua::tointeger(L, 2);
|
auto y = lua::tointeger(L, 2);
|
||||||
auto z = lua::tointeger(L, 3);
|
auto z = lua::tointeger(L, 3);
|
||||||
@@ -109,7 +109,7 @@ static int l_inventory_unbind_block(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_inventory_create(lua::State* L) {
|
static int l_create(lua::State* L) {
|
||||||
auto invsize = lua::tointeger(L, 1);
|
auto invsize = lua::tointeger(L, 1);
|
||||||
auto inv = level->inventories->create(invsize);
|
auto inv = level->inventories->create(invsize);
|
||||||
if (inv == nullptr) {
|
if (inv == nullptr) {
|
||||||
@@ -118,18 +118,13 @@ static int l_inventory_create(lua::State* L) {
|
|||||||
return lua::pushinteger(L, inv->getId());
|
return lua::pushinteger(L, inv->getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_inventory_remove(lua::State* L) {
|
static int l_remove(lua::State* L) {
|
||||||
auto invid = lua::tointeger(L, 1);
|
auto invid = lua::tointeger(L, 1);
|
||||||
auto inv = get_inventory(invid);
|
|
||||||
if (inv == nullptr) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
level->inventories->remove(invid);
|
level->inventories->remove(invid);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_inventory_clone(lua::State* L) {
|
static int l_clone(lua::State* L) {
|
||||||
auto id = lua::tointeger(L, 1);
|
auto id = lua::tointeger(L, 1);
|
||||||
auto clone = level->inventories->clone(id);
|
auto clone = level->inventories->clone(id);
|
||||||
if (clone == nullptr) {
|
if (clone == nullptr) {
|
||||||
@@ -138,54 +133,69 @@ static int l_inventory_clone(lua::State* L) {
|
|||||||
return lua::pushinteger(L, clone->getId());
|
return lua::pushinteger(L, clone->getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_inventory_move(lua::State* L) {
|
static int l_move(lua::State* L) {
|
||||||
auto invAid = lua::tointeger(L, 1);
|
auto invAid = lua::tointeger(L, 1);
|
||||||
auto slotAid = lua::tointeger(L, 2);
|
auto slotAid = lua::tointeger(L, 2);
|
||||||
auto invA = get_inventory(invAid, 1);
|
auto& invA = get_inventory(invAid, 1);
|
||||||
validate_slotid(slotAid, invA.get());
|
validate_slotid(slotAid, invA);
|
||||||
|
|
||||||
auto invBid = lua::tointeger(L, 3);
|
auto invBid = lua::tointeger(L, 3);
|
||||||
auto slotBid = lua::isnil(L, 4) ? -1 : lua::tointeger(L, 4);
|
auto slotBid = lua::isnil(L, 4) ? -1 : lua::tointeger(L, 4);
|
||||||
auto invB = get_inventory(invBid, 3);
|
auto& invB = get_inventory(invBid, 3);
|
||||||
auto& slot = invA->getSlot(slotAid);
|
auto& slot = invA.getSlot(slotAid);
|
||||||
if (slotBid == -1) {
|
if (slotBid == -1) {
|
||||||
invB->move(slot, content->getIndices());
|
invB.move(slot, content->getIndices());
|
||||||
} else {
|
} else {
|
||||||
invB->move(slot, content->getIndices(), slotBid, slotBid + 1);
|
invB.move(slot, content->getIndices(), slotBid, slotBid + 1);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_inventory_move_range(lua::State* L) {
|
static int l_move_range(lua::State* L) {
|
||||||
auto invAid = lua::tointeger(L, 1);
|
auto invAid = lua::tointeger(L, 1);
|
||||||
auto slotAid = lua::tointeger(L, 2);
|
auto slotAid = lua::tointeger(L, 2);
|
||||||
auto invA = get_inventory(invAid, 1);
|
auto& invA = get_inventory(invAid, 1);
|
||||||
validate_slotid(slotAid, invA.get());
|
validate_slotid(slotAid, invA);
|
||||||
|
|
||||||
auto invBid = lua::tointeger(L, 3);
|
auto invBid = lua::tointeger(L, 3);
|
||||||
auto slotBegin = lua::isnoneornil(L, 4) ? -1 : lua::tointeger(L, 4);
|
auto slotBegin = lua::isnoneornil(L, 4) ? -1 : lua::tointeger(L, 4);
|
||||||
auto slotEnd = lua::isnoneornil(L, 5) ? -1 : lua::tointeger(L, 5) + 1;
|
auto slotEnd = lua::isnoneornil(L, 5) ? -1 : lua::tointeger(L, 5) + 1;
|
||||||
auto invB = get_inventory(invBid, 3);
|
auto invB = get_inventory(invBid, 3);
|
||||||
auto& slot = invA->getSlot(slotAid);
|
auto& slot = invA.getSlot(slotAid);
|
||||||
if (slotBegin == -1) {
|
if (slotBegin == -1) {
|
||||||
invB->move(slot, content->getIndices());
|
invB.move(slot, content->getIndices());
|
||||||
} else {
|
} else {
|
||||||
invB->move(slot, content->getIndices(), slotBegin, slotEnd);
|
invB.move(slot, content->getIndices(), slotBegin, slotEnd);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_find_by_item(lua::State* L) {
|
||||||
|
auto invId = lua::tointeger(L, 1);
|
||||||
|
auto& inv = get_inventory(invId, 1);
|
||||||
|
integer_t blockid = lua::tointeger(L, 2);
|
||||||
|
integer_t begin = lua::isnumber(L, 3) ? lua::tointeger(L, 3) : 0;
|
||||||
|
integer_t end = lua::isnumber(L, 4) ? lua::tointeger(L, 4) : -1;
|
||||||
|
integer_t minCount = lua::isnumber(L, 5) ? lua::tointeger(L, 5) : blockid != 0;
|
||||||
|
size_t index = inv.findSlotByItem(blockid, begin, end, minCount);
|
||||||
|
if (index == Inventory::npos) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return lua::pushinteger(L, index);
|
||||||
|
}
|
||||||
|
|
||||||
const luaL_Reg inventorylib[] = {
|
const luaL_Reg inventorylib[] = {
|
||||||
{"get", lua::wrap<l_inventory_get>},
|
{"get", lua::wrap<l_get>},
|
||||||
{"set", lua::wrap<l_inventory_set>},
|
{"set", lua::wrap<l_set>},
|
||||||
{"size", lua::wrap<l_inventory_size>},
|
{"size", lua::wrap<l_size>},
|
||||||
{"add", lua::wrap<l_inventory_add>},
|
{"add", lua::wrap<l_add>},
|
||||||
{"move", lua::wrap<l_inventory_move>},
|
{"move", lua::wrap<l_move>},
|
||||||
{"move_range", lua::wrap<l_inventory_move_range>},
|
{"move_range", lua::wrap<l_move_range>},
|
||||||
{"get_block", lua::wrap<l_inventory_get_block>},
|
{"find_by_item", lua::wrap<l_find_by_item>},
|
||||||
{"bind_block", lua::wrap<l_inventory_bind_block>},
|
{"get_block", lua::wrap<l_get_block>},
|
||||||
{"unbind_block", lua::wrap<l_inventory_unbind_block>},
|
{"bind_block", lua::wrap<l_bind_block>},
|
||||||
{"create", lua::wrap<l_inventory_create>},
|
{"unbind_block", lua::wrap<l_unbind_block>},
|
||||||
{"remove", lua::wrap<l_inventory_remove>},
|
{"create", lua::wrap<l_create>},
|
||||||
{"clone", lua::wrap<l_inventory_clone>},
|
{"remove", lua::wrap<l_remove>},
|
||||||
|
{"clone", lua::wrap<l_clone>},
|
||||||
{NULL, NULL}};
|
{NULL, NULL}};
|
||||||
|
|||||||
@@ -101,6 +101,13 @@ static int l_get_inv(lua::State* L) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_set_selected_slot(lua::State* L) {
|
||||||
|
if (auto player = get_player(L, 1)) {
|
||||||
|
player->setChosenSlot(lua::tointeger(L, 2) % 10);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int l_is_flight(lua::State* L) {
|
static int l_is_flight(lua::State* L) {
|
||||||
if (auto player = get_player(L, 1)) {
|
if (auto player = get_player(L, 1)) {
|
||||||
return lua::pushboolean(L, player->isFlight());
|
return lua::pushboolean(L, player->isFlight());
|
||||||
@@ -157,6 +164,20 @@ static int l_set_instant_destruction(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_is_loading_chunks(lua::State* L) {
|
||||||
|
if (auto player = get_player(L, 1)) {
|
||||||
|
return lua::pushboolean(L, player->isLoadingChunks());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_set_loading_chunks(lua::State* L) {
|
||||||
|
if (auto player = get_player(L, 1)) {
|
||||||
|
player->setLoadingChunks(lua::toboolean(L, 2));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int l_get_selected_block(lua::State* L) {
|
static int l_get_selected_block(lua::State* L) {
|
||||||
if (auto player = get_player(L, 1)) {
|
if (auto player = get_player(L, 1)) {
|
||||||
if (player->selection.vox.id == BLOCK_VOID) {
|
if (player->selection.vox.id == BLOCK_VOID) {
|
||||||
@@ -275,6 +296,9 @@ const luaL_Reg playerlib[] = {
|
|||||||
{"set_infinite_items", lua::wrap<l_set_infinite_items>},
|
{"set_infinite_items", lua::wrap<l_set_infinite_items>},
|
||||||
{"is_instant_destruction", lua::wrap<l_is_instant_destruction>},
|
{"is_instant_destruction", lua::wrap<l_is_instant_destruction>},
|
||||||
{"set_instant_destruction", lua::wrap<l_set_instant_destruction>},
|
{"set_instant_destruction", lua::wrap<l_set_instant_destruction>},
|
||||||
|
{"is_loading_chunks", lua::wrap<l_is_loading_chunks>},
|
||||||
|
{"set_loading_chunks", lua::wrap<l_set_loading_chunks>},
|
||||||
|
{"set_selected_slot", lua::wrap<l_set_selected_slot>},
|
||||||
{"get_selected_block", lua::wrap<l_get_selected_block>},
|
{"get_selected_block", lua::wrap<l_get_selected_block>},
|
||||||
{"get_selected_entity", lua::wrap<l_get_selected_entity>},
|
{"get_selected_entity", lua::wrap<l_get_selected_entity>},
|
||||||
{"set_spawnpoint", lua::wrap<l_set_spawnpoint>},
|
{"set_spawnpoint", lua::wrap<l_set_spawnpoint>},
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
#include <stdexcept>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "data/dv.hpp"
|
#include "data/dv.hpp"
|
||||||
@@ -698,4 +699,25 @@ namespace lua {
|
|||||||
}
|
}
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void read_bytes_from_table(
|
||||||
|
lua::State* L, int tableIndex, std::vector<ubyte>& bytes
|
||||||
|
) {
|
||||||
|
if (!lua::istable(L, tableIndex)) {
|
||||||
|
throw std::runtime_error("table expected");
|
||||||
|
} else {
|
||||||
|
size_t size = lua::objlen(L, tableIndex);
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
lua::rawgeti(L, i + 1, tableIndex);
|
||||||
|
const int byte = lua::tointeger(L, -1);
|
||||||
|
lua::pop(L);
|
||||||
|
if (byte < 0 || byte > 255) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"invalid byte '" + std::to_string(byte) + "'"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
bytes.push_back(byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "util/listutil.hpp"
|
||||||
#include "../lua_util.hpp"
|
#include "../lua_util.hpp"
|
||||||
|
|
||||||
using namespace lua;
|
using namespace lua;
|
||||||
@@ -18,8 +19,16 @@ LuaBytearray::~LuaBytearray() {
|
|||||||
|
|
||||||
static int l_append(lua::State* L) {
|
static int l_append(lua::State* L) {
|
||||||
if (auto buffer = touserdata<LuaBytearray>(L, 1)) {
|
if (auto buffer = touserdata<LuaBytearray>(L, 1)) {
|
||||||
auto value = tointeger(L, 2);
|
if (lua::isnumber(L, 2)) {
|
||||||
buffer->data().push_back(static_cast<ubyte>(value));
|
auto value = tointeger(L, 2);
|
||||||
|
buffer->data().push_back(static_cast<ubyte>(value));
|
||||||
|
} else if (lua::istable(L, 2)) {
|
||||||
|
lua::read_bytes_from_table(L, 2, buffer->data());
|
||||||
|
} else if (auto extension = lua::touserdata<LuaBytearray>(L, 2)) {
|
||||||
|
util::concat(buffer->data(), extension->data());
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("integer/table/Bytearray expected");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -34,8 +43,19 @@ static int l_insert(lua::State* L) {
|
|||||||
if (static_cast<size_t>(index) > data.size()) {
|
if (static_cast<size_t>(index) > data.size()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
auto value = tointeger(L, 3);
|
if (lua::isnumber(L, 3)) {
|
||||||
data.insert(data.begin() + index, static_cast<ubyte>(value));
|
auto value = tointeger(L, 3);
|
||||||
|
data.insert(data.begin() + index, static_cast<ubyte>(value));
|
||||||
|
} else if (lua::istable(L, 3)) {
|
||||||
|
std::vector<ubyte> temp;
|
||||||
|
lua::read_bytes_from_table(L, 3, temp);
|
||||||
|
data.insert(data.begin() + index, temp.begin(), temp.end());
|
||||||
|
} else if (auto extension = lua::touserdata<LuaBytearray>(L, 3)) {
|
||||||
|
const std::vector<ubyte>& src = extension->data();
|
||||||
|
data.insert(data.begin() + index, src.begin(), src.end());
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("integer/table/Bytearray expected");
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -336,16 +336,24 @@ void scripting::random_update_block(const Block& block, const glm::ivec3& pos) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void scripting::on_block_placed(
|
/// TODO: replace template with index
|
||||||
Player* player, const Block& block, const glm::ivec3& pos
|
template<bool WorldFuncsSet::*worldfunc>
|
||||||
|
static bool on_block_common(
|
||||||
|
const std::string& suffix,
|
||||||
|
bool blockfunc,
|
||||||
|
Player* player,
|
||||||
|
const Block& block,
|
||||||
|
const glm::ivec3& pos
|
||||||
) {
|
) {
|
||||||
if (block.rt.funcsset.onplaced) {
|
bool result = false;
|
||||||
std::string name = block.name + ".placed";
|
if (blockfunc) {
|
||||||
lua::emit_event(lua::get_main_state(), name, [pos, player](auto L) {
|
std::string name = block.name + "." + suffix;
|
||||||
lua::pushivec_stack(L, pos);
|
result =
|
||||||
lua::pushinteger(L, player ? player->getId() : -1);
|
lua::emit_event(lua::get_main_state(), name, [pos, player](auto L) {
|
||||||
return 4;
|
lua::pushivec_stack(L, pos);
|
||||||
});
|
lua::pushinteger(L, player->getId());
|
||||||
|
return 4;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
auto args = [&](lua::State* L) {
|
auto args = [&](lua::State* L) {
|
||||||
lua::pushinteger(L, block.rt.id);
|
lua::pushinteger(L, block.rt.id);
|
||||||
@@ -354,93 +362,53 @@ void scripting::on_block_placed(
|
|||||||
return 5;
|
return 5;
|
||||||
};
|
};
|
||||||
for (auto& [packid, pack] : content->getPacks()) {
|
for (auto& [packid, pack] : content->getPacks()) {
|
||||||
if (pack->worldfuncsset.onblockplaced) {
|
if (pack->worldfuncsset.*worldfunc) {
|
||||||
lua::emit_event(
|
lua::emit_event(
|
||||||
lua::get_main_state(), packid + ":.blockplaced", args
|
lua::get_main_state(), packid + ":.block" + suffix, args
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scripting::on_block_placed(
|
||||||
|
Player* player, const Block& block, const glm::ivec3& pos
|
||||||
|
) {
|
||||||
|
on_block_common<&WorldFuncsSet::onblockplaced>(
|
||||||
|
"placed", block.rt.funcsset.onplaced, player, block, pos
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scripting::on_block_replaced(
|
void scripting::on_block_replaced(
|
||||||
Player* player, const Block& block, const glm::ivec3& pos
|
Player* player, const Block& block, const glm::ivec3& pos
|
||||||
) {
|
) {
|
||||||
if (block.rt.funcsset.onreplaced) {
|
on_block_common<&WorldFuncsSet::onblockreplaced>(
|
||||||
std::string name = block.name + ".replaced";
|
"replaced", block.rt.funcsset.onreplaced, player, block, pos
|
||||||
lua::emit_event(lua::get_main_state(), name, [pos, player](auto L) {
|
);
|
||||||
lua::pushivec_stack(L, pos);
|
}
|
||||||
lua::pushinteger(L, player ? player->getId() : -1);
|
|
||||||
return 4;
|
void scripting::on_block_breaking(
|
||||||
});
|
Player* player, const Block& block, const glm::ivec3& pos
|
||||||
}
|
) {
|
||||||
auto args = [&](lua::State* L) {
|
on_block_common<&WorldFuncsSet::onblockbreaking>(
|
||||||
lua::pushinteger(L, block.rt.id);
|
"breaking", block.rt.funcsset.onbreaking, player, block, pos
|
||||||
lua::pushivec_stack(L, pos);
|
);
|
||||||
lua::pushinteger(L, player ? player->getId() : -1);
|
|
||||||
return 5;
|
|
||||||
};
|
|
||||||
for (auto& [packid, pack] : content->getPacks()) {
|
|
||||||
if (pack->worldfuncsset.onblockreplaced) {
|
|
||||||
lua::emit_event(
|
|
||||||
lua::get_main_state(), packid + ":.blockreplaced", args
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void scripting::on_block_broken(
|
void scripting::on_block_broken(
|
||||||
Player* player, const Block& block, const glm::ivec3& pos
|
Player* player, const Block& block, const glm::ivec3& pos
|
||||||
) {
|
) {
|
||||||
if (block.rt.funcsset.onbroken) {
|
on_block_common<&WorldFuncsSet::onblockbroken>(
|
||||||
std::string name = block.name + ".broken";
|
"broken", block.rt.funcsset.onbroken, player, block, pos
|
||||||
lua::emit_event(
|
);
|
||||||
lua::get_main_state(),
|
|
||||||
name,
|
|
||||||
[pos, player](auto L) {
|
|
||||||
lua::pushivec_stack(L, pos);
|
|
||||||
lua::pushinteger(L, player ? player->getId() : -1);
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
auto args = [&](lua::State* L) {
|
|
||||||
lua::pushinteger(L, block.rt.id);
|
|
||||||
lua::pushivec_stack(L, pos);
|
|
||||||
lua::pushinteger(L, player ? player->getId() : -1);
|
|
||||||
return 5;
|
|
||||||
};
|
|
||||||
for (auto& [packid, pack] : content->getPacks()) {
|
|
||||||
if (pack->worldfuncsset.onblockbroken) {
|
|
||||||
lua::emit_event(
|
|
||||||
lua::get_main_state(), packid + ":.blockbroken", args
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool scripting::on_block_interact(
|
bool scripting::on_block_interact(
|
||||||
Player* player, const Block& block, const glm::ivec3& pos
|
Player* player, const Block& block, const glm::ivec3& pos
|
||||||
) {
|
) {
|
||||||
std::string name = block.name + ".interact";
|
return on_block_common<&WorldFuncsSet::onblockinteract>(
|
||||||
auto result = lua::emit_event(lua::get_main_state(), name, [pos, player](auto L) {
|
"interact", block.rt.funcsset.oninteract, player, block, pos
|
||||||
lua::pushivec_stack(L, pos);
|
);
|
||||||
lua::pushinteger(L, player->getId());
|
|
||||||
return 4;
|
|
||||||
});
|
|
||||||
auto args = [&](lua::State* L) {
|
|
||||||
lua::pushinteger(L, block.rt.id);
|
|
||||||
lua::pushivec_stack(L, pos);
|
|
||||||
lua::pushinteger(L, player ? player->getId() : -1);
|
|
||||||
return 5;
|
|
||||||
};
|
|
||||||
for (auto& [packid, pack] : content->getPacks()) {
|
|
||||||
if (pack->worldfuncsset.onblockinteract) {
|
|
||||||
lua::emit_event(
|
|
||||||
lua::get_main_state(), packid + ":.blockinteract", args
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void scripting::on_player_tick(Player* player, int tps) {
|
void scripting::on_player_tick(Player* player, int tps) {
|
||||||
@@ -599,7 +567,7 @@ static void process_entity_callback(
|
|||||||
static void process_entity_callback(
|
static void process_entity_callback(
|
||||||
const Entity& entity,
|
const Entity& entity,
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
bool entity_funcs_set::*flag,
|
bool EntityFuncsSet::*flag,
|
||||||
std::function<int(lua::State*)> args
|
std::function<int(lua::State*)> args
|
||||||
) {
|
) {
|
||||||
const auto& script = entity.getScripting();
|
const auto& script = entity.getScripting();
|
||||||
@@ -612,7 +580,7 @@ static void process_entity_callback(
|
|||||||
|
|
||||||
void scripting::on_entity_despawn(const Entity& entity) {
|
void scripting::on_entity_despawn(const Entity& entity) {
|
||||||
process_entity_callback(
|
process_entity_callback(
|
||||||
entity, "on_despawn", &entity_funcs_set::on_despawn, nullptr
|
entity, "on_despawn", &EntityFuncsSet::on_despawn, nullptr
|
||||||
);
|
);
|
||||||
auto L = lua::get_main_state();
|
auto L = lua::get_main_state();
|
||||||
lua::get_from(L, "stdcomp", "remove_Entity", true);
|
lua::get_from(L, "stdcomp", "remove_Entity", true);
|
||||||
@@ -624,20 +592,20 @@ void scripting::on_entity_grounded(const Entity& entity, float force) {
|
|||||||
process_entity_callback(
|
process_entity_callback(
|
||||||
entity,
|
entity,
|
||||||
"on_grounded",
|
"on_grounded",
|
||||||
&entity_funcs_set::on_grounded,
|
&EntityFuncsSet::on_grounded,
|
||||||
[force](auto L) { return lua::pushnumber(L, force); }
|
[force](auto L) { return lua::pushnumber(L, force); }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scripting::on_entity_fall(const Entity& entity) {
|
void scripting::on_entity_fall(const Entity& entity) {
|
||||||
process_entity_callback(
|
process_entity_callback(
|
||||||
entity, "on_fall", &entity_funcs_set::on_fall, nullptr
|
entity, "on_fall", &EntityFuncsSet::on_fall, nullptr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scripting::on_entity_save(const Entity& entity) {
|
void scripting::on_entity_save(const Entity& entity) {
|
||||||
process_entity_callback(
|
process_entity_callback(
|
||||||
entity, "on_save", &entity_funcs_set::on_save, nullptr
|
entity, "on_save", &EntityFuncsSet::on_save, nullptr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,7 +615,7 @@ void scripting::on_sensor_enter(
|
|||||||
process_entity_callback(
|
process_entity_callback(
|
||||||
entity,
|
entity,
|
||||||
"on_sensor_enter",
|
"on_sensor_enter",
|
||||||
&entity_funcs_set::on_sensor_enter,
|
&EntityFuncsSet::on_sensor_enter,
|
||||||
[index, oid](auto L) {
|
[index, oid](auto L) {
|
||||||
lua::pushinteger(L, index);
|
lua::pushinteger(L, index);
|
||||||
lua::pushinteger(L, oid);
|
lua::pushinteger(L, oid);
|
||||||
@@ -662,7 +630,7 @@ void scripting::on_sensor_exit(
|
|||||||
process_entity_callback(
|
process_entity_callback(
|
||||||
entity,
|
entity,
|
||||||
"on_sensor_exit",
|
"on_sensor_exit",
|
||||||
&entity_funcs_set::on_sensor_exit,
|
&EntityFuncsSet::on_sensor_exit,
|
||||||
[index, oid](auto L) {
|
[index, oid](auto L) {
|
||||||
lua::pushinteger(L, index);
|
lua::pushinteger(L, index);
|
||||||
lua::pushinteger(L, oid);
|
lua::pushinteger(L, oid);
|
||||||
@@ -675,7 +643,7 @@ void scripting::on_aim_on(const Entity& entity, Player* player) {
|
|||||||
process_entity_callback(
|
process_entity_callback(
|
||||||
entity,
|
entity,
|
||||||
"on_aim_on",
|
"on_aim_on",
|
||||||
&entity_funcs_set::on_aim_on,
|
&EntityFuncsSet::on_aim_on,
|
||||||
[player](auto L) { return lua::pushinteger(L, player->getId()); }
|
[player](auto L) { return lua::pushinteger(L, player->getId()); }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -684,7 +652,7 @@ void scripting::on_aim_off(const Entity& entity, Player* player) {
|
|||||||
process_entity_callback(
|
process_entity_callback(
|
||||||
entity,
|
entity,
|
||||||
"on_aim_off",
|
"on_aim_off",
|
||||||
&entity_funcs_set::on_aim_off,
|
&EntityFuncsSet::on_aim_off,
|
||||||
[player](auto L) { return lua::pushinteger(L, player->getId()); }
|
[player](auto L) { return lua::pushinteger(L, player->getId()); }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -695,7 +663,7 @@ void scripting::on_attacked(
|
|||||||
process_entity_callback(
|
process_entity_callback(
|
||||||
entity,
|
entity,
|
||||||
"on_attacked",
|
"on_attacked",
|
||||||
&entity_funcs_set::on_attacked,
|
&EntityFuncsSet::on_attacked,
|
||||||
[player, attacker](auto L) {
|
[player, attacker](auto L) {
|
||||||
lua::pushinteger(L, attacker);
|
lua::pushinteger(L, attacker);
|
||||||
lua::pushinteger(L, player->getId());
|
lua::pushinteger(L, player->getId());
|
||||||
@@ -708,7 +676,7 @@ void scripting::on_entity_used(const Entity& entity, Player* player) {
|
|||||||
process_entity_callback(
|
process_entity_callback(
|
||||||
entity,
|
entity,
|
||||||
"on_used",
|
"on_used",
|
||||||
&entity_funcs_set::on_used,
|
&EntityFuncsSet::on_used,
|
||||||
[player](auto L) { return lua::pushinteger(L, player->getId()); }
|
[player](auto L) { return lua::pushinteger(L, player->getId()); }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -796,7 +764,7 @@ void scripting::load_content_script(
|
|||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
const fs::path& file,
|
const fs::path& file,
|
||||||
const std::string& fileName,
|
const std::string& fileName,
|
||||||
block_funcs_set& funcsset
|
BlockFuncsSet& funcsset
|
||||||
) {
|
) {
|
||||||
int env = *senv;
|
int env = *senv;
|
||||||
lua::pop(lua::get_main_state(), load_script(env, "block", file, fileName));
|
lua::pop(lua::get_main_state(), load_script(env, "block", file, fileName));
|
||||||
@@ -804,6 +772,8 @@ void scripting::load_content_script(
|
|||||||
funcsset.update = register_event(env, "on_update", prefix + ".update");
|
funcsset.update = register_event(env, "on_update", prefix + ".update");
|
||||||
funcsset.randupdate =
|
funcsset.randupdate =
|
||||||
register_event(env, "on_random_update", prefix + ".randupdate");
|
register_event(env, "on_random_update", prefix + ".randupdate");
|
||||||
|
funcsset.onbreaking =
|
||||||
|
register_event(env, "on_breaking", prefix + ".breaking");
|
||||||
funcsset.onbroken = register_event(env, "on_broken", prefix + ".broken");
|
funcsset.onbroken = register_event(env, "on_broken", prefix + ".broken");
|
||||||
funcsset.onplaced = register_event(env, "on_placed", prefix + ".placed");
|
funcsset.onplaced = register_event(env, "on_placed", prefix + ".placed");
|
||||||
funcsset.onreplaced =
|
funcsset.onreplaced =
|
||||||
@@ -819,7 +789,7 @@ void scripting::load_content_script(
|
|||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
const fs::path& file,
|
const fs::path& file,
|
||||||
const std::string& fileName,
|
const std::string& fileName,
|
||||||
item_funcs_set& funcsset
|
ItemFuncsSet& funcsset
|
||||||
) {
|
) {
|
||||||
int env = *senv;
|
int env = *senv;
|
||||||
lua::pop(lua::get_main_state(), load_script(env, "item", file, fileName));
|
lua::pop(lua::get_main_state(), load_script(env, "item", file, fileName));
|
||||||
@@ -846,7 +816,7 @@ void scripting::load_world_script(
|
|||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
const fs::path& file,
|
const fs::path& file,
|
||||||
const std::string& fileName,
|
const std::string& fileName,
|
||||||
world_funcs_set& funcsset
|
WorldFuncsSet& funcsset
|
||||||
) {
|
) {
|
||||||
int env = *senv;
|
int env = *senv;
|
||||||
lua::pop(lua::get_main_state(), load_script(env, "world", file, fileName));
|
lua::pop(lua::get_main_state(), load_script(env, "world", file, fileName));
|
||||||
@@ -857,6 +827,8 @@ void scripting::load_world_script(
|
|||||||
register_event(env, "on_world_quit", prefix + ":.worldquit");
|
register_event(env, "on_world_quit", prefix + ":.worldquit");
|
||||||
funcsset.onblockplaced =
|
funcsset.onblockplaced =
|
||||||
register_event(env, "on_block_placed", prefix + ":.blockplaced");
|
register_event(env, "on_block_placed", prefix + ":.blockplaced");
|
||||||
|
funcsset.onblockbreaking =
|
||||||
|
register_event(env, "on_block_breaking", prefix + ":.blockbreaking");
|
||||||
funcsset.onblockbroken =
|
funcsset.onblockbroken =
|
||||||
register_event(env, "on_block_broken", prefix + ":.blockbroken");
|
register_event(env, "on_block_broken", prefix + ":.blockbroken");
|
||||||
funcsset.onblockreplaced =
|
funcsset.onblockreplaced =
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ class Player;
|
|||||||
struct ItemDef;
|
struct ItemDef;
|
||||||
class Inventory;
|
class Inventory;
|
||||||
class UiDocument;
|
class UiDocument;
|
||||||
struct block_funcs_set;
|
struct BlockFuncsSet;
|
||||||
struct item_funcs_set;
|
struct ItemFuncsSet;
|
||||||
struct world_funcs_set;
|
struct WorldFuncsSet;
|
||||||
struct UserComponent;
|
struct UserComponent;
|
||||||
struct uidocscript;
|
struct uidocscript;
|
||||||
class BlocksController;
|
class BlocksController;
|
||||||
@@ -77,6 +77,9 @@ namespace scripting {
|
|||||||
void on_block_replaced(
|
void on_block_replaced(
|
||||||
Player* player, const Block& block, const glm::ivec3& pos
|
Player* player, const Block& block, const glm::ivec3& pos
|
||||||
);
|
);
|
||||||
|
void on_block_breaking(
|
||||||
|
Player* player, const Block& block, const glm::ivec3& pos
|
||||||
|
);
|
||||||
void on_block_broken(
|
void on_block_broken(
|
||||||
Player* player, const Block& block, const glm::ivec3& pos
|
Player* player, const Block& block, const glm::ivec3& pos
|
||||||
);
|
);
|
||||||
@@ -141,7 +144,7 @@ namespace scripting {
|
|||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
const std::filesystem::path& file,
|
const std::filesystem::path& file,
|
||||||
const std::string& fileName,
|
const std::string& fileName,
|
||||||
block_funcs_set& funcsset
|
BlockFuncsSet& funcsset
|
||||||
);
|
);
|
||||||
|
|
||||||
/// @brief Load script associated with an Item
|
/// @brief Load script associated with an Item
|
||||||
@@ -155,7 +158,7 @@ namespace scripting {
|
|||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
const std::filesystem::path& file,
|
const std::filesystem::path& file,
|
||||||
const std::string& fileName,
|
const std::string& fileName,
|
||||||
item_funcs_set& funcsset
|
ItemFuncsSet& funcsset
|
||||||
);
|
);
|
||||||
|
|
||||||
/// @brief Load component script
|
/// @brief Load component script
|
||||||
@@ -184,7 +187,7 @@ namespace scripting {
|
|||||||
const std::string& packid,
|
const std::string& packid,
|
||||||
const std::filesystem::path& file,
|
const std::filesystem::path& file,
|
||||||
const std::string& fileName,
|
const std::string& fileName,
|
||||||
world_funcs_set& funcsset
|
WorldFuncsSet& funcsset
|
||||||
);
|
);
|
||||||
|
|
||||||
/// @brief Load script associated with an UiDocument
|
/// @brief Load script associated with an UiDocument
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include "UVRegion.hpp"
|
||||||
|
|
||||||
|
struct UVFace {
|
||||||
|
std::array<glm::vec2, 4> points;
|
||||||
|
|
||||||
|
UVFace(const UVRegion& region) {
|
||||||
|
points[0] = {region.u1, region.v1};
|
||||||
|
points[1] = {region.u2, region.v1};
|
||||||
|
points[2] = {region.u2, region.v2};
|
||||||
|
points[3] = {region.u1, region.v2};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int n>
|
||||||
|
inline void rotate(int times) {
|
||||||
|
int times = n % 4;
|
||||||
|
if (times < 0) {
|
||||||
|
times += 4;
|
||||||
|
}
|
||||||
|
std::array<glm::vec2, 4> temp = points;
|
||||||
|
points[0] = temp[times];
|
||||||
|
points[1] = temp[(times + 1) % 4];
|
||||||
|
points[2] = temp[(times + 2) % 4];
|
||||||
|
points[3] = temp[(times + 3) % 4];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -162,7 +162,7 @@ entityid_t Entities::spawn(
|
|||||||
|
|
||||||
for (auto& componentName : def.components) {
|
for (auto& componentName : def.components) {
|
||||||
auto component = std::make_unique<UserComponent>(
|
auto component = std::make_unique<UserComponent>(
|
||||||
componentName, entity_funcs_set {}, nullptr
|
componentName, EntityFuncsSet {}, nullptr
|
||||||
);
|
);
|
||||||
scripting.components.emplace_back(std::move(component));
|
scripting.components.emplace_back(std::move(component));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
#include <glm/gtx/norm.hpp>
|
#include <glm/gtx/norm.hpp>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
struct entity_funcs_set {
|
struct EntityFuncsSet {
|
||||||
bool init;
|
bool init;
|
||||||
bool on_despawn;
|
bool on_despawn;
|
||||||
bool on_grounded;
|
bool on_grounded;
|
||||||
@@ -77,11 +77,11 @@ struct Rigidbody {
|
|||||||
|
|
||||||
struct UserComponent {
|
struct UserComponent {
|
||||||
std::string name;
|
std::string name;
|
||||||
entity_funcs_set funcsset;
|
EntityFuncsSet funcsset;
|
||||||
scriptenv env;
|
scriptenv env;
|
||||||
|
|
||||||
UserComponent(
|
UserComponent(
|
||||||
const std::string& name, entity_funcs_set funcsset, scriptenv env
|
const std::string& name, EntityFuncsSet funcsset, scriptenv env
|
||||||
)
|
)
|
||||||
: name(name), funcsset(funcsset), env(env) {
|
: name(name), funcsset(funcsset), env(env) {
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-11
@@ -135,18 +135,7 @@ void Player::updateInput(PlayerInput& input, float delta) {
|
|||||||
hitbox->velocity.y = JUMP_FORCE;
|
hitbox->velocity.y = JUMP_FORCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((input.flight && !noclip) || (input.noclip && flight == noclip)) {
|
|
||||||
flight = !flight;
|
|
||||||
if (flight) {
|
|
||||||
hitbox->velocity.y += 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hitbox->type = noclip ? BodyType::KINEMATIC : BodyType::DYNAMIC;
|
hitbox->type = noclip ? BodyType::KINEMATIC : BodyType::DYNAMIC;
|
||||||
if (input.noclip) {
|
|
||||||
noclip = !noclip;
|
|
||||||
}
|
|
||||||
input.noclip = false;
|
|
||||||
input.flight = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::updateSelectedEntity() {
|
void Player::updateSelectedEntity() {
|
||||||
@@ -262,6 +251,14 @@ void Player::setInstantDestruction(bool flag) {
|
|||||||
instantDestruction = flag;
|
instantDestruction = flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Player::isLoadingChunks() const {
|
||||||
|
return loadingChunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::setLoadingChunks(bool flag) {
|
||||||
|
loadingChunks = flag;
|
||||||
|
}
|
||||||
|
|
||||||
entityid_t Player::getEntity() const {
|
entityid_t Player::getEntity() const {
|
||||||
return eid;
|
return eid;
|
||||||
}
|
}
|
||||||
@@ -308,6 +305,7 @@ dv::value Player::serialize() const {
|
|||||||
root["noclip"] = noclip;
|
root["noclip"] = noclip;
|
||||||
root["infinite-items"] = infiniteItems;
|
root["infinite-items"] = infiniteItems;
|
||||||
root["instant-destruction"] = instantDestruction;
|
root["instant-destruction"] = instantDestruction;
|
||||||
|
root["loading-chunks"] = loadingChunks;
|
||||||
root["chosen-slot"] = chosenSlot;
|
root["chosen-slot"] = chosenSlot;
|
||||||
root["entity"] = eid;
|
root["entity"] = eid;
|
||||||
root["inventory"] = inventory->serialize();
|
root["inventory"] = inventory->serialize();
|
||||||
@@ -340,6 +338,7 @@ void Player::deserialize(const dv::value& src) {
|
|||||||
noclip = src["noclip"].asBoolean();
|
noclip = src["noclip"].asBoolean();
|
||||||
src.at("infinite-items").get(infiniteItems);
|
src.at("infinite-items").get(infiniteItems);
|
||||||
src.at("instant-destruction").get(instantDestruction);
|
src.at("instant-destruction").get(instantDestruction);
|
||||||
|
src.at("loading-chunks").get(loadingChunks);
|
||||||
|
|
||||||
setChosenSlot(src["chosen-slot"].asInteger());
|
setChosenSlot(src["chosen-slot"].asInteger());
|
||||||
eid = src["entity"].asNumber();
|
eid = src["entity"].asNumber();
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ struct PlayerInput {
|
|||||||
bool shift : 1;
|
bool shift : 1;
|
||||||
bool cheat : 1;
|
bool cheat : 1;
|
||||||
bool jump : 1;
|
bool jump : 1;
|
||||||
bool noclip : 1;
|
|
||||||
bool flight : 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CursorSelection {
|
struct CursorSelection {
|
||||||
@@ -53,13 +51,13 @@ class Player : public Serializable {
|
|||||||
bool noclip = false;
|
bool noclip = false;
|
||||||
bool infiniteItems = true;
|
bool infiniteItems = true;
|
||||||
bool instantDestruction = true;
|
bool instantDestruction = true;
|
||||||
|
bool loadingChunks = true;
|
||||||
entityid_t eid;
|
entityid_t eid;
|
||||||
entityid_t selectedEid = 0;
|
entityid_t selectedEid = 0;
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<Chunks> chunks; // not in use yet
|
std::unique_ptr<Chunks> chunks;
|
||||||
std::shared_ptr<Camera> fpCamera, spCamera, tpCamera;
|
std::shared_ptr<Camera> fpCamera, spCamera, tpCamera;
|
||||||
std::shared_ptr<Camera> currentCamera;
|
std::shared_ptr<Camera> currentCamera;;
|
||||||
bool debug = false;
|
|
||||||
glm::vec3 cam {};
|
glm::vec3 cam {};
|
||||||
CursorSelection selection {};
|
CursorSelection selection {};
|
||||||
|
|
||||||
@@ -99,6 +97,9 @@ public:
|
|||||||
bool isInstantDestruction() const;
|
bool isInstantDestruction() const;
|
||||||
void setInstantDestruction(bool flag);
|
void setInstantDestruction(bool flag);
|
||||||
|
|
||||||
|
bool isLoadingChunks() const;
|
||||||
|
void setLoadingChunks(bool flag);
|
||||||
|
|
||||||
entityid_t getEntity() const;
|
entityid_t getEntity() const;
|
||||||
void setEntity(entityid_t eid);
|
void setEntity(entityid_t eid);
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ dv::value ParticlesPreset::serialize() const {
|
|||||||
root["explosion"] = dv::to_value(explosion);
|
root["explosion"] = dv::to_value(explosion);
|
||||||
root["size"] = dv::to_value(size);
|
root["size"] = dv::to_value(size);
|
||||||
root["size_spread"] = sizeSpread;
|
root["size_spread"] = sizeSpread;
|
||||||
|
root["angle_spread"] = angleSpread;
|
||||||
|
root["min_angular_vel"] = minAngularVelocity;
|
||||||
|
root["max_angular_vel"] = maxAngularVelocity;
|
||||||
root["spawn_spread"] = dv::to_value(size);
|
root["spawn_spread"] = dv::to_value(size);
|
||||||
root["spawn_shape"] = to_string(spawnShape);
|
root["spawn_shape"] = to_string(spawnShape);
|
||||||
root["random_sub_uv"] = randomSubUV;
|
root["random_sub_uv"] = randomSubUV;
|
||||||
@@ -58,6 +61,9 @@ void ParticlesPreset::deserialize(const dv::value& src) {
|
|||||||
src.at("spawn_interval").get(spawnInterval);
|
src.at("spawn_interval").get(spawnInterval);
|
||||||
src.at("lifetime").get(lifetime);
|
src.at("lifetime").get(lifetime);
|
||||||
src.at("lifetime_spread").get(lifetimeSpread);
|
src.at("lifetime_spread").get(lifetimeSpread);
|
||||||
|
src.at("angle_spread").get(angleSpread);
|
||||||
|
src.at("min_angular_vel").get(minAngularVelocity);
|
||||||
|
src.at("max_angular_vel").get(maxAngularVelocity);
|
||||||
src.at("random_sub_uv").get(randomSubUV);
|
src.at("random_sub_uv").get(randomSubUV);
|
||||||
if (src.has("velocity")) {
|
if (src.has("velocity")) {
|
||||||
dv::get_vec(src["velocity"], velocity);
|
dv::get_vec(src["velocity"], velocity);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ struct ParticlesPreset : public Serializable {
|
|||||||
/// @brief Use global up vector instead of camera-dependent one
|
/// @brief Use global up vector instead of camera-dependent one
|
||||||
bool globalUpVector = false;
|
bool globalUpVector = false;
|
||||||
/// @brief Max distance of actually spawning particles.
|
/// @brief Max distance of actually spawning particles.
|
||||||
float maxDistance = 16.0f;
|
float maxDistance = 32.0f;
|
||||||
/// @brief Particles spawn interval
|
/// @brief Particles spawn interval
|
||||||
float spawnInterval = 0.1f;
|
float spawnInterval = 0.1f;
|
||||||
/// @brief Particle life time
|
/// @brief Particle life time
|
||||||
@@ -44,6 +44,12 @@ struct ParticlesPreset : public Serializable {
|
|||||||
glm::vec3 size {0.1f};
|
glm::vec3 size {0.1f};
|
||||||
/// @brief Particles size spread
|
/// @brief Particles size spread
|
||||||
float sizeSpread = 0.2f;
|
float sizeSpread = 0.2f;
|
||||||
|
/// @brief Random initial angle spread
|
||||||
|
float angleSpread = 0.0f;
|
||||||
|
/// @brief Minimum angular velocity
|
||||||
|
float minAngularVelocity = 0.0f;
|
||||||
|
/// @brief Maximum angular velocity
|
||||||
|
float maxAngularVelocity = 0.0f;
|
||||||
/// @brief Spawn spread shape
|
/// @brief Spawn spread shape
|
||||||
ParticleSpawnShape spawnShape = BALL;
|
ParticleSpawnShape spawnShape = BALL;
|
||||||
/// @brief Spawn spread
|
/// @brief Spawn spread
|
||||||
|
|||||||
@@ -63,16 +63,24 @@ struct GraphicsSettings {
|
|||||||
NumberSetting gamma {1.0f, 0.4f, 1.0f};
|
NumberSetting gamma {1.0f, 0.4f, 1.0f};
|
||||||
/// @brief Enable blocks backlight to prevent complete darkness
|
/// @brief Enable blocks backlight to prevent complete darkness
|
||||||
FlagSetting backlight {true};
|
FlagSetting backlight {true};
|
||||||
|
/// @brief Disable culling with 'optional' mode
|
||||||
|
FlagSetting denseRender {true};
|
||||||
/// @brief Enable chunks frustum culling
|
/// @brief Enable chunks frustum culling
|
||||||
FlagSetting frustumCulling {true};
|
FlagSetting frustumCulling {true};
|
||||||
|
/// @brief Skybox texture face resolution
|
||||||
IntegerSetting skyboxResolution {64 + 32, 64, 128};
|
IntegerSetting skyboxResolution {64 + 32, 64, 128};
|
||||||
|
/// @brief Chunk renderer vertices buffer capacity
|
||||||
IntegerSetting chunkMaxVertices {200'000, 0, 4'000'000};
|
IntegerSetting chunkMaxVertices {200'000, 0, 4'000'000};
|
||||||
|
/// @brief Chunk renderer vertices buffer capacity in dense render mode
|
||||||
|
IntegerSetting chunkMaxVerticesDense {800'000, 0, 8'000'000};
|
||||||
|
/// @brief Limit of chunk renderers count
|
||||||
IntegerSetting chunkMaxRenderers {6, -4, 32};
|
IntegerSetting chunkMaxRenderers {6, -4, 32};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DebugSettings {
|
struct DebugSettings {
|
||||||
/// @brief Turns off chunks saving/loading
|
/// @brief Turns off chunks saving/loading
|
||||||
FlagSetting generatorTestMode {false};
|
FlagSetting generatorTestMode {false};
|
||||||
|
/// @brief Write lights cache
|
||||||
FlagSetting doWriteLights {true};
|
FlagSetting doWriteLights {true};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,30 @@ std::optional<BlockModel> BlockModel_from(std::string_view str) {
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string to_string(CullingMode mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case CullingMode::DEFAULT:
|
||||||
|
return "default";
|
||||||
|
case CullingMode::OPTIONAL:
|
||||||
|
return "optional";
|
||||||
|
case CullingMode::DISABLED:
|
||||||
|
return "disabled";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<CullingMode> CullingMode_from(std::string_view str) {
|
||||||
|
if (str == "default") {
|
||||||
|
return CullingMode::DEFAULT;
|
||||||
|
} else if (str == "optional") {
|
||||||
|
return CullingMode::OPTIONAL;
|
||||||
|
} else if (str == "disabled") {
|
||||||
|
return CullingMode::DISABLED;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
CoordSystem::CoordSystem(glm::ivec3 axisX, glm::ivec3 axisY, glm::ivec3 axisZ)
|
CoordSystem::CoordSystem(glm::ivec3 axisX, glm::ivec3 axisY, glm::ivec3 axisZ)
|
||||||
: axisX(axisX), axisY(axisY), axisZ(axisZ) {
|
: axisX(axisX), axisY(axisY), axisZ(axisZ) {
|
||||||
fix = glm::ivec3(0);
|
fix = glm::ivec3(0);
|
||||||
|
|||||||
+15
-2
@@ -34,10 +34,11 @@ inline constexpr size_t MAX_USER_BLOCK_FIELDS_SIZE = 240;
|
|||||||
|
|
||||||
inline std::string DEFAULT_MATERIAL = "base:stone";
|
inline std::string DEFAULT_MATERIAL = "base:stone";
|
||||||
|
|
||||||
struct block_funcs_set {
|
struct BlockFuncsSet {
|
||||||
bool init : 1;
|
bool init : 1;
|
||||||
bool update : 1;
|
bool update : 1;
|
||||||
bool onplaced : 1;
|
bool onplaced : 1;
|
||||||
|
bool onbreaking : 1;
|
||||||
bool onbroken : 1;
|
bool onbroken : 1;
|
||||||
bool onreplaced : 1;
|
bool onreplaced : 1;
|
||||||
bool oninteract : 1;
|
bool oninteract : 1;
|
||||||
@@ -97,6 +98,15 @@ enum class BlockModel {
|
|||||||
std::string to_string(BlockModel model);
|
std::string to_string(BlockModel model);
|
||||||
std::optional<BlockModel> BlockModel_from(std::string_view str);
|
std::optional<BlockModel> BlockModel_from(std::string_view str);
|
||||||
|
|
||||||
|
enum class CullingMode {
|
||||||
|
DEFAULT,
|
||||||
|
OPTIONAL,
|
||||||
|
DISABLED,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string to_string(CullingMode mode);
|
||||||
|
std::optional<CullingMode> CullingMode_from(std::string_view str);
|
||||||
|
|
||||||
using BoxModel = AABB;
|
using BoxModel = AABB;
|
||||||
|
|
||||||
/// @brief Common kit of block properties applied to groups of blocks
|
/// @brief Common kit of block properties applied to groups of blocks
|
||||||
@@ -142,6 +152,9 @@ public:
|
|||||||
|
|
||||||
std::string modelName = "";
|
std::string modelName = "";
|
||||||
|
|
||||||
|
/// @brief Culling mode
|
||||||
|
CullingMode culling = CullingMode::DEFAULT;
|
||||||
|
|
||||||
/// @brief Does the block passing lights into itself
|
/// @brief Does the block passing lights into itself
|
||||||
bool lightPassing = false;
|
bool lightPassing = false;
|
||||||
|
|
||||||
@@ -229,7 +242,7 @@ public:
|
|||||||
std::vector<AABB> hitboxes[BlockRotProfile::MAX_COUNT];
|
std::vector<AABB> hitboxes[BlockRotProfile::MAX_COUNT];
|
||||||
|
|
||||||
/// @brief set of block callbacks flags
|
/// @brief set of block callbacks flags
|
||||||
block_funcs_set funcsset {};
|
BlockFuncsSet funcsset {};
|
||||||
|
|
||||||
/// @brief picking item integer id
|
/// @brief picking item integer id
|
||||||
itemid_t pickingItem = 0;
|
itemid_t pickingItem = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user