diff --git a/doc/en/block-properties.md b/doc/en/block-properties.md
index 19cd01d1..1827a026 100644
--- a/doc/en/block-properties.md
+++ b/doc/en/block-properties.md
@@ -71,6 +71,10 @@ Vertical sky light ray ignores block if **true**. (used for water)
Turns off block model shading
+### *ambient-occlusion* (Vertex-based Ambient-Occlusion)
+
+Determines the presence of the vertex AO effect. Turned-on by default.
+
## Physics
### *obstacle*
diff --git a/doc/en/scripting.md b/doc/en/scripting.md
index 2ae09e3b..5de576e5 100644
--- a/doc/en/scripting.md
+++ b/doc/en/scripting.md
@@ -13,6 +13,7 @@ Subsections:
- [entities](scripting/builtins/libentities.md)
- [cameras](scripting/builtins/libcameras.md)
- [mat4](scripting/builtins/libmat4.md)
+ - [player](scripting/builtins/libplayer.md)
- [quat](scripting/builtins/libquat.md)
- [vec2, vec3, vec4](scripting/builtins/libvecn.md)
- [Module core:bit_converter](scripting/modules/core_bit_converter.md)
@@ -62,76 +63,55 @@ file.write(pack.data_file(PACK_ID, "example.txt"), text)
For pack *containermod* will write text to the file `world:data/containermod/example.txt`
-## *player* library
+```python
+pack.get_folder(packid: str) -> str
+```
+
+Returns installed content-pack folder.
```python
-player.get_pos(playerid: int) -> number, number, number
+pack.is_installed(packid: str) -> bool
```
-Returns x, y, z coordinates of the player
+Check if the world has specified pack installed.
```python
-player.set_pos(playerid: int, x: number, y: number, z: number)
+pack.get_installed() -> strings array
```
-Set player position
+Returns all installed content-pack ids.
```python
-player.get_rot(playerid: int) -> number, number, number
+pack.get_available() -> strings array
```
-Returns x, y, z of camera rotation (radians)
+Returns the ids of all content packs available but not installed in the world.
```python
-player.set_rot(playerid: int, x: number, y: number, z: number)
+pack.get_base_packs() -> strings array
```
-Set camera rotation (radians)
+Returns the id of all base packages (non-removeable)
```python
-player.get_inventory(playerid: int) -> int, int
+pack.get_info(packid: str) -> {
+ id: str,
+ title: str,
+ creator: str,
+ description: str,
+ version: str,
+ icon: str,
+ dependencies: optional strings array
+}
```
-Returns player inventory ID and selected slot index (0-9)
-
-```python
-player.is_flight() -> bool
-player.set_flight(bool)
-```
-
-Getter and setter for player flight mode
-
-```python
-player.is_noclip() -> bool
-player.set_noclip(bool)
-```
-
-Getter and setter for player noclip mode (collisions disabled)
-
-``` python
-player.set_spawnpoint(playerid: int, x: number, y: number, z: number)
-player.get_spawnpoint(playerid: int) -> number, number, number
-```
-
-Point setter and getter added by player
-
-```python
-player.get_selected_block(playerid: int) -> x,y,z
-```
-
-Returns position of the selected block or nil
-
-```python
-player.get_selected_entity(playerid: int) -> int
-```
-
-Returns unique indentifier of the entity selected by player
-
-```python
-player.get_entity(playerid: int) -> int
-```
-
-Returns unique identifier of the player entity
+Returns information about the pack (not necessarily installed).
+- icon - name of the preview texture (loading automatically)
+- dependencies - strings following format `{lvl}{id}`, where lvl:
+ - `!` - required
+ - `?` - optional
+ - `~` - weak
+ for example `!teal`
## *world* library
@@ -200,57 +180,6 @@ world.exists() -> bool
Checks the existence of a world by name.
-## *pack* library
-
-```python
-pack.get_folder(packid: str) -> str
-```
-
-Returns installed content-pack folder.
-
-```python
-pack.is_installed(packid: str) -> bool
-```
-
-Check if the world has specified pack installed.
-
-```python
-pack.get_installed() -> strings array
-```
-
-Returns all installed content-pack ids.
-
-```python
-pack.get_available() -> strings array
-```
-
-Returns the ids of all content packs available but not installed in the world.
-
-```python
-pack.get_base_packs() -> strings array
-```
-
-Returns the id of all base packages (non-removeable)
-
-```python
-pack.get_info(packid: str) -> {
- id: str,
- title: str,
- creator: str,
- description: str,
- version: str,
- icon: str,
- dependencies: optional strings array
-}
-```
-
-Returns information about the pack (not necessarily installed).
-- icon - name of the preview texture (loading automatically)
-- dependencies - strings following format `{lvl}{id}`, where lvl:
- - `!` - required
- - `?` - optional
- - `~` - weak
- for example `!teal`
## *gui* library
@@ -282,7 +211,7 @@ gui.get_env(document: str) -> table
Returns environment (global variables table) of the specified document.
```python
-get_locales_info() -> table of tables where
+gui.get_locales_info() -> table of tables where
key - locale id following isolangcode_ISOCOUNTRYCODE format
value - table {
name: str # name of the locale in its language
diff --git a/doc/en/scripting/builtins/libblock.md b/doc/en/scripting/builtins/libblock.md
index 9516524c..6346f9d2 100644
--- a/doc/en/scripting/builtins/libblock.md
+++ b/doc/en/scripting/builtins/libblock.md
@@ -14,6 +14,7 @@ block.material(blockid: int) -> str
block.caption(blockid: int) -> str
-- Returns integer ID by block position
+-- If the chunk at the specified coordinates is not loaded, returns -1.
block.get(x: int, y: int, z: int) -> int
-- Returns block state (rotation + additional information) as an integer.
@@ -31,6 +32,12 @@ block.place(x: int, y: int, z: int, id: int, states: int, [optional] playerid: i
-- Breaks a block at the given coordinates on behalf of the player, triggering the on_broken event.
-- playerid is optional
block.destruct(x: int, y: int, z: int, playerid: int)
+
+-- Compose the complete state as an integer
+block.compose_state(rotation: int, segment: int, userbits: int) -> int
+
+-- Decompose the complete state into: rotation, segment, user bits
+block.decompose_state(state: int) -> int, int, int
```
> [!WARNING]
diff --git a/doc/en/scripting/builtins/libplayer.md b/doc/en/scripting/builtins/libplayer.md
new file mode 100644
index 00000000..dda4f450
--- /dev/null
+++ b/doc/en/scripting/builtins/libplayer.md
@@ -0,0 +1,70 @@
+# *player* library
+
+```python
+player.get_pos(playerid: int) -> number, number, number
+```
+
+Returns x, y, z coordinates of the player
+
+```python
+player.set_pos(playerid: int, x: number, y: number, z: number)
+```
+
+Set player position
+
+```python
+player.get_rot(playerid: int) -> number, number, number
+```
+
+Returns x, y, z of camera rotation (radians)
+
+```python
+player.set_rot(playerid: int, x: number, y: number, z: number)
+```
+
+Set camera rotation (radians)
+
+```python
+player.get_inventory(playerid: int) -> int, int
+```
+
+Returns player inventory ID and selected slot index (0-9)
+
+```python
+player.is_flight() -> bool
+player.set_flight(bool)
+```
+
+Getter and setter for player flight mode
+
+```python
+player.is_noclip() -> bool
+player.set_noclip(bool)
+```
+
+Getter and setter for player noclip mode (collisions disabled)
+
+``` python
+player.set_spawnpoint(playerid: int, x: number, y: number, z: number)
+player.get_spawnpoint(playerid: int) -> number, number, number
+```
+
+Point setter and getter added by player
+
+```python
+player.get_selected_block(playerid: int) -> x,y,z
+```
+
+Returns position of the selected block or nil
+
+```python
+player.get_selected_entity(playerid: int) -> int
+```
+
+Returns unique indentifier of the entity selected by player
+
+```python
+player.get_entity(playerid: int) -> int
+```
+
+Returns unique identifier of the player entity
diff --git a/doc/en/xml-ui-layouts.md b/doc/en/xml-ui-layouts.md
index cdd13aa3..61451b80 100644
--- a/doc/en/xml-ui-layouts.md
+++ b/doc/en/xml-ui-layouts.md
@@ -6,71 +6,120 @@ See also [ui elements in scripting](scripting/ui.md).
**2D vector** - pair of numbers separated with comma.
Examples:
-- "500,200"
-- "0.4,53.01"
-- "0,0"
+- `"500,200"`
+- `"0.4,53.01"`
+- `"0,0"`
**3D vector** - three numbers separated with comma.
Examples:
-- "60,30,53"
-- "0.4,0.1,0.753"
+- `"60,30,53"`
+- `"0.4,0.1,0.753"`
**4D vector** - four numbers separated with comma.
-- "10,5,10,3"
-- "0.1,0.5,0.0,0.0"
+Examples:
+- `"10,5,10,3"`
+- `"0.1,0.5,0.0,0.0"`
**RGBA color** - only HEX notation available
Examples:
-- "#FF8000" - opaque orange
-- "#FFFFFF80" - semi-transparent white
-- "#000000FF" - opaque black
+- `"#FF8000"` - opaque orange
+- `"#FFFFFF80"` - semi-transparent white
+- `"#000000FF"` - opaque black
# Common element attributes
-- **id** - element identifier. Type: string.
-- **pos** - element position. Type: 2D vector.
-- **size** - element size. Type: 2D vector.
-- **color** - element color. Type: RGBA color.
-- **margin** - element margin. Type: 4D vector
+- `id` - element identifier. Type: string.
+- `pos` - element position. Type: 2D vector.
+- `size` - element size. Type: 2D vector.
+- `color` - element color. Type: RGBA color.
+- `margin` - element margin. Type: 4D vector
*left, top, right, bottom*
-- **visible** - element visibility. Type: boolean (true/false)
-- **position-func** - position supplier for an element (two numbers), called on every parent container size update or on element adding on a container. May be called before *on_hud_open*
+- `visible` - element visibility. Type: boolean (true/false)
+- `position-func` - position supplier for an element (two numbers), called on every parent container size update or on element adding on a container. May be called before *on_hud_open*
+- `size-func` - element size provider (two numbers), called when the size of the container in which the element is located changes, or when an element is added to the container. Can be called before on_hud_open is called.
+- `onclick` - lua function called when an element is clicked.
+- `ondoubleclick` - lua function called when you double click on an element.
+- `tooltip` - tooltip text
+- `tooltip-delay` - tooltip show-up delay
+- `gravity` - automatic positioning of the element in the container. (Does not work in automatic containers like panel). Values: *top-left, top-center, top-right, center-left, center-center, center-right, bottom-left, bottom-center, bottom-right*.
+- `z-index` - determines the order of elements, with a larger value it will overlap elements with a smaller one.
+- `interactive` - if false, hovering over the element and all sub-elements will be ignored.
+
+# Template attributes
+
+- `if` with values ('', 'false', 'nil') the element will be ignored, including sub-elements.
+- `ifnot` is the same as `if`, but with the opposite condition.
+
# Common *container* attributes
Buttons and panels are also containers.
-- **padding** - element padding. Type: 4D vector.
+- `padding` - element padding. Type: 4D vector.
*left, top, right, bottom*
- **scrollable** - element scrollability. Works on panels only. Type: boolean
+ `scrollable` - element scrollability. Works on panels only. Type: boolean
# Common *panel* attributes
Buttons are also panels.
-- **max-length** - maximal length of panel stretching before scrolling (if scrollable = true). Type: number
+- `max-length` - maximal length of panel stretching before scrolling (if scrollable = true). Type: number
+- `orientation` - panel orientation: horizontal/vertical.
+
# Common elements
## *button*
Inner text is a button text.
-- **text-align** - inner text alignment (*left/center/right*). Type: string.
-- **onclick** - Lua function called on button press.
+- `text-align` - inner text alignment (*left/center/right*). Type: string.
+
+## *checkbox*
+
+- `checked` - defines the checked state.
+- `supplier` - mark state supplier (called every frame).
+- `consumer` - lua function-consumer of the state of the mark.
+
+## *label*
+
+- `valign` - vertical text alignment: top/center/bottom.
+- `supplier` - text supplier (called every frame).
+- `autoresize` - automatic change of element size (default - false). Does not affect font size.
+- `multiline` - allows display of multiline text.
+- `text-wrap` - allows automatic text wrapping (works only with multiline: "true").
## *image*
-- **src** - name of an image stored in textures folder. Extension is not specified. Type: string.
+- `src` - name of an image stored in textures folder. Extension is not specified. Type: string.
Example: *gui/error*
+ ## *textbox*
+
+Inner text - initially entered text
+
+- `placeholder` - placeholder text (used if the text field is empty)
+- `supplier` - text supplier (called every frame)
+- `consumer` - lua function that receives the entered text. Called only when input is complete
+- `autoresize` - automatic change of element size (default - false). Does not affect font size.
+- `multiline` - allows display of multiline text.
+- `text-wrap` - allows automatic text wrapping (works only with multiline: "true")
+- `editable` - determines whether the text can be edited.
+- `error-color` - color when entering incorrect data (the text does not pass the validator check). Type: RGBA color.
+- `validator` - lua function that checks text for correctness. Takes a string as input, returns true if the text is correct.
+- `onup` - lua function called when the up arrow is pressed.
+- `ondown` - lua function called when the down arrow is pressed.
+
## *trackbar*
-- **min** - minimal value. Type: number. Default: 0
-- **max** - maximal value. Type: number. Default: 1
-- **value** - initial value. Type: number. Default: 0
-- **step** - track step size. Type: number: Default: 1
-- **track-width** track pointer width (in steps). Type: number. Default: 1
-- **consumer** - Lua function - new value consumer
-- **supplier** - Lua function - value supplier
+- `min` - minimal value. Type: number. Default: 0
+- `max` - maximal value. Type: number. Default: 1
+- `value` - initial value. Type: number. Default: 0
+- `step` - track step size. Type: number: Default: 1
+- `track-width` track pointer width (in steps). Type: number. Default: 1
+- `track-color` - the color of the pointer when hovering over the cursor. Type: RGBA color.
+- `consumer` - Lua function - new value consumer
+- `sub-consumer` - Lua function that receives intermediate values (use to update text when `change-on-release="true"`)
+- `supplier` - Lua function - value supplier
+- `change-on-release` - Call consumer on trackbar release only. Type: boolean. Default: false
# Inventory elements
@@ -84,21 +133,21 @@ Element is a container. Does not have specific attributes.
## *slot*
Element must be in direct sub-element of *inventory*.
-- **index** - inventory slot index (starting from 0). Type: integer
-- **item-source** - content access panel behaviour (infinite source of an item). Type: boolean
-- **sharefunc** - Lua event called on LMB + Shift. Inventory id and slot index passed as arguments.
-- **updatefunc** - Lua event called on slot content update.Inventory id and slot index passed as arguments.
-- **onrightclick** - Lua event called on RMB click. Inventory id and slot index passed as arguments.
+- `index` - inventory slot index (starting from 0). Type: integer
+- `item-source` - content access panel behaviour (infinite source of an item). Type: boolean
+- `sharefunc` - Lua event called on LMB + Shift. Inventory id and slot index passed as arguments.
+- `updatefunc` - Lua event called on slot content update.Inventory id and slot index passed as arguments.
+- `onrightclick` - Lua event called on RMB click. Inventory id and slot index passed as arguments.
## *slots-grid*
-- **start-index** - inventory slot index of the first slot. Type: integer
-- **rows** - number of grid rows (unnecessary if *cols* and *count* specified). Type: integer
-- **cols** - number of grid columns (unnecessary if *rows* and *count* specified). Type: integer
-- **count** - total number of slots in grid (unnecessary if *rows* and *cols* specified). Type: integer
-- **interval** - visual slots interval. Type: number
-- **padding** - grid padding (not slots interval). Type: number. (*deprecated*)
-- **sharefunc** - Lua event called on LMB + Shift. Inventory id and slot index passed as arguments.
-- **updatefunc** - Lua event called on slot content update.Inventory id and slot index passed as arguments.
-- **onrightclick** - Lua event called on RMB click. Inventory id and slot index passed as arguments.
+- `start-index` - inventory slot index of the first slot. Type: integer
+- `rows` - number of grid rows (unnecessary if *cols* and *count* specified). Type: integer
+- `cols` - number of grid columns (unnecessary if *rows* and *count* specified). Type: integer
+- `count` - total number of slots in grid (unnecessary if *rows* and *cols* specified). Type: integer
+- `interval` - visual slots interval. Type: number
+- `padding` - grid padding (not slots interval). Type: number. (*deprecated*)
+- `sharefunc` - Lua event called on LMB + Shift. Inventory id and slot index passed as arguments.
+- `updatefunc` - Lua event called on slot content update.Inventory id and slot index passed as arguments.
+- `onrightclick` - Lua event called on RMB click. Inventory id and slot index passed as arguments.
diff --git a/doc/ru/block-properties.md b/doc/ru/block-properties.md
index 495fd8ca..7e3a9768 100644
--- a/doc/ru/block-properties.md
+++ b/doc/ru/block-properties.md
@@ -74,6 +74,10 @@
Выключает освещение на модели блока.
+### Вершинный Ambient-Occlusion - *ambient-occlusion*
+
+Определяет наличие эффекта вершинного AO. Включен по-умолчанию.
+
## Физика
### Препятствие - *obstacle*
diff --git a/doc/ru/scripting.md b/doc/ru/scripting.md
index 88ef3b09..c2c124e4 100644
--- a/doc/ru/scripting.md
+++ b/doc/ru/scripting.md
@@ -13,6 +13,7 @@
- [entities](scripting/builtins/libentities.md)
- [cameras](scripting/builtins/libcameras.md)
- [mat4](scripting/builtins/libmat4.md)
+ - [player](scripting/builtins/libplayer.md)
- [quat](scripting/builtins/libquat.md)
- [vec2, vec3, vec4](scripting/builtins/libvecn.md)
- [Модуль core:bit_converter](scripting/modules/core_bit_converter.md)
@@ -58,76 +59,55 @@ file.write(pack.data_file(PACK_ID, "example.txt"), text)
```
Для пака *containermod* запишет текст в файл `world:data/containermod/example.txt`
-## Библиотека *player*
-
```python
-player.get_pos(playerid: int) -> number, number, number
+pack.get_folder(packid: str) -> str
```
-Возвращает x, y, z координаты игрока
+Возвращает путь к папке установленного контент-пака.
```python
-player.set_pos(playerid: int, x: number, y: number, z: number)
+pack.is_installed(packid: str) -> bool
```
-Устанавливает x, y, z координаты игрока
+Проверяет наличие контент-пака в мире
```python
-player.get_rot(playerid: int) -> number, number, number
+pack.get_installed() -> массив строк
```
-Возвращает x, y, z вращения камеры (в радианах)
+Возращает id всех установленных в мире контент-паков.
```python
-player.set_rot(playerid: int, x: number, y: number, z: number)
+pack.get_available() -> массив строк
```
-Устанавливает x, y вращения камеры (в радианах)
+Возвращает id всех доступных, но не установленных в мире контент-паков.
```python
-player.get_inventory(playerid: int) -> int, int
+pack.get_base_packs() -> массив строк
```
-Возвращает id инвентаря игрока и индекс выбранного слота (от 0 до 9)
+Возвращает id всех базовых паков (неудаляемых)
```python
-player.is_flight() -> bool
-player.set_flight(bool)
+pack.get_info(packid: str) -> {
+ id: str,
+ title: str,
+ creator: str,
+ description: str,
+ version: str,
+ icon: str,
+ dependencies: опциональный массив строк
+}
```
-Геттер и сеттер режима полета
-
-```python
-player.is_noclip() -> bool
-player.set_noclip(bool)
-```
-
-Геттер и сеттер noclip режима (выключенная коллизия игрока)
-
-```python
-player.set_spawnpoint(playerid: int, x: number, y: number, z: number)
-player.get_spawnpoint(playerid: int) -> number, number, number
-```
-
-Сеттер и геттер точки спавна игрока
-
-```python
-player.get_selected_block(playerid: int) -> x,y,z
-```
-
-Возвращает координаты выделенного блока, либо nil
-
-```python
-player.get_selected_entity(playerid: int) -> int
-```
-
-Возвращает уникальный идентификатор сущности, на которую нацелен игрок
-
-```python
-player.get_entity(playerid: int) -> int
-```
-
-Возвращает уникальный идентификатор сущности игрока
+Возвращает информацию о паке (не обязательно установленном).
+- icon - название текстуры предпросмотра (загружается автоматически)
+- dependencies - строки в формате `{lvl}{id}`, где lvl:
+ - `!` - required
+ - `?` - optional
+ - `~` - weak
+ например `!teal`
## Библиотека *world*
@@ -194,58 +174,6 @@ world.is_night() -> bool
Проверяет является ли текущее время ночью. От 0.8(8 вечера) до 0.2(8 утра)
-## Библиотека *pack*
-
-```python
-pack.get_folder(packid: str) -> str
-```
-
-Возвращает путь к папке установленного контент-пака.
-
-```python
-pack.is_installed(packid: str) -> bool
-```
-
-Проверяет наличие контент-пака в мире
-
-```python
-pack.get_installed() -> массив строк
-```
-
-Возращает id всех установленных в мире контент-паков.
-
-```python
-pack.get_available() -> массив строк
-```
-
-Возвращает id всех доступных, но не установленных в мире контент-паков.
-
-```python
-pack.get_base_packs() -> массив строк
-```
-
-Возвращает id всех базовых паков (неудаляемых)
-
-```python
-pack.get_info(packid: str) -> {
- id: str,
- title: str,
- creator: str,
- description: str,
- version: str,
- icon: str,
- dependencies: опциональный массив строк
-}
-```
-
-Возвращает информацию о паке (не обязательно установленном).
-- icon - название текстуры предпросмотра (загружается автоматически)
-- dependencies - строки в формате `{lvl}{id}`, где lvl:
- - `!` - required
- - `?` - optional
- - `~` - weak
- например `!teal`
-
## Библиотека *gui*
Библиотека содержит функции для доступа к свойствам UI элементов. Вместо gui следует использовать объектную обертку, предоставляющую доступ к свойствам через мета-методы __index, __newindex:
diff --git a/doc/ru/scripting/builtins/libblock.md b/doc/ru/scripting/builtins/libblock.md
index 55de7aeb..c89cc5c5 100644
--- a/doc/ru/scripting/builtins/libblock.md
+++ b/doc/ru/scripting/builtins/libblock.md
@@ -17,7 +17,7 @@ block.caption(blockid: int) -> str
-- Если чанк на указанных координатах не загружен, возвращает -1.
block.get(x: int, y: int, z: int) -> int
--- Возвращает состояние (поворот + доп. информация) в виде целого числа
+-- Возвращает полное состояние (поворот + сегмент + доп. информация) в виде целого числа
block.get_states(x: int, y: int, z: int) -> int
-- Устанавливает блок с заданным числовым id и состоянием (0 - по-умолчанию) на заданных координатах.
@@ -31,6 +31,12 @@ block.place(x: int, y: int, z: int, id: int, states: int, [optional] playerid: i
-- Ломает блок на заданных координатах от лица игрока, вызывая событие on_broken.
-- playerid не является обязательным
block.destruct(x: int, y: int, z: int, playerid: int)
+
+-- Собирает полное состояние в виде целого числа
+block.compose_state(rotation: int, segment: int, userbits: int) -> int
+
+-- Разбирает полное состояние на: вращение, сегмент, пользовательские биты
+block.decompose_state(state: int) -> int, int, int
```
> [!WARNING]
diff --git a/doc/ru/scripting/builtins/libplayer.md b/doc/ru/scripting/builtins/libplayer.md
new file mode 100644
index 00000000..8b15d8df
--- /dev/null
+++ b/doc/ru/scripting/builtins/libplayer.md
@@ -0,0 +1,70 @@
+# Библиотека *player*
+
+```python
+player.get_pos(playerid: int) -> number, number, number
+```
+
+Возвращает x, y, z координаты игрока
+
+```python
+player.set_pos(playerid: int, x: number, y: number, z: number)
+```
+
+Устанавливает x, y, z координаты игрока
+
+```python
+player.get_rot(playerid: int) -> number, number, number
+```
+
+Возвращает x, y, z вращения камеры (в радианах)
+
+```python
+player.set_rot(playerid: int, x: number, y: number, z: number)
+```
+
+Устанавливает x, y вращения камеры (в радианах)
+
+```python
+player.get_inventory(playerid: int) -> int, int
+```
+
+Возвращает id инвентаря игрока и индекс выбранного слота (от 0 до 9)
+
+```python
+player.is_flight() -> bool
+player.set_flight(bool)
+```
+
+Геттер и сеттер режима полета
+
+```python
+player.is_noclip() -> bool
+player.set_noclip(bool)
+```
+
+Геттер и сеттер noclip режима (выключенная коллизия игрока)
+
+```python
+player.set_spawnpoint(playerid: int, x: number, y: number, z: number)
+player.get_spawnpoint(playerid: int) -> number, number, number
+```
+
+Сеттер и геттер точки спавна игрока
+
+```python
+player.get_selected_block(playerid: int) -> x,y,z
+```
+
+Возвращает координаты выделенного блока, либо nil
+
+```python
+player.get_selected_entity(playerid: int) -> int
+```
+
+Возвращает уникальный идентификатор сущности, на которую нацелен игрок
+
+```python
+player.get_entity(playerid: int) -> int
+```
+
+Возвращает уникальный идентификатор сущности игрока
diff --git a/doc/ru/xml-ui-layouts.md b/doc/ru/xml-ui-layouts.md
index 6707f93c..16007a2e 100644
--- a/doc/ru/xml-ui-layouts.md
+++ b/doc/ru/xml-ui-layouts.md
@@ -79,7 +79,8 @@
- `checked` - определяет состояние отметки.
- `supplier` - поставщик состояния отметки (вызывается каждый кадр)
-- `consumer` - lua функция-приемник состояния отметки. Вызывается только при завершении ввода
+- `consumer` - lua функция-приемник состояния отметки.
+
## Метка - *label*
- `valign` - вертикальное выравнивание текста: top/center/bottom
@@ -96,7 +97,7 @@
Внутренний текст - изначально введенный текст
-- `placeholder` - текст подстановки (используется текстовое поле пусто)
+- `placeholder` - текст подстановки (используется если текстовое поле пусто)
- `supplier` - поставщик текста (вызывается каждый кадр)
- `consumer` - lua функция-приемник введенного текста. Вызывается только при завершении ввода
- `autoresize` - автоматическое изменение размера элемента (по-умолчанию - false). Не влияет на размер шрифта.
@@ -107,6 +108,7 @@
- `validator` - lua функция, проверяющая текст на корректность. Принимает на вход строку, возвращает true если текст корректен.
- `onup` - lua функция вызываемая при нажатии стрелки вверх.
- `ondown` - lua функция вызываемая при нажатии стрелки вниз.
+
## Ползунок - *trackbar*
- `min` - минимальное значение. Тип: число. По-умолчанию: 0
@@ -116,7 +118,9 @@
- `track-width` - ширина указателя (в пикселях). Тип: число. По-умолчанию: 12
- `track-color` - цвет указателя при наведении курсора. Тип: RGBA цвет.
- `consumer` - lua функция-приемник установленного значения
+- `sub-consumer` - lua функция-приемник промежуточных значений (используйте для обновления текста при `change-on-release="true"`)
- `supplier` - lua функция-поставщик значения
+- `change-on-release` - Вызов функции-приемника (consumer) происходит только тогда, когда пользователь отпускает указатель. Тип: логический. По-умолчанию: false
# Элементы инвентаря
diff --git a/res/content/base/blocks/wooden_door.json b/res/content/base/blocks/wooden_door.json
index 9a1eb666..59d192b5 100644
--- a/res/content/base/blocks/wooden_door.json
+++ b/res/content/base/blocks/wooden_door.json
@@ -13,5 +13,6 @@
"size": [1, 2, 1],
"rotation": "pane",
"model": "aabb",
- "hitbox": [0.0, 0.0, 0.8, 1.0, 2.0, 0.2]
+ "hitbox": [0.0, 0.0, 0.8, 1.0, 2.0, 0.2],
+ "ambient-occlusion": false
}
diff --git a/res/layouts/pages/settings_display.xml.lua b/res/layouts/pages/settings_display.xml.lua
index e861deb3..6e64a7d6 100644
--- a/res/layouts/pages/settings_display.xml.lua
+++ b/res/layouts/pages/settings_display.xml.lua
@@ -1,7 +1,8 @@
-function create_setting(id, name, step, postfix, tooltip)
+function create_setting(id, name, step, postfix, tooltip, changeonrelease)
local info = core.get_setting_info(id)
postfix = postfix or ""
tooltip = tooltip or ""
+ changeonrelease = changeonrelease or ""
document.root:add(gui.template("track_setting", {
id=id,
name=gui.str(name, "settings"),
@@ -10,13 +11,13 @@ function create_setting(id, name, step, postfix, tooltip)
max=info.max,
step=step,
postfix=postfix,
- tooltip=tooltip
+ tooltip=tooltip,
+ changeonrelease=changeonrelease
}))
update_setting(core.get_setting(id), id, name, postfix)
end
function update_setting(x, id, name, postfix)
- core.set_setting(id, x)
-- updating label
document[id..".L"].text = string.format(
"%s: %s%s",
diff --git a/res/layouts/pages/settings_graphics.xml.lua b/res/layouts/pages/settings_graphics.xml.lua
index de00c87b..8a479a1c 100644
--- a/res/layouts/pages/settings_graphics.xml.lua
+++ b/res/layouts/pages/settings_graphics.xml.lua
@@ -1,7 +1,8 @@
-function create_setting(id, name, step, postfix, tooltip)
+function create_setting(id, name, step, postfix, tooltip, changeonrelease)
local info = core.get_setting_info(id)
postfix = postfix or ""
tooltip = tooltip or ""
+ changeonrelease = changeonrelease or ""
document.root:add(gui.template("track_setting", {
id=id,
name=gui.str(name, "settings"),
@@ -10,13 +11,13 @@ function create_setting(id, name, step, postfix, tooltip)
max=info.max,
step=step,
postfix=postfix,
- tooltip=tooltip
+ tooltip=tooltip,
+ changeonrelease=changeonrelease
}))
update_setting(core.get_setting(id), id, name, postfix)
end
function update_setting(x, id, name, postfix)
- core.set_setting(id, x)
-- updating label
document[id..".L"].text = string.format(
"%s: %s%s",
diff --git a/res/layouts/templates/track_setting.xml b/res/layouts/templates/track_setting.xml
index 82ee81c1..519ba334 100644
--- a/res/layouts/templates/track_setting.xml
+++ b/res/layouts/templates/track_setting.xml
@@ -2,5 +2,6 @@
+ consumer='function(x) core.set_setting("%{id}", x) end' change-on-release='%{changeonrelease}'
+ sub-consumer='function(x) update_setting(x, "%{id}", "%{name}", "%{postfix}") end'/>
diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp
index 56480dfb..448754a2 100644
--- a/src/content/ContentLoader.cpp
+++ b/src/content/ContentLoader.cpp
@@ -217,6 +217,7 @@ void ContentLoader::loadBlock(Block& def, const std::string& name, const fs::pat
root->flag("light-passing", def.lightPassing);
root->flag("sky-light-passing", def.skyLightPassing);
root->flag("shadeless", def.shadeless);
+ root->flag("ambient-occlusion", def.ambientOcclusion);
root->flag("breakable", def.breakable);
root->flag("selectable", def.selectable);
root->flag("grounded", def.grounded);
diff --git a/src/data/dynamic_fwd.hpp b/src/data/dynamic_fwd.hpp
index 1a398edd..6faff946 100644
--- a/src/data/dynamic_fwd.hpp
+++ b/src/data/dynamic_fwd.hpp
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
namespace dynamic {
class Map;
@@ -27,6 +28,8 @@ namespace dynamic {
bool,
integer_t
>;
+
+ using to_string_func = std::function;
}
#endif // DATA_DYNAMIC_FWD_HPP_
diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp
index 21dbc2c7..e43c4f6b 100644
--- a/src/frontend/hud.cpp
+++ b/src/frontend/hud.cpp
@@ -175,6 +175,7 @@ Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player)
auto dplotter = std::make_shared(350, 250, 2000, 16);
dplotter->setGravity(Gravity::bottom_right);
+ dplotter->setInteractive(false);
add(HudElement(hud_element_mode::permanent, nullptr, dplotter, true));
}
diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp
index ed20f7b3..b5ea8194 100644
--- a/src/graphics/render/BlocksRenderer.cpp
+++ b/src/graphics/render/BlocksRenderer.cpp
@@ -104,7 +104,7 @@ void BlocksRenderer::face(
index(0, 1, 3, 1, 2, 3);
}
-void BlocksRenderer::vertex(
+void BlocksRenderer::vertexAO(
const vec3& coord,
float u, float v,
const vec4& tint,
@@ -117,7 +117,7 @@ void BlocksRenderer::vertex(
vertex(coord, u, v, light * tint);
}
-void BlocksRenderer::face(
+void BlocksRenderer::faceAO(
const vec3& coord,
const vec3& X,
const vec3& Y,
@@ -140,12 +140,12 @@ void BlocksRenderer::face(
vec3 axisZ = glm::normalize(Z);
vec4 tint(d);
- vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint, axisX, axisY, axisZ);
- vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, axisX, axisY, axisZ);
- vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisX, axisY, axisZ);
- vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisX, axisY, axisZ);
+ vertexAO(coord + (-X - Y + Z) * s, region.u1, region.v1, tint, axisX, axisY, axisZ);
+ vertexAO(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, axisX, axisY, axisZ);
+ vertexAO(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisX, axisY, axisZ);
+ vertexAO(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisX, axisY, axisZ);
} else {
- vec4 tint(1.0f);
+ glm::vec4 tint(1.0f);
vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint);
vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint);
vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint);
@@ -154,6 +154,33 @@ void BlocksRenderer::face(
index(0, 1, 2, 0, 2, 3);
}
+void BlocksRenderer::face(
+ const vec3& coord,
+ const vec3& X,
+ const vec3& Y,
+ const vec3& Z,
+ const UVRegion& region,
+ vec4 tint,
+ bool lights
+) {
+ if (vertexOffset + BlocksRenderer::VERTEX_SIZE * 4 > capacity) {
+ overflow = true;
+ return;
+ }
+
+ float s = 0.5f;
+ if (lights) {
+ float d = glm::dot(glm::normalize(Z), SUN_VECTOR);
+ d = 0.8f + d * 0.2f;
+ tint *= d;
+ }
+ vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint);
+ vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint);
+ vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint);
+ vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint);
+ index(0, 1, 2, 0, 2, 3);
+}
+
void BlocksRenderer::tetragonicFace(
const vec3& coord,
const vec3& p1, const vec3& p2, const vec3& p3, const vec3& p4,
@@ -231,7 +258,8 @@ void BlocksRenderer::blockAABB(
const UVRegion(&texfaces)[6],
const Block* block,
ubyte rotation,
- bool lights
+ bool lights,
+ bool ao
) {
if (block->hitboxes.empty()) {
return;
@@ -256,18 +284,30 @@ void BlocksRenderer::blockAABB(
}
coord = vec3(icoord) - vec3(0.5f) + hitbox.center();
- face(coord, X*size.x, Y*size.y, Z*size.z, texfaces[5], lights); // north
- face(coord, -X*size.x, Y*size.y, -Z*size.z, texfaces[4], lights); // south
+ if (ao) {
+ faceAO(coord, X*size.x, Y*size.y, Z*size.z, texfaces[5], lights); // north
+ faceAO(coord, -X*size.x, Y*size.y, -Z*size.z, texfaces[4], lights); // south
- face(coord, X*size.x, -Z*size.z, Y*size.y, texfaces[3], lights); // top
- face(coord, -X*size.x, -Z*size.z, -Y*size.y, texfaces[2], lights); // bottom
+ faceAO(coord, X*size.x, -Z*size.z, Y*size.y, texfaces[3], lights); // top
+ faceAO(coord, -X*size.x, -Z*size.z, -Y*size.y, texfaces[2], lights); // bottom
- face(coord, -Z*size.z, Y*size.y, X*size.x, texfaces[1], lights); // west
- face(coord, Z*size.z, Y*size.y, -X*size.x, texfaces[0], lights); // east
+ faceAO(coord, -Z*size.z, Y*size.y, X*size.x, texfaces[1], lights); // west
+ faceAO(coord, Z*size.z, Y*size.y, -X*size.x, texfaces[0], lights); // east
+ } else {
+ auto tint = pickLight(icoord);
+ face(coord, X*size.x, Y*size.y, Z*size.z, texfaces[5], tint, lights); // north
+ face(coord, -X*size.x, Y*size.y, -Z*size.z, texfaces[4], tint, lights); // south
+
+ face(coord, X*size.x, -Z*size.z, Y*size.y, texfaces[3], tint, lights); // top
+ face(coord, -X*size.x, -Z*size.z, -Y*size.y, texfaces[2], tint, lights); // bottom
+
+ face(coord, -Z*size.z, Y*size.y, X*size.x, texfaces[1], tint, lights); // west
+ face(coord, Z*size.z, Y*size.y, -X*size.x, texfaces[0], tint, lights); // east
+ }
}
void BlocksRenderer::blockCustomModel(
- const ivec3& icoord, const Block* block, ubyte rotation, bool lights
+ const ivec3& icoord, const Block* block, ubyte rotation, bool lights, bool ao
) {
vec3 X(1, 0, 0);
vec3 Y(0, 1, 0);
@@ -289,12 +329,12 @@ void BlocksRenderer::blockCustomModel(
orient.transform(box);
}
vec3 center_coord = coord - vec3(0.5f) + box.center();
- face(center_coord, X * size.x, Y * size.y, Z * size.z, block->modelUVs[i * 6 + 5], lights); // north
- face(center_coord, -X * size.x, Y * size.y, -Z * size.z, block->modelUVs[i * 6 + 4], lights); // south
- face(center_coord, X * size.x, -Z * size.z, Y * size.y, block->modelUVs[i * 6 + 3], lights); // top
- face(center_coord, -X * size.x, -Z * size.z, -Y * size.y, block->modelUVs[i * 6 + 2], lights); // bottom
- face(center_coord, -Z * size.z, Y * size.y, X * size.x, block->modelUVs[i * 6 + 1], lights); // west
- face(center_coord, Z * size.z, Y * size.y, -X * size.x, block->modelUVs[i * 6 + 0], lights); // east
+ faceAO(center_coord, X * size.x, Y * size.y, Z * size.z, block->modelUVs[i * 6 + 5], lights); // north
+ faceAO(center_coord, -X * size.x, Y * size.y, -Z * size.z, block->modelUVs[i * 6 + 4], lights); // south
+ faceAO(center_coord, X * size.x, -Z * size.z, Y * size.y, block->modelUVs[i * 6 + 3], lights); // top
+ faceAO(center_coord, -X * size.x, -Z * size.z, -Y * size.y, block->modelUVs[i * 6 + 2], lights); // bottom
+ faceAO(center_coord, -Z * size.z, Y * size.y, X * size.x, block->modelUVs[i * 6 + 1], lights); // west
+ faceAO(center_coord, Z * size.z, Y * size.y, -X * size.x, block->modelUVs[i * 6 + 0], lights); // east
}
for (size_t i = 0; i < block->modelExtraPoints.size()/4; i++) {
@@ -314,7 +354,8 @@ void BlocksRenderer::blockCube(
const UVRegion(&texfaces)[6],
const Block* block,
blockstate states,
- bool lights
+ bool lights,
+ bool ao
) {
ubyte group = block->drawGroup;
@@ -330,23 +371,44 @@ void BlocksRenderer::blockCube(
Z = orient.axisZ;
}
- if (isOpen(x+Z.x, y+Z.y, z+Z.z, group)) {
- face(coord, X, Y, Z, texfaces[5], lights);
- }
- if (isOpen(x-Z.x, y-Z.y, z-Z.z, group)) {
- face(coord, -X, Y, -Z, texfaces[4], lights);
- }
- if (isOpen(x+Y.x, y+Y.y, z+Y.z, group)) {
- face(coord, X, -Z, Y, texfaces[3], lights);
- }
- if (isOpen(x-Y.x, y-Y.y, z-Y.z, group)) {
- face(coord, X, Z, -Y, texfaces[2], lights);
- }
- if (isOpen(x+X.x, y+X.y, z+X.z, group)) {
- face(coord, -Z, Y, X, texfaces[1], lights);
- }
- if (isOpen(x-X.x, y-X.y, z-X.z, group)) {
- face(coord, Z, Y, -X, texfaces[0], lights);
+ if (ao) {
+ if (isOpen(x+Z.x, y+Z.y, z+Z.z, group)) {
+ faceAO(coord, X, Y, Z, texfaces[5], lights);
+ }
+ if (isOpen(x-Z.x, y-Z.y, z-Z.z, group)) {
+ faceAO(coord, -X, Y, -Z, texfaces[4], lights);
+ }
+ if (isOpen(x+Y.x, y+Y.y, z+Y.z, group)) {
+ faceAO(coord, X, -Z, Y, texfaces[3], lights);
+ }
+ if (isOpen(x-Y.x, y-Y.y, z-Y.z, group)) {
+ faceAO(coord, X, Z, -Y, texfaces[2], lights);
+ }
+ if (isOpen(x+X.x, y+X.y, z+X.z, group)) {
+ faceAO(coord, -Z, Y, X, texfaces[1], lights);
+ }
+ if (isOpen(x-X.x, y-X.y, z-X.z, group)) {
+ faceAO(coord, Z, Y, -X, texfaces[0], lights);
+ }
+ } else {
+ if (isOpen(x+Z.x, y+Z.y, z+Z.z, group)) {
+ face(coord, X, Y, Z, texfaces[5], pickLight({x, y, z+1}), lights);
+ }
+ if (isOpen(x-Z.x, y-Z.y, z-Z.z, group)) {
+ face(coord, -X, Y, -Z, texfaces[4], pickLight({x, y, z-1}), lights);
+ }
+ if (isOpen(x+Y.x, y+Y.y, z+Y.z, group)) {
+ face(coord, X, -Z, Y, texfaces[3], pickLight({x, y+1, z}), lights);
+ }
+ if (isOpen(x-Y.x, y-Y.y, z-Y.z, group)) {
+ face(coord, X, Z, -Y, texfaces[2], pickLight({x, y-1, z}), lights);
+ }
+ if (isOpen(x+X.x, y+X.y, z+X.z, group)) {
+ face(coord, -Z, Y, X, texfaces[1], pickLight({x+1, y, z}), lights);
+ }
+ if (isOpen(x-X.x, y-X.y, z-X.z, group)) {
+ face(coord, Z, Y, -X, texfaces[0], pickLight({x-1, y, z}), lights);
+ }
}
}
@@ -440,7 +502,8 @@ void BlocksRenderer::render(const voxel* voxels) {
int z = (i / CHUNK_D) % CHUNK_W;
switch (def.model) {
case BlockModel::block:
- blockCube(x, y, z, texfaces, &def, vox.state, !def.shadeless);
+ blockCube(x, y, z, texfaces, &def, vox.state, !def.shadeless,
+ def.ambientOcclusion);
break;
case BlockModel::xsprite: {
blockXSprite(x, y, z, vec3(1.0f),
@@ -448,11 +511,13 @@ void BlocksRenderer::render(const voxel* voxels) {
break;
}
case BlockModel::aabb: {
- blockAABB(ivec3(x,y,z), texfaces, &def, vox.state.rotation, !def.shadeless);
+ blockAABB(ivec3(x,y,z), texfaces, &def, vox.state.rotation,
+ !def.shadeless, def.ambientOcclusion);
break;
}
case BlockModel::custom: {
- blockCustomModel(ivec3(x, y, z), &def, vox.state.rotation, !def.shadeless);
+ blockCustomModel(ivec3(x, y, z), &def, vox.state.rotation,
+ !def.shadeless, def.ambientOcclusion);
break;
}
default:
diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp
index e31fd163..d6cd6eb1 100644
--- a/src/graphics/render/BlocksRenderer.hpp
+++ b/src/graphics/render/BlocksRenderer.hpp
@@ -40,7 +40,7 @@ class BlocksRenderer {
void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light);
void index(int a, int b, int c, int d, int e, int f);
- void vertex(
+ void vertexAO(
const glm::vec3& coord, float u, float v,
const glm::vec4& brightness,
const glm::vec3& axisX,
@@ -58,6 +58,15 @@ class BlocksRenderer {
const glm::vec4& tint
);
void face(
+ const glm::vec3& coord,
+ const glm::vec3& X,
+ const glm::vec3& Y,
+ const glm::vec3& Z,
+ const UVRegion& region,
+ glm::vec4 tint,
+ bool lights
+ );
+ void faceAO(
const glm::vec3& coord,
const glm::vec3& axisX,
const glm::vec3& axisY,
@@ -80,14 +89,16 @@ class BlocksRenderer {
const UVRegion(&faces)[6],
const Block* block,
blockstate states,
- bool lights
+ bool lights,
+ bool ao
);
void blockAABB(
const glm::ivec3& coord,
const UVRegion(&faces)[6],
const Block* block,
ubyte rotation,
- bool lights
+ bool lights,
+ bool ambientOcclusion
);
void blockXSprite(
int x, int y, int z,
@@ -100,7 +111,8 @@ class BlocksRenderer {
const glm::ivec3& icoord,
const Block* block,
ubyte rotation,
- bool lights
+ bool lights,
+ bool ao
);
bool isOpenForLight(int x, int y, int z) const;
diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp
index b46137af..0e7fe5cd 100644
--- a/src/graphics/render/ChunksRenderer.cpp
+++ b/src/graphics/render/ChunksRenderer.cpp
@@ -50,6 +50,7 @@ ChunksRenderer::ChunksRenderer(
renderer = std::make_unique(
RENDERER_CAPACITY, level->content, cache, settings
);
+ logger.info() << "created " << threadPool.getWorkersCount() << " workers";
}
ChunksRenderer::~ChunksRenderer() {
diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp
index 54c04476..13f32a38 100644
--- a/src/graphics/ui/GUI.cpp
+++ b/src/graphics/ui/GUI.cpp
@@ -131,7 +131,7 @@ void GUI::actMouse(float delta) {
focus->defocus();
focus = nullptr;
}
- } else if (pressed) {
+ } else if (!Events::clicked(mousecode::BUTTON_1) && pressed) {
pressed->mouseRelease(this, Events::cursor.x, Events::cursor.y);
pressed = nullptr;
}
diff --git a/src/graphics/ui/elements/TrackBar.cpp b/src/graphics/ui/elements/TrackBar.cpp
index e7bcc8d3..ab90b763 100644
--- a/src/graphics/ui/elements/TrackBar.cpp
+++ b/src/graphics/ui/elements/TrackBar.cpp
@@ -50,6 +50,10 @@ void TrackBar::setConsumer(doubleconsumer consumer) {
this->consumer = std::move(consumer);
}
+void TrackBar::setSubConsumer(doubleconsumer consumer) {
+ this->subconsumer = std::move(consumer);
+}
+
void TrackBar::mouseMove(GUI*, int x, int) {
glm::vec2 pos = calcPos();
value = x - trackWidth/2;
@@ -60,11 +64,19 @@ void TrackBar::mouseMove(GUI*, int x, int) {
value = (value < min) ? min : value;
value = (int64_t)round(value / step) * step;
- if (consumer) {
+ if (consumer && !changeOnRelease) {
consumer(value);
}
+ if (subconsumer) {
+ subconsumer(value);
+ }
}
+void TrackBar::mouseRelease(GUI*, int, int) {
+ if (consumer && changeOnRelease) {
+ consumer(value);
+ }
+}
double TrackBar::getValue() const {
return value;
@@ -90,6 +102,10 @@ glm::vec4 TrackBar::getTrackColor() const {
return trackColor;
}
+bool TrackBar::isChangeOnRelease() const {
+ return changeOnRelease;
+}
+
void TrackBar::setValue(double x) {
value = x;
}
@@ -113,3 +129,7 @@ void TrackBar::setTrackWidth(int width) {
void TrackBar::setTrackColor(glm::vec4 color) {
trackColor = color;
}
+
+void TrackBar::setChangeOnRelease(bool flag) {
+ changeOnRelease = flag;
+}
diff --git a/src/graphics/ui/elements/TrackBar.hpp b/src/graphics/ui/elements/TrackBar.hpp
index ec62f87f..6e055e61 100644
--- a/src/graphics/ui/elements/TrackBar.hpp
+++ b/src/graphics/ui/elements/TrackBar.hpp
@@ -2,6 +2,7 @@
#define GRAPHICS_UI_ELEMENTS_TRACKBAR_HPP_
#include "UINode.hpp"
+#include "../../../data/dynamic_fwd.hpp"
namespace gui {
class TrackBar : public UINode {
@@ -9,11 +10,13 @@ namespace gui {
glm::vec4 trackColor {1.0f, 1.0f, 1.0f, 0.4f};
doublesupplier supplier = nullptr;
doubleconsumer consumer = nullptr;
+ doubleconsumer subconsumer = nullptr;
double min;
double max;
double value;
double step;
int trackWidth;
+ bool changeOnRelease = false;
public:
TrackBar(double min,
double max,
@@ -22,10 +25,12 @@ namespace gui {
int trackWidth=12);
virtual void draw(const DrawContext* pctx, Assets* assets) override;
- virtual void setSupplier(doublesupplier supplier);
- virtual void setConsumer(doubleconsumer consumer);
+ virtual void setSupplier(doublesupplier);
+ virtual void setConsumer(doubleconsumer);
+ virtual void setSubConsumer(doubleconsumer);
virtual void mouseMove(GUI*, int x, int y) override;
+ virtual void mouseRelease(GUI*, int x, int y) override;
virtual double getValue() const;
virtual double getMin() const;
@@ -33,6 +38,7 @@ namespace gui {
virtual double getStep() const;
virtual int getTrackWidth() const;
virtual glm::vec4 getTrackColor() const;
+ virtual bool isChangeOnRelease() const;
virtual void setValue(double);
virtual void setMin(double);
@@ -40,6 +46,7 @@ namespace gui {
virtual void setStep(double);
virtual void setTrackWidth(int);
virtual void setTrackColor(glm::vec4);
+ virtual void setChangeOnRelease(bool);
};
}
diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp
index 94a0522d..297ee4ac 100644
--- a/src/graphics/ui/gui_xml.cpp
+++ b/src/graphics/ui/gui_xml.cpp
@@ -392,30 +392,33 @@ static std::shared_ptr readImage(UiXmlReader& reader, const xml::xmlelem
}
static std::shared_ptr readTrackBar(UiXmlReader& reader, const xml::xmlelement& element) {
- float min = element->attr("min", "0.0").asFloat();
- float max = element->attr("max", "1.0").asFloat();
+ const auto& env = reader.getEnvironment();
+ const auto& file = reader.getFilename();
+ float minv = element->attr("min", "0.0").asFloat();
+ float maxv = element->attr("max", "1.0").asFloat();
float def = element->attr("value", "0.0").asFloat();
float step = element->attr("step", "1.0").asFloat();
int trackWidth = element->attr("track-width", "12").asInt();
- auto bar = std::make_shared(min, max, def, step, trackWidth);
+ auto bar = std::make_shared(minv, maxv, def, step, trackWidth);
_readUINode(reader, element, *bar);
if (element->has("consumer")) {
bar->setConsumer(scripting::create_number_consumer(
- reader.getEnvironment(),
- element->attr("consumer").getText(),
- reader.getFilename()
- ));
+ env, element->attr("consumer").getText(), file));
+ }
+ if (element->has("sub-consumer")) {
+ bar->setSubConsumer(scripting::create_number_consumer(
+ env, element->attr("sub-consumer").getText(), file));
}
if (element->has("supplier")) {
bar->setSupplier(scripting::create_number_supplier(
- reader.getEnvironment(),
- element->attr("supplier").getText(),
- reader.getFilename()
- ));
+ env, element->attr("supplier").getText(), file));
}
if (element->has("track-color")) {
bar->setTrackColor(element->attr("track-color").asColor());
}
+ if (element->has("change-on-release")) {
+ bar->setChangeOnRelease(element->attr("change-on-release").asBool());
+ }
return bar;
}
diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp
index 91801d79..3afd98a6 100644
--- a/src/logic/PlayerController.cpp
+++ b/src/logic/PlayerController.cpp
@@ -169,13 +169,13 @@ void CameraControl::update(const PlayerInput& input, float delta, Chunks* chunks
if (player->currentCamera == spCamera) {
spCamera->position = chunks->rayCastToObstacle(
- camera->position, camera->front, 3.0f) - 0.2f * camera->front;
+ camera->position, camera->front, 3.0f) - 0.4f * camera->front;
spCamera->dir = -camera->dir;
spCamera->front = -camera->front;
}
else if (player->currentCamera == tpCamera) {
tpCamera->position = chunks->rayCastToObstacle(
- camera->position, -camera->front, 3.0f) + 0.2f * camera->front;
+ camera->position, -camera->front, 3.0f) + 0.4f * camera->front;
tpCamera->dir = camera->dir;
tpCamera->front = camera->front;
}
@@ -391,7 +391,7 @@ voxel* PlayerController::updateSelection(float maxDistance) {
selection.position = chunks->seekOrigin(
iend, indices->blocks.get(selection.vox.id), selectedState
);
- auto origin = chunks->get(iend);
+ auto origin = chunks->get(selection.position);
if (origin && origin->id != vox->id) {
chunks->set(iend.x, iend.y, iend.z, 0, {});
return updateSelection(maxDistance);
diff --git a/src/logic/scripting/lua/libblock.cpp b/src/logic/scripting/lua/libblock.cpp
index 51182807..af2863b0 100644
--- a/src/logic/scripting/lua/libblock.cpp
+++ b/src/logic/scripting/lua/libblock.cpp
@@ -380,6 +380,23 @@ static int l_raycast(lua::State* L) {
return 0;
}
+static int l_compose_state(lua::State* L) {
+ blockstate state {};
+ state.rotation = lua::tointeger(L, 1);
+ state.segment = lua::tointeger(L, 2);
+ state.userbits = lua::tointeger(L, 3);
+ return lua::pushinteger(L, blockstate2int(state));
+}
+
+static int l_decompose_state(lua::State* L) {
+ auto stateInt = static_cast(lua::tointeger(L, 1));
+ auto state = int2blockstate(stateInt);
+ lua::pushinteger(L, state.rotation);
+ lua::pushinteger(L, state.segment);
+ lua::pushinteger(L, state.userbits);
+ return 3;
+}
+
const luaL_Reg blocklib [] = {
{"index", lua::wrap},
{"name", lua::wrap},
@@ -411,5 +428,7 @@ const luaL_Reg blocklib [] = {
{"place", lua::wrap},
{"destruct", lua::wrap},
{"raycast", lua::wrap},
+ {"compose_state", lua::wrap},
+ {"decompose_state", lua::wrap},
{NULL, NULL}
};
diff --git a/src/logic/scripting/scripting_functional.cpp b/src/logic/scripting/scripting_functional.cpp
index b758f336..b3ad82af 100644
--- a/src/logic/scripting/scripting_functional.cpp
+++ b/src/logic/scripting/scripting_functional.cpp
@@ -2,6 +2,7 @@
#include "lua/lua_engine.hpp"
#include "../../debug/Logger.hpp"
+#include "../../coders/json.hpp"
#include "../../util/stringutil.hpp"
using namespace scripting;
@@ -177,3 +178,25 @@ vec2supplier scripting::create_vec2_supplier(
return glm::vec2(0, 0);
};
}
+
+dynamic::to_string_func scripting::create_tostring(
+ const scriptenv& env,
+ const std::string& src,
+ const std::string& file
+) {
+ auto L = lua::get_main_thread();
+ try {
+ lua::loadbuffer(L, *env, src, file);
+ lua::call(L, 0, 1);
+ auto func = lua::create_lambda(L);
+ return [func](const dynamic::Value& value) {
+ auto result = func({value});
+ return json::stringify(result, true, " ");
+ };
+ } catch (const lua::luaerror& err) {
+ logger.error() << err.what();
+ return [](const auto& value) {
+ return json::stringify(value, true, " ");
+ };
+ }
+}
diff --git a/src/logic/scripting/scripting_functional.hpp b/src/logic/scripting/scripting_functional.hpp
index 9b1cc715..01141262 100644
--- a/src/logic/scripting/scripting_functional.hpp
+++ b/src/logic/scripting/scripting_functional.hpp
@@ -72,6 +72,12 @@ namespace scripting {
const std::string& src,
const std::string& file=""
);
+
+ dynamic::to_string_func create_tostring(
+ const scriptenv& env,
+ const std::string& src,
+ const std::string& file=""
+ );
}
#endif // LOGIC_SCRIPTING_SCRIPTING_FUNCTIONAL_HPP_
diff --git a/src/util/ThreadPool.hpp b/src/util/ThreadPool.hpp
index 4fb1dff5..6b098b09 100644
--- a/src/util/ThreadPool.hpp
+++ b/src/util/ThreadPool.hpp
@@ -200,7 +200,7 @@ public:
}
}
- void enqueueJob(std::shared_ptr job) {
+ void enqueueJob(const std::shared_ptr& job) {
{
std::lock_guard lock(jobsMutex);
jobs.push(job);
@@ -244,6 +244,10 @@ public:
update();
}
}
+
+ uint getWorkersCount() const {
+ return threads.size();
+ }
};
} // namespace util
diff --git a/src/util/timeutil.hpp b/src/util/timeutil.hpp
index 3d117b73..75f72bfd 100644
--- a/src/util/timeutil.hpp
+++ b/src/util/timeutil.hpp
@@ -20,11 +20,11 @@ namespace timeutil {
* ...
* }
*/
- class ScopeLogTimer : public Timer{
- long long scopeid_;
- public:
- ScopeLogTimer(long long id);
- ~ScopeLogTimer();
+ class ScopeLogTimer : public Timer {
+ long long scopeid_;
+ public:
+ ScopeLogTimer(long long id);
+ ~ScopeLogTimer();
};
inline constexpr float time_value(float hour, float minute, float second) {
diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp
index ce83079d..5c0dcfaa 100644
--- a/src/voxels/Block.hpp
+++ b/src/voxels/Block.hpp
@@ -136,6 +136,9 @@ public:
/// @brief Does block model have shading
bool shadeless = false;
+
+ /// @brief Does block model have vertex-based AO effect
+ bool ambientOcclusion = true;
/// @brief Is the block a physical obstacle
bool obstacle = true;