Merge branch 'main' of https://github.com/MihailRis/VoxelEngine-Cpp
This commit is contained in:
commit
eb59c3ae2f
51
.github/workflows/macos.yml
vendored
Normal file
51
.github/workflows/macos.yml
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
name: Macos Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-dmg:
|
||||||
|
runs-on: macos-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
|
||||||
|
- name: Install dependencies from brew
|
||||||
|
run: |
|
||||||
|
brew install glfw3 glew libpng openal-soft luajit libvorbis
|
||||||
|
|
||||||
|
- name: Install specific version of GLM
|
||||||
|
run: |
|
||||||
|
curl -O https://raw.githubusercontent.com/Homebrew/homebrew-core/5c7655a866646aa4b857c002b8ae5465b9d26f65/Formula/g/glm.rb
|
||||||
|
brew install --formula glm.rb
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_APPDIR=1
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build build -t install
|
||||||
|
|
||||||
|
- name: Make fix_dylibs.sh executable
|
||||||
|
run: chmod +x fix_dylibs.sh
|
||||||
|
|
||||||
|
- name: Fix dylibs
|
||||||
|
run: ./fix_dylibs.sh VoxelEngine Release build
|
||||||
|
|
||||||
|
- name: Create DMG
|
||||||
|
run: |
|
||||||
|
mkdir VoxelEngineDmgContent
|
||||||
|
cp -r build/res VoxelEngineDmgContent/
|
||||||
|
cp -r build/VoxelEngine VoxelEngineDmgContent/
|
||||||
|
cp -r build/libs VoxelEngineDmgContent/libs
|
||||||
|
hdiutil create VoxelEngineMacApp.dmg -volname "VoxelEngine" -srcfolder VoxelEngineDmgContent -ov -format UDZO
|
||||||
|
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: VoxelEngineMacOs
|
||||||
|
path: VoxelEngineMacApp.dmg
|
||||||
48
.github/workflows/windows.yml
vendored
Normal file
48
.github/workflows/windows.yml
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
name: Windows Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-windows:
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: windows-latest
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
|
||||||
|
- name: Set up vcpkg
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/microsoft/vcpkg.git
|
||||||
|
cd vcpkg
|
||||||
|
.\bootstrap-vcpkg.bat
|
||||||
|
.\vcpkg integrate install
|
||||||
|
cd ..
|
||||||
|
- name: Configure and build project with CMake and vcpkg
|
||||||
|
run: |
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_WINDOWS_VCPKG=ON ..
|
||||||
|
Remove-Item -Path CMakeFiles -Recurse -Force
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_WINDOWS_VCPKG=ON ..
|
||||||
|
cmake --build . --config Release
|
||||||
|
- name: Package for Windows
|
||||||
|
run: |
|
||||||
|
mkdir packaged
|
||||||
|
cp -r build/* packaged/
|
||||||
|
working-directory: ${{ github.workspace }}
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: Windows-Build
|
||||||
|
path: 'packaged/Release/*'
|
||||||
@ -50,6 +50,9 @@ else()
|
|||||||
-Wformat-nonliteral -Wcast-align
|
-Wformat-nonliteral -Wcast-align
|
||||||
-Wpointer-arith -Wundef
|
-Wpointer-arith -Wundef
|
||||||
-Wwrite-strings -Wno-unused-parameter)
|
-Wwrite-strings -Wno-unused-parameter)
|
||||||
|
if (CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||||
|
target_compile_options(${PROJECT_NAME} PRIVATE -Og)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(VOXELENGINE_BUILD_WINDOWS_VCPKG AND WIN32)
|
if(VOXELENGINE_BUILD_WINDOWS_VCPKG AND WIN32)
|
||||||
@ -98,6 +101,18 @@ if (WIN32)
|
|||||||
set(VORBISLIB vorbis vorbisfile) # not tested
|
set(VORBISLIB vorbis vorbisfile) # not tested
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/glfw)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/glfw)
|
||||||
endif()
|
endif()
|
||||||
|
elseif(APPLE)
|
||||||
|
find_package(PkgConfig)
|
||||||
|
pkg_check_modules(LUAJIT REQUIRED luajit)
|
||||||
|
pkg_check_modules(VORBIS REQUIRED vorbis vorbisfile)
|
||||||
|
set(LUA_INCLUDE_DIR "/opt/homebrew/include/luajit-2.1")
|
||||||
|
set(LUA_LIBRARIES "/opt/homebrew/lib/libluajit-5.1.a")
|
||||||
|
message(STATUS "LUA Libraries: ${LUA_LIBRARIES}")
|
||||||
|
message(STATUS "LUA Include Dir: ${LUA_INCLUDE_DIR}")
|
||||||
|
find_package(PNG REQUIRED)
|
||||||
|
set(PNGLIB PNG::PNG)
|
||||||
|
set(VORBISLIB ${VORBIS_LDFLAGS})
|
||||||
|
message(STATUS "Vorbis Lib: ${VORBIS_LDFLAGS}")
|
||||||
else()
|
else()
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
pkg_check_modules(LUAJIT REQUIRED luajit)
|
pkg_check_modules(LUAJIT REQUIRED luajit)
|
||||||
|
|||||||
@ -52,10 +52,10 @@ player.set_pos(playerid: int, x: number, y: number, z: number)
|
|||||||
Set player position
|
Set player position
|
||||||
|
|
||||||
```python
|
```python
|
||||||
player.get_rot(playerid: int) -> number, number
|
player.get_rot(playerid: int) -> number, number, number
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns x, y of camera rotation (radians)
|
Returns x, y, z of camera rotation (radians)
|
||||||
|
|
||||||
```python
|
```python
|
||||||
player.set_rot(playerid: int, x: number, y: number, z: number)
|
player.set_rot(playerid: int, x: number, y: number, z: number)
|
||||||
@ -69,6 +69,20 @@ player.get_inventory(playerid: int) -> int, int
|
|||||||
|
|
||||||
Returns player inventory ID and selected slot index (0-9)
|
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)
|
||||||
|
|
||||||
## *world* library
|
## *world* library
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|||||||
@ -26,14 +26,31 @@
|
|||||||
|
|
||||||
# Общие атрибуты элементов
|
# Общие атрибуты элементов
|
||||||
|
|
||||||
|
- `enabled` - при значении false блокирует элемент, в отличие от interactive, обозначая это состояние визуально.
|
||||||
- `id` - идентификатор элемента. Тип: строка.
|
- `id` - идентификатор элемента. Тип: строка.
|
||||||
- `pos` - позиция элемента. Тип: 2D вектор.
|
- `pos` - позиция элемента. Тип: 2D вектор.
|
||||||
- `size` - размер элемента. Тип: 2D вектор.
|
- `size` - размер элемента. Тип: 2D вектор.
|
||||||
|
- `context` - указывает контекст перевода для `@`-строк.
|
||||||
- `color` - цвет элемента. Тип: RGBA цвет.
|
- `color` - цвет элемента. Тип: RGBA цвет.
|
||||||
|
- `hover-color` - цвет элемента при наведении курсора. Тип: RGBA цвет.
|
||||||
|
- `pressed-color` - цвет элемента при нажатии на элемент. Тип: RGBA цвет.
|
||||||
- `margin` - внешний отступ элемента. Тип: 4D вектор.
|
- `margin` - внешний отступ элемента. Тип: 4D вектор.
|
||||||
Порядок: `"left,top,right,bottom"`
|
Порядок: `"left,top,right,bottom"`
|
||||||
- `visible` - видимость элемента. Тип: логический ("true"/"false").
|
- `visible` - видимость элемента. Тип: логический ("true"/"false").
|
||||||
- `position-func` - поставщик позиции элемента (два числа), вызываемый при изменении размера контейнера, в котором находится элемент, либо при добавлении элемента в контейнер. Может быть вызван до вызова on_hud_open.
|
- `position-func` - поставщик позиции элемента (два числа), вызываемый при изменении размера контейнера, в котором находится элемент, либо при добавлении элемента в контейнер. Может быть вызван до вызова on_hud_open.
|
||||||
|
- `size-func` - поставщик размера элемента (два числа), вызываемый при изменении размера контейнера, в котором находится элемент, либо при добавлении элемента в контейнер. Может быть вызван до вызова on_hud_open.
|
||||||
|
- `onclick` - lua функция вызываемая при нажатии на элемент.
|
||||||
|
- `ondoubleclick` - lua функция вызываемая при двойном нажатии на элемент.
|
||||||
|
- `tooltip` - текст всплывающей подсказки
|
||||||
|
- `tooltip-delay` - задержка появления всплывающей подсказки
|
||||||
|
- `gravity` - автоматическое позиционирование элемента в контейнере. (Не работает в автоматических контейнерах, как panel). Значения: *top-left, top-center, top-right, center-left, center-center, center-right, bottom-left, bottom-center, bottom-right*.
|
||||||
|
- `z-index` - определяет порядок элементов, при большем значении будет перекрывать элементы с меньшим.
|
||||||
|
- `interactive` - при значении false наведение на элемент и все под-элементы будет игнорироваться.
|
||||||
|
|
||||||
|
# Атрибуты шаблонов
|
||||||
|
|
||||||
|
- `if` при значениях ('', 'false', 'nil') элемент будет проигнорирован, включая под-элементы.
|
||||||
|
- `ifnot` то же, что и `if`, но с обратным условием.
|
||||||
|
|
||||||
# Общие атрибуты контейнеров
|
# Общие атрибуты контейнеров
|
||||||
|
|
||||||
@ -46,47 +63,69 @@
|
|||||||
|
|
||||||
В число панелей также входят кнопки.
|
В число панелей также входят кнопки.
|
||||||
- `max-length` - максимальная длина, на которую растягивается панель до начала скроллинга (если scrollable = true). Тип: число
|
- `max-length` - максимальная длина, на которую растягивается панель до начала скроллинга (если scrollable = true). Тип: число
|
||||||
|
- `orientation` - ориентация панели: horizontal/vertical.
|
||||||
|
|
||||||
# Основные элементы
|
# Основные элементы
|
||||||
|
|
||||||
## Кнопка `button`
|
## Кнопка - *button*
|
||||||
|
|
||||||
Внутренний текст - текст кнопки.
|
Внутренний текст - текст кнопки.
|
||||||
|
|
||||||
- `text-align` - выравнивание текста ("left", "center" или "right"). Тип: строка.
|
- `text-align` - выравнивание текста ("left", "center" или "right"). Тип: строка.
|
||||||
- `onclick` - lua функция вызываемая при нажатии на кнопку.
|
|
||||||
|
|
||||||
## Изображение `image`
|
## Флажок - *checkbox*
|
||||||
|
|
||||||
|
- `checked` - определяет состояние отметки.
|
||||||
|
- `supplier` - поставщик состояния отметки (вызывается каждый кадр)
|
||||||
|
- `consumer` - lua функция-приемник состояния отметки. Вызывается только при завершении ввода
|
||||||
|
## Метка - *label*
|
||||||
|
|
||||||
|
- `valign` - вертикальное выравнивание текста: top/center/bottom
|
||||||
|
- `supplier` - поставщик текста (вызывается каждый кадр)
|
||||||
|
- `autoresize` - автоматическое изменение размера элемента (по-умолчанию - false). Не влияет на размер шрифта.
|
||||||
|
- `multiline` - разрешает отображение многострочного текста.
|
||||||
|
- `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true")
|
||||||
|
|
||||||
|
## Изображение - *image*
|
||||||
|
|
||||||
- `src` - имя изображения в папке textures без указания расширения. Тип: строка. Например `gui/error`
|
- `src` - имя изображения в папке textures без указания расширения. Тип: строка. Например `gui/error`
|
||||||
|
|
||||||
# Текстовое поле `textbox`
|
## Текстовое поле - *textbox*
|
||||||
|
|
||||||
Внутренний текст - изначально введенный текст
|
Внутренний текст - изначально введенный текст
|
||||||
|
|
||||||
- `placeholder` - текст подстановки (используется текстовое поле пусто)
|
- `placeholder` - текст подстановки (используется текстовое поле пусто)
|
||||||
|
- `supplier` - поставщик текста (вызывается каждый кадр)
|
||||||
- `consumer` - lua функция-приемник введенного текста. Вызывается только при завершении ввода
|
- `consumer` - lua функция-приемник введенного текста. Вызывается только при завершении ввода
|
||||||
|
- `autoresize` - автоматическое изменение размера элемента (по-умолчанию - false). Не влияет на размер шрифта.
|
||||||
## Ползунок `trackbar`
|
- `multiline` - разрешает отображение многострочного текста.
|
||||||
|
- `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true")
|
||||||
|
- `editable`- определяет возможность редактирования текста.
|
||||||
|
- `error-color` - цвет при вводе некорректных данных (текст не проходит проверку валидатора). Тип: RGBA цвет.
|
||||||
|
- `validator` - lua функция, проверяющая текст на корректность. Принимает на вход строку, возвращает true если текст корректен.
|
||||||
|
- `onup` - lua функция вызываемая при нажатии стрелки вверх.
|
||||||
|
- `ondown` - lua функция вызываемая при нажатии стрелки вниз.
|
||||||
|
## Ползунок - *trackbar*
|
||||||
|
|
||||||
- `min` - минимальное значение. Тип: число. По-умолчанию: 0
|
- `min` - минимальное значение. Тип: число. По-умолчанию: 0
|
||||||
- `max` - максимальное значение. Тип: число. По-умолчанию: 1
|
- `max` - максимальное значение. Тип: число. По-умолчанию: 1
|
||||||
- `value` - изначальное значение. Тип: число. По-умолчанию: 0
|
- `value` - изначальное значение. Тип: число. По-умолчанию: 0
|
||||||
- `step` - размер деления ползунка. Тип: число. По-умолчанию: 1
|
- `step` - размер деления ползунка. Тип: число. По-умолчанию: 1
|
||||||
- `track-width` - ширина указателя (в делениях). Тип: число. По-умолчанию: 1
|
- `track-width` - ширина указателя (в пикселях). Тип: число. По-умолчанию: 12
|
||||||
|
- `track-color` - цвет указателя при наведении курсора. Тип: RGBA цвет.
|
||||||
- `consumer` - lua функция-приемник установленного значения
|
- `consumer` - lua функция-приемник установленного значения
|
||||||
- `supplier` - lua функция-поставщик значения
|
- `supplier` - lua функция-поставщик значения
|
||||||
|
|
||||||
# Элементы инвентаря
|
# Элементы инвентаря
|
||||||
|
|
||||||
## Инвентарь `inventory`
|
## Инвентарь - *inventory*
|
||||||
|
|
||||||
Элемент является контейнером. На данный момент не имеет специфических атрибутов.
|
Элемент является контейнером. На данный момент не имеет специфических атрибутов.
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> Расположение инвентарей управляется движком и не может быть изменено свойствами pos, margin и т.д.
|
> Расположение инвентарей управляется движком и не может быть изменено свойствами pos, margin и т.д.
|
||||||
|
|
||||||
## Одиночный слот `slot`
|
## Одиночный слот - *slot*
|
||||||
|
|
||||||
Элемент должен находиться внутри `inventory` элемента, без посредников.
|
Элемент должен находиться внутри `inventory` элемента, без посредников.
|
||||||
- `index` - индекс слота инвентаря. (Нумерация с 0)
|
- `index` - индекс слота инвентаря. (Нумерация с 0)
|
||||||
@ -95,7 +134,7 @@
|
|||||||
- `updatefunc` - lua событие вызываемое при изменении содержимого слота
|
- `updatefunc` - lua событие вызываемое при изменении содержимого слота
|
||||||
- `onrightclick` - lua событие вызываемое при использовании ПКМ. Передается id инвентаря и индекс слота
|
- `onrightclick` - lua событие вызываемое при использовании ПКМ. Передается id инвентаря и индекс слота
|
||||||
|
|
||||||
## Решетка слотов `slots-grid`
|
## Сетка слотов - *slots-grid*
|
||||||
|
|
||||||
Элемент должен находиться внутри `inventory` элемента, без посредников.
|
Элемент должен находиться внутри `inventory` элемента, без посредников.
|
||||||
- `start-index` - индекс первого слота
|
- `start-index` - индекс первого слота
|
||||||
|
|||||||
@ -2,11 +2,7 @@
|
|||||||
|
|
||||||
В качестве языка сценариев используется LuaJIT
|
В качестве языка сценариев используется LuaJIT
|
||||||
|
|
||||||
## Функции, доступные в скриптах
|
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
load_script("контентпак:scripts/имя_скрипта.lua") -- загружает скрипт, если ещё не загружен
|
|
||||||
load_script("контентпак:scripts/имя_скрипта.lua", true) -- перезагружает скрипт
|
|
||||||
require "контентпак:имя_модуля" -- загружает lua модуль из папки modules (расширение не указывается)
|
require "контентпак:имя_модуля" -- загружает lua модуль из папки modules (расширение не указывается)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -46,10 +42,10 @@ player.set_pos(playerid: int, x: number, y: number, z: number)
|
|||||||
Устанавливает x, y, z координаты игрока
|
Устанавливает x, y, z координаты игрока
|
||||||
|
|
||||||
```python
|
```python
|
||||||
player.get_rot(playerid: int) -> number, number
|
player.get_rot(playerid: int) -> number, number, number
|
||||||
```
|
```
|
||||||
|
|
||||||
Возвращает x, y вращения камеры (в радианах)
|
Возвращает x, y, z вращения камеры (в радианах)
|
||||||
|
|
||||||
```python
|
```python
|
||||||
player.set_rot(playerid: int, x: number, y: number, z: number)
|
player.set_rot(playerid: int, x: number, y: number, z: number)
|
||||||
@ -63,8 +59,37 @@ player.get_inventory(playerid: int) -> int, int
|
|||||||
|
|
||||||
Возвращает id инвентаря игрока и индекс выбранного слота (от 0 до 9)
|
Возвращает id инвентаря игрока и индекс выбранного слота (от 0 до 9)
|
||||||
|
|
||||||
|
```python
|
||||||
|
player.is_flight() -> bool
|
||||||
|
player.set_flight(bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
Геттер и сеттер режима полета
|
||||||
|
|
||||||
|
```python
|
||||||
|
player.is_noclip() -> bool
|
||||||
|
player.set_noclip(bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
Геттер и сеттер noclip режима (выключенная коллизия игрока)
|
||||||
|
|
||||||
|
```python
|
||||||
|
player.get_selected_block(playerid: int) -> x,y,z
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает координаты выделенного блока, либо nil
|
||||||
|
|
||||||
## Библиотека world
|
## Библиотека world
|
||||||
|
|
||||||
|
```python
|
||||||
|
world.get_list() -> массив таблиц {
|
||||||
|
name: str,
|
||||||
|
icon: str
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает информацию о мирах: название и предпросмотр (автоматически загружаемая текстура).
|
||||||
|
|
||||||
```python
|
```python
|
||||||
world.get_day_time() -> number
|
world.get_day_time() -> number
|
||||||
```
|
```
|
||||||
@ -89,6 +114,12 @@ world.get_seed() -> int
|
|||||||
|
|
||||||
Возвращает зерно мира.
|
Возвращает зерно мира.
|
||||||
|
|
||||||
|
```python
|
||||||
|
world.exists() -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверяет существование мира по имени.
|
||||||
|
|
||||||
## Библиотека pack
|
## Библиотека pack
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -109,6 +140,38 @@ pack.get_installed() -> массив строк
|
|||||||
|
|
||||||
Возращает id всех установленных в мире контент-паков
|
Возращает 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
|
## Библиотека gui
|
||||||
|
|
||||||
Библиотека содержит функции для доступа к свойствам UI элементов. Вместо gui следует использовать объектную обертку, предоставляющую доступ к свойствам через мета-методы __index, __newindex:
|
Библиотека содержит функции для доступа к свойствам UI элементов. Вместо gui следует использовать объектную обертку, предоставляющую доступ к свойствам через мета-методы __index, __newindex:
|
||||||
@ -120,6 +183,33 @@ indentory_doc.some_button.text = "new text"
|
|||||||
|
|
||||||
В скрипте макета `layouts/файл_макета.xml` - `layouts/файл_макета.xml.lua` уже доступна переменная **document** содержащая объект класса Document
|
В скрипте макета `layouts/файл_макета.xml` - `layouts/файл_макета.xml.lua` уже доступна переменная **document** содержащая объект класса Document
|
||||||
|
|
||||||
|
```python
|
||||||
|
gui.str(text: str, context: str) -> str
|
||||||
|
```
|
||||||
|
|
||||||
|
Возращает переведенный текст.
|
||||||
|
|
||||||
|
```python
|
||||||
|
gui.get_viewport() -> {int, int}
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает размер главного контейнера (окна).
|
||||||
|
|
||||||
|
```python
|
||||||
|
gui.get_env(document: str) -> table
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает окружение (таблица глобальных переменных) указанного документа.
|
||||||
|
|
||||||
|
```python
|
||||||
|
get_locales_info() -> таблица таблиц где
|
||||||
|
ключ - id локали в формате isolangcode_ISOCOUNTRYCODE
|
||||||
|
значение - таблица {
|
||||||
|
name: str # название локали на её языке
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает информацию о всех загруженных локалях (res/texts/\*).
|
||||||
## Библиотека inventory
|
## Библиотека inventory
|
||||||
|
|
||||||
Библиотека функций для работы с инвентарем.
|
Библиотека функций для работы с инвентарем.
|
||||||
@ -197,6 +287,18 @@ block.index(name: str) -> int
|
|||||||
|
|
||||||
Возвращает числовой id блока, принимая в качестве агрумента строковый
|
Возвращает числовой id блока, принимая в качестве агрумента строковый
|
||||||
|
|
||||||
|
```python
|
||||||
|
block.material(blockid: int) -> str
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает id материала блока.
|
||||||
|
|
||||||
|
```python
|
||||||
|
block.caption(blockid: int) -> str
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает название блока, отображаемое в интерфейсе.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
block.get(x: int, y: int, z: int) -> int
|
block.get(x: int, y: int, z: int) -> int
|
||||||
```
|
```
|
||||||
@ -359,206 +461,27 @@ hud.close(layoutid: str)
|
|||||||
hud.get_block_inventory() -> int
|
hud.get_block_inventory() -> int
|
||||||
```
|
```
|
||||||
|
|
||||||
Получить ID инвентаря открытого блока или 0
|
Дает ID инвентаря открытого блока или 0
|
||||||
|
|
||||||
## События блоков
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_placed(x, y, z, playerid)
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается после установки блока игроком
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_broken(x, y, z, playerid)
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается после разрушения блока игроком
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_interact(x, y, z, playerid) -> bool
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается при нажатии на блок ПКМ. Предотвращает установку блоков, если возвращает `true`
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_update(x, y, z)
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается при обновлении блока (если изменился соседний блок)
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_random_update(x, y, z)
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается в случайные моменты времени (рост травы на блоках земли)
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_blocks_tick(tps: int)
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается tps (20) раз в секунду
|
|
||||||
|
|
||||||
## События предметов
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_use(playerid: int)
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается при нажатии ПКМ не на блок.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_use_on_block(x: int, y: int, z: int, playerid: int)
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается при нажатии ПКМ на блок. Предотвращает установку блока, прописанного в `placing-block` если возвращает `true`
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_block_break_by(x: int, y: int, z: int, playerid: int)
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается при нажатии ЛКМ на блок (в т.ч неразрушимый). Предотвращает разрушение блока, если возвращает `true`
|
|
||||||
|
|
||||||
## События мира
|
|
||||||
|
|
||||||
События мира для контент-пака прописываются в `scripts/world.lua`
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_world_open()
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается при загрузке мира
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_world_save()
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается перед сохранением мира
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_world_tick()
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается 20 раз в секунду
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_world_quit()
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается при выходе из мира (после сохранения)
|
|
||||||
|
|
||||||
## События макета
|
|
||||||
|
|
||||||
События прописываются в файле `layouts/имя_макета.xml.lua`.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_open(invid: int, x: int, y: int, z: int)
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается при добавлении элемента на экран.
|
|
||||||
При отсутствии привязки к инвентарю invid будет равен 0.
|
|
||||||
При отсутствии привязки к блоку x, y, z так же будут равны 0.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_close(invid: int)
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается при удалении элемента с экрана.
|
|
||||||
|
|
||||||
## События HUD
|
|
||||||
|
|
||||||
События связанные с игровым интерфейсом прописываются в файле `scripts/hud.lua`
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_hud_open(playerid: int)
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается после входа в мир, когда становится доступна библиотека hud. Здесь на экран добавляются постоянные элементы.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function on_hud_close(playerid: int)
|
|
||||||
```
|
|
||||||
|
|
||||||
Вызывается при выходе из мира, перед его сохранением.
|
|
||||||
|
|
||||||
## Библиотеки движка
|
|
||||||
|
|
||||||
### file
|
|
||||||
|
|
||||||
Библиотека функций для работы с файлами
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
file.resolve(путь: str) -> str
|
hud.get_player() -> int
|
||||||
```
|
```
|
||||||
|
|
||||||
Функция приводит запись `точка_входа:путь` (например `user:worlds/house1`) к обычному пути. (например `C://Users/user/.voxeng/worlds/house1`)
|
Дает ID игрока, к которому привязан пользовательский интерфейс
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> Функцию не нужно использовать в сочетании с другими функциями из библиотеки, так как они делают это автоматически
|
|
||||||
|
|
||||||
Возвращаемый путь не является каноническим и может быть как абсолютным, так и относительным.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
file.read(путь: str) -> str
|
hud.pause()
|
||||||
```
|
```
|
||||||
|
|
||||||
Читает весь текстовый файл и возвращает в виде строки
|
Открывает меню паузы
|
||||||
|
|
||||||
```python
|
```python
|
||||||
file.read_bytes(путь: str) -> array of integers
|
hud.resume()
|
||||||
```
|
```
|
||||||
|
|
||||||
Читает файл в массив байт.
|
Закрывает меню паузы.
|
||||||
|
|
||||||
```python
|
## Библиотека time
|
||||||
file.write(путь: str, текст: str) -> nil
|
|
||||||
```
|
|
||||||
|
|
||||||
Записывает текст в файл (с перезаписью)
|
|
||||||
|
|
||||||
```python
|
|
||||||
file.write_bytes(путь: str, data: array of integers)
|
|
||||||
```
|
|
||||||
|
|
||||||
Записывает массив байт в файл (с перезаписью)
|
|
||||||
|
|
||||||
```python
|
|
||||||
file.length(путь: str) -> int
|
|
||||||
```
|
|
||||||
|
|
||||||
Возвращает размер файла в байтах, либо -1, если файл не найден
|
|
||||||
|
|
||||||
```python
|
|
||||||
file.exists(путь: str) -> bool
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверяет, существует ли по данному пути файл или директория
|
|
||||||
|
|
||||||
```python
|
|
||||||
file.isfile(путь: str) -> bool
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверяет, существует ли по данному пути файл
|
|
||||||
|
|
||||||
```python
|
|
||||||
file.isdir(путь: str) -> bool
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверяет, существует ли по данному пути директория
|
|
||||||
|
|
||||||
```python
|
|
||||||
file.mkdir(путь: str) -> bool
|
|
||||||
```
|
|
||||||
|
|
||||||
Создает директорию. Возвращает true если была создана новая директория
|
|
||||||
|
|
||||||
```python
|
|
||||||
file.mkdirs(путь: str) -> bool
|
|
||||||
```
|
|
||||||
|
|
||||||
Создает всю цепочку директорий. Возвращает true если были созданы директории.
|
|
||||||
|
|
||||||
### time
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
time.uptime() -> float
|
time.uptime() -> float
|
||||||
@ -566,24 +489,8 @@ time.uptime() -> float
|
|||||||
|
|
||||||
Возвращает время с момента запуска движка в секундах
|
Возвращает время с момента запуска движка в секундах
|
||||||
|
|
||||||
## Доступные модули
|
```python
|
||||||
|
time.delta() -> float
|
||||||
### TOML сериализация/десериализация
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local toml = require "core:toml"
|
|
||||||
|
|
||||||
local t = {a=53, b=42, s="test", sub={x=1, y=6}}
|
|
||||||
local s = toml.serialize(t)
|
|
||||||
print(s)
|
|
||||||
local t2 = toml.deserialize(s)
|
|
||||||
```
|
|
||||||
вывод:
|
|
||||||
```toml
|
|
||||||
b = 42
|
|
||||||
s = "test"
|
|
||||||
a = 53
|
|
||||||
[sub]
|
|
||||||
y = 6
|
|
||||||
x = 1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Возвращает дельту времени (время прошедшее с предыдущего кадра)
|
||||||
|
|||||||
109
doc/ru/Консоль.md
Normal file
109
doc/ru/Консоль.md
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# Консоль
|
||||||
|
|
||||||
|
Для работы с командным интерпретатором предоставляется библиотека **console**
|
||||||
|
|
||||||
|
## Создание команд
|
||||||
|
|
||||||
|
Для создания команды консоли используется следующая функция:
|
||||||
|
|
||||||
|
```python
|
||||||
|
console.add_command(схема: str, исполнитель: function)
|
||||||
|
```
|
||||||
|
|
||||||
|
Схема имеет следующий синтаксис:
|
||||||
|
|
||||||
|
```
|
||||||
|
название позиционные параметры {именованные параметры}
|
||||||
|
```
|
||||||
|
|
||||||
|
Название может содержать:
|
||||||
|
- латинницу
|
||||||
|
- цифры (кроме первого символа)
|
||||||
|
- `.`, `_`, `-`
|
||||||
|
|
||||||
|
Позиционные параметры разделяются пробелами и имеют следующий синтаксис:
|
||||||
|
|
||||||
|
```
|
||||||
|
название:тип (вариант 1)
|
||||||
|
название:тип=по-умолчанию (вариант 2)
|
||||||
|
название:тип~центральное-значение (вариант 3)
|
||||||
|
название:тип=по-умолчанию~центральное-значение (вариант 4)
|
||||||
|
```
|
||||||
|
|
||||||
|
Доступные типы:
|
||||||
|
- **int** - целое число
|
||||||
|
- **num** - дробное число
|
||||||
|
- **str** - строка
|
||||||
|
- **sel** - селектор (id объекта представленный целым числом)
|
||||||
|
- **enum** - перечисление
|
||||||
|
|
||||||
|
На вариантах 3 и 4 показан оператор `~` позволяющий использовать относительные значения. *Центральное значение* - значение, относительно которого будет указываться пользовательское. Например позиция игрока.
|
||||||
|
|
||||||
|
Относительный оператор работает только с числами (num или int)
|
||||||
|
|
||||||
|
В качестве центральных значений могут указываться переменные, назначаемые через **console.set**.
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```python
|
||||||
|
x:num~pos.x
|
||||||
|
```
|
||||||
|
|
||||||
|
Переменные можно указывать и в качестве значений по-умолчанию, при использовании префикса `$`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
t:int=$time
|
||||||
|
```
|
||||||
|
|
||||||
|
Перечисления указывазываются в формате:
|
||||||
|
|
||||||
|
```python
|
||||||
|
mode:[replace|destruct|none]
|
||||||
|
```
|
||||||
|
|
||||||
|
Либо через переменную:
|
||||||
|
|
||||||
|
```python
|
||||||
|
mode:enum $modes
|
||||||
|
```
|
||||||
|
|
||||||
|
Селекторы указываются с префиксом `@`. На данный момент являются заглушкой, по причине отсутствия объектной модели. Следует делать опциональными и использовать переменные:
|
||||||
|
|
||||||
|
```python
|
||||||
|
obj:sel=$obj.id # obj.id - id игрока
|
||||||
|
```
|
||||||
|
|
||||||
|
Именованные аргументы указываются в специальном блоке, ограниченном фигурными скобками `{ }` по той же схеме.
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```python
|
||||||
|
eval name:str="World" {greeting:str='Hello'}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Примеры схем команд
|
||||||
|
|
||||||
|
Схемы существующих команд можно найти в файле `res/script/stdcmd.lua`.
|
||||||
|
|
||||||
|
Пример - команда **tp**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
tp obj:sel=$obj.id x:num~pos.x y:num~pos.y z:num~pos.z
|
||||||
|
```
|
||||||
|
|
||||||
|
Полный lua код создания команды:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
console.add_command(
|
||||||
|
"tp obj:sel=$obj.id x:num~pos.x y:num~pos.y z:num~pos.z",
|
||||||
|
"Teleport object",
|
||||||
|
function (args, kwargs)
|
||||||
|
player.set_pos(unpack(args))
|
||||||
|
end
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
- В args передаются готовые значения позиционных аргументов.
|
||||||
|
- В kwargs передается таблица значений именованных аргументов.
|
||||||
|
|
||||||
|
Проверку и приведение типов интерпретатор команд производит автоматически.
|
||||||
59
doc/ru/Пользовательский-ввод.md
Normal file
59
doc/ru/Пользовательский-ввод.md
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# Пользовательский ввод
|
||||||
|
|
||||||
|
Обработка нажатий клавиш и кнопок мыши обрабатываются через привязки (bindings), которые назначаются в паке, в файле `config/bindings.toml` в формате:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
packid.binding.name="inputtype:codename"
|
||||||
|
```
|
||||||
|
|
||||||
|
- packid - опционально, но желательно
|
||||||
|
- inputtype - key или mouse
|
||||||
|
- codename - имя клавиши или кнопки мыши (left/right/middle)
|
||||||
|
|
||||||
|
## Имена клавиш
|
||||||
|
|
||||||
|
- space, backspace, tab, enter, caps-lock, escape
|
||||||
|
- left-ctrl, left-shift, left-alt, left-super
|
||||||
|
- right-ctrl, right-shift, right-alt, right-super
|
||||||
|
- delete, home, end, insert, page-up, page-down
|
||||||
|
- left, right, down, up
|
||||||
|
- a..z
|
||||||
|
- 0..9
|
||||||
|
- f1..f25
|
||||||
|
|
||||||
|
## Библиотека input
|
||||||
|
|
||||||
|
```python
|
||||||
|
input.keycode(keyname: str) -> int
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает код клавиши по имени, либо -1
|
||||||
|
|
||||||
|
```python
|
||||||
|
input.mousecode(mousename: str) -> int
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает код кнопки мыши по имени, либо -1
|
||||||
|
|
||||||
|
```python
|
||||||
|
input.add_callback(bindname: str, callback: function)
|
||||||
|
```
|
||||||
|
|
||||||
|
Назначает функцию, которая будет вызываться при активации привязки. Пример:
|
||||||
|
```lua
|
||||||
|
input.add_callback("hud.inventory", function ()
|
||||||
|
print("Inventory open key pressed")
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
input.get_mouse_pos() -> {int, int}
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает позицию курсора на экране.
|
||||||
|
|
||||||
|
```python
|
||||||
|
input.get_bindings() -> массив строк
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает названия всех доступных привязок.
|
||||||
126
doc/ru/События-движка.md
Normal file
126
doc/ru/События-движка.md
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
# События движка
|
||||||
|
|
||||||
|
## События блоков
|
||||||
|
|
||||||
|
Функции для обработки событий, прописываемые в скрипте блока.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_placed(x, y, z, playerid)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается после установки блока игроком
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_broken(x, y, z, playerid)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается после разрушения блока игроком
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_interact(x, y, z, playerid) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается при нажатии на блок ПКМ. Предотвращает установку блоков, если возвращает `true`
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_update(x, y, z)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается при обновлении блока (если изменился соседний блок)
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_random_update(x, y, z)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается в случайные моменты времени (рост травы на блоках земли)
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_blocks_tick(tps: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается tps (20) раз в секунду
|
||||||
|
|
||||||
|
## События предметов
|
||||||
|
|
||||||
|
Функции для обработки событий, прописываемые в скрипте предмета.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_use(playerid: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается при нажатии ПКМ не на блок.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
|
||||||
|
function on_use_on_block(x: int, y: int, z: int, playerid: int)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается при нажатии ПКМ на блок. Предотвращает установку блока, прописанного в `placing-block` если возвращает `true`
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_block_break_by(x: int, y: int, z: int, playerid: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается при нажатии ЛКМ на блок (в т.ч неразрушимый). Предотвращает разрушение блока, если возвращает `true`
|
||||||
|
|
||||||
|
## События мира
|
||||||
|
|
||||||
|
События мира для контент-пака прописываются в `scripts/world.lua`
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_world_open()
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается при загрузке мира
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_world_save()
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается перед сохранением мира
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_world_tick()
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается 20 раз в секунду
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_world_quit()
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается при выходе из мира (после сохранения)
|
||||||
|
## События макета
|
||||||
|
|
||||||
|
События прописываются в файле `layouts/имя_макета.xml.lua`.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_open(invid: int, x: int, y: int, z: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается при добавлении элемента на экран.
|
||||||
|
- При отсутствии привязки к инвентарю invid будет равен 0.
|
||||||
|
- При отсутствии привязки к блоку x, y, z так же будут равны 0.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_close(invid: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается при удалении элемента с экрана.
|
||||||
|
|
||||||
|
## События HUD
|
||||||
|
|
||||||
|
События связанные с игровым интерфейсом прописываются в файле `scripts/hud.lua`
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_hud_open(playerid: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается после входа в мир, когда становится доступна библиотека hud. Здесь на экран добавляются постоянные элементы.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_hud_close(playerid: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается при выходе из мира, перед его сохранением.
|
||||||
137
doc/ru/Файловая-система-и-сериализация.md
Normal file
137
doc/ru/Файловая-система-и-сериализация.md
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
## Библиотека *file*
|
||||||
|
|
||||||
|
Библиотека функций для работы с файлами
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.resolve(путь: str) -> str
|
||||||
|
```
|
||||||
|
|
||||||
|
Функция приводит запись `точка_входа:путь` (например `user:worlds/house1`) к обычному пути. (например `C://Users/user/.voxeng/worlds/house1`)
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Функцию не нужно использовать в сочетании с другими функциями из библиотеки, так как они делают это автоматически
|
||||||
|
|
||||||
|
Возвращаемый путь не является каноническим и может быть как абсолютным, так и относительным.
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.read(путь: str) -> str
|
||||||
|
```
|
||||||
|
|
||||||
|
Читает весь текстовый файл и возвращает в виде строки
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.read_bytes(путь: str) -> array of integers
|
||||||
|
```
|
||||||
|
|
||||||
|
Читает файл в массив байт.
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.write(путь: str, текст: str) -> nil
|
||||||
|
```
|
||||||
|
|
||||||
|
Записывает текст в файл (с перезаписью)
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.write_bytes(путь: str, data: array of integers)
|
||||||
|
```
|
||||||
|
|
||||||
|
Записывает массив байт в файл (с перезаписью)
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.length(путь: str) -> int
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает размер файла в байтах, либо -1, если файл не найден
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.exists(путь: str) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверяет, существует ли по данному пути файл или директория
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.isfile(путь: str) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверяет, существует ли по данному пути файл
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.isdir(путь: str) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверяет, существует ли по данному пути директория
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.mkdir(путь: str) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Создает директорию. Возвращает true если была создана новая директория
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.mkdirs(путь: str) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Создает всю цепочку директорий. Возвращает true если были созданы директории.
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.find(путь: str) -> str
|
||||||
|
```
|
||||||
|
|
||||||
|
Ищет файл от последнего пака до res. Путь указывается без префикса. Возвращает путь с нужным префиксом. Если файл не найден, возвращает nil.
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.remove(путь: str) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Удаляет файл. Возращает **true** если файл существовал. Бросает исключение при нарушении доступа.
|
||||||
|
|
||||||
|
```python
|
||||||
|
file.remove_tree(путь: str) -> int
|
||||||
|
```
|
||||||
|
|
||||||
|
Рекурсивно удаляет файлы. Возвращает число удаленных файлов.
|
||||||
|
|
||||||
|
## Библиотека json
|
||||||
|
|
||||||
|
Библиотека содержит функции для сериализации и десериализации таблиц:
|
||||||
|
|
||||||
|
```python
|
||||||
|
json.tostring(object: table, human_readable: bool=false) -> str
|
||||||
|
```
|
||||||
|
|
||||||
|
Сериализует объект в JSON строку. При значении второго параметра **true** будет использовано многострочное форматирование, удобное для чтения человеком, а не компактное, использующееся по-умолчанию.
|
||||||
|
|
||||||
|
```python
|
||||||
|
json.parse(code: str) -> table
|
||||||
|
```
|
||||||
|
|
||||||
|
Парсит JSON строку в таблицу.
|
||||||
|
|
||||||
|
## Библиотека toml
|
||||||
|
|
||||||
|
Библиотека содержит функции для сериализации и десериализации таблиц:
|
||||||
|
|
||||||
|
```python
|
||||||
|
toml.tostring(object: table) -> str
|
||||||
|
```
|
||||||
|
|
||||||
|
Сериализует объект в TOML строку.
|
||||||
|
|
||||||
|
```python
|
||||||
|
toml.parse(code: str) -> table
|
||||||
|
```
|
||||||
|
|
||||||
|
Парсит TOML строку в таблицу.
|
||||||
|
|
||||||
|
## Сохранение данных в мире
|
||||||
|
|
||||||
|
При сохранении данных пака в мире следует использовать функцию
|
||||||
|
```python
|
||||||
|
pack.data_file(packid: str, filename: str) -> str
|
||||||
|
```
|
||||||
|
|
||||||
|
Функция возвращает путь к файлу данных по типу: `world:data/packid/filename`
|
||||||
|
|
||||||
|
и создает недостающие директории в пути.
|
||||||
|
|
||||||
|
При использовании путей не соответствующим `data/{packid}/...` возможна потеря данных при перезаписи мира.
|
||||||
24
fix_dylibs.sh
Executable file
24
fix_dylibs.sh
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PROJECT_NAME=$1
|
||||||
|
CONFIG=$2
|
||||||
|
OUTPUT_DIR=$3
|
||||||
|
LIBS_DIR="$OUTPUT_DIR/libs"
|
||||||
|
|
||||||
|
mkdir -p "$LIBS_DIR"
|
||||||
|
|
||||||
|
TMP_BINARY="$OUTPUT_DIR/tmp_$PROJECT_NAME"
|
||||||
|
BINARY="$OUTPUT_DIR/$PROJECT_NAME"
|
||||||
|
|
||||||
|
cp "$BINARY" "$TMP_BINARY"
|
||||||
|
|
||||||
|
otool -L "$TMP_BINARY" | grep -o '/.*dylib' | while read -r dylib; do
|
||||||
|
if [[ "$dylib" == /usr/lib/* || "$dylib" == /System/Library/* ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp "$dylib" "$LIBS_DIR"
|
||||||
|
install_name_tool -change "$dylib" "@executable_path/libs/$(basename "$dylib")" "$TMP_BINARY"
|
||||||
|
done
|
||||||
|
|
||||||
|
mv "$TMP_BINARY" "$BINARY"
|
||||||
18
res/config/bindings.toml
Normal file
18
res/config/bindings.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
devtools.console="key:grave-accent"
|
||||||
|
chunks.reload="key:f5"
|
||||||
|
movement.forward="key:w"
|
||||||
|
movement.back="key:s"
|
||||||
|
movement.left="key:a"
|
||||||
|
movement.right="key:d"
|
||||||
|
movement.jump="key:space"
|
||||||
|
movement.sprint="key:left-ctrl"
|
||||||
|
movement.crouch="key:left-shift"
|
||||||
|
movement.cheat="key:r"
|
||||||
|
camera.zoom="key:c"
|
||||||
|
camera.mode="key:f4"
|
||||||
|
player.noclip="key:n"
|
||||||
|
player.flight="key:f"
|
||||||
|
player.attack="mouse:left"
|
||||||
|
player.build="mouse:right"
|
||||||
|
player.pick="mouse:middle"
|
||||||
|
hud.inventory="key:tab"
|
||||||
1
res/config/builtins.list
Normal file
1
res/config/builtins.list
Normal file
@ -0,0 +1 @@
|
|||||||
|
base
|
||||||
@ -1,15 +1,15 @@
|
|||||||
function on_random_update(x, y, z)
|
function on_random_update(x, y, z)
|
||||||
local dirtid = block_index('base:dirt');
|
local dirtid = block.index('base:dirt');
|
||||||
if is_solid_at(x, y+1, z) then
|
if block.is_solid_at(x, y+1, z) then
|
||||||
set_block(x, y, z, dirtid, 0)
|
block.set(x, y, z, dirtid, 0)
|
||||||
else
|
else
|
||||||
local grassblockid = block_index('base:grass_block')
|
local grassblockid = block.index('base:grass_block')
|
||||||
for lx=-1,1 do
|
for lx=-1,1 do
|
||||||
for ly=-1,1 do
|
for ly=-1,1 do
|
||||||
for lz=-1,1 do
|
for lz=-1,1 do
|
||||||
if get_block(x + lx, y + ly, z + lz) == dirtid then
|
if block.get(x + lx, y + ly, z + lz) == dirtid then
|
||||||
if not is_solid_at(x + lx, y + ly + 1, z + lz) then
|
if not block.is_solid_at(x + lx, y + ly + 1, z + lz) then
|
||||||
set_block(x + lx, y + ly, z + lz, grassblockid, 0)
|
block.set(x + lx, y + ly, z + lz, grassblockid, 0)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -35,6 +35,7 @@ function submit(text)
|
|||||||
add_to_history(text)
|
add_to_history(text)
|
||||||
setup_variables()
|
setup_variables()
|
||||||
|
|
||||||
|
document.log.caret = -1
|
||||||
local status, result = pcall(function() return console.execute(text) end)
|
local status, result = pcall(function() return console.execute(text) end)
|
||||||
if result ~= nil then
|
if result ~= nil then
|
||||||
local prevtext = document.log.text
|
local prevtext = document.log.text
|
||||||
|
|||||||
@ -9,10 +9,9 @@ function on_open()
|
|||||||
table.sort(names)
|
table.sort(names)
|
||||||
|
|
||||||
local panel = document.root
|
local panel = document.root
|
||||||
for _,k in ipairs(names) do
|
for _,name in ipairs(names) do
|
||||||
panel:add(string.format(
|
panel:add(gui.template(
|
||||||
"<button onclick=%q>%s</button>",
|
"language", {id=invlocales[name], name=name}
|
||||||
string.format("core.set_setting('ui.language', %q) menu:back()", invlocales[k]), k
|
|
||||||
))
|
))
|
||||||
end
|
end
|
||||||
panel:add("<button onclick='menu:back()'>@Back</button>")
|
panel:add("<button onclick='menu:back()'>@Back</button>")
|
||||||
|
|||||||
@ -16,7 +16,8 @@ function on_open()
|
|||||||
refresh_sensitivity()
|
refresh_sensitivity()
|
||||||
|
|
||||||
local panel = document.bindings_panel
|
local panel = document.bindings_panel
|
||||||
local bindings = core.get_bindings()
|
local bindings = input.get_bindings()
|
||||||
|
table.sort(bindings, function(a, b) return a > b end)
|
||||||
for i,name in ipairs(bindings) do
|
for i,name in ipairs(bindings) do
|
||||||
panel:add(gui.template("binding", {
|
panel:add(gui.template("binding", {
|
||||||
id=name, name=gui.str(name)
|
id=name, name=gui.str(name)
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
function create_setting(id, name, step, postfix)
|
function create_setting(id, name, step, postfix, tooltip)
|
||||||
local info = core.get_setting_info(id)
|
local info = core.get_setting_info(id)
|
||||||
postfix = postfix or ""
|
postfix = postfix or ""
|
||||||
|
tooltip = tooltip or ""
|
||||||
document.root:add(gui.template("track_setting", {
|
document.root:add(gui.template("track_setting", {
|
||||||
id=id,
|
id=id,
|
||||||
name=gui.str(name, "settings"),
|
name=gui.str(name, "settings"),
|
||||||
@ -8,7 +9,8 @@ function create_setting(id, name, step, postfix)
|
|||||||
min=info.min,
|
min=info.min,
|
||||||
max=info.max,
|
max=info.max,
|
||||||
step=step,
|
step=step,
|
||||||
postfix=postfix
|
postfix=postfix,
|
||||||
|
tooltip=tooltip
|
||||||
}))
|
}))
|
||||||
update_setting(core.get_setting(id), id, name, postfix)
|
update_setting(core.get_setting(id), id, name, postfix)
|
||||||
end
|
end
|
||||||
@ -24,10 +26,11 @@ function update_setting(x, id, name, postfix)
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
function create_checkbox(id, name)
|
function create_checkbox(id, name, tooltip)
|
||||||
|
tooltip = tooltip or ''
|
||||||
document.root:add(string.format(
|
document.root:add(string.format(
|
||||||
"<checkbox consumer='function(x) core.set_setting(\"%s\", x) end' checked='%s'>%s</checkbox>",
|
"<checkbox consumer='function(x) core.set_setting(\"%s\", x) end' checked='%s' tooltip='%s'>%s</checkbox>",
|
||||||
id, core.str_setting(id), gui.str(name, "settings")
|
id, core.str_setting(id), gui.str(tooltip, "settings"), gui.str(name, "settings")
|
||||||
))
|
))
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -35,10 +38,10 @@ function on_open()
|
|||||||
create_setting("chunks.load-distance", "Load Distance", 1)
|
create_setting("chunks.load-distance", "Load Distance", 1)
|
||||||
create_setting("chunks.load-speed", "Load Speed", 1)
|
create_setting("chunks.load-speed", "Load Speed", 1)
|
||||||
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)
|
create_setting("graphics.gamma", "Gamma", 0.05, "", "graphics.gamma.tooltip")
|
||||||
create_setting("camera.fov", "FOV", 1, "°")
|
create_setting("camera.fov", "FOV", 1, "°")
|
||||||
create_checkbox("display.fullscreen", "Fullscreen")
|
create_checkbox("display.fullscreen", "Fullscreen")
|
||||||
create_checkbox("display.vsync", "V-Sync")
|
create_checkbox("display.vsync", "V-Sync")
|
||||||
create_checkbox("graphics.backlight", "Backlight")
|
create_checkbox("graphics.backlight", "Backlight", "graphics.backlight.tooltip")
|
||||||
create_checkbox("camera.shaking", "Camera Shaking")
|
create_checkbox("camera.shaking", "Camera Shaking")
|
||||||
end
|
end
|
||||||
|
|||||||
4
res/layouts/templates/language.xml
Normal file
4
res/layouts/templates/language.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<button
|
||||||
|
onclick='core.set_setting("ui.language", "%{id}") menu:back()'>
|
||||||
|
%{name}
|
||||||
|
</button>
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<panel color='0' context='settings'>
|
<panel color='0' context='settings'>
|
||||||
<label id='%{id}.L' margin='0,3,0,0'>%{name}: %{value}%{postfix}</label>
|
<label id='%{id}.L' margin='0,3,0,0'>%{name}: %{value}%{postfix}</label>
|
||||||
<trackbar
|
<trackbar
|
||||||
value='%{value}' min='%{min}' max='%{max}' step='%{step}'
|
value='%{value}' min='%{min}' max='%{max}' step='%{step}' tooltip='%{tooltip}'
|
||||||
consumer='function(x) update_setting(x, "%{id}", "%{name}", "%{postfix}") end'/>
|
consumer='function(x) update_setting(x, "%{id}", "%{name}", "%{postfix}") end'/>
|
||||||
</panel>
|
</panel>
|
||||||
|
|||||||
@ -1,65 +1,4 @@
|
|||||||
-- TOML serialization module
|
print("WARNING: toml is replaced with built-in library, just remove 'require \"core:toml\"'")
|
||||||
local toml = {}
|
toml.serialize = toml.tostring
|
||||||
|
toml.deserialize = toml.parse
|
||||||
-- Convert table to TOML
|
|
||||||
function toml.serialize(tb, isinner)
|
|
||||||
local text = ""
|
|
||||||
for k, v in pairs(tb) do
|
|
||||||
local tp = type(v)
|
|
||||||
if tp ~= "table" then
|
|
||||||
text = text..k.." = "
|
|
||||||
if tp == "string" then
|
|
||||||
text = text..string.format("%q", v)
|
|
||||||
else
|
|
||||||
text = text..tostring(v)
|
|
||||||
end
|
|
||||||
text = text.."\n"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for k, v in pairs(tb) do
|
|
||||||
local tp = type(v)
|
|
||||||
if tp == "table" then
|
|
||||||
if isinner then
|
|
||||||
error("only one level of subtables supported")
|
|
||||||
end
|
|
||||||
text = text.."["..k.."]\n"..toml.serialize(v).."\n"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return text
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Parse TOML to new table
|
|
||||||
function toml.deserialize(s)
|
|
||||||
local output = {}
|
|
||||||
local current = output
|
|
||||||
local lines = {}
|
|
||||||
for line in string.gmatch(s, "[^\r\n]+") do
|
|
||||||
line = string.gsub(line, "%s+", "")
|
|
||||||
table.insert(lines, line)
|
|
||||||
end
|
|
||||||
for i = 1,#lines do
|
|
||||||
local s = lines[i]
|
|
||||||
if string.sub(s, 1, 1) == "[" then
|
|
||||||
local section = s.sub(s, 2, #s-1)
|
|
||||||
current = {}
|
|
||||||
output[section] = current
|
|
||||||
else
|
|
||||||
for k, v in string.gmatch(s, "(%w+)=(.+)" ) do
|
|
||||||
v = string.gsub(v, "%s+", "")
|
|
||||||
if v.sub(v, 1, 1) == "\"" then
|
|
||||||
current[k] = v.sub(v, 2, #v-1)
|
|
||||||
elseif v == "true" or v == "false" then
|
|
||||||
current[k] = v == "true"
|
|
||||||
end
|
|
||||||
|
|
||||||
local num = tonumber(v)
|
|
||||||
if num ~= nil then
|
|
||||||
current[k] = num
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return output
|
|
||||||
end
|
|
||||||
|
|
||||||
return toml
|
return toml
|
||||||
|
|||||||
@ -51,7 +51,7 @@ console.add_command(
|
|||||||
)
|
)
|
||||||
|
|
||||||
console.add_command(
|
console.add_command(
|
||||||
"obj.tp obj:sel=$obj.id x:num~pos.x y:num~pos.y z:num~pos.z",
|
"tp obj:sel=$obj.id x:num~pos.x y:num~pos.y z:num~pos.z",
|
||||||
"Teleport object",
|
"Teleport object",
|
||||||
function (args, kwargs)
|
function (args, kwargs)
|
||||||
player.set_pos(unpack(args))
|
player.set_pos(unpack(args))
|
||||||
|
|||||||
@ -12,47 +12,55 @@ error.pack-not-found=Не ўдалося знайсці пакет
|
|||||||
error.dependency-not-found=Выкарыстоўваная залежнасць не знойдзена
|
error.dependency-not-found=Выкарыстоўваная залежнасць не знойдзена
|
||||||
pack.remove-confirm=Выдаліць увесь кантэнт які пастаўляецца пакам са свету (беззваротна)?
|
pack.remove-confirm=Выдаліць увесь кантэнт які пастаўляецца пакам са свету (беззваротна)?
|
||||||
|
|
||||||
|
# Подсказки
|
||||||
|
graphics.gamma.tooltip=Крывая яркасці асвятлення
|
||||||
|
graphics.backlight.tooltip=Падсветка, якая прадухіляе поўную цемру
|
||||||
|
|
||||||
# Меню
|
# Меню
|
||||||
menu.New World=Новы Свет
|
menu.Apply=Ужыць
|
||||||
menu.Quit=Выхад
|
|
||||||
menu.Continue=Працягнуть
|
|
||||||
menu.Save and Quit to Menu=Захаваць і Выйсці ў Меню
|
|
||||||
menu.missing-content=Адсутнічае Кантэнт!
|
|
||||||
menu.Content Error=Памылка Кантэнту
|
|
||||||
menu.Controls=Кіраванне
|
|
||||||
menu.Back to Main Menu=Вярнуцца ў Меню
|
|
||||||
menu.Settings=Налады
|
|
||||||
menu.Content=Кантэнт
|
|
||||||
menu.Audio=Гук
|
menu.Audio=Гук
|
||||||
|
menu.Back to Main Menu=Вярнуцца ў Меню
|
||||||
|
menu.Content Error=Памылка Кантэнту
|
||||||
|
menu.Content=Кантэнт
|
||||||
|
menu.Continue=Працягнуть
|
||||||
|
menu.Controls=Кіраванне
|
||||||
|
menu.Graphics=Графіка
|
||||||
|
menu.missing-content=Адсутнічае Кантэнт!
|
||||||
|
menu.New World=Новы Свет
|
||||||
|
menu.Page not found=Старонка не знойдзена
|
||||||
|
menu.Quit=Выхад
|
||||||
|
menu.Save and Quit to Menu=Захаваць і Выйсці ў Меню
|
||||||
|
menu.Settings=Налады
|
||||||
|
|
||||||
world.Seed=Зерне
|
world.Seed=Зерне
|
||||||
world.Name=Назва
|
world.Name=Назва
|
||||||
|
|
||||||
world.World generator=Генератар свету
|
world.World generator=Генератар свету
|
||||||
world.generators.default=Звычайны
|
world.generators.default=Звычайны
|
||||||
world.generators.flat=Плоскі
|
world.generators.flat=Плоскі
|
||||||
menu.Create World=Стварыць Свет
|
world.Create World=Стварыць Свет
|
||||||
|
|
||||||
world.convert-request=Ёсць змены ў індэксах! Канвертаваць свет?
|
world.convert-request=Ёсць змены ў індэксах! Канвертаваць свет?
|
||||||
world.delete-confirm=Выдаліць свет незваротна?
|
world.delete-confirm=Выдаліць свет незваротна?
|
||||||
|
|
||||||
# Настройки
|
# Настройки
|
||||||
|
settings.Ambient=Фон
|
||||||
|
settings.Backlight=Падсветка
|
||||||
|
settings.Camera Shaking=Труска Камеры
|
||||||
|
settings.Fog Curve=Крывая Туману
|
||||||
|
settings.FOV=Поле Зроку
|
||||||
|
settings.Fullscreen=Поўны экран
|
||||||
|
settings.Gamma=Гама
|
||||||
|
settings.Language=Мова
|
||||||
settings.Load Distance=Дыстанцыя Загрузкі
|
settings.Load Distance=Дыстанцыя Загрузкі
|
||||||
settings.Load Speed=Хуткасць Загрузкі
|
settings.Load Speed=Хуткасць Загрузкі
|
||||||
settings.Fog Curve=Крывая Туману
|
|
||||||
settings.Backlight=Падсветка
|
|
||||||
settings.V-Sync=Вертыкальная Сінхранізацыя
|
|
||||||
settings.Camera Shaking=Труска Камеры
|
|
||||||
settings.Master Volume=Агульная Гучнасць
|
settings.Master Volume=Агульная Гучнасць
|
||||||
|
settings.Mouse Sensitivity=Адчувальнасць Мышы
|
||||||
|
settings.Music=Музыка
|
||||||
settings.Regular Sounds=Звычайныя Гукі
|
settings.Regular Sounds=Звычайныя Гукі
|
||||||
settings.UI Sounds=Гукі Інтэрфейсу
|
settings.UI Sounds=Гукі Інтэрфейсу
|
||||||
settings.Ambient=Фон
|
settings.V-Sync=Вертыкальная Сінхранізацыя
|
||||||
settings.Music=Музыка
|
|
||||||
|
|
||||||
settings.FOV=Поле Зроку
|
|
||||||
settings.Mouse Sensitivity=Адчувальнасць Мышы
|
|
||||||
settings.Language=Мова
|
|
||||||
|
|
||||||
# Управление
|
# Управление
|
||||||
|
devtools.console=Кансоль
|
||||||
movement.forward=Уперад
|
movement.forward=Уперад
|
||||||
movement.back=Назад
|
movement.back=Назад
|
||||||
movement.left=Улева
|
movement.left=Улева
|
||||||
|
|||||||
@ -8,7 +8,12 @@ world.delete-confirm=Do you want to delete world forever?
|
|||||||
world.generators.default=Default
|
world.generators.default=Default
|
||||||
world.generators.flat=Flat
|
world.generators.flat=Flat
|
||||||
|
|
||||||
|
# Tooltips
|
||||||
|
graphics.gamma.tooltip=Lighting brightness curve
|
||||||
|
graphics.backlight.tooltip=Backlight to prevent total darkness
|
||||||
|
|
||||||
# Bindings
|
# Bindings
|
||||||
|
chunks.reload=Reload Chunks
|
||||||
devtools.console=Console
|
devtools.console=Console
|
||||||
movement.forward=Forward
|
movement.forward=Forward
|
||||||
movement.back=Back
|
movement.back=Back
|
||||||
|
|||||||
@ -12,6 +12,10 @@ error.pack-not-found=Не удалось найти пакет
|
|||||||
error.dependency-not-found=Используемая зависимость не найдена
|
error.dependency-not-found=Используемая зависимость не найдена
|
||||||
pack.remove-confirm=Удалить весь поставляемый паком/паками контент из мира (безвозвратно)?
|
pack.remove-confirm=Удалить весь поставляемый паком/паками контент из мира (безвозвратно)?
|
||||||
|
|
||||||
|
# Подсказки
|
||||||
|
graphics.gamma.tooltip=Кривая яркости освещения
|
||||||
|
graphics.backlight.tooltip=Подсветка, предотвращающая полную темноту
|
||||||
|
|
||||||
# Меню
|
# Меню
|
||||||
menu.Apply=Применить
|
menu.Apply=Применить
|
||||||
menu.Audio=Звук
|
menu.Audio=Звук
|
||||||
@ -56,6 +60,7 @@ settings.UI Sounds=Звуки Интерфейса
|
|||||||
settings.V-Sync=Вертикальная Синхронизация
|
settings.V-Sync=Вертикальная Синхронизация
|
||||||
|
|
||||||
# Управление
|
# Управление
|
||||||
|
chunks.reload=Перезагрузить Чанки
|
||||||
devtools.console=Консоль
|
devtools.console=Консоль
|
||||||
movement.forward=Вперёд
|
movement.forward=Вперёд
|
||||||
movement.back=Назад
|
movement.back=Назад
|
||||||
|
|||||||
@ -18,8 +18,8 @@ Texture* Assets::getTexture(std::string name) const {
|
|||||||
return found->second.get();
|
return found->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assets::store(Texture* texture, std::string name){
|
void Assets::store(std::unique_ptr<Texture> texture, std::string name){
|
||||||
textures.emplace(name, texture);
|
textures.emplace(name, std::move(texture));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -30,8 +30,8 @@ Shader* Assets::getShader(std::string name) const{
|
|||||||
return found->second.get();
|
return found->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assets::store(Shader* shader, std::string name){
|
void Assets::store(std::unique_ptr<Shader> shader, std::string name){
|
||||||
shaders.emplace(name, shader);
|
shaders.emplace(name, std::move(shader));
|
||||||
}
|
}
|
||||||
|
|
||||||
Font* Assets::getFont(std::string name) const {
|
Font* Assets::getFont(std::string name) const {
|
||||||
@ -41,8 +41,8 @@ Font* Assets::getFont(std::string name) const {
|
|||||||
return found->second.get();
|
return found->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assets::store(Font* font, std::string name){
|
void Assets::store(std::unique_ptr<Font> font, std::string name){
|
||||||
fonts.emplace(name, font);
|
fonts.emplace(name, std::move(font));
|
||||||
}
|
}
|
||||||
|
|
||||||
Atlas* Assets::getAtlas(std::string name) const {
|
Atlas* Assets::getAtlas(std::string name) const {
|
||||||
@ -52,8 +52,8 @@ Atlas* Assets::getAtlas(std::string name) const {
|
|||||||
return found->second.get();
|
return found->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assets::store(Atlas* atlas, std::string name){
|
void Assets::store(std::unique_ptr<Atlas> atlas, std::string name){
|
||||||
atlases.emplace(name, atlas);
|
atlases.emplace(name, std::move(atlas));
|
||||||
}
|
}
|
||||||
|
|
||||||
audio::Sound* Assets::getSound(std::string name) const {
|
audio::Sound* Assets::getSound(std::string name) const {
|
||||||
@ -63,8 +63,8 @@ audio::Sound* Assets::getSound(std::string name) const {
|
|||||||
return found->second.get();
|
return found->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assets::store(audio::Sound* sound, std::string name) {
|
void Assets::store(std::unique_ptr<audio::Sound> sound, std::string name) {
|
||||||
sounds.emplace(name, sound);
|
sounds.emplace(name, std::move(sound));
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<TextureAnimation>& Assets::getAnimations() {
|
const std::vector<TextureAnimation>& Assets::getAnimations() {
|
||||||
@ -82,6 +82,6 @@ UiDocument* Assets::getLayout(std::string name) const {
|
|||||||
return found->second.get();
|
return found->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assets::store(UiDocument* layout, std::string name) {
|
void Assets::store(std::unique_ptr<UiDocument> layout, std::string name) {
|
||||||
layouts[name] = std::shared_ptr<UiDocument>(layout);
|
layouts[name] = std::shared_ptr<UiDocument>(std::move(layout));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,25 +39,25 @@ public:
|
|||||||
~Assets();
|
~Assets();
|
||||||
|
|
||||||
Texture* getTexture(std::string name) const;
|
Texture* getTexture(std::string name) const;
|
||||||
void store(Texture* texture, std::string name);
|
void store(std::unique_ptr<Texture> texture, std::string name);
|
||||||
|
|
||||||
Shader* getShader(std::string name) const;
|
Shader* getShader(std::string name) const;
|
||||||
void store(Shader* shader, std::string name);
|
void store(std::unique_ptr<Shader> shader, std::string name);
|
||||||
|
|
||||||
Font* getFont(std::string name) const;
|
Font* getFont(std::string name) const;
|
||||||
void store(Font* font, std::string name);
|
void store(std::unique_ptr<Font> font, std::string name);
|
||||||
|
|
||||||
Atlas* getAtlas(std::string name) const;
|
Atlas* getAtlas(std::string name) const;
|
||||||
void store(Atlas* atlas, std::string name);
|
void store(std::unique_ptr<Atlas> atlas, std::string name);
|
||||||
|
|
||||||
audio::Sound* getSound(std::string name) const;
|
audio::Sound* getSound(std::string name) const;
|
||||||
void store(audio::Sound* sound, std::string name);
|
void store(std::unique_ptr<audio::Sound> sound, std::string name);
|
||||||
|
|
||||||
const std::vector<TextureAnimation>& getAnimations();
|
const std::vector<TextureAnimation>& getAnimations();
|
||||||
void store(const TextureAnimation& animation);
|
void store(const TextureAnimation& animation);
|
||||||
|
|
||||||
UiDocument* getLayout(std::string name) const;
|
UiDocument* getLayout(std::string name) const;
|
||||||
void store(UiDocument* layout, std::string name);
|
void store(std::unique_ptr<UiDocument> layout, std::string name);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ASSETS_ASSETS_HPP_
|
#endif // ASSETS_ASSETS_HPP_
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "../files/engine_paths.hpp"
|
#include "../files/engine_paths.hpp"
|
||||||
#include "../content/Content.hpp"
|
#include "../content/Content.hpp"
|
||||||
#include "../content/ContentPack.hpp"
|
#include "../content/ContentPack.hpp"
|
||||||
|
#include "../voxels/Block.hpp"
|
||||||
#include "../graphics/core/Texture.hpp"
|
#include "../graphics/core/Texture.hpp"
|
||||||
#include "../logic/scripting/scripting.hpp"
|
#include "../logic/scripting/scripting.hpp"
|
||||||
|
|
||||||
@ -187,7 +188,7 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
|
|||||||
loader.processPreloadConfigs(content);
|
loader.processPreloadConfigs(content);
|
||||||
|
|
||||||
for (auto& entry : content->getBlockMaterials()) {
|
for (auto& entry : content->getBlockMaterials()) {
|
||||||
auto& material = entry.second;
|
auto& material = *entry.second;
|
||||||
loader.tryAddSound(material.stepsSound);
|
loader.tryAddSound(material.stepsSound);
|
||||||
loader.tryAddSound(material.placeSound);
|
loader.tryAddSound(material.placeSound);
|
||||||
loader.tryAddSound(material.breakSound);
|
loader.tryAddSound(material.breakSound);
|
||||||
@ -217,7 +218,7 @@ bool AssetsLoader::loadExternalTexture(
|
|||||||
if (fs::exists(path)) {
|
if (fs::exists(path)) {
|
||||||
try {
|
try {
|
||||||
auto image = imageio::read(path.string());
|
auto image = imageio::read(path.string());
|
||||||
assets->store(Texture::from(image.get()).release(), name);
|
assets->store(Texture::from(image.get()), name);
|
||||||
return true;
|
return true;
|
||||||
} catch (const std::exception& err) {
|
} catch (const std::exception& err) {
|
||||||
logger.error() << "error while loading external "
|
logger.error() << "error while loading external "
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "../audio/audio.hpp"
|
#include "../audio/audio.hpp"
|
||||||
#include "../files/files.hpp"
|
#include "../files/files.hpp"
|
||||||
#include "../files/engine_paths.hpp"
|
#include "../files/engine_paths.hpp"
|
||||||
|
#include "../coders/commons.hpp"
|
||||||
#include "../coders/imageio.hpp"
|
#include "../coders/imageio.hpp"
|
||||||
#include "../coders/json.hpp"
|
#include "../coders/json.hpp"
|
||||||
#include "../coders/GLSLExtension.hpp"
|
#include "../coders/GLSLExtension.hpp"
|
||||||
@ -43,7 +44,7 @@ assetload::postfunc assetload::texture(
|
|||||||
imageio::read(paths->find(filename+".png").u8string()).release()
|
imageio::read(paths->find(filename+".png").u8string()).release()
|
||||||
);
|
);
|
||||||
return [name, image](auto assets) {
|
return [name, image](auto assets) {
|
||||||
assets->store(Texture::from(image.get()).release(), name);
|
assets->store(Texture::from(image.get()), name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +103,7 @@ assetload::postfunc assetload::atlas(
|
|||||||
Atlas* atlas = builder.build(2, false).release();
|
Atlas* atlas = builder.build(2, false).release();
|
||||||
return [=](auto assets) {
|
return [=](auto assets) {
|
||||||
atlas->prepare();
|
atlas->prepare();
|
||||||
assets->store(atlas, name);
|
assets->store(std::unique_ptr<Atlas>(atlas), name);
|
||||||
for (const auto& file : names) {
|
for (const auto& file : names) {
|
||||||
animation(assets, paths, name, directory, file, atlas);
|
animation(assets, paths, name, directory, file, atlas);
|
||||||
}
|
}
|
||||||
@ -128,7 +129,7 @@ assetload::postfunc assetload::font(
|
|||||||
for (auto& page : *pages) {
|
for (auto& page : *pages) {
|
||||||
textures.emplace_back(Texture::from(page.get()));
|
textures.emplace_back(Texture::from(page.get()));
|
||||||
}
|
}
|
||||||
assets->store(new Font(std::move(textures), res, 4), name);
|
assets->store(std::make_unique<Font>(std::move(textures), res, 4), name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,8 +143,7 @@ assetload::postfunc assetload::layout(
|
|||||||
return [=](auto assets) {
|
return [=](auto assets) {
|
||||||
try {
|
try {
|
||||||
auto cfg = std::dynamic_pointer_cast<LayoutCfg>(config);
|
auto cfg = std::dynamic_pointer_cast<LayoutCfg>(config);
|
||||||
auto document = UiDocument::read(cfg->env, name, file);
|
assets->store(UiDocument::read(cfg->env, name, file), name);
|
||||||
assets->store(document.release(), name);
|
|
||||||
} catch (const parsing_error& err) {
|
} catch (const parsing_error& err) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"failed to parse layout XML '"+file+"':\n"+err.errorLog()
|
"failed to parse layout XML '"+file+"':\n"+err.errorLog()
|
||||||
@ -189,7 +189,7 @@ assetload::postfunc assetload::sound(
|
|||||||
}
|
}
|
||||||
auto sound = baseSound.release();
|
auto sound = baseSound.release();
|
||||||
return [=](auto assets) {
|
return [=](auto assets) {
|
||||||
assets->store(sound, name);
|
assets->store(std::unique_ptr<audio::Sound>(sound), name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +304,7 @@ static bool animation(
|
|||||||
auto animation = create_animation(
|
auto animation = create_animation(
|
||||||
srcAtlas.get(), dstAtlas, name, builder.getNames(), frameList
|
srcAtlas.get(), dstAtlas, name, builder.getNames(), frameList
|
||||||
);
|
);
|
||||||
assets->store(srcAtlas.release(), atlasName + "/" + name + "_animation");
|
assets->store(std::move(srcAtlas), atlasName + "/" + name + "_animation");
|
||||||
assets->store(animation);
|
assets->store(animation);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -389,7 +389,7 @@ std::unique_ptr<Stream> ALAudio::openStream(std::shared_ptr<PCMStream> stream, b
|
|||||||
return std::make_unique<ALStream>(this, stream, keepSource);
|
return std::make_unique<ALStream>(this, stream, keepSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALAudio* ALAudio::create() {
|
std::unique_ptr<ALAudio> ALAudio::create() {
|
||||||
ALCdevice* device = alcOpenDevice(nullptr);
|
ALCdevice* device = alcOpenDevice(nullptr);
|
||||||
if (device == nullptr)
|
if (device == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -400,7 +400,7 @@ ALAudio* ALAudio::create() {
|
|||||||
}
|
}
|
||||||
AL_CHECK();
|
AL_CHECK();
|
||||||
logger.info() << "initialized";
|
logger.info() << "initialized";
|
||||||
return new ALAudio(device, context);
|
return std::make_unique<ALAudio>(device, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint ALAudio::getFreeSource(){
|
uint ALAudio::getFreeSource(){
|
||||||
|
|||||||
@ -136,9 +136,8 @@ namespace audio {
|
|||||||
std::vector<uint> freebuffers;
|
std::vector<uint> freebuffers;
|
||||||
|
|
||||||
uint maxSources = 256;
|
uint maxSources = 256;
|
||||||
|
|
||||||
ALAudio(ALCdevice* device, ALCcontext* context);
|
|
||||||
public:
|
public:
|
||||||
|
ALAudio(ALCdevice* device, ALCcontext* context);
|
||||||
~ALAudio();
|
~ALAudio();
|
||||||
|
|
||||||
uint getFreeSource();
|
uint getFreeSource();
|
||||||
@ -164,7 +163,7 @@ namespace audio {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ALAudio* create();
|
static std::unique_ptr<ALAudio> create();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,6 @@ std::unique_ptr<Stream> NoAudio::openStream(std::shared_ptr<PCMStream> stream, b
|
|||||||
return std::make_unique<NoStream>(stream, keepSource);
|
return std::make_unique<NoStream>(stream, keepSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
NoAudio* NoAudio::create() {
|
std::unique_ptr<NoAudio> NoAudio::create() {
|
||||||
return new NoAudio();
|
return std::make_unique<NoAudio>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,7 +81,7 @@ namespace audio {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NoAudio* create();
|
static std::unique_ptr<NoAudio> create();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -147,11 +147,11 @@ public:
|
|||||||
|
|
||||||
void audio::initialize(bool enabled) {
|
void audio::initialize(bool enabled) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
backend = ALAudio::create();
|
backend = ALAudio::create().release();
|
||||||
}
|
}
|
||||||
if (backend == nullptr) {
|
if (backend == nullptr) {
|
||||||
std::cerr << "could not to initialize audio" << std::endl;
|
std::cerr << "could not to initialize audio" << std::endl;
|
||||||
backend = NoAudio::create();
|
backend = NoAudio::create().release();
|
||||||
}
|
}
|
||||||
create_channel("master");
|
create_channel("master");
|
||||||
}
|
}
|
||||||
@ -333,7 +333,7 @@ int audio::create_channel(const std::string& name) {
|
|||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
channels.emplace_back(new Channel(name));
|
channels.emplace_back(std::make_unique<Channel>(name));
|
||||||
return channels.size()-1;
|
return channels.size()-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,20 +11,20 @@ namespace dynamic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace json {
|
namespace json {
|
||||||
const int BJSON_END = 0x0;
|
inline constexpr int BJSON_END = 0x0;
|
||||||
const int BJSON_TYPE_DOCUMENT = 0x1;
|
inline constexpr int BJSON_TYPE_DOCUMENT = 0x1;
|
||||||
const int BJSON_TYPE_LIST = 0x2;
|
inline constexpr int BJSON_TYPE_LIST = 0x2;
|
||||||
const int BJSON_TYPE_BYTE = 0x3;
|
inline constexpr int BJSON_TYPE_BYTE = 0x3;
|
||||||
const int BJSON_TYPE_INT16 = 0x4;
|
inline constexpr int BJSON_TYPE_INT16 = 0x4;
|
||||||
const int BJSON_TYPE_INT32 = 0x5;
|
inline constexpr int BJSON_TYPE_INT32 = 0x5;
|
||||||
const int BJSON_TYPE_INT64 = 0x6;
|
inline constexpr int BJSON_TYPE_INT64 = 0x6;
|
||||||
const int BJSON_TYPE_NUMBER = 0x7;
|
inline constexpr int BJSON_TYPE_NUMBER = 0x7;
|
||||||
const int BJSON_TYPE_STRING = 0x8;
|
inline constexpr int BJSON_TYPE_STRING = 0x8;
|
||||||
const int BJSON_TYPE_BYTES = 0x9;
|
inline constexpr int BJSON_TYPE_BYTES = 0x9;
|
||||||
const int BJSON_TYPE_FALSE = 0xA;
|
inline constexpr int BJSON_TYPE_FALSE = 0xA;
|
||||||
const int BJSON_TYPE_TRUE = 0xB;
|
inline constexpr int BJSON_TYPE_TRUE = 0xB;
|
||||||
const int BJSON_TYPE_NULL = 0xC;
|
inline constexpr int BJSON_TYPE_NULL = 0xC;
|
||||||
const int BJSON_TYPE_CDOCUMENT = 0x1F;
|
inline constexpr int BJSON_TYPE_CDOCUMENT = 0x1F;
|
||||||
|
|
||||||
extern std::vector<ubyte> to_binary(const dynamic::Map* obj, bool compress=false);
|
extern std::vector<ubyte> to_binary(const dynamic::Map* obj, bool compress=false);
|
||||||
extern std::shared_ptr<dynamic::Map> from_binary(const ubyte* src, size_t size);
|
extern std::shared_ptr<dynamic::Map> from_binary(const ubyte* src, size_t size);
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
#include "../data/dynamic.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
#include "../util/stringutil.hpp"
|
#include "../util/stringutil.hpp"
|
||||||
|
|
||||||
@ -240,11 +242,11 @@ Value Parser::parseValue() {
|
|||||||
throw error("unexpected character '"+std::string({next})+"'");
|
throw error("unexpected character '"+std::string({next})+"'");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Map> json::parse(const std::string& filename, const std::string& source) {
|
dynamic::Map_sptr json::parse(const std::string& filename, const std::string& source) {
|
||||||
Parser parser(filename, source);
|
Parser parser(filename, source);
|
||||||
return parser.parse();
|
return parser.parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Map> json::parse(const std::string& source) {
|
dynamic::Map_sptr json::parse(const std::string& source) {
|
||||||
return parse("<string>", source);
|
return parse("<string>", source);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,16 @@
|
|||||||
#ifndef CODERS_JSON_HPP_
|
#ifndef CODERS_JSON_HPP_
|
||||||
#define CODERS_JSON_HPP_
|
#define CODERS_JSON_HPP_
|
||||||
|
|
||||||
#include "commons.hpp"
|
|
||||||
#include "binary_json.hpp"
|
#include "binary_json.hpp"
|
||||||
|
|
||||||
#include "../data/dynamic.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
#include "../typedefs.hpp"
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace json {
|
namespace json {
|
||||||
std::unique_ptr<dynamic::Map> parse(const std::string& filename, const std::string& source);
|
dynamic::Map_sptr parse(const std::string& filename, const std::string& source);
|
||||||
std::unique_ptr<dynamic::Map> parse(const std::string& source);
|
dynamic::Map_sptr parse(const std::string& source);
|
||||||
|
|
||||||
std::string stringify(
|
std::string stringify(
|
||||||
const dynamic::Map* obj,
|
const dynamic::Map* obj,
|
||||||
|
|||||||
@ -7,15 +7,14 @@
|
|||||||
#include "../files/settings_io.hpp"
|
#include "../files/settings_io.hpp"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
using namespace toml;
|
using namespace toml;
|
||||||
|
|
||||||
class Reader : BasicParser {
|
class TomlReader : BasicParser {
|
||||||
SettingsHandler& handler;
|
dynamic::Map_sptr root;
|
||||||
|
|
||||||
void skipWhitespace() override {
|
void skipWhitespace() override {
|
||||||
BasicParser::skipWhitespace();
|
BasicParser::skipWhitespace();
|
||||||
@ -26,7 +25,34 @@ class Reader : BasicParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void readSection(const std::string& section) {
|
|
||||||
|
dynamic::Map& getSection(const std::string& section) {
|
||||||
|
if (section.empty()) {
|
||||||
|
return *root;
|
||||||
|
}
|
||||||
|
size_t offset = 0;
|
||||||
|
auto& rootMap = *root;
|
||||||
|
do {
|
||||||
|
size_t index = section.find('.', offset);
|
||||||
|
if (index == std::string::npos) {
|
||||||
|
auto map = rootMap.map(section);
|
||||||
|
if (map == nullptr) {
|
||||||
|
return rootMap.putMap(section);
|
||||||
|
}
|
||||||
|
return *map;
|
||||||
|
}
|
||||||
|
auto subsection = section.substr(offset, index);
|
||||||
|
auto map = rootMap.map(subsection);
|
||||||
|
if (map == nullptr) {
|
||||||
|
rootMap = rootMap.putMap(subsection);
|
||||||
|
} else {
|
||||||
|
rootMap = *map;
|
||||||
|
}
|
||||||
|
offset = index+1;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readSection(const std::string& section, dynamic::Map& map) {
|
||||||
while (hasNext()) {
|
while (hasNext()) {
|
||||||
skipWhitespace();
|
skipWhitespace();
|
||||||
if (!hasNext()) {
|
if (!hasNext()) {
|
||||||
@ -36,43 +62,31 @@ class Reader : BasicParser {
|
|||||||
if (c == '[') {
|
if (c == '[') {
|
||||||
std::string name = parseName();
|
std::string name = parseName();
|
||||||
pos++;
|
pos++;
|
||||||
readSection(name);
|
readSection(name, getSection(name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pos--;
|
pos--;
|
||||||
std::string name = section+"."+parseName();
|
std::string name = parseName();
|
||||||
expect('=');
|
expect('=');
|
||||||
c = peek();
|
c = peek();
|
||||||
if (is_digit(c)) {
|
if (is_digit(c)) {
|
||||||
auto num = parseNumber(1);
|
map.put(name, parseNumber(1));
|
||||||
if (handler.has(name)) {
|
|
||||||
handler.setValue(name, num);
|
|
||||||
}
|
|
||||||
} else if (c == '-' || c == '+') {
|
} else if (c == '-' || c == '+') {
|
||||||
int sign = c == '-' ? -1 : 1;
|
int sign = c == '-' ? -1 : 1;
|
||||||
pos++;
|
pos++;
|
||||||
auto num = parseNumber(sign);
|
map.put(name, parseNumber(sign));
|
||||||
if (handler.has(name)) {
|
|
||||||
handler.setValue(name, num);
|
|
||||||
}
|
|
||||||
} else if (is_identifier_start(c)) {
|
} else if (is_identifier_start(c)) {
|
||||||
std::string identifier = parseName();
|
std::string identifier = parseName();
|
||||||
if (handler.has(name)) {
|
|
||||||
if (identifier == "true" || identifier == "false") {
|
if (identifier == "true" || identifier == "false") {
|
||||||
bool flag = identifier == "true";
|
map.put(name, identifier == "true");
|
||||||
handler.setValue(name, flag);
|
|
||||||
} else if (identifier == "inf") {
|
} else if (identifier == "inf") {
|
||||||
handler.setValue(name, INFINITY);
|
map.put(name, INFINITY);
|
||||||
} else if (identifier == "nan") {
|
} else if (identifier == "nan") {
|
||||||
handler.setValue(name, NAN);
|
map.put(name, NAN);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (c == '"' || c == '\'') {
|
} else if (c == '"' || c == '\'') {
|
||||||
pos++;
|
pos++;
|
||||||
std::string str = parseString(c);
|
map.put(name, parseString(c));
|
||||||
if (handler.has(name)) {
|
|
||||||
handler.setValue(name, str);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw error("feature is not supported");
|
throw error("feature is not supported");
|
||||||
}
|
}
|
||||||
@ -81,29 +95,67 @@ class Reader : BasicParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Reader(
|
TomlReader(
|
||||||
SettingsHandler& handler,
|
|
||||||
std::string_view file,
|
std::string_view file,
|
||||||
std::string_view source)
|
std::string_view source)
|
||||||
: BasicParser(file, source), handler(handler) {
|
: BasicParser(file, source) {
|
||||||
|
root = dynamic::create_map();
|
||||||
}
|
}
|
||||||
|
|
||||||
void read() {
|
dynamic::Map_sptr read() {
|
||||||
skipWhitespace();
|
skipWhitespace();
|
||||||
if (!hasNext()) {
|
if (!hasNext()) {
|
||||||
return;
|
return root;
|
||||||
}
|
}
|
||||||
readSection("");
|
readSection("", *root);
|
||||||
|
return root;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dynamic::Map_sptr toml::parse(std::string_view file, std::string_view source) {
|
||||||
|
return TomlReader(file, source).read();
|
||||||
|
}
|
||||||
|
|
||||||
void toml::parse(
|
void toml::parse(
|
||||||
SettingsHandler& handler,
|
SettingsHandler& handler, std::string_view file, std::string_view source
|
||||||
const std::string& file,
|
|
||||||
const std::string& source
|
|
||||||
) {
|
) {
|
||||||
Reader reader(handler, file, source);
|
auto map = parse(file, source);
|
||||||
reader.read();
|
for (auto& entry : map->values) {
|
||||||
|
const auto& sectionName = entry.first;
|
||||||
|
auto sectionMap = std::get_if<dynamic::Map_sptr>(&entry.second);
|
||||||
|
if (sectionMap == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (auto& sectionEntry : (*sectionMap)->values) {
|
||||||
|
const auto& name = sectionEntry.first;
|
||||||
|
auto& value = sectionEntry.second;
|
||||||
|
auto fullname = sectionName+"."+name;
|
||||||
|
if (handler.has(fullname)) {
|
||||||
|
handler.setValue(fullname, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string toml::stringify(dynamic::Map& root, const std::string& name) {
|
||||||
|
std::stringstream ss;
|
||||||
|
if (!name.empty()) {
|
||||||
|
ss << "[" << name << "]\n";
|
||||||
|
}
|
||||||
|
for (auto& entry : root.values) {
|
||||||
|
if (!std::holds_alternative<dynamic::Map_sptr>(entry.second)) {
|
||||||
|
ss << entry.first << " = ";
|
||||||
|
ss << entry.second << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& entry : root.values) {
|
||||||
|
if (auto submap = std::get_if<dynamic::Map_sptr>(&entry.second)) {
|
||||||
|
ss << "\n" << toml::stringify(
|
||||||
|
**submap, name.empty() ? entry.first : name+"."+entry.first
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toml::stringify(SettingsHandler& handler) {
|
std::string toml::stringify(SettingsHandler& handler) {
|
||||||
|
|||||||
@ -1,19 +1,20 @@
|
|||||||
#ifndef CODERS_TOML_HPP_
|
#ifndef CODERS_TOML_HPP_
|
||||||
#define CODERS_TOML_HPP_
|
#define CODERS_TOML_HPP_
|
||||||
|
|
||||||
#include "commons.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class SettingsHandler;
|
class SettingsHandler;
|
||||||
|
|
||||||
namespace toml {
|
namespace toml {
|
||||||
std::string stringify(SettingsHandler& handler);
|
std::string stringify(SettingsHandler& handler);
|
||||||
|
std::string stringify(dynamic::Map& root, const std::string& name="");
|
||||||
|
dynamic::Map_sptr parse(std::string_view file, std::string_view source);
|
||||||
|
|
||||||
void parse(
|
void parse(
|
||||||
SettingsHandler& handler,
|
SettingsHandler& handler,
|
||||||
const std::string& file,
|
std::string_view file,
|
||||||
const std::string& source
|
std::string_view source
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,127 +10,6 @@
|
|||||||
#include "ContentPack.hpp"
|
#include "ContentPack.hpp"
|
||||||
#include "../logic/scripting/scripting.hpp"
|
#include "../logic/scripting/scripting.hpp"
|
||||||
|
|
||||||
ContentBuilder::~ContentBuilder() {}
|
|
||||||
|
|
||||||
void ContentBuilder::add(Block* def) {
|
|
||||||
checkIdentifier(def->name);
|
|
||||||
blockDefs[def->name] = def;
|
|
||||||
blockIds.push_back(def->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContentBuilder::add(ItemDef* def) {
|
|
||||||
checkIdentifier(def->name);
|
|
||||||
itemDefs[def->name] = def;
|
|
||||||
itemIds.push_back(def->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContentBuilder::add(ContentPackRuntime* pack) {
|
|
||||||
packs.emplace(pack->getId(), pack);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContentBuilder::add(BlockMaterial material) {
|
|
||||||
blockMaterials.emplace(material.name, material);
|
|
||||||
}
|
|
||||||
|
|
||||||
Block& ContentBuilder::createBlock(std::string id) {
|
|
||||||
auto found = blockDefs.find(id);
|
|
||||||
if (found != blockDefs.end()) {
|
|
||||||
return *found->second;
|
|
||||||
// throw namereuse_error("name "+id+" is already used", contenttype::item);
|
|
||||||
}
|
|
||||||
Block* block = new Block(id);
|
|
||||||
add(block);
|
|
||||||
return *block;
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemDef& ContentBuilder::createItem(std::string id) {
|
|
||||||
auto found = itemDefs.find(id);
|
|
||||||
if (found != itemDefs.end()) {
|
|
||||||
// if (found->second->generated) {
|
|
||||||
return *found->second;
|
|
||||||
// }
|
|
||||||
// throw namereuse_error("name "+id+" is already used", contenttype::item);
|
|
||||||
}
|
|
||||||
ItemDef* item = new ItemDef(id);
|
|
||||||
add(item);
|
|
||||||
return *item;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContentBuilder::checkIdentifier(std::string id) {
|
|
||||||
contenttype result;
|
|
||||||
if (((result = checkContentType(id)) != contenttype::none)) {
|
|
||||||
throw namereuse_error("name "+id+" is already used", result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contenttype ContentBuilder::checkContentType(std::string id) {
|
|
||||||
if (blockDefs.find(id) != blockDefs.end()) {
|
|
||||||
return contenttype::block;
|
|
||||||
}
|
|
||||||
if (itemDefs.find(id) != itemDefs.end()) {
|
|
||||||
return contenttype::item;
|
|
||||||
}
|
|
||||||
return contenttype::none;
|
|
||||||
}
|
|
||||||
|
|
||||||
Content* ContentBuilder::build() {
|
|
||||||
std::vector<Block*> blockDefsIndices;
|
|
||||||
auto groups = std::make_unique<DrawGroups>();
|
|
||||||
for (const std::string& name : blockIds) {
|
|
||||||
Block* def = blockDefs[name];
|
|
||||||
|
|
||||||
// Generating runtime info
|
|
||||||
def->rt.id = blockDefsIndices.size();
|
|
||||||
def->rt.emissive = *reinterpret_cast<uint32_t*>(def->emission);
|
|
||||||
def->rt.solid = def->model == BlockModel::block;
|
|
||||||
|
|
||||||
if (def->rotatable) {
|
|
||||||
for (uint i = 0; i < BlockRotProfile::MAX_COUNT; i++) {
|
|
||||||
def->rt.hitboxes[i].reserve(def->hitboxes.size());
|
|
||||||
for (AABB aabb : def->hitboxes) {
|
|
||||||
def->rotations.variants[i].transform(aabb);
|
|
||||||
def->rt.hitboxes[i].push_back(aabb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blockDefsIndices.push_back(def);
|
|
||||||
groups->insert(def->drawGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ItemDef*> itemDefsIndices;
|
|
||||||
for (const std::string& name : itemIds) {
|
|
||||||
ItemDef* def = itemDefs[name];
|
|
||||||
|
|
||||||
// Generating runtime info
|
|
||||||
def->rt.id = itemDefsIndices.size();
|
|
||||||
def->rt.emissive = *reinterpret_cast<uint32_t*>(def->emission);
|
|
||||||
itemDefsIndices.push_back(def);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto indices = new ContentIndices(blockDefsIndices, itemDefsIndices);
|
|
||||||
|
|
||||||
auto content = std::make_unique<Content>(
|
|
||||||
indices,
|
|
||||||
std::move(groups),
|
|
||||||
blockDefs,
|
|
||||||
itemDefs,
|
|
||||||
std::move(packs),
|
|
||||||
std::move(blockMaterials)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Now, it's time to resolve foreign keys
|
|
||||||
for (Block* def : blockDefsIndices) {
|
|
||||||
def->rt.pickingItem = content->requireItem(def->pickingItem).rt.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ItemDef* def : itemDefsIndices) {
|
|
||||||
def->rt.placingBlock = content->requireBlock(def->placingBlock).rt.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return content.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentIndices::ContentIndices(
|
ContentIndices::ContentIndices(
|
||||||
std::vector<Block*> blockDefs,
|
std::vector<Block*> blockDefs,
|
||||||
std::vector<ItemDef*> itemDefs
|
std::vector<ItemDef*> itemDefs
|
||||||
@ -139,27 +18,21 @@ ContentIndices::ContentIndices(
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
Content::Content(
|
Content::Content(
|
||||||
ContentIndices* indices,
|
std::unique_ptr<ContentIndices> indices,
|
||||||
std::unique_ptr<DrawGroups> drawGroups,
|
std::unique_ptr<DrawGroups> drawGroups,
|
||||||
std::unordered_map<std::string, Block*> blockDefs,
|
std::unordered_map<std::string, std::unique_ptr<Block>> blockDefs,
|
||||||
std::unordered_map<std::string, ItemDef*> itemDefs,
|
std::unordered_map<std::string, std::unique_ptr<ItemDef>> itemDefs,
|
||||||
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs,
|
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs,
|
||||||
std::unordered_map<std::string, BlockMaterial> blockMaterials
|
std::unordered_map<std::string, std::unique_ptr<BlockMaterial>> blockMaterials
|
||||||
) : blockDefs(blockDefs),
|
) : blockDefs(std::move(blockDefs)),
|
||||||
itemDefs(itemDefs),
|
itemDefs(std::move(itemDefs)),
|
||||||
indices(indices),
|
indices(std::move(indices)),
|
||||||
packs(std::move(packs)),
|
packs(std::move(packs)),
|
||||||
blockMaterials(std::move(blockMaterials)),
|
blockMaterials(std::move(blockMaterials)),
|
||||||
drawGroups(std::move(drawGroups))
|
drawGroups(std::move(drawGroups))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Content::~Content() {
|
Content::~Content() {
|
||||||
for (auto& entry : blockDefs) {
|
|
||||||
delete entry.second;
|
|
||||||
}
|
|
||||||
for (auto& entry : itemDefs) {
|
|
||||||
delete entry.second;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Block* Content::findBlock(std::string id) const {
|
Block* Content::findBlock(std::string id) const {
|
||||||
@ -167,7 +40,7 @@ Block* Content::findBlock(std::string id) const {
|
|||||||
if (found == blockDefs.end()) {
|
if (found == blockDefs.end()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return found->second;
|
return found->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Block& Content::requireBlock(std::string id) const {
|
Block& Content::requireBlock(std::string id) const {
|
||||||
@ -183,7 +56,7 @@ ItemDef* Content::findItem(std::string id) const {
|
|||||||
if (found == itemDefs.end()) {
|
if (found == itemDefs.end()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return found->second;
|
return found->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemDef& Content::requireItem(std::string id) const {
|
ItemDef& Content::requireItem(std::string id) const {
|
||||||
@ -199,7 +72,7 @@ const BlockMaterial* Content::findBlockMaterial(std::string id) const {
|
|||||||
if (found == blockMaterials.end()) {
|
if (found == blockMaterials.end()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &found->second;
|
return found->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ContentPackRuntime* Content::getPackRuntime(std::string id) const {
|
const ContentPackRuntime* Content::getPackRuntime(std::string id) const {
|
||||||
@ -210,7 +83,7 @@ const ContentPackRuntime* Content::getPackRuntime(std::string id) const {
|
|||||||
return found->second.get();
|
return found->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<std::string, BlockMaterial>& Content::getBlockMaterials() const {
|
const std::unordered_map<std::string, std::unique_ptr<BlockMaterial>>& Content::getBlockMaterials() const {
|
||||||
return blockMaterials;
|
return blockMaterials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,19 @@
|
|||||||
#ifndef CONTENT_CONTENT_HPP_
|
#ifndef CONTENT_CONTENT_HPP_
|
||||||
#define CONTENT_CONTENT_HPP_
|
#define CONTENT_CONTENT_HPP_
|
||||||
|
|
||||||
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include "../typedefs.hpp"
|
|
||||||
#include "../voxels/Block.hpp"
|
|
||||||
|
|
||||||
using DrawGroups = std::set<ubyte>;
|
using DrawGroups = std::set<ubyte>;
|
||||||
|
|
||||||
|
class Block;
|
||||||
|
struct BlockMaterial;
|
||||||
class ItemDef;
|
class ItemDef;
|
||||||
class Content;
|
class Content;
|
||||||
class ContentPackRuntime;
|
class ContentPackRuntime;
|
||||||
@ -41,33 +43,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContentBuilder {
|
|
||||||
std::unordered_map<std::string, Block*> blockDefs;
|
|
||||||
std::vector<std::string> blockIds;
|
|
||||||
|
|
||||||
std::unordered_map<std::string, ItemDef*> itemDefs;
|
|
||||||
std::vector<std::string> itemIds;
|
|
||||||
|
|
||||||
std::unordered_map<std::string, BlockMaterial> blockMaterials;
|
|
||||||
|
|
||||||
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs;
|
|
||||||
public:
|
|
||||||
~ContentBuilder();
|
|
||||||
|
|
||||||
void add(Block* def);
|
|
||||||
void add(ItemDef* def);
|
|
||||||
void add(ContentPackRuntime* pack);
|
|
||||||
void add(BlockMaterial material);
|
|
||||||
|
|
||||||
Block& createBlock(std::string id);
|
|
||||||
ItemDef& createItem(std::string id);
|
|
||||||
|
|
||||||
void checkIdentifier(std::string id);
|
|
||||||
contenttype checkContentType(std::string id);
|
|
||||||
|
|
||||||
Content* build();
|
|
||||||
};
|
|
||||||
|
|
||||||
/// @brief Runtime defs cache: indices
|
/// @brief Runtime defs cache: indices
|
||||||
class ContentIndices {
|
class ContentIndices {
|
||||||
std::vector<Block*> blockDefs;
|
std::vector<Block*> blockDefs;
|
||||||
@ -110,21 +85,21 @@ public:
|
|||||||
|
|
||||||
/* Content is a definitions repository */
|
/* Content is a definitions repository */
|
||||||
class Content {
|
class Content {
|
||||||
std::unordered_map<std::string, Block*> blockDefs;
|
std::unordered_map<std::string, std::unique_ptr<Block>> blockDefs;
|
||||||
std::unordered_map<std::string, ItemDef*> itemDefs;
|
std::unordered_map<std::string, std::unique_ptr<ItemDef>> itemDefs;
|
||||||
std::unique_ptr<ContentIndices> indices;
|
std::unique_ptr<ContentIndices> indices;
|
||||||
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs;
|
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs;
|
||||||
std::unordered_map<std::string, BlockMaterial> blockMaterials;
|
std::unordered_map<std::string, std::unique_ptr<BlockMaterial>> blockMaterials;
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<DrawGroups> const drawGroups;
|
std::unique_ptr<DrawGroups> const drawGroups;
|
||||||
|
|
||||||
Content(
|
Content(
|
||||||
ContentIndices* indices,
|
std::unique_ptr<ContentIndices> indices,
|
||||||
std::unique_ptr<DrawGroups> drawGroups,
|
std::unique_ptr<DrawGroups> drawGroups,
|
||||||
std::unordered_map<std::string, Block*> blockDefs,
|
std::unordered_map<std::string, std::unique_ptr<Block>> blockDefs,
|
||||||
std::unordered_map<std::string, ItemDef*> itemDefs,
|
std::unordered_map<std::string, std::unique_ptr<ItemDef>> itemDefs,
|
||||||
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs,
|
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs,
|
||||||
std::unordered_map<std::string, BlockMaterial> blockMaterials
|
std::unordered_map<std::string, std::unique_ptr<BlockMaterial>> blockMaterials
|
||||||
);
|
);
|
||||||
~Content();
|
~Content();
|
||||||
|
|
||||||
@ -142,7 +117,7 @@ public:
|
|||||||
|
|
||||||
const ContentPackRuntime* getPackRuntime(std::string id) const;
|
const ContentPackRuntime* getPackRuntime(std::string id) const;
|
||||||
|
|
||||||
const std::unordered_map<std::string, BlockMaterial>& getBlockMaterials() const;
|
const std::unordered_map<std::string, std::unique_ptr<BlockMaterial>>& getBlockMaterials() const;
|
||||||
const std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>>& getPacks() const;
|
const std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>>& getPacks() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
109
src/content/ContentBuilder.cpp
Normal file
109
src/content/ContentBuilder.cpp
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#include "ContentBuilder.hpp"
|
||||||
|
|
||||||
|
ContentBuilder::~ContentBuilder() {}
|
||||||
|
|
||||||
|
void ContentBuilder::add(std::unique_ptr<ContentPackRuntime> pack) {
|
||||||
|
packs[pack->getId()] = std::move(pack);
|
||||||
|
}
|
||||||
|
|
||||||
|
Block& ContentBuilder::createBlock(std::string id) {
|
||||||
|
auto found = blockDefs.find(id);
|
||||||
|
if (found != blockDefs.end()) {
|
||||||
|
return *found->second;
|
||||||
|
}
|
||||||
|
checkIdentifier(id);
|
||||||
|
blockIds.push_back(id);
|
||||||
|
blockDefs[id] = std::make_unique<Block>(id);
|
||||||
|
return *blockDefs[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemDef& ContentBuilder::createItem(std::string id) {
|
||||||
|
auto found = itemDefs.find(id);
|
||||||
|
if (found != itemDefs.end()) {
|
||||||
|
return *found->second;
|
||||||
|
}
|
||||||
|
checkIdentifier(id);
|
||||||
|
itemIds.push_back(id);
|
||||||
|
itemDefs[id] = std::make_unique<ItemDef>(id);
|
||||||
|
return *itemDefs[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockMaterial& ContentBuilder::createBlockMaterial(std::string id) {
|
||||||
|
blockMaterials[id] = std::make_unique<BlockMaterial>();
|
||||||
|
auto& material = *blockMaterials[id];
|
||||||
|
material.name = id;
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContentBuilder::checkIdentifier(std::string id) {
|
||||||
|
contenttype result;
|
||||||
|
if (((result = checkContentType(id)) != contenttype::none)) {
|
||||||
|
throw namereuse_error("name "+id+" is already used", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contenttype ContentBuilder::checkContentType(std::string id) {
|
||||||
|
if (blockDefs.find(id) != blockDefs.end()) {
|
||||||
|
return contenttype::block;
|
||||||
|
}
|
||||||
|
if (itemDefs.find(id) != itemDefs.end()) {
|
||||||
|
return contenttype::item;
|
||||||
|
}
|
||||||
|
return contenttype::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Content> ContentBuilder::build() {
|
||||||
|
std::vector<Block*> blockDefsIndices;
|
||||||
|
auto groups = std::make_unique<DrawGroups>();
|
||||||
|
for (const std::string& name : blockIds) {
|
||||||
|
Block& def = *blockDefs[name];
|
||||||
|
|
||||||
|
// Generating runtime info
|
||||||
|
def.rt.id = blockDefsIndices.size();
|
||||||
|
def.rt.emissive = *reinterpret_cast<uint32_t*>(def.emission);
|
||||||
|
def.rt.solid = def.model == BlockModel::block;
|
||||||
|
|
||||||
|
if (def.rotatable) {
|
||||||
|
for (uint i = 0; i < BlockRotProfile::MAX_COUNT; i++) {
|
||||||
|
def.rt.hitboxes[i].reserve(def.hitboxes.size());
|
||||||
|
for (AABB aabb : def.hitboxes) {
|
||||||
|
def.rotations.variants[i].transform(aabb);
|
||||||
|
def.rt.hitboxes[i].push_back(aabb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blockDefsIndices.push_back(&def);
|
||||||
|
groups->insert(def.drawGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ItemDef*> itemDefsIndices;
|
||||||
|
for (const std::string& name : itemIds) {
|
||||||
|
ItemDef& def = *itemDefs[name];
|
||||||
|
|
||||||
|
// Generating runtime info
|
||||||
|
def.rt.id = itemDefsIndices.size();
|
||||||
|
def.rt.emissive = *reinterpret_cast<uint32_t*>(def.emission);
|
||||||
|
itemDefsIndices.push_back(&def);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto content = std::make_unique<Content>(
|
||||||
|
std::make_unique<ContentIndices>(blockDefsIndices, itemDefsIndices),
|
||||||
|
std::move(groups),
|
||||||
|
std::move(blockDefs),
|
||||||
|
std::move(itemDefs),
|
||||||
|
std::move(packs),
|
||||||
|
std::move(blockMaterials)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now, it's time to resolve foreign keys
|
||||||
|
for (Block* def : blockDefsIndices) {
|
||||||
|
def->rt.pickingItem = content->requireItem(def->pickingItem).rt.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ItemDef* def : itemDefsIndices) {
|
||||||
|
def->rt.placingBlock = content->requireBlock(def->placingBlock).rt.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
37
src/content/ContentBuilder.hpp
Normal file
37
src/content/ContentBuilder.hpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef CONTENT_CONTENT_BUILDER_HPP_
|
||||||
|
#define CONTENT_CONTENT_BUILDER_HPP_
|
||||||
|
|
||||||
|
#include "../items/ItemDef.hpp"
|
||||||
|
#include "../voxels/Block.hpp"
|
||||||
|
#include "../content/Content.hpp"
|
||||||
|
#include "../content/ContentPack.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class ContentBuilder {
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<Block>> blockDefs;
|
||||||
|
std::vector<std::string> blockIds;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<ItemDef>> itemDefs;
|
||||||
|
std::vector<std::string> itemIds;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<BlockMaterial>> blockMaterials;
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>> packs;
|
||||||
|
public:
|
||||||
|
~ContentBuilder();
|
||||||
|
|
||||||
|
void add(std::unique_ptr<ContentPackRuntime> pack);
|
||||||
|
|
||||||
|
Block& createBlock(std::string id);
|
||||||
|
ItemDef& createItem(std::string id);
|
||||||
|
BlockMaterial& createBlockMaterial(std::string id);
|
||||||
|
|
||||||
|
void checkIdentifier(std::string id);
|
||||||
|
contenttype checkContentType(std::string id);
|
||||||
|
|
||||||
|
std::unique_ptr<Content> build();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONTENT_CONTENT_BUILDER_HPP_
|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "Content.hpp"
|
#include "Content.hpp"
|
||||||
#include "ContentPack.hpp"
|
#include "ContentPack.hpp"
|
||||||
|
#include "ContentBuilder.hpp"
|
||||||
#include "../coders/json.hpp"
|
#include "../coders/json.hpp"
|
||||||
#include "../core_defs.hpp"
|
#include "../core_defs.hpp"
|
||||||
#include "../data/dynamic.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
@ -26,9 +27,11 @@ static debug::Logger logger("content-loader");
|
|||||||
ContentLoader::ContentLoader(ContentPack* pack) : pack(pack) {
|
ContentLoader::ContentLoader(ContentPack* pack) : pack(pack) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContentLoader::fixPackIndices(fs::path folder,
|
bool ContentLoader::fixPackIndices(
|
||||||
|
fs::path folder,
|
||||||
dynamic::Map* indicesRoot,
|
dynamic::Map* indicesRoot,
|
||||||
std::string contentSection) {
|
std::string contentSection
|
||||||
|
) {
|
||||||
std::vector<std::string> detected;
|
std::vector<std::string> detected;
|
||||||
std::vector<std::string> indexed;
|
std::vector<std::string> indexed;
|
||||||
if (fs::is_directory(folder)) {
|
if (fs::is_directory(folder)) {
|
||||||
@ -209,6 +212,10 @@ void ContentLoader::loadBlock(Block& def, std::string name, fs::path file) {
|
|||||||
root->str("script-name", def.scriptName);
|
root->str("script-name", def.scriptName);
|
||||||
root->str("ui-layout", def.uiLayout);
|
root->str("ui-layout", def.uiLayout);
|
||||||
root->num("inventory-size", def.inventorySize);
|
root->num("inventory-size", def.inventorySize);
|
||||||
|
root->num("tick-interval", def.tickInterval);
|
||||||
|
if (def.tickInterval == 0) {
|
||||||
|
def.tickInterval = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (def.hidden && def.pickingItem == def.name+BLOCK_ITEM_SUFFIX) {
|
if (def.hidden && def.pickingItem == def.name+BLOCK_ITEM_SUFFIX) {
|
||||||
def.pickingItem = CORE_EMPTY;
|
def.pickingItem = CORE_EMPTY;
|
||||||
@ -312,22 +319,22 @@ void ContentLoader::loadItem(ItemDef& def, std::string full, std::string name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockMaterial ContentLoader::loadBlockMaterial(fs::path file, std::string full) {
|
void ContentLoader::loadBlockMaterial(BlockMaterial& def, fs::path file) {
|
||||||
auto root = files::read_json(file);
|
auto root = files::read_json(file);
|
||||||
BlockMaterial material {full};
|
root->str("steps-sound", def.stepsSound);
|
||||||
root->str("steps-sound", material.stepsSound);
|
root->str("place-sound", def.placeSound);
|
||||||
root->str("place-sound", material.placeSound);
|
root->str("break-sound", def.breakSound);
|
||||||
root->str("break-sound", material.breakSound);
|
|
||||||
return material;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentLoader::load(ContentBuilder& builder) {
|
void ContentLoader::load(ContentBuilder& builder) {
|
||||||
logger.info() << "loading pack [" << pack->id << "]";
|
logger.info() << "loading pack [" << pack->id << "]";
|
||||||
|
|
||||||
auto runtime = new ContentPackRuntime(*pack, scripting::create_pack_environment(*pack));
|
auto runtime = std::make_unique<ContentPackRuntime>(
|
||||||
builder.add(runtime);
|
*pack, scripting::create_pack_environment(*pack)
|
||||||
|
);
|
||||||
env = runtime->getEnvironment();
|
env = runtime->getEnvironment();
|
||||||
ContentPackStats& stats = runtime->getStatsWriteable();
|
ContentPackStats& stats = runtime->getStatsWriteable();
|
||||||
|
builder.add(std::move(runtime));
|
||||||
|
|
||||||
fixPackIndices();
|
fixPackIndices();
|
||||||
|
|
||||||
@ -350,7 +357,9 @@ void ContentLoader::load(ContentBuilder& builder) {
|
|||||||
std::string full = colon == std::string::npos ? pack->id + ":" + name : name;
|
std::string full = colon == std::string::npos ? pack->id + ":" + name : name;
|
||||||
if (colon != std::string::npos) name[colon] = '/';
|
if (colon != std::string::npos) name[colon] = '/';
|
||||||
auto& def = builder.createBlock(full);
|
auto& def = builder.createBlock(full);
|
||||||
if (colon != std::string::npos) def.scriptName = name.substr(0, colon) + '/' + def.scriptName;
|
if (colon != std::string::npos) {
|
||||||
|
def.scriptName = name.substr(0, colon) + '/' + def.scriptName;
|
||||||
|
}
|
||||||
loadBlock(def, full, name);
|
loadBlock(def, full, name);
|
||||||
stats.totalBlocks++;
|
stats.totalBlocks++;
|
||||||
if (!def.hidden) {
|
if (!def.hidden) {
|
||||||
@ -388,7 +397,7 @@ void ContentLoader::load(ContentBuilder& builder) {
|
|||||||
for (auto entry : fs::directory_iterator(materialsDir)) {
|
for (auto entry : fs::directory_iterator(materialsDir)) {
|
||||||
fs::path file = entry.path();
|
fs::path file = entry.path();
|
||||||
std::string name = pack->id+":"+file.stem().u8string();
|
std::string name = pack->id+":"+file.stem().u8string();
|
||||||
builder.add(loadBlockMaterial(file, name));
|
loadBlockMaterial(builder.createBlockMaterial(name), file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
#ifndef CONTENT_CONTENT_LOADER_HPP_
|
#ifndef CONTENT_CONTENT_LOADER_HPP_
|
||||||
#define CONTENT_CONTENT_LOADER_HPP_
|
#define CONTENT_CONTENT_LOADER_HPP_
|
||||||
|
|
||||||
#include "../voxels/Block.hpp"
|
#include "../typedefs.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
class Block;
|
||||||
|
struct BlockMaterial;
|
||||||
class ItemDef;
|
class ItemDef;
|
||||||
struct ContentPack;
|
struct ContentPack;
|
||||||
class ContentBuilder;
|
class ContentBuilder;
|
||||||
@ -23,7 +25,7 @@ class ContentLoader {
|
|||||||
void loadBlock(Block& def, std::string full, std::string name);
|
void loadBlock(Block& def, std::string full, std::string name);
|
||||||
void loadCustomBlockModel(Block& def, dynamic::Map* primitives);
|
void loadCustomBlockModel(Block& def, dynamic::Map* primitives);
|
||||||
void loadItem(ItemDef& def, std::string full, std::string name);
|
void loadItem(ItemDef& def, std::string full, std::string name);
|
||||||
BlockMaterial loadBlockMaterial(fs::path file, std::string full);
|
void loadBlockMaterial(BlockMaterial& def, fs::path file);
|
||||||
public:
|
public:
|
||||||
ContentLoader(ContentPack* pack);
|
ContentLoader(ContentPack* pack);
|
||||||
|
|
||||||
|
|||||||
@ -12,17 +12,11 @@ class EnginePaths;
|
|||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
namespace scripting {
|
|
||||||
class Environment;
|
|
||||||
}
|
|
||||||
|
|
||||||
class contentpack_error : public std::runtime_error {
|
class contentpack_error : public std::runtime_error {
|
||||||
std::string packId;
|
std::string packId;
|
||||||
fs::path folder;
|
fs::path folder;
|
||||||
public:
|
public:
|
||||||
contentpack_error(std::string packId,
|
contentpack_error(std::string packId, fs::path folder, std::string message);
|
||||||
fs::path folder,
|
|
||||||
std::string message);
|
|
||||||
|
|
||||||
std::string getPackId() const;
|
std::string getPackId() const;
|
||||||
fs::path getFolder() const;
|
fs::path getFolder() const;
|
||||||
@ -31,11 +25,11 @@ public:
|
|||||||
enum class DependencyLevel {
|
enum class DependencyLevel {
|
||||||
required, // dependency must be installed
|
required, // dependency must be installed
|
||||||
optional, // dependency will be installed if found
|
optional, // dependency will be installed if found
|
||||||
weak, // dependency will not be installed automatically
|
weak, // only affects packs order
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// @brief Content-pack that should be installed before the dependent
|
/// @brief Content-pack that should be installed earlier the dependent
|
||||||
struct DependencyPack {
|
struct DependencyPack {
|
||||||
DependencyLevel level;
|
DependencyLevel level;
|
||||||
std::string id;
|
std::string id;
|
||||||
|
|||||||
@ -2,13 +2,16 @@
|
|||||||
|
|
||||||
#include "items/ItemDef.hpp"
|
#include "items/ItemDef.hpp"
|
||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
|
#include "content/ContentBuilder.hpp"
|
||||||
|
#include "files/files.hpp"
|
||||||
|
#include "files/engine_paths.hpp"
|
||||||
#include "window/Window.hpp"
|
#include "window/Window.hpp"
|
||||||
#include "window/Events.hpp"
|
#include "window/Events.hpp"
|
||||||
#include "window/input.hpp"
|
#include "window/input.hpp"
|
||||||
#include "voxels/Block.hpp"
|
#include "voxels/Block.hpp"
|
||||||
|
|
||||||
// All in-game definitions (blocks, items, etc..)
|
// All in-game definitions (blocks, items, etc..)
|
||||||
void corecontent::setup(ContentBuilder* builder) {
|
void corecontent::setup(EnginePaths* paths, ContentBuilder* builder) {
|
||||||
Block& block = builder->createBlock("core:air");
|
Block& block = builder->createBlock("core:air");
|
||||||
block.replaceable = true;
|
block.replaceable = true;
|
||||||
block.drawGroup = 1;
|
block.drawGroup = 1;
|
||||||
@ -21,24 +24,11 @@ void corecontent::setup(ContentBuilder* builder) {
|
|||||||
|
|
||||||
ItemDef& item = builder->createItem("core:empty");
|
ItemDef& item = builder->createItem("core:empty");
|
||||||
item.iconType = item_icon_type::none;
|
item.iconType = item_icon_type::none;
|
||||||
}
|
|
||||||
|
|
||||||
void corecontent::setup_bindings() {
|
auto bindsFile = paths->getResources()/fs::path("bindings.toml");
|
||||||
Events::bind(BIND_DEVTOOLS_CONSOLE, inputtype::keyboard, keycode::GRAVE_ACCENT);
|
if (fs::is_regular_file(bindsFile)) {
|
||||||
Events::bind(BIND_MOVE_FORWARD, inputtype::keyboard, keycode::W);
|
Events::loadBindings(
|
||||||
Events::bind(BIND_MOVE_BACK, inputtype::keyboard, keycode::S);
|
bindsFile.u8string(), files::read_string(bindsFile)
|
||||||
Events::bind(BIND_MOVE_RIGHT, inputtype::keyboard, keycode::D);
|
);
|
||||||
Events::bind(BIND_MOVE_LEFT, inputtype::keyboard, keycode::A);
|
}
|
||||||
Events::bind(BIND_MOVE_JUMP, inputtype::keyboard, keycode::SPACE);
|
|
||||||
Events::bind(BIND_MOVE_SPRINT, inputtype::keyboard, keycode::LEFT_CONTROL);
|
|
||||||
Events::bind(BIND_MOVE_CROUCH, inputtype::keyboard, keycode::LEFT_SHIFT);
|
|
||||||
Events::bind(BIND_MOVE_CHEAT, inputtype::keyboard, keycode::R);
|
|
||||||
Events::bind(BIND_CAM_ZOOM, inputtype::keyboard, keycode::C);
|
|
||||||
Events::bind(BIND_CAM_MODE, inputtype::keyboard, keycode::F4);
|
|
||||||
Events::bind(BIND_PLAYER_NOCLIP, inputtype::keyboard, keycode::N);
|
|
||||||
Events::bind(BIND_PLAYER_FLIGHT, inputtype::keyboard, keycode::F);
|
|
||||||
Events::bind(BIND_PLAYER_ATTACK, inputtype::mouse, mousecode::BUTTON_1);
|
|
||||||
Events::bind(BIND_PLAYER_BUILD, inputtype::mouse, mousecode::BUTTON_2);
|
|
||||||
Events::bind(BIND_PLAYER_PICK, inputtype::mouse, mousecode::BUTTON_3);
|
|
||||||
Events::bind(BIND_HUD_INVENTORY, inputtype::keyboard, keycode::TAB);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ inline const std::string TEXTURE_NOTFOUND = "notfound";
|
|||||||
|
|
||||||
// built-in bindings
|
// built-in bindings
|
||||||
inline const std::string BIND_DEVTOOLS_CONSOLE = "devtools.console";
|
inline const std::string BIND_DEVTOOLS_CONSOLE = "devtools.console";
|
||||||
|
inline const std::string BIND_CHUNKS_RELOAD = "chunks.reload";
|
||||||
inline const std::string BIND_MOVE_FORWARD = "movement.forward";
|
inline const std::string BIND_MOVE_FORWARD = "movement.forward";
|
||||||
inline const std::string BIND_MOVE_BACK = "movement.back";
|
inline const std::string BIND_MOVE_BACK = "movement.back";
|
||||||
inline const std::string BIND_MOVE_LEFT = "movement.left";
|
inline const std::string BIND_MOVE_LEFT = "movement.left";
|
||||||
@ -27,11 +28,11 @@ inline const std::string BIND_PLAYER_BUILD = "player.build";
|
|||||||
inline const std::string BIND_PLAYER_PICK = "player.pick";
|
inline const std::string BIND_PLAYER_PICK = "player.pick";
|
||||||
inline const std::string BIND_HUD_INVENTORY = "hud.inventory";
|
inline const std::string BIND_HUD_INVENTORY = "hud.inventory";
|
||||||
|
|
||||||
|
class EnginePaths;
|
||||||
class ContentBuilder;
|
class ContentBuilder;
|
||||||
|
|
||||||
namespace corecontent {
|
namespace corecontent {
|
||||||
void setup_bindings();
|
void setup(EnginePaths* paths, ContentBuilder* builder);
|
||||||
void setup(ContentBuilder* builder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CORE_DEFS_HPP_
|
#endif // CORE_DEFS_HPP_
|
||||||
|
|||||||
@ -214,7 +214,7 @@ void Map::flag(const std::string& key, bool& dst) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map& Map::put(std::string key, const Value& value) {
|
Map& Map::put(std::string key, const Value& value) {
|
||||||
values.emplace(key, value);
|
values[key] = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <ostream>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -151,6 +152,9 @@ namespace dynamic {
|
|||||||
Map& put(std::string key, bool value) {
|
Map& put(std::string key, bool value) {
|
||||||
return put(key, Value(static_cast<bool>(value)));
|
return put(key, Value(static_cast<bool>(value)));
|
||||||
}
|
}
|
||||||
|
Map& put(std::string key, const char* value) {
|
||||||
|
return put(key, Value(value));
|
||||||
|
}
|
||||||
Map& put(std::string key, const Value& value);
|
Map& put(std::string key, const Value& value);
|
||||||
|
|
||||||
void remove(const std::string& key);
|
void remove(const std::string& key);
|
||||||
|
|||||||
@ -44,13 +44,14 @@ void Logger::log(LogLevel level, const std::string& name, std::string message) {
|
|||||||
auto ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch()) % 1000;
|
auto ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch()) % 1000;
|
||||||
ss << " " << std::put_time(std::localtime(&tm), "%Y/%m/%d %T");
|
ss << " " << std::put_time(std::localtime(&tm), "%Y/%m/%d %T");
|
||||||
ss << '.' << std::setfill('0') << std::setw(3) << ms.count();
|
ss << '.' << std::setfill('0') << std::setw(3) << ms.count();
|
||||||
ss << utcOffset << " (" << std::setfill(' ') << std::setw(moduleLen) << name << ") ";
|
ss << utcOffset << " [" << std::setfill(' ') << std::setw(moduleLen) << name << "] ";
|
||||||
ss << message;
|
ss << message;
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
auto string = ss.str();
|
auto string = ss.str();
|
||||||
if (file.good()) {
|
if (file.good()) {
|
||||||
file << string << '\n';
|
file << string << '\n';
|
||||||
|
file.flush();
|
||||||
}
|
}
|
||||||
std::cout << string << std::endl;
|
std::cout << string << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "coders/imageio.hpp"
|
#include "coders/imageio.hpp"
|
||||||
#include "coders/json.hpp"
|
#include "coders/json.hpp"
|
||||||
#include "coders/toml.hpp"
|
#include "coders/toml.hpp"
|
||||||
|
#include "content/ContentBuilder.hpp"
|
||||||
#include "content/ContentLoader.hpp"
|
#include "content/ContentLoader.hpp"
|
||||||
#include "core_defs.hpp"
|
#include "core_defs.hpp"
|
||||||
#include "files/files.hpp"
|
#include "files/files.hpp"
|
||||||
@ -34,6 +35,7 @@
|
|||||||
#include "window/input.hpp"
|
#include "window/input.hpp"
|
||||||
#include "window/Window.hpp"
|
#include "window/Window.hpp"
|
||||||
#include "world/WorldGenerators.hpp"
|
#include "world/WorldGenerators.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -56,20 +58,20 @@ inline void create_channel(Engine* engine, std::string name, NumberSetting& sett
|
|||||||
}
|
}
|
||||||
engine->keepAlive(setting.observe([=](auto value) {
|
engine->keepAlive(setting.observe([=](auto value) {
|
||||||
audio::get_channel(name)->setVolume(value*value);
|
audio::get_channel(name)->setVolume(value*value);
|
||||||
}));
|
}, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
Engine::Engine(EngineSettings& settings, SettingsHandler& settingsHandler, EnginePaths* paths)
|
Engine::Engine(EngineSettings& settings, SettingsHandler& settingsHandler, EnginePaths* paths)
|
||||||
: settings(settings), settingsHandler(settingsHandler), paths(paths),
|
: settings(settings), settingsHandler(settingsHandler), paths(paths),
|
||||||
interpreter(std::make_unique<cmd::CommandsInterpreter>())
|
interpreter(std::make_unique<cmd::CommandsInterpreter>())
|
||||||
{
|
{
|
||||||
corecontent::setup_bindings();
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
controller = std::make_unique<EngineController>(this);
|
controller = std::make_unique<EngineController>(this);
|
||||||
if (Window::initialize(&this->settings.display)){
|
if (Window::initialize(&this->settings.display)){
|
||||||
throw initialize_error("could not initialize window");
|
throw initialize_error("could not initialize window");
|
||||||
}
|
}
|
||||||
|
loadControls();
|
||||||
audio::initialize(settings.audio.enabled.get());
|
audio::initialize(settings.audio.enabled.get());
|
||||||
create_channel(this, "master", settings.audio.volumeMaster);
|
create_channel(this, "master", settings.audio.volumeMaster);
|
||||||
create_channel(this, "regular", settings.audio.volumeRegular);
|
create_channel(this, "regular", settings.audio.volumeRegular);
|
||||||
@ -93,6 +95,9 @@ Engine::Engine(EngineSettings& settings, SettingsHandler& settingsHandler, Engin
|
|||||||
addWorldGenerators();
|
addWorldGenerators();
|
||||||
|
|
||||||
scripting::initialize(this);
|
scripting::initialize(this);
|
||||||
|
|
||||||
|
auto resdir = paths->getResources();
|
||||||
|
basePacks = files::read_list(resdir/fs::path("config/builtins.list"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::loadSettings() {
|
void Engine::loadSettings() {
|
||||||
@ -102,11 +107,22 @@ void Engine::loadSettings() {
|
|||||||
std::string text = files::read_string(settings_file);
|
std::string text = files::read_string(settings_file);
|
||||||
toml::parse(settingsHandler, settings_file.string(), text);
|
toml::parse(settingsHandler, settings_file.string(), text);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::loadControls() {
|
||||||
fs::path controls_file = paths->getControlsFile();
|
fs::path controls_file = paths->getControlsFile();
|
||||||
if (fs::is_regular_file(controls_file)) {
|
if (fs::is_regular_file(controls_file)) {
|
||||||
logger.info() << "loading controls";
|
logger.info() << "loading controls";
|
||||||
std::string text = files::read_string(controls_file);
|
std::string text = files::read_string(controls_file);
|
||||||
Events::loadBindings(controls_file.u8string(), text);
|
Events::loadBindings(controls_file.u8string(), text);
|
||||||
|
} else {
|
||||||
|
controls_file = paths->getControlsFileOld();
|
||||||
|
if (fs::is_regular_file(controls_file)) {
|
||||||
|
logger.info() << "loading controls (old)";
|
||||||
|
std::string text = files::read_string(controls_file);
|
||||||
|
Events::loadBindingsOld(controls_file.u8string(), text);
|
||||||
|
fs::remove(controls_file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,10 +267,20 @@ void Engine::loadAssets() {
|
|||||||
assets.reset(new_assets.release());
|
assets.reset(new_assets.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void load_configs(const fs::path& root) {
|
||||||
|
auto configFolder = root/fs::path("config");
|
||||||
|
auto bindsFile = configFolder/fs::path("bindings.toml");
|
||||||
|
if (fs::is_regular_file(bindsFile)) {
|
||||||
|
Events::loadBindings(
|
||||||
|
bindsFile.u8string(), files::read_string(bindsFile)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Engine::loadContent() {
|
void Engine::loadContent() {
|
||||||
auto resdir = paths->getResources();
|
auto resdir = paths->getResources();
|
||||||
ContentBuilder contentBuilder;
|
ContentBuilder contentBuilder;
|
||||||
corecontent::setup(&contentBuilder);
|
corecontent::setup(paths, &contentBuilder);
|
||||||
paths->setContentPacks(&contentPacks);
|
paths->setContentPacks(&contentPacks);
|
||||||
|
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
@ -272,8 +298,12 @@ void Engine::loadContent() {
|
|||||||
|
|
||||||
ContentLoader loader(&pack);
|
ContentLoader loader(&pack);
|
||||||
loader.load(contentBuilder);
|
loader.load(contentBuilder);
|
||||||
|
|
||||||
|
load_configs(pack.folder);
|
||||||
}
|
}
|
||||||
content.reset(contentBuilder.build());
|
load_configs(paths->getResources());
|
||||||
|
|
||||||
|
content = contentBuilder.build();
|
||||||
resPaths = std::make_unique<ResPaths>(resdir, resRoots);
|
resPaths = std::make_unique<ResPaths>(resdir, resRoots);
|
||||||
|
|
||||||
langs::setup(resdir, langs::current->getId(), contentPacks);
|
langs::setup(resdir, langs::current->getId(), contentPacks);
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#define ENGINE_HPP_
|
#define ENGINE_HPP_
|
||||||
|
|
||||||
#include "delegates.hpp"
|
#include "delegates.hpp"
|
||||||
#include "settings.hpp"
|
|
||||||
#include "typedefs.hpp"
|
#include "typedefs.hpp"
|
||||||
|
|
||||||
#include "assets/Assets.hpp"
|
#include "assets/Assets.hpp"
|
||||||
@ -27,6 +26,7 @@ class ResPaths;
|
|||||||
class Batch2D;
|
class Batch2D;
|
||||||
class EngineController;
|
class EngineController;
|
||||||
class SettingsHandler;
|
class SettingsHandler;
|
||||||
|
struct EngineSettings;
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ class Engine : public util::ObjectsKeeper {
|
|||||||
std::recursive_mutex postRunnablesMutex;
|
std::recursive_mutex postRunnablesMutex;
|
||||||
std::unique_ptr<EngineController> controller;
|
std::unique_ptr<EngineController> controller;
|
||||||
std::unique_ptr<cmd::CommandsInterpreter> interpreter;
|
std::unique_ptr<cmd::CommandsInterpreter> interpreter;
|
||||||
std::vector<std::string> basePacks {"base"};
|
std::vector<std::string> basePacks;
|
||||||
|
|
||||||
uint64_t frame = 0;
|
uint64_t frame = 0;
|
||||||
double lastTime = 0.0;
|
double lastTime = 0.0;
|
||||||
@ -65,6 +65,7 @@ class Engine : public util::ObjectsKeeper {
|
|||||||
|
|
||||||
std::unique_ptr<gui::GUI> gui;
|
std::unique_ptr<gui::GUI> gui;
|
||||||
|
|
||||||
|
void loadControls();
|
||||||
void loadSettings();
|
void loadSettings();
|
||||||
void saveSettings();
|
void saveSettings();
|
||||||
void updateTimers();
|
void updateTimers();
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
#include "../objects/Player.hpp"
|
#include "../objects/Player.hpp"
|
||||||
#include "../physics/Hitbox.hpp"
|
#include "../physics/Hitbox.hpp"
|
||||||
#include "../typedefs.hpp"
|
#include "../typedefs.hpp"
|
||||||
|
#include "../settings.hpp"
|
||||||
#include "../util/data_io.hpp"
|
#include "../util/data_io.hpp"
|
||||||
#include "../voxels/Block.hpp"
|
#include "../voxels/Block.hpp"
|
||||||
#include "../voxels/Chunk.hpp"
|
#include "../voxels/Chunk.hpp"
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include "files.hpp"
|
#include "files.hpp"
|
||||||
#include "../typedefs.hpp"
|
#include "../typedefs.hpp"
|
||||||
#include "../settings.hpp"
|
|
||||||
#include "../content/ContentPack.hpp"
|
#include "../content/ContentPack.hpp"
|
||||||
#include "../voxels/Chunk.hpp"
|
#include "../voxels/Chunk.hpp"
|
||||||
|
|
||||||
@ -24,6 +23,7 @@ class Player;
|
|||||||
class Content;
|
class Content;
|
||||||
class ContentIndices;
|
class ContentIndices;
|
||||||
class World;
|
class World;
|
||||||
|
struct DebugSettings;
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
|||||||
@ -374,7 +374,7 @@ void WorldRegions::put(Chunk* chunk){
|
|||||||
chunk->encode(), CHUNK_DATA_LEN, true);
|
chunk->encode(), CHUNK_DATA_LEN, true);
|
||||||
|
|
||||||
// Writing lights cache
|
// Writing lights cache
|
||||||
if (doWriteLights && chunk->isLighted()) {
|
if (doWriteLights && chunk->flags.lighted) {
|
||||||
put(chunk->x, chunk->z, REGION_LAYER_LIGHTS,
|
put(chunk->x, chunk->z, REGION_LAYER_LIGHTS,
|
||||||
chunk->lightmap.encode(), LIGHTMAP_DATA_LEN, true);
|
chunk->lightmap.encode(), LIGHTMAP_DATA_LEN, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
#include "WorldFiles.hpp"
|
#include "WorldFiles.hpp"
|
||||||
|
|
||||||
const fs::path SCREENSHOTS_FOLDER {"screenshots"};
|
const fs::path SCREENSHOTS_FOLDER {"screenshots"};
|
||||||
const fs::path CONTROLS_FILE {"controls.json"};
|
const fs::path CONTROLS_FILE {"controls.toml"};
|
||||||
const fs::path SETTINGS_FILE {"settings.toml"};
|
const fs::path SETTINGS_FILE {"settings.toml"};
|
||||||
|
|
||||||
fs::path EnginePaths::getUserfiles() const {
|
fs::path EnginePaths::getUserfiles() const {
|
||||||
@ -60,6 +60,10 @@ fs::path EnginePaths::getControlsFile() {
|
|||||||
return userfiles/fs::path(CONTROLS_FILE);
|
return userfiles/fs::path(CONTROLS_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fs::path EnginePaths::getControlsFileOld() {
|
||||||
|
return userfiles/fs::path("controls.json");
|
||||||
|
}
|
||||||
|
|
||||||
fs::path EnginePaths::getSettingsFile() {
|
fs::path EnginePaths::getSettingsFile() {
|
||||||
return userfiles/fs::path(SETTINGS_FILE);
|
return userfiles/fs::path(SETTINGS_FILE);
|
||||||
}
|
}
|
||||||
@ -135,7 +139,7 @@ static fs::path toCanonic(fs::path path) {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path EnginePaths::resolve(std::string path) {
|
fs::path EnginePaths::resolve(std::string path, bool throwErr) {
|
||||||
size_t separator = path.find(':');
|
size_t separator = path.find(':');
|
||||||
if (separator == std::string::npos) {
|
if (separator == std::string::npos) {
|
||||||
throw files_access_error("no entry point specified");
|
throw files_access_error("no entry point specified");
|
||||||
@ -161,8 +165,11 @@ fs::path EnginePaths::resolve(std::string path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (throwErr) {
|
||||||
throw files_access_error("unknown entry point '"+prefix+"'");
|
throw files_access_error("unknown entry point '"+prefix+"'");
|
||||||
}
|
}
|
||||||
|
return fs::path(filename);
|
||||||
|
}
|
||||||
|
|
||||||
ResPaths::ResPaths(fs::path mainRoot, std::vector<PathsRoot> roots)
|
ResPaths::ResPaths(fs::path mainRoot, std::vector<PathsRoot> roots)
|
||||||
: mainRoot(mainRoot), roots(roots) {
|
: mainRoot(mainRoot), roots(roots) {
|
||||||
|
|||||||
@ -29,6 +29,7 @@ public:
|
|||||||
fs::path getWorldFolder();
|
fs::path getWorldFolder();
|
||||||
fs::path getWorldFolder(const std::string& name);
|
fs::path getWorldFolder(const std::string& name);
|
||||||
fs::path getControlsFile();
|
fs::path getControlsFile();
|
||||||
|
fs::path getControlsFileOld(); // TODO: remove in 0.22
|
||||||
fs::path getSettingsFile();
|
fs::path getSettingsFile();
|
||||||
bool isWorldNameUsed(std::string name);
|
bool isWorldNameUsed(std::string name);
|
||||||
|
|
||||||
@ -39,7 +40,7 @@ public:
|
|||||||
|
|
||||||
std::vector<fs::path> scanForWorlds();
|
std::vector<fs::path> scanForWorlds();
|
||||||
|
|
||||||
fs::path resolve(std::string path);
|
fs::path resolve(std::string path, bool throwErr=true);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PathsRoot {
|
struct PathsRoot {
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
#include "files.hpp"
|
#include "files.hpp"
|
||||||
|
|
||||||
|
#include "../coders/commons.hpp"
|
||||||
#include "../coders/json.hpp"
|
#include "../coders/json.hpp"
|
||||||
|
#include "../coders/toml.hpp"
|
||||||
#include "../coders/gzip.hpp"
|
#include "../coders/gzip.hpp"
|
||||||
#include "../util/stringutil.hpp"
|
#include "../util/stringutil.hpp"
|
||||||
#include "../data/dynamic.hpp"
|
#include "../data/dynamic.hpp"
|
||||||
@ -107,8 +109,7 @@ bool files::write_binary_json(fs::path filename, const dynamic::Map* obj, bool c
|
|||||||
std::shared_ptr<dynamic::Map> files::read_json(fs::path filename) {
|
std::shared_ptr<dynamic::Map> files::read_json(fs::path filename) {
|
||||||
std::string text = files::read_string(filename);
|
std::string text = files::read_string(filename);
|
||||||
try {
|
try {
|
||||||
auto obj = json::parse(filename.string(), text);
|
return json::parse(filename.string(), text);;
|
||||||
return obj;
|
|
||||||
} catch (const parsing_error& error) {
|
} catch (const parsing_error& error) {
|
||||||
std::cerr << error.errorLog() << std::endl;
|
std::cerr << error.errorLog() << std::endl;
|
||||||
throw std::runtime_error("could not to parse "+filename.string());
|
throw std::runtime_error("could not to parse "+filename.string());
|
||||||
@ -121,6 +122,10 @@ std::shared_ptr<dynamic::Map> files::read_binary_json(fs::path file) {
|
|||||||
return json::from_binary(bytes.get(), size);
|
return json::from_binary(bytes.get(), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<dynamic::Map> files::read_toml(fs::path file) {
|
||||||
|
return toml::parse(file.u8string(), files::read_string(file));
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> files::read_list(fs::path filename) {
|
std::vector<std::string> files::read_list(fs::path filename) {
|
||||||
std::ifstream file(filename);
|
std::ifstream file(filename);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
|
|||||||
@ -20,7 +20,7 @@ namespace files {
|
|||||||
std::ifstream file;
|
std::ifstream file;
|
||||||
size_t filelength;
|
size_t filelength;
|
||||||
public:
|
public:
|
||||||
rafile(std::filesystem::path filename);
|
rafile(fs::path filename);
|
||||||
|
|
||||||
void seekg(std::streampos pos);
|
void seekg(std::streampos pos);
|
||||||
void read(char* buffer, std::streamsize size);
|
void read(char* buffer, std::streamsize size);
|
||||||
@ -44,10 +44,7 @@ namespace files {
|
|||||||
|
|
||||||
/// @brief Write dynamic data to the JSON file
|
/// @brief Write dynamic data to the JSON file
|
||||||
/// @param nice if true, human readable format will be used, otherwise minimal
|
/// @param nice if true, human readable format will be used, otherwise minimal
|
||||||
bool write_json(
|
bool write_json(fs::path filename, const dynamic::Map* obj, bool nice=true);
|
||||||
fs::path filename,
|
|
||||||
const dynamic::Map* obj,
|
|
||||||
bool nice=true);
|
|
||||||
|
|
||||||
/// @brief Write dynamic data to the binary JSON file
|
/// @brief Write dynamic data to the binary JSON file
|
||||||
/// (see src/coders/binary_json_spec.md)
|
/// (see src/coders/binary_json_spec.md)
|
||||||
@ -66,6 +63,7 @@ namespace files {
|
|||||||
/// @param file *.json or *.bjson file
|
/// @param file *.json or *.bjson file
|
||||||
std::shared_ptr<dynamic::Map> read_json(fs::path file);
|
std::shared_ptr<dynamic::Map> read_json(fs::path file);
|
||||||
std::shared_ptr<dynamic::Map> read_binary_json(fs::path file);
|
std::shared_ptr<dynamic::Map> read_binary_json(fs::path file);
|
||||||
|
std::shared_ptr<dynamic::Map> read_toml(fs::path file);
|
||||||
std::vector<std::string> read_list(fs::path file);
|
std::vector<std::string> read_list(fs::path file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ LevelFrontend::LevelFrontend(LevelController* controller, Assets* assets)
|
|||||||
contentCache(std::make_unique<ContentGfxCache>(level->content, assets))
|
contentCache(std::make_unique<ContentGfxCache>(level->content, assets))
|
||||||
{
|
{
|
||||||
assets->store(
|
assets->store(
|
||||||
BlocksPreview::build(contentCache.get(), assets, level->content).release(),
|
BlocksPreview::build(contentCache.get(), assets, level->content),
|
||||||
"block-previews"
|
"block-previews"
|
||||||
);
|
);
|
||||||
controller->getPlayerController()->listenBlockInteraction(
|
controller->getPlayerController()->listenBlockInteraction(
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#include "../audio/audio.hpp"
|
#include "../audio/audio.hpp"
|
||||||
#include "../delegates.hpp"
|
#include "../delegates.hpp"
|
||||||
#include "../engine.hpp"
|
#include "../engine.hpp"
|
||||||
|
#include "../settings.hpp"
|
||||||
#include "../graphics/core/Mesh.hpp"
|
#include "../graphics/core/Mesh.hpp"
|
||||||
#include "../graphics/ui/elements/CheckBox.hpp"
|
#include "../graphics/ui/elements/CheckBox.hpp"
|
||||||
#include "../graphics/ui/elements/TextBox.hpp"
|
#include "../graphics/ui/elements/TextBox.hpp"
|
||||||
@ -19,6 +20,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
using namespace gui;
|
using namespace gui;
|
||||||
|
|
||||||
@ -71,15 +73,24 @@ std::shared_ptr<UINode> create_debug_panel(
|
|||||||
L" visible: "+std::to_wstring(level->chunks->visible);
|
L" visible: "+std::to_wstring(level->chunks->visible);
|
||||||
}));
|
}));
|
||||||
panel->add(create_label([=](){
|
panel->add(create_label([=](){
|
||||||
auto* indices = level->content->getIndices();
|
|
||||||
auto def = indices->getBlockDef(player->selectedVoxel.id);
|
|
||||||
std::wstringstream stream;
|
std::wstringstream stream;
|
||||||
stream << std::hex << player->selectedVoxel.states;
|
stream << "r:" << player->selectedVoxel.state.rotation << " s:"
|
||||||
if (def) {
|
<< player->selectedVoxel.state.segment << " u:"
|
||||||
stream << L" (" << util::str2wstr_utf8(def->name) << L")";
|
<< std::bitset<8>(player->selectedVoxel.state.userbits);
|
||||||
}
|
if (player->selectedVoxel.id == BLOCK_VOID) {
|
||||||
|
return std::wstring {L"block: -"};
|
||||||
|
} else {
|
||||||
return L"block: "+std::to_wstring(player->selectedVoxel.id)+
|
return L"block: "+std::to_wstring(player->selectedVoxel.id)+
|
||||||
L" "+stream.str();
|
L" "+stream.str();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
panel->add(create_label([=](){
|
||||||
|
auto* indices = level->content->getIndices();
|
||||||
|
if (auto def = indices->getBlockDef(player->selectedVoxel.id)) {
|
||||||
|
return L"name: " + util::str2wstr_utf8(def->name);
|
||||||
|
} else {
|
||||||
|
return std::wstring {L"name: void"};
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
panel->add(create_label([=](){
|
panel->add(create_label([=](){
|
||||||
return L"seed: "+std::to_wstring(level->getWorld()->getSeed());
|
return L"seed: "+std::to_wstring(level->getWorld()->getSeed());
|
||||||
@ -137,8 +148,8 @@ std::shared_ptr<UINode> create_debug_panel(
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 0.0f, 0.005f, 8);
|
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 0.0f, 0.005f, 8);
|
||||||
bar->setSupplier([=]() {return WorldRenderer::fog;});
|
bar->setSupplier([=]() {return level->getWorld()->fog;});
|
||||||
bar->setConsumer([=](double val) {WorldRenderer::fog = val;});
|
bar->setConsumer([=](double val) {level->getWorld()->fog = val;});
|
||||||
panel->add(bar);
|
panel->add(bar);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|||||||
@ -333,7 +333,7 @@ void Hud::openInventory(
|
|||||||
if (blockinv == nullptr) {
|
if (blockinv == nullptr) {
|
||||||
blockinv = level->inventories->createVirtual(blockUI->getSlotsCount());
|
blockinv = level->inventories->createVirtual(blockUI->getSlotsCount());
|
||||||
}
|
}
|
||||||
level->chunks->getChunkByVoxel(block.x, block.y, block.z)->setUnsaved(true);
|
level->chunks->getChunkByVoxel(block.x, block.y, block.z)->flags.unsaved = true;
|
||||||
blockUI->bind(blockinv, content);
|
blockUI->bind(blockinv, content);
|
||||||
blockPos = block;
|
blockPos = block;
|
||||||
currentblockid = level->chunks->get(block.x, block.y, block.z)->id;
|
currentblockid = level->chunks->get(block.x, block.y, block.z)->id;
|
||||||
|
|||||||
@ -62,9 +62,11 @@ gui::page_loader_func menus::create_page_loader(Engine* engine) {
|
|||||||
auto file = engine->getResPaths()->find("layouts/pages/"+name+".xml");
|
auto file = engine->getResPaths()->find("layouts/pages/"+name+".xml");
|
||||||
auto fullname = "core:pages/"+name;
|
auto fullname = "core:pages/"+name;
|
||||||
|
|
||||||
auto document = UiDocument::read(scripting::get_root_environment(), fullname, file).release();
|
auto document_ptr = UiDocument::read(
|
||||||
engine->getAssets()->store(document, fullname);
|
scripting::get_root_environment(), fullname, file
|
||||||
|
);
|
||||||
|
auto document = document_ptr.get();
|
||||||
|
engine->getAssets()->store(std::move(document_ptr), fullname);
|
||||||
scripting::on_ui_open(document, std::move(args));
|
scripting::on_ui_open(document, std::move(args));
|
||||||
return document->getRoot();
|
return document->getRoot();
|
||||||
};
|
};
|
||||||
@ -75,8 +77,11 @@ UiDocument* menus::show(Engine* engine, const std::string& name, std::vector<dyn
|
|||||||
auto file = engine->getResPaths()->find("layouts/"+name+".xml");
|
auto file = engine->getResPaths()->find("layouts/"+name+".xml");
|
||||||
auto fullname = "core:layouts/"+name;
|
auto fullname = "core:layouts/"+name;
|
||||||
|
|
||||||
auto document = UiDocument::read(scripting::get_root_environment(), fullname, file).release();
|
auto document_ptr = UiDocument::read(
|
||||||
engine->getAssets()->store(document, fullname);
|
scripting::get_root_environment(), fullname, file
|
||||||
|
);
|
||||||
|
auto document = document_ptr.get();
|
||||||
|
engine->getAssets()->store(std::move(document_ptr), fullname);
|
||||||
scripting::on_ui_open(document, std::move(args));
|
scripting::on_ui_open(document, std::move(args));
|
||||||
menu->addPage(name, document->getRoot());
|
menu->addPage(name, document->getRoot());
|
||||||
menu->setPage(name);
|
menu->setPage(name);
|
||||||
|
|||||||
@ -1,27 +1,30 @@
|
|||||||
#include "LevelScreen.hpp"
|
#include "LevelScreen.hpp"
|
||||||
|
|
||||||
|
#include "../../core_defs.hpp"
|
||||||
#include "../hud.hpp"
|
#include "../hud.hpp"
|
||||||
#include "../LevelFrontend.hpp"
|
#include "../LevelFrontend.hpp"
|
||||||
#include "../../debug/Logger.hpp"
|
|
||||||
#include "../../audio/audio.hpp"
|
#include "../../audio/audio.hpp"
|
||||||
#include "../../coders/imageio.hpp"
|
#include "../../coders/imageio.hpp"
|
||||||
#include "../../graphics/core/PostProcessing.hpp"
|
#include "../../debug/Logger.hpp"
|
||||||
|
#include "../../engine.hpp"
|
||||||
|
#include "../../files/files.hpp"
|
||||||
#include "../../graphics/core/DrawContext.hpp"
|
#include "../../graphics/core/DrawContext.hpp"
|
||||||
#include "../../graphics/core/Viewport.hpp"
|
|
||||||
#include "../../graphics/core/ImageData.hpp"
|
#include "../../graphics/core/ImageData.hpp"
|
||||||
#include "../../graphics/ui/GUI.hpp"
|
#include "../../graphics/core/PostProcessing.hpp"
|
||||||
#include "../../graphics/ui/elements/Menu.hpp"
|
#include "../../graphics/core/Viewport.hpp"
|
||||||
#include "../../graphics/render/WorldRenderer.hpp"
|
#include "../../graphics/render/WorldRenderer.hpp"
|
||||||
|
#include "../../graphics/ui/elements/Menu.hpp"
|
||||||
|
#include "../../graphics/ui/GUI.hpp"
|
||||||
#include "../../logic/LevelController.hpp"
|
#include "../../logic/LevelController.hpp"
|
||||||
#include "../../logic/scripting/scripting_hud.hpp"
|
#include "../../logic/scripting/scripting_hud.hpp"
|
||||||
|
#include "../../util/stringutil.hpp"
|
||||||
#include "../../physics/Hitbox.hpp"
|
#include "../../physics/Hitbox.hpp"
|
||||||
#include "../../voxels/Chunks.hpp"
|
#include "../../voxels/Chunks.hpp"
|
||||||
#include "../../world/Level.hpp"
|
|
||||||
#include "../../world/World.hpp"
|
|
||||||
#include "../../window/Camera.hpp"
|
#include "../../window/Camera.hpp"
|
||||||
#include "../../window/Events.hpp"
|
#include "../../window/Events.hpp"
|
||||||
#include "../../window/Window.hpp"
|
#include "../../window/Window.hpp"
|
||||||
#include "../../engine.hpp"
|
#include "../../world/Level.hpp"
|
||||||
|
#include "../../world/World.hpp"
|
||||||
|
|
||||||
static debug::Logger logger("level-screen");
|
static debug::Logger logger("level-screen");
|
||||||
|
|
||||||
@ -45,6 +48,9 @@ LevelScreen::LevelScreen(Engine* engine, std::unique_ptr<Level> level)
|
|||||||
keepAlive(settings.camera.fov.observe([=](double value) {
|
keepAlive(settings.camera.fov.observe([=](double value) {
|
||||||
controller->getPlayer()->camera->setFov(glm::radians(value));
|
controller->getPlayer()->camera->setFov(glm::radians(value));
|
||||||
}));
|
}));
|
||||||
|
keepAlive(Events::getBinding(BIND_CHUNKS_RELOAD).onactived.add([=](){
|
||||||
|
controller->getLevel()->chunks->saveAndClear();
|
||||||
|
}));
|
||||||
|
|
||||||
animator = std::make_unique<TextureAnimator>();
|
animator = std::make_unique<TextureAnimator>();
|
||||||
animator->addAnimations(assets->getAnimations());
|
animator->addAnimations(assets->getAnimations());
|
||||||
@ -55,15 +61,18 @@ LevelScreen::LevelScreen(Engine* engine, std::unique_ptr<Level> level)
|
|||||||
void LevelScreen::initializeContent() {
|
void LevelScreen::initializeContent() {
|
||||||
auto content = controller->getLevel()->content;
|
auto content = controller->getLevel()->content;
|
||||||
for (auto& entry : content->getPacks()) {
|
for (auto& entry : content->getPacks()) {
|
||||||
auto pack = entry.second.get();
|
initializePack(entry.second.get());
|
||||||
|
}
|
||||||
|
scripting::on_frontend_init(hud.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelScreen::initializePack(ContentPackRuntime* pack) {
|
||||||
const ContentPack& info = pack->getInfo();
|
const ContentPack& info = pack->getInfo();
|
||||||
fs::path scriptFile = info.folder/fs::path("scripts/hud.lua");
|
fs::path scriptFile = info.folder/fs::path("scripts/hud.lua");
|
||||||
if (fs::is_regular_file(scriptFile)) {
|
if (fs::is_regular_file(scriptFile)) {
|
||||||
scripting::load_hud_script(pack->getEnvironment(), info.id, scriptFile);
|
scripting::load_hud_script(pack->getEnvironment(), info.id, scriptFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scripting::on_frontend_init(hud.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
LevelScreen::~LevelScreen() {
|
LevelScreen::~LevelScreen() {
|
||||||
saveWorldPreview();
|
saveWorldPreview();
|
||||||
@ -83,8 +92,11 @@ void LevelScreen::saveWorldPreview() {
|
|||||||
// camera special copy for world preview
|
// camera special copy for world preview
|
||||||
Camera camera = *player->camera;
|
Camera camera = *player->camera;
|
||||||
camera.setFov(glm::radians(70.0f));
|
camera.setFov(glm::radians(70.0f));
|
||||||
|
|
||||||
|
DrawContext pctx(nullptr, {Window::width, Window::height}, batch.get());
|
||||||
|
|
||||||
Viewport viewport(previewSize * 1.5, previewSize);
|
Viewport viewport(previewSize * 1.5, previewSize);
|
||||||
DrawContext ctx(nullptr, viewport, batch.get());
|
DrawContext ctx(&pctx, viewport, batch.get());
|
||||||
|
|
||||||
worldRenderer->draw(ctx, &camera, false, postProcessing.get());
|
worldRenderer->draw(ctx, &camera, false, postProcessing.get());
|
||||||
auto image = postProcessing->toImage();
|
auto image = postProcessing->toImage();
|
||||||
@ -106,9 +118,6 @@ void LevelScreen::updateHotkeys() {
|
|||||||
if (Events::jpressed(keycode::F3)) {
|
if (Events::jpressed(keycode::F3)) {
|
||||||
controller->getPlayer()->debug = !controller->getPlayer()->debug;
|
controller->getPlayer()->debug = !controller->getPlayer()->debug;
|
||||||
}
|
}
|
||||||
if (Events::jpressed(keycode::F5)) {
|
|
||||||
controller->getLevel()->chunks->saveAndClear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LevelScreen::update(float delta) {
|
void LevelScreen::update(float delta) {
|
||||||
@ -138,7 +147,7 @@ void LevelScreen::update(float delta) {
|
|||||||
controller->getLevel()->getWorld()->updateTimers(delta);
|
controller->getLevel()->getWorld()->updateTimers(delta);
|
||||||
animator->update(delta);
|
animator->update(delta);
|
||||||
}
|
}
|
||||||
controller->update(delta, !inputLocked, hud->isPause());
|
controller->update(glm::min(delta, 0.2f), !inputLocked, hud->isPause());
|
||||||
hud->update(hudVisible);
|
hud->update(hudVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,21 +12,23 @@ class LevelController;
|
|||||||
class WorldRenderer;
|
class WorldRenderer;
|
||||||
class TextureAnimator;
|
class TextureAnimator;
|
||||||
class PostProcessing;
|
class PostProcessing;
|
||||||
|
class ContentPackRuntime;
|
||||||
class Level;
|
class Level;
|
||||||
|
|
||||||
class LevelScreen : public Screen {
|
class LevelScreen : public Screen {
|
||||||
std::unique_ptr<LevelFrontend> frontend;
|
std::unique_ptr<LevelFrontend> frontend;
|
||||||
std::unique_ptr<Hud> hud;
|
|
||||||
std::unique_ptr<LevelController> controller;
|
std::unique_ptr<LevelController> controller;
|
||||||
std::unique_ptr<WorldRenderer> worldRenderer;
|
std::unique_ptr<WorldRenderer> worldRenderer;
|
||||||
std::unique_ptr<TextureAnimator> animator;
|
std::unique_ptr<TextureAnimator> animator;
|
||||||
std::unique_ptr<PostProcessing> postProcessing;
|
std::unique_ptr<PostProcessing> postProcessing;
|
||||||
|
std::unique_ptr<Hud> hud;
|
||||||
|
|
||||||
void saveWorldPreview();
|
void saveWorldPreview();
|
||||||
|
|
||||||
bool hudVisible = true;
|
bool hudVisible = true;
|
||||||
void updateHotkeys();
|
void updateHotkeys();
|
||||||
void initializeContent();
|
void initializeContent();
|
||||||
|
void initializePack(ContentPackRuntime* pack);
|
||||||
public:
|
public:
|
||||||
LevelScreen(Engine* engine, std::unique_ptr<Level> level);
|
LevelScreen(Engine* engine, std::unique_ptr<Level> level);
|
||||||
~LevelScreen();
|
~LevelScreen();
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "../../graphics/core/Batch2D.hpp"
|
#include "../../graphics/core/Batch2D.hpp"
|
||||||
#include "../../graphics/core/Shader.hpp"
|
#include "../../graphics/core/Shader.hpp"
|
||||||
#include "../../graphics/core/Texture.hpp"
|
#include "../../graphics/core/Texture.hpp"
|
||||||
|
#include "../../maths/UVRegion.hpp"
|
||||||
#include "../../window/Window.hpp"
|
#include "../../window/Window.hpp"
|
||||||
#include "../../window/Camera.hpp"
|
#include "../../window/Camera.hpp"
|
||||||
#include "../../engine.hpp"
|
#include "../../engine.hpp"
|
||||||
|
|||||||
@ -13,19 +13,18 @@ Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){
|
|||||||
{2}, {2}, {4}, {0}
|
{2}, {2}, {4}, {0}
|
||||||
};
|
};
|
||||||
|
|
||||||
buffer = new float[capacity * B2D_VERTEX_SIZE];
|
buffer = std::make_unique<float[]>(capacity * B2D_VERTEX_SIZE);
|
||||||
mesh = std::make_unique<Mesh>(buffer, 0, attrs);
|
mesh = std::make_unique<Mesh>(buffer.get(), 0, attrs);
|
||||||
index = 0;
|
index = 0;
|
||||||
|
|
||||||
ubyte pixels[] = {
|
ubyte pixels[] = {
|
||||||
0xFF, 0xFF, 0xFF, 0xFF
|
0xFF, 0xFF, 0xFF, 0xFF
|
||||||
};
|
};
|
||||||
blank = std::make_unique<Texture>(pixels, 1, 1, ImageFormat::rgba8888);
|
blank = std::make_unique<Texture>(pixels, 1, 1, ImageFormat::rgba8888);
|
||||||
_texture = nullptr;
|
currentTexture = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Batch2D::~Batch2D(){
|
Batch2D::~Batch2D(){
|
||||||
delete[] buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch2D::setPrimitive(DrawPrimitive primitive) {
|
void Batch2D::setPrimitive(DrawPrimitive primitive) {
|
||||||
@ -37,7 +36,7 @@ void Batch2D::setPrimitive(DrawPrimitive primitive) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Batch2D::begin(){
|
void Batch2D::begin(){
|
||||||
_texture = nullptr;
|
currentTexture = nullptr;
|
||||||
blank->bind();
|
blank->bind();
|
||||||
color = glm::vec4(1.0f);
|
color = glm::vec4(1.0f);
|
||||||
primitive = DrawPrimitive::triangle;
|
primitive = DrawPrimitive::triangle;
|
||||||
@ -73,15 +72,17 @@ void Batch2D::vertex(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Batch2D::texture(Texture* new_texture){
|
void Batch2D::texture(Texture* new_texture){
|
||||||
if (_texture == new_texture)
|
if (currentTexture == new_texture) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
flush();
|
flush();
|
||||||
_texture = new_texture;
|
currentTexture = new_texture;
|
||||||
if (new_texture == nullptr)
|
if (new_texture == nullptr) {
|
||||||
blank->bind();
|
blank->bind();
|
||||||
else
|
} else {
|
||||||
new_texture->bind();
|
new_texture->bind();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Batch2D::untexture() {
|
void Batch2D::untexture() {
|
||||||
texture(nullptr);
|
texture(nullptr);
|
||||||
@ -327,7 +328,7 @@ void Batch2D::sprite(float x, float y, float w, float h, int atlasRes, int index
|
|||||||
void Batch2D::flush() {
|
void Batch2D::flush() {
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
return;
|
return;
|
||||||
mesh->reload(buffer, index / B2D_VERTEX_SIZE);
|
mesh->reload(buffer.get(), index / B2D_VERTEX_SIZE);
|
||||||
mesh->draw(gl::to_glenum(primitive));
|
mesh->draw(gl::to_glenum(primitive));
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,13 +12,13 @@ class Texture;
|
|||||||
struct UVRegion;
|
struct UVRegion;
|
||||||
|
|
||||||
class Batch2D {
|
class Batch2D {
|
||||||
float* buffer;
|
std::unique_ptr<float[]> buffer;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
std::unique_ptr<Mesh> mesh;
|
std::unique_ptr<Mesh> mesh;
|
||||||
std::unique_ptr<Texture> blank;
|
std::unique_ptr<Texture> blank;
|
||||||
size_t index;
|
size_t index;
|
||||||
glm::vec4 color;
|
glm::vec4 color;
|
||||||
Texture* _texture;
|
Texture* currentTexture;
|
||||||
DrawPrimitive primitive = DrawPrimitive::triangle;
|
DrawPrimitive primitive = DrawPrimitive::triangle;
|
||||||
|
|
||||||
void setPrimitive(DrawPrimitive primitive);
|
void setPrimitive(DrawPrimitive primitive);
|
||||||
|
|||||||
@ -14,28 +14,29 @@ Batch3D::Batch3D(size_t capacity)
|
|||||||
{3}, {2}, {4}, {0}
|
{3}, {2}, {4}, {0}
|
||||||
};
|
};
|
||||||
|
|
||||||
buffer = new float[capacity * B3D_VERTEX_SIZE];
|
buffer = std::make_unique<float[]>(capacity * B3D_VERTEX_SIZE);
|
||||||
mesh = std::make_unique<Mesh>(buffer, 0, attrs);
|
mesh = std::make_unique<Mesh>(buffer.get(), 0, attrs);
|
||||||
index = 0;
|
index = 0;
|
||||||
|
|
||||||
ubyte pixels[] = {
|
ubyte pixels[] = {
|
||||||
255, 255, 255, 255,
|
255, 255, 255, 255,
|
||||||
};
|
};
|
||||||
blank = std::make_unique<Texture>(pixels, 1, 1, ImageFormat::rgba8888);
|
blank = std::make_unique<Texture>(pixels, 1, 1, ImageFormat::rgba8888);
|
||||||
_texture = nullptr;
|
currentTexture = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Batch3D::~Batch3D(){
|
Batch3D::~Batch3D(){
|
||||||
delete[] buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch3D::begin(){
|
void Batch3D::begin(){
|
||||||
_texture = nullptr;
|
currentTexture = nullptr;
|
||||||
blank->bind();
|
blank->bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch3D::vertex(float x, float y, float z, float u, float v,
|
void Batch3D::vertex(
|
||||||
float r, float g, float b, float a) {
|
float x, float y, float z, float u, float v,
|
||||||
|
float r, float g, float b, float a
|
||||||
|
) {
|
||||||
buffer[index++] = x;
|
buffer[index++] = x;
|
||||||
buffer[index++] = y;
|
buffer[index++] = y;
|
||||||
buffer[index++] = z;
|
buffer[index++] = z;
|
||||||
@ -46,8 +47,10 @@ void Batch3D::vertex(float x, float y, float z, float u, float v,
|
|||||||
buffer[index++] = b;
|
buffer[index++] = b;
|
||||||
buffer[index++] = a;
|
buffer[index++] = a;
|
||||||
}
|
}
|
||||||
void Batch3D::vertex(glm::vec3 coord, float u, float v,
|
void Batch3D::vertex(
|
||||||
float r, float g, float b, float a) {
|
glm::vec3 coord, float u, float v,
|
||||||
|
float r, float g, float b, float a
|
||||||
|
) {
|
||||||
buffer[index++] = coord.x;
|
buffer[index++] = coord.x;
|
||||||
buffer[index++] = coord.y;
|
buffer[index++] = coord.y;
|
||||||
buffer[index++] = coord.z;
|
buffer[index++] = coord.z;
|
||||||
@ -58,9 +61,11 @@ void Batch3D::vertex(glm::vec3 coord, float u, float v,
|
|||||||
buffer[index++] = b;
|
buffer[index++] = b;
|
||||||
buffer[index++] = a;
|
buffer[index++] = a;
|
||||||
}
|
}
|
||||||
void Batch3D::vertex(glm::vec3 point,
|
void Batch3D::vertex(
|
||||||
|
glm::vec3 point,
|
||||||
glm::vec2 uvpoint,
|
glm::vec2 uvpoint,
|
||||||
float r, float g, float b, float a) {
|
float r, float g, float b, float a
|
||||||
|
) {
|
||||||
buffer[index++] = point.x;
|
buffer[index++] = point.x;
|
||||||
buffer[index++] = point.y;
|
buffer[index++] = point.y;
|
||||||
buffer[index++] = point.z;
|
buffer[index++] = point.z;
|
||||||
@ -99,10 +104,10 @@ void Batch3D::face(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Batch3D::texture(Texture* new_texture){
|
void Batch3D::texture(Texture* new_texture){
|
||||||
if (_texture == new_texture)
|
if (currentTexture == new_texture)
|
||||||
return;
|
return;
|
||||||
flush();
|
flush();
|
||||||
_texture = new_texture;
|
currentTexture = new_texture;
|
||||||
if (new_texture == nullptr)
|
if (new_texture == nullptr)
|
||||||
blank->bind();
|
blank->bind();
|
||||||
else
|
else
|
||||||
@ -166,7 +171,9 @@ inline glm::vec4 do_tint(float value) {
|
|||||||
return glm::vec4(value, value, value, 1.0f);
|
return glm::vec4(value, value, value, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch3D::xSprite(float w, float h, const UVRegion& uv, const glm::vec4 tint, bool shading) {
|
void Batch3D::xSprite(
|
||||||
|
float w, float h, const UVRegion& uv, const glm::vec4 tint, bool shading
|
||||||
|
) {
|
||||||
face(
|
face(
|
||||||
glm::vec3(-w * 0.25f, 0.0f, -w * 0.25f),
|
glm::vec3(-w * 0.25f, 0.0f, -w * 0.25f),
|
||||||
w, h,
|
w, h,
|
||||||
@ -244,13 +251,13 @@ void Batch3D::point(glm::vec3 coord, glm::vec4 tint) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Batch3D::flush() {
|
void Batch3D::flush() {
|
||||||
mesh->reload(buffer, index / B3D_VERTEX_SIZE);
|
mesh->reload(buffer.get(), index / B3D_VERTEX_SIZE);
|
||||||
mesh->draw();
|
mesh->draw();
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch3D::flushPoints() {
|
void Batch3D::flushPoints() {
|
||||||
mesh->reload(buffer, index / B3D_VERTEX_SIZE);
|
mesh->reload(buffer.get(), index / B3D_VERTEX_SIZE);
|
||||||
mesh->draw(GL_POINTS);
|
mesh->draw(GL_POINTS);
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,28 +12,35 @@ class Mesh;
|
|||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
class Batch3D {
|
class Batch3D {
|
||||||
float* buffer;
|
std::unique_ptr<float[]> buffer;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
std::unique_ptr<Mesh> mesh;
|
std::unique_ptr<Mesh> mesh;
|
||||||
std::unique_ptr<Texture> blank;
|
std::unique_ptr<Texture> blank;
|
||||||
size_t index;
|
size_t index;
|
||||||
|
|
||||||
Texture* _texture;
|
Texture* currentTexture;
|
||||||
|
|
||||||
void vertex(float x, float y, float z,
|
void vertex(
|
||||||
|
float x, float y, float z,
|
||||||
float u, float v,
|
float u, float v,
|
||||||
float r, float g, float b, float a);
|
float r, float g, float b, float a
|
||||||
void vertex(glm::vec3 coord,
|
);
|
||||||
|
void vertex(
|
||||||
|
glm::vec3 coord,
|
||||||
float u, float v,
|
float u, float v,
|
||||||
float r, float g, float b, float a);
|
float r, float g, float b, float a
|
||||||
void vertex(glm::vec3 point, glm::vec2 uvpoint,
|
);
|
||||||
float r, float g, float b, float a);
|
void vertex(
|
||||||
|
glm::vec3 point, glm::vec2 uvpoint,
|
||||||
void face(const glm::vec3& coord, float w, float h,
|
float r, float g, float b, float a
|
||||||
|
);
|
||||||
|
void face(
|
||||||
|
const glm::vec3& coord, float w, float h,
|
||||||
const glm::vec3& axisX,
|
const glm::vec3& axisX,
|
||||||
const glm::vec3& axisY,
|
const glm::vec3& axisY,
|
||||||
const UVRegion& region,
|
const UVRegion& region,
|
||||||
const glm::vec4& tint);
|
const glm::vec4& tint
|
||||||
|
);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Batch3D(size_t capacity);
|
Batch3D(size_t capacity);
|
||||||
|
|||||||
@ -98,7 +98,7 @@ glshader compile_shader(GLenum type, const GLchar* source, const std::string& fi
|
|||||||
return glshader(new GLuint(shader), shader_deleter);
|
return glshader(new GLuint(shader), shader_deleter);
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader* Shader::create(
|
std::unique_ptr<Shader> Shader::create(
|
||||||
const std::string& vertexFile,
|
const std::string& vertexFile,
|
||||||
const std::string& fragmentFile,
|
const std::string& fragmentFile,
|
||||||
const std::string& vertexCode,
|
const std::string& vertexCode,
|
||||||
@ -125,5 +125,5 @@ Shader* Shader::create(
|
|||||||
"shader program linking failed:\n"+std::string(infoLog)
|
"shader program linking failed:\n"+std::string(infoLog)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return new Shader(id);
|
return std::make_unique<Shader>(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include "../../typedefs.hpp"
|
#include "../../typedefs.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ public:
|
|||||||
/// @param vertexSource vertex shader source code
|
/// @param vertexSource vertex shader source code
|
||||||
/// @param fragmentSource fragment shader source code
|
/// @param fragmentSource fragment shader source code
|
||||||
/// @return linked shader program containing vertex and fragment shaders
|
/// @return linked shader program containing vertex and fragment shaders
|
||||||
static Shader* create(
|
static std::unique_ptr<Shader> create(
|
||||||
const std::string& vertexFile,
|
const std::string& vertexFile,
|
||||||
const std::string& fragmentFile,
|
const std::string& fragmentFile,
|
||||||
const std::string& vertexSource,
|
const std::string& vertexSource,
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
#include "../../typedefs.hpp"
|
#include "../../typedefs.hpp"
|
||||||
#include "ImageData.hpp"
|
#include "ImageData.hpp"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class Texture {
|
class Texture {
|
||||||
|
|||||||
@ -44,13 +44,18 @@ std::unique_ptr<ImageData> BlocksPreview::draw(
|
|||||||
break;
|
break;
|
||||||
case BlockModel::aabb:
|
case BlockModel::aabb:
|
||||||
{
|
{
|
||||||
glm::vec3 hitbox = glm::vec3();
|
glm::vec3 hitbox {};
|
||||||
for (const auto& box : def->hitboxes)
|
for (const auto& box : def->hitboxes) {
|
||||||
hitbox = glm::max(hitbox, box.size());
|
hitbox = glm::max(hitbox, box.size());
|
||||||
offset.y += (1.0f - hitbox).y * 0.5f;
|
}
|
||||||
|
offset = glm::vec3(1, 1, 0.0f);
|
||||||
shader->uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset));
|
shader->uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset));
|
||||||
batch->blockCube(hitbox * glm::vec3(size * 0.63f),
|
batch->cube(
|
||||||
texfaces, glm::vec4(1.0f), !def->rt.emissive);
|
-hitbox * glm::vec3(size * 0.63f)*0.5f * glm::vec3(1,1,-1),
|
||||||
|
hitbox * glm::vec3(size * 0.63f),
|
||||||
|
texfaces, glm::vec4(1.0f),
|
||||||
|
!def->rt.emissive
|
||||||
|
);
|
||||||
}
|
}
|
||||||
batch->flush();
|
batch->flush();
|
||||||
break;
|
break;
|
||||||
@ -138,7 +143,7 @@ std::unique_ptr<Atlas> BlocksPreview::build(
|
|||||||
shader->uniformMatrix("u_projview",
|
shader->uniformMatrix("u_projview",
|
||||||
glm::ortho(0.0f, float(iconSize), 0.0f, float(iconSize),
|
glm::ortho(0.0f, float(iconSize), 0.0f, float(iconSize),
|
||||||
-100.0f, 100.0f) *
|
-100.0f, 100.0f) *
|
||||||
glm::lookAt(glm::vec3(2, 2, 2),
|
glm::lookAt(glm::vec3(0.57735f),
|
||||||
glm::vec3(0.0f),
|
glm::vec3(0.0f),
|
||||||
glm::vec3(0, 1, 0)));
|
glm::vec3(0, 1, 0)));
|
||||||
|
|
||||||
|
|||||||
@ -219,10 +219,13 @@ void BlocksRenderer::blockXSprite(int x, int y, int z,
|
|||||||
// HINT: texture faces order: {east, west, bottom, top, south, north}
|
// HINT: texture faces order: {east, west, bottom, top, south, north}
|
||||||
|
|
||||||
/* AABB blocks render method */
|
/* AABB blocks render method */
|
||||||
void BlocksRenderer::blockAABB(const ivec3& icoord,
|
void BlocksRenderer::blockAABB(
|
||||||
|
const ivec3& icoord,
|
||||||
const UVRegion(&texfaces)[6],
|
const UVRegion(&texfaces)[6],
|
||||||
const Block* block, ubyte rotation,
|
const Block* block,
|
||||||
bool lights) {
|
ubyte rotation,
|
||||||
|
bool lights
|
||||||
|
) {
|
||||||
if (block->hitboxes.empty()) {
|
if (block->hitboxes.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -301,11 +304,13 @@ void BlocksRenderer::blockCustomModel(const ivec3& icoord,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Fastest solid shaded blocks render method */
|
/* Fastest solid shaded blocks render method */
|
||||||
void BlocksRenderer::blockCube(int x, int y, int z,
|
void BlocksRenderer::blockCube(
|
||||||
|
int x, int y, int z,
|
||||||
const UVRegion(&texfaces)[6],
|
const UVRegion(&texfaces)[6],
|
||||||
const Block* block,
|
const Block* block,
|
||||||
ubyte states,
|
blockstate states,
|
||||||
bool lights) {
|
bool lights
|
||||||
|
) {
|
||||||
ubyte group = block->drawGroup;
|
ubyte group = block->drawGroup;
|
||||||
|
|
||||||
vec3 X(1, 0, 0);
|
vec3 X(1, 0, 0);
|
||||||
@ -314,7 +319,7 @@ void BlocksRenderer::blockCube(int x, int y, int z,
|
|||||||
vec3 coord(x, y, z);
|
vec3 coord(x, y, z);
|
||||||
if (block->rotatable) {
|
if (block->rotatable) {
|
||||||
auto& rotations = block->rotations;
|
auto& rotations = block->rotations;
|
||||||
auto& orient = rotations.variants[states & BLOCK_ROT_MASK];
|
auto& orient = rotations.variants[states.rotation];
|
||||||
X = orient.axisX;
|
X = orient.axisX;
|
||||||
Y = orient.axisY;
|
Y = orient.axisY;
|
||||||
Z = orient.axisZ;
|
Z = orient.axisZ;
|
||||||
@ -423,7 +428,7 @@ void BlocksRenderer::render(const voxel* voxels) {
|
|||||||
int z = (i / CHUNK_D) % CHUNK_W;
|
int z = (i / CHUNK_D) % CHUNK_W;
|
||||||
switch (def.model) {
|
switch (def.model) {
|
||||||
case BlockModel::block:
|
case BlockModel::block:
|
||||||
blockCube(x, y, z, texfaces, &def, vox.states, !def.rt.emissive);
|
blockCube(x, y, z, texfaces, &def, vox.state, !def.rt.emissive);
|
||||||
break;
|
break;
|
||||||
case BlockModel::xsprite: {
|
case BlockModel::xsprite: {
|
||||||
blockXSprite(x, y, z, vec3(1.0f),
|
blockXSprite(x, y, z, vec3(1.0f),
|
||||||
@ -431,11 +436,11 @@ void BlocksRenderer::render(const voxel* voxels) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BlockModel::aabb: {
|
case BlockModel::aabb: {
|
||||||
blockAABB(ivec3(x,y,z), texfaces, &def, vox.rotation(), !def.rt.emissive);
|
blockAABB(ivec3(x,y,z), texfaces, &def, vox.state.rotation, !def.rt.emissive);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BlockModel::custom: {
|
case BlockModel::custom: {
|
||||||
blockCustomModel(ivec3(x, y, z), &def, vox.rotation(), !def.rt.emissive);
|
blockCustomModel(ivec3(x, y, z), &def, vox.state.rotation, !def.rt.emissive);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -70,16 +70,33 @@ class BlocksRenderer {
|
|||||||
const UVRegion& texreg,
|
const UVRegion& texreg,
|
||||||
bool lights);
|
bool lights);
|
||||||
|
|
||||||
void blockCube(int x, int y, int z, const UVRegion(&faces)[6], const Block* block, ubyte states, bool lights);
|
void blockCube(
|
||||||
void blockAABB(const glm::ivec3& coord,
|
int x, int y, int z,
|
||||||
|
const UVRegion(&faces)[6],
|
||||||
|
const Block* block,
|
||||||
|
blockstate states,
|
||||||
|
bool lights
|
||||||
|
);
|
||||||
|
void blockAABB(
|
||||||
|
const glm::ivec3& coord,
|
||||||
const UVRegion(&faces)[6],
|
const UVRegion(&faces)[6],
|
||||||
const Block* block,
|
const Block* block,
|
||||||
ubyte rotation,
|
ubyte rotation,
|
||||||
bool lights);
|
bool lights
|
||||||
void blockXSprite(int x, int y, int z, const glm::vec3& size, const UVRegion& face1, const UVRegion& face2, float spread);
|
);
|
||||||
void blockCustomModel(const glm::ivec3& icoord,
|
void blockXSprite(
|
||||||
const Block* block, ubyte rotation,
|
int x, int y, int z,
|
||||||
bool lights);
|
const glm::vec3& size,
|
||||||
|
const UVRegion& face1,
|
||||||
|
const UVRegion& face2,
|
||||||
|
float spread
|
||||||
|
);
|
||||||
|
void blockCustomModel(
|
||||||
|
const glm::ivec3& icoord,
|
||||||
|
const Block* block,
|
||||||
|
ubyte rotation,
|
||||||
|
bool lights
|
||||||
|
);
|
||||||
|
|
||||||
bool isOpenForLight(int x, int y, int z) const;
|
bool isOpenForLight(int x, int y, int z) const;
|
||||||
bool isOpen(int x, int y, int z, ubyte group) const;
|
bool isOpen(int x, int y, int z, ubyte group) const;
|
||||||
|
|||||||
@ -56,19 +56,16 @@ ChunksRenderer::~ChunksRenderer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Mesh> ChunksRenderer::render(std::shared_ptr<Chunk> chunk, bool important) {
|
std::shared_ptr<Mesh> ChunksRenderer::render(std::shared_ptr<Chunk> chunk, bool important) {
|
||||||
chunk->setModified(false);
|
chunk->flags.modified = false;
|
||||||
|
|
||||||
if (important) {
|
if (important) {
|
||||||
auto mesh = renderer->render(chunk.get(), level->chunksStorage.get());
|
auto mesh = renderer->render(chunk.get(), level->chunksStorage.get());
|
||||||
meshes[glm::ivec2(chunk->x, chunk->z)] = mesh;
|
meshes[glm::ivec2(chunk->x, chunk->z)] = mesh;
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::ivec2 key(chunk->x, chunk->z);
|
glm::ivec2 key(chunk->x, chunk->z);
|
||||||
if (inwork.find(key) != inwork.end()) {
|
if (inwork.find(key) != inwork.end()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inwork[key] = true;
|
inwork[key] = true;
|
||||||
threadPool.enqueueJob(chunk);
|
threadPool.enqueueJob(chunk);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -86,7 +83,7 @@ std::shared_ptr<Mesh> ChunksRenderer::getOrRender(std::shared_ptr<Chunk> chunk,
|
|||||||
if (found == meshes.end()) {
|
if (found == meshes.end()) {
|
||||||
return render(chunk, important);
|
return render(chunk, important);
|
||||||
}
|
}
|
||||||
if (chunk->isModified()) {
|
if (chunk->flags.modified) {
|
||||||
render(chunk, important);
|
render(chunk, important);
|
||||||
}
|
}
|
||||||
return found->second;
|
return found->second;
|
||||||
|
|||||||
@ -37,6 +37,9 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include <glm/ext.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
bool WorldRenderer::showChunkBorders = false;
|
bool WorldRenderer::showChunkBorders = false;
|
||||||
|
|
||||||
WorldRenderer::WorldRenderer(Engine* engine, LevelFrontend* frontend, Player* player)
|
WorldRenderer::WorldRenderer(Engine* engine, LevelFrontend* frontend, Player* player)
|
||||||
@ -76,7 +79,7 @@ bool WorldRenderer::drawChunk(
|
|||||||
bool culling
|
bool culling
|
||||||
){
|
){
|
||||||
auto chunk = level->chunks->chunks[index];
|
auto chunk = level->chunks->chunks[index];
|
||||||
if (!chunk->isLighted()) {
|
if (!chunk->flags.lighted) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
float distance = glm::distance(
|
float distance = glm::distance(
|
||||||
@ -160,6 +163,7 @@ void WorldRenderer::renderLevel(
|
|||||||
shader->use();
|
shader->use();
|
||||||
shader->uniformMatrix("u_proj", camera->getProjection());
|
shader->uniformMatrix("u_proj", camera->getProjection());
|
||||||
shader->uniformMatrix("u_view", camera->getView());
|
shader->uniformMatrix("u_view", camera->getView());
|
||||||
|
shader->uniform1f("u_timer", Window::time());
|
||||||
shader->uniform1f("u_gamma", settings.graphics.gamma.get());
|
shader->uniform1f("u_gamma", settings.graphics.gamma.get());
|
||||||
shader->uniform1f("u_fogFactor", fogFactor);
|
shader->uniform1f("u_fogFactor", fogFactor);
|
||||||
shader->uniform1f("u_fogCurve", settings.graphics.fogCurve.get());
|
shader->uniform1f("u_fogCurve", settings.graphics.fogCurve.get());
|
||||||
@ -194,19 +198,19 @@ void WorldRenderer::renderBlockSelection(Camera* camera, Shader* linesShader) {
|
|||||||
auto indices = level->content->getIndices();
|
auto indices = level->content->getIndices();
|
||||||
blockid_t id = PlayerController::selectedBlockId;
|
blockid_t id = PlayerController::selectedBlockId;
|
||||||
auto block = indices->getBlockDef(id);
|
auto block = indices->getBlockDef(id);
|
||||||
const glm::vec3 pos = PlayerController::selectedBlockPosition;
|
const glm::ivec3 pos = player->selectedBlockPosition;
|
||||||
const glm::vec3 point = PlayerController::selectedPointPosition;
|
const glm::vec3 point = PlayerController::selectedPointPosition;
|
||||||
const glm::vec3 norm = PlayerController::selectedBlockNormal;
|
const glm::vec3 norm = PlayerController::selectedBlockNormal;
|
||||||
|
|
||||||
const std::vector<AABB>& hitboxes = block->rotatable
|
const std::vector<AABB>& hitboxes = block->rotatable
|
||||||
? block->rt.hitboxes[PlayerController::selectedBlockStates]
|
? block->rt.hitboxes[PlayerController::selectedBlockRotation]
|
||||||
: block->hitboxes;
|
: block->hitboxes;
|
||||||
|
|
||||||
linesShader->use();
|
linesShader->use();
|
||||||
linesShader->uniformMatrix("u_projview", camera->getProjView());
|
linesShader->uniformMatrix("u_projview", camera->getProjView());
|
||||||
lineBatch->lineWidth(2.0f);
|
lineBatch->lineWidth(2.0f);
|
||||||
for (auto& hitbox: hitboxes) {
|
for (auto& hitbox: hitboxes) {
|
||||||
const glm::vec3 center = pos + hitbox.center();
|
const glm::vec3 center = glm::vec3(pos) + hitbox.center();
|
||||||
const glm::vec3 size = hitbox.size();
|
const glm::vec3 size = hitbox.size();
|
||||||
lineBatch->box(center, size + glm::vec3(0.02), glm::vec4(0.f, 0.f, 0.f, 0.5f));
|
lineBatch->box(center, size + glm::vec3(0.02), glm::vec4(0.f, 0.f, 0.f, 0.5f));
|
||||||
if (player->debug) {
|
if (player->debug) {
|
||||||
@ -274,11 +278,12 @@ void WorldRenderer::draw(
|
|||||||
bool hudVisible,
|
bool hudVisible,
|
||||||
PostProcessing* postProcessing
|
PostProcessing* postProcessing
|
||||||
){
|
){
|
||||||
|
auto world = level->getWorld();
|
||||||
const Viewport& vp = pctx.getViewport();
|
const Viewport& vp = pctx.getViewport();
|
||||||
camera->aspect = vp.getWidth() / static_cast<float>(vp.getHeight());
|
camera->aspect = vp.getWidth() / static_cast<float>(vp.getHeight());
|
||||||
|
|
||||||
const EngineSettings& settings = engine->getSettings();
|
const EngineSettings& settings = engine->getSettings();
|
||||||
skybox->refresh(pctx, level->getWorld()->daytime, 1.0f+fog*2.0f, 4);
|
skybox->refresh(pctx, world->daytime, 1.0f+world->fog*2.0f, 4);
|
||||||
|
|
||||||
Assets* assets = engine->getAssets();
|
Assets* assets = engine->getAssets();
|
||||||
Shader* linesShader = assets->getShader("lines");
|
Shader* linesShader = assets->getShader("lines");
|
||||||
@ -291,7 +296,7 @@ void WorldRenderer::draw(
|
|||||||
Window::clearDepth();
|
Window::clearDepth();
|
||||||
|
|
||||||
// Drawing background sky plane
|
// Drawing background sky plane
|
||||||
skybox->draw(pctx, camera, assets, level->getWorld()->daytime, fog);
|
skybox->draw(pctx, camera, assets, world->daytime, world->fog);
|
||||||
|
|
||||||
// Actually world render with depth buffer on
|
// Actually world render with depth buffer on
|
||||||
{
|
{
|
||||||
@ -355,5 +360,3 @@ void WorldRenderer::drawBorders(int sx, int sy, int sz, int ex, int ey, int ez)
|
|||||||
}
|
}
|
||||||
lineBatch->render();
|
lineBatch->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
float WorldRenderer::fog = 0.0f;
|
|
||||||
|
|||||||
@ -8,8 +8,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/ext.hpp>
|
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
|
||||||
|
|
||||||
class Level;
|
class Level;
|
||||||
class Player;
|
class Player;
|
||||||
@ -76,8 +74,6 @@ public:
|
|||||||
Camera* camera,
|
Camera* camera,
|
||||||
const EngineSettings& settings
|
const EngineSettings& settings
|
||||||
);
|
);
|
||||||
|
|
||||||
static float fog;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
#include "GUI.hpp"
|
#include "GUI.hpp"
|
||||||
|
|
||||||
|
#include "gui_util.hpp"
|
||||||
|
|
||||||
#include "elements/UINode.hpp"
|
#include "elements/UINode.hpp"
|
||||||
|
#include "elements/Label.hpp"
|
||||||
#include "elements/Menu.hpp"
|
#include "elements/Menu.hpp"
|
||||||
|
|
||||||
#include "../../assets/Assets.hpp"
|
#include "../../assets/Assets.hpp"
|
||||||
#include "../../frontend/UiDocument.hpp"
|
#include "../../frontend/UiDocument.hpp"
|
||||||
|
#include "../../frontend/locale.hpp"
|
||||||
#include "../../graphics/core/Batch2D.hpp"
|
#include "../../graphics/core/Batch2D.hpp"
|
||||||
#include "../../graphics/core/Shader.hpp"
|
#include "../../graphics/core/Shader.hpp"
|
||||||
#include "../../graphics/core/DrawContext.hpp"
|
#include "../../graphics/core/DrawContext.hpp"
|
||||||
@ -27,6 +32,15 @@ GUI::GUI() {
|
|||||||
menu->setId("menu");
|
menu->setId("menu");
|
||||||
container->add(menu);
|
container->add(menu);
|
||||||
container->setScrollable(false);
|
container->setScrollable(false);
|
||||||
|
|
||||||
|
tooltip = guiutil::create(
|
||||||
|
"<container color='#000000A0' interactive='false' z-index='999'>"
|
||||||
|
"<label id='tooltip.label' pos='2' autoresize='true'></label>"
|
||||||
|
"</container>"
|
||||||
|
);
|
||||||
|
store("tooltip", tooltip);
|
||||||
|
store("tooltip.label", UINode::find(tooltip, "tooltip.label"));
|
||||||
|
container->add(tooltip);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI::~GUI() {
|
GUI::~GUI() {
|
||||||
@ -37,7 +51,7 @@ std::shared_ptr<Menu> GUI::getMenu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GUI::onAssetsLoad(Assets* assets) {
|
void GUI::onAssetsLoad(Assets* assets) {
|
||||||
assets->store(new UiDocument(
|
assets->store(std::make_unique<UiDocument>(
|
||||||
"core:root",
|
"core:root",
|
||||||
uidocscript {},
|
uidocscript {},
|
||||||
std::dynamic_pointer_cast<gui::UINode>(container),
|
std::dynamic_pointer_cast<gui::UINode>(container),
|
||||||
@ -45,10 +59,41 @@ void GUI::onAssetsLoad(Assets* assets) {
|
|||||||
), "core:root");
|
), "core:root");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUI::resetTooltip() {
|
||||||
|
tooltipTimer = 0.0f;
|
||||||
|
tooltip->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUI::updateTooltip(float delta) {
|
||||||
|
if (hover == nullptr || !hover->isInside(Events::cursor)) {
|
||||||
|
return resetTooltip();
|
||||||
|
}
|
||||||
|
if (tooltipTimer + delta >= hover->getTooltipDelay()) {
|
||||||
|
auto label = std::dynamic_pointer_cast<gui::Label>(get("tooltip.label"));
|
||||||
|
const auto& text = hover->getTooltip();
|
||||||
|
if (text.empty() && tooltip->isVisible()) {
|
||||||
|
return resetTooltip();
|
||||||
|
}
|
||||||
|
if (label && !text.empty()) {
|
||||||
|
tooltip->setVisible(true);
|
||||||
|
label->setText(langs::get(text));
|
||||||
|
auto size = label->getSize()+glm::vec2(4.0f);
|
||||||
|
auto pos = Events::cursor+glm::vec2(10.0f);
|
||||||
|
auto rootSize = container->getSize();
|
||||||
|
pos.x = glm::min(pos.x, rootSize.x-size.x);
|
||||||
|
pos.y = glm::min(pos.y, rootSize.y-size.y);
|
||||||
|
tooltip->setSize(size);
|
||||||
|
tooltip->setPos(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tooltipTimer += delta;
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Mouse related input and logic handling
|
/// @brief Mouse related input and logic handling
|
||||||
void GUI::actMouse(float delta) {
|
void GUI::actMouse(float delta) {
|
||||||
|
float mouseDelta = glm::length(Events::delta);
|
||||||
doubleClicked = false;
|
doubleClicked = false;
|
||||||
doubleClickTimer += delta + glm::length(Events::delta) * 0.1f;
|
doubleClickTimer += delta + mouseDelta * 0.1f;
|
||||||
|
|
||||||
auto hover = container->getAt(Events::cursor, nullptr);
|
auto hover = container->getAt(Events::cursor, nullptr);
|
||||||
if (this->hover && this->hover != hover) {
|
if (this->hover && this->hover != hover) {
|
||||||
@ -134,8 +179,14 @@ void GUI::act(float delta, const Viewport& vp) {
|
|||||||
container->act(delta);
|
container->act(delta);
|
||||||
auto prevfocus = focus;
|
auto prevfocus = focus;
|
||||||
|
|
||||||
|
updateTooltip(delta);
|
||||||
if (!Events::_cursor_locked) {
|
if (!Events::_cursor_locked) {
|
||||||
actMouse(delta);
|
actMouse(delta);
|
||||||
|
} else {
|
||||||
|
if (hover) {
|
||||||
|
hover->setHover(false);
|
||||||
|
hover = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (focus) {
|
if (focus) {
|
||||||
|
|||||||
@ -54,21 +54,25 @@ namespace gui {
|
|||||||
/// @brief The main UI controller
|
/// @brief The main UI controller
|
||||||
class GUI {
|
class GUI {
|
||||||
std::shared_ptr<Container> container;
|
std::shared_ptr<Container> container;
|
||||||
std::shared_ptr<UINode> hover = nullptr;
|
std::shared_ptr<UINode> hover;
|
||||||
std::shared_ptr<UINode> pressed = nullptr;
|
std::shared_ptr<UINode> pressed;
|
||||||
std::shared_ptr<UINode> focus = nullptr;
|
std::shared_ptr<UINode> focus;
|
||||||
|
std::shared_ptr<UINode> tooltip;
|
||||||
std::unordered_map<std::string, std::shared_ptr<UINode>> storage;
|
std::unordered_map<std::string, std::shared_ptr<UINode>> storage;
|
||||||
|
|
||||||
std::unique_ptr<Camera> uicamera;
|
std::unique_ptr<Camera> uicamera;
|
||||||
std::shared_ptr<Menu> menu;
|
std::shared_ptr<Menu> menu;
|
||||||
std::queue<runnable> postRunnables;
|
std::queue<runnable> postRunnables;
|
||||||
|
|
||||||
|
float tooltipTimer = 0.0f;
|
||||||
float doubleClickTimer = 0.0f;
|
float doubleClickTimer = 0.0f;
|
||||||
float doubleClickDelay = 0.5f;
|
float doubleClickDelay = 0.5f;
|
||||||
bool doubleClicked = false;
|
bool doubleClicked = false;
|
||||||
|
|
||||||
void actMouse(float delta);
|
void actMouse(float delta);
|
||||||
void actFocused();
|
void actFocused();
|
||||||
|
void updateTooltip(float delta);
|
||||||
|
void resetTooltip();
|
||||||
public:
|
public:
|
||||||
GUI();
|
GUI();
|
||||||
~GUI();
|
~GUI();
|
||||||
|
|||||||
@ -7,7 +7,8 @@
|
|||||||
using namespace gui;
|
using namespace gui;
|
||||||
|
|
||||||
CheckBox::CheckBox(bool checked) : UINode(glm::vec2(32.0f)), checked(checked) {
|
CheckBox::CheckBox(bool checked) : UINode(glm::vec2(32.0f)), checked(checked) {
|
||||||
setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
setColor({0.0f, 0.0f, 0.0f, 0.5f});
|
||||||
|
setHoverColor({0.05f, 0.1f, 0.2f, 0.75f});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckBox::draw(const DrawContext* pctx, Assets*) {
|
void CheckBox::draw(const DrawContext* pctx, Assets*) {
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
namespace gui {
|
namespace gui {
|
||||||
class CheckBox : public UINode {
|
class CheckBox : public UINode {
|
||||||
protected:
|
protected:
|
||||||
glm::vec4 hoverColor {0.05f, 0.1f, 0.2f, 0.75f};
|
|
||||||
glm::vec4 checkColor {1.0f, 1.0f, 1.0f, 0.4f};
|
glm::vec4 checkColor {1.0f, 1.0f, 1.0f, 0.4f};
|
||||||
boolsupplier supplier = nullptr;
|
boolsupplier supplier = nullptr;
|
||||||
boolconsumer consumer = nullptr;
|
boolconsumer consumer = nullptr;
|
||||||
@ -51,6 +50,11 @@ namespace gui {
|
|||||||
virtual bool isChecked() const {
|
virtual bool isChecked() const {
|
||||||
return checkbox->isChecked();
|
return checkbox->isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void setTooltip(const std::wstring& text) override {
|
||||||
|
Panel::setTooltip(text);
|
||||||
|
checkbox->setTooltip(text);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ Container::Container(glm::vec2 size) : UINode(size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<UINode> Container::getAt(glm::vec2 pos, std::shared_ptr<UINode> self) {
|
std::shared_ptr<UINode> Container::getAt(glm::vec2 pos, std::shared_ptr<UINode> self) {
|
||||||
if (!interactive || !isEnabled()) {
|
if (!isInteractive() || !isEnabled()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (!isInside(pos)) return nullptr;
|
if (!isInside(pos)) return nullptr;
|
||||||
@ -127,6 +127,14 @@ void Container::remove(std::shared_ptr<UINode> selected) {
|
|||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Container::remove(const std::string& id) {
|
||||||
|
for (auto& node : nodes) {
|
||||||
|
if (node->getId() == id) {
|
||||||
|
return remove(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Container::clear() {
|
void Container::clear() {
|
||||||
for (auto node : nodes) {
|
for (auto node : nodes) {
|
||||||
node->setParent(nullptr);
|
node->setParent(nullptr);
|
||||||
|
|||||||
@ -26,6 +26,7 @@ namespace gui {
|
|||||||
virtual void add(std::shared_ptr<UINode> node, glm::vec2 pos);
|
virtual void add(std::shared_ptr<UINode> node, glm::vec2 pos);
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
virtual void remove(std::shared_ptr<UINode> node);
|
virtual void remove(std::shared_ptr<UINode> node);
|
||||||
|
virtual void remove(const std::string& id);
|
||||||
virtual void scrolled(int value) override;
|
virtual void scrolled(int value) override;
|
||||||
virtual void setScrollable(bool flag);
|
virtual void setScrollable(bool flag);
|
||||||
void listenInterval(float interval, ontimeout callback, int repeat=-1);
|
void listenInterval(float interval, ontimeout callback, int repeat=-1);
|
||||||
|
|||||||
@ -33,3 +33,11 @@ void Image::setAutoResize(bool flag) {
|
|||||||
bool Image::isAutoResize() const {
|
bool Image::isAutoResize() const {
|
||||||
return autoresize;
|
return autoresize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& Image::getTexture() const {
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::setTexture(const std::string& name) {
|
||||||
|
texture = name;
|
||||||
|
}
|
||||||
|
|||||||
@ -15,6 +15,8 @@ namespace gui {
|
|||||||
|
|
||||||
virtual void setAutoResize(bool flag);
|
virtual void setAutoResize(bool flag);
|
||||||
virtual bool isAutoResize() const;
|
virtual bool isAutoResize() const;
|
||||||
|
virtual const std::string& getTexture() const;
|
||||||
|
virtual void setTexture(const std::string& name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
#include "InventoryView.hpp"
|
#include "InventoryView.hpp"
|
||||||
|
|
||||||
#include "../../../assets/Assets.hpp"
|
#include "../../../assets/Assets.hpp"
|
||||||
#include "../../../content/Content.hpp"
|
#include "../../../content/Content.hpp"
|
||||||
#include "../../../frontend/LevelFrontend.hpp"
|
#include "../../../frontend/LevelFrontend.hpp"
|
||||||
|
#include "../../../frontend/locale.hpp"
|
||||||
#include "../../../items/Inventories.hpp"
|
#include "../../../items/Inventories.hpp"
|
||||||
#include "../../../items/Inventory.hpp"
|
#include "../../../items/Inventory.hpp"
|
||||||
#include "../../../items/ItemDef.hpp"
|
#include "../../../items/ItemDef.hpp"
|
||||||
@ -22,7 +24,6 @@
|
|||||||
#include "../../render/BlocksPreview.hpp"
|
#include "../../render/BlocksPreview.hpp"
|
||||||
#include "../GUI.hpp"
|
#include "../GUI.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
using namespace gui;
|
using namespace gui;
|
||||||
@ -108,6 +109,7 @@ SlotView::SlotView(
|
|||||||
layout(layout)
|
layout(layout)
|
||||||
{
|
{
|
||||||
setColor(glm::vec4(0, 0, 0, 0.2f));
|
setColor(glm::vec4(0, 0, 0, 0.2f));
|
||||||
|
setTooltipDelay(0.05f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SlotView::draw(const DrawContext* pctx, Assets* assets) {
|
void SlotView::draw(const DrawContext* pctx, Assets* assets) {
|
||||||
@ -251,11 +253,12 @@ void SlotView::clicked(gui::GUI* gui, mousecode button) {
|
|||||||
stack.setCount(halfremain);
|
stack.setCount(halfremain);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
auto stackDef = content->getIndices()->getItemDef(stack.getItemId());
|
||||||
if (stack.isEmpty()) {
|
if (stack.isEmpty()) {
|
||||||
stack.set(grabbed);
|
stack.set(grabbed);
|
||||||
stack.setCount(1);
|
stack.setCount(1);
|
||||||
grabbed.setCount(grabbed.getCount()-1);
|
grabbed.setCount(grabbed.getCount()-1);
|
||||||
} else if (stack.accepts(grabbed)){
|
} else if (stack.accepts(grabbed) && stack.getCount() < stackDef->stackSize){
|
||||||
stack.setCount(stack.getCount()+1);
|
stack.setCount(stack.getCount()+1);
|
||||||
grabbed.setCount(grabbed.getCount()-1);
|
grabbed.setCount(grabbed.getCount()-1);
|
||||||
}
|
}
|
||||||
@ -270,6 +273,17 @@ void SlotView::onFocus(gui::GUI* gui) {
|
|||||||
clicked(gui, mousecode::BUTTON_1);
|
clicked(gui, mousecode::BUTTON_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::wstring SlotView::getTooltip() const {
|
||||||
|
const auto str = UINode::getTooltip();
|
||||||
|
if (!str.empty() || bound->isEmpty()) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
auto def = content->getIndices()->getItemDef(bound->getItemId());
|
||||||
|
return util::pascal_case(
|
||||||
|
langs::get(util::str2wstr_utf8(def->caption))
|
||||||
|
); // TODO: cache
|
||||||
|
}
|
||||||
|
|
||||||
void SlotView::bind(
|
void SlotView::bind(
|
||||||
int64_t inventoryid,
|
int64_t inventoryid,
|
||||||
ItemStack& stack,
|
ItemStack& stack,
|
||||||
|
|||||||
@ -63,6 +63,7 @@ namespace gui {
|
|||||||
|
|
||||||
virtual void clicked(gui::GUI*, mousecode) override;
|
virtual void clicked(gui::GUI*, mousecode) override;
|
||||||
virtual void onFocus(gui::GUI*) override;
|
virtual void onFocus(gui::GUI*) override;
|
||||||
|
virtual const std::wstring getTooltip() const override;
|
||||||
|
|
||||||
void bind(
|
void bind(
|
||||||
int64_t inventoryid,
|
int64_t inventoryid,
|
||||||
|
|||||||
@ -64,12 +64,28 @@ Label::Label(std::wstring text, std::string fontName)
|
|||||||
cache.update(this->text, multiline, textWrap);
|
cache.update(this->text, multiline, textWrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec2 Label::calcSize() {
|
||||||
|
auto font = cache.font;
|
||||||
|
uint lineHeight = font->getLineHeight();
|
||||||
|
if (cache.lines.size() > 1) {
|
||||||
|
lineHeight *= lineInterval;
|
||||||
|
}
|
||||||
|
return glm::vec2 (
|
||||||
|
cache.font->calcWidth(text),
|
||||||
|
lineHeight * cache.lines.size() + font->getYOffset()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void Label::setText(std::wstring text) {
|
void Label::setText(std::wstring text) {
|
||||||
if (text == this->text && !cache.resetFlag) {
|
if (text == this->text && !cache.resetFlag) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->text = text;
|
this->text = text;
|
||||||
cache.update(this->text, multiline, textWrap);
|
cache.update(this->text, multiline, textWrap);
|
||||||
|
|
||||||
|
if (cache.font && autoresize) {
|
||||||
|
setSize(calcSize());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::wstring& Label::getText() const {
|
const std::wstring& Label::getText() const {
|
||||||
@ -156,10 +172,10 @@ void Label::draw(const DrawContext* pctx, Assets* assets) {
|
|||||||
lineHeight *= lineInterval;
|
lineHeight *= lineInterval;
|
||||||
}
|
}
|
||||||
glm::vec2 size = getSize();
|
glm::vec2 size = getSize();
|
||||||
glm::vec2 newsize (
|
glm::vec2 newsize = calcSize();
|
||||||
font->calcWidth(text),
|
if (autoresize) {
|
||||||
lineHeight * cache.lines.size() + font->getYOffset()
|
setSize(newsize);
|
||||||
);
|
}
|
||||||
|
|
||||||
glm::vec2 pos = calcPos();
|
glm::vec2 pos = calcPos();
|
||||||
switch (align) {
|
switch (align) {
|
||||||
@ -194,6 +210,13 @@ void Label::textSupplier(wstringsupplier supplier) {
|
|||||||
this->supplier = supplier;
|
this->supplier = supplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Label::setAutoResize(bool flag) {
|
||||||
|
this->autoresize = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Label::isAutoResize() const {
|
||||||
|
return autoresize;
|
||||||
|
}
|
||||||
|
|
||||||
void Label::setMultiline(bool multiline) {
|
void Label::setMultiline(bool multiline) {
|
||||||
if (multiline != this->multiline) {
|
if (multiline != this->multiline) {
|
||||||
|
|||||||
@ -24,6 +24,8 @@ namespace gui {
|
|||||||
|
|
||||||
class Label : public UINode {
|
class Label : public UINode {
|
||||||
LabelCache cache;
|
LabelCache cache;
|
||||||
|
|
||||||
|
glm::vec2 calcSize();
|
||||||
protected:
|
protected:
|
||||||
std::wstring text;
|
std::wstring text;
|
||||||
std::string fontName;
|
std::string fontName;
|
||||||
@ -47,6 +49,9 @@ namespace gui {
|
|||||||
|
|
||||||
/// @brief Text line height multiplied by line interval
|
/// @brief Text line height multiplied by line interval
|
||||||
int totalLineHeight = 1;
|
int totalLineHeight = 1;
|
||||||
|
|
||||||
|
/// @brief Auto resize label to fit text
|
||||||
|
bool autoresize = false;
|
||||||
public:
|
public:
|
||||||
Label(std::string text, std::string fontName="normal");
|
Label(std::string text, std::string fontName="normal");
|
||||||
Label(std::wstring text, std::string fontName="normal");
|
Label(std::wstring text, std::string fontName="normal");
|
||||||
@ -95,6 +100,9 @@ namespace gui {
|
|||||||
|
|
||||||
virtual void textSupplier(wstringsupplier supplier);
|
virtual void textSupplier(wstringsupplier supplier);
|
||||||
|
|
||||||
|
virtual void setAutoResize(bool flag);
|
||||||
|
virtual bool isAutoResize() const;
|
||||||
|
|
||||||
virtual void setMultiline(bool multiline);
|
virtual void setMultiline(bool multiline);
|
||||||
virtual bool isMultiline() const;
|
virtual bool isMultiline() const;
|
||||||
|
|
||||||
|
|||||||
@ -337,6 +337,9 @@ inline std::wstring get_alphabet(wchar_t c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::tokenSelectAt(int index) {
|
void TextBox::tokenSelectAt(int index) {
|
||||||
|
if (input.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int left = index;
|
int left = index;
|
||||||
int right = index;
|
int right = index;
|
||||||
|
|
||||||
@ -369,7 +372,7 @@ void TextBox::click(GUI*, int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::mouseMove(GUI*, int x, int y) {
|
void TextBox::mouseMove(GUI*, int x, int y) {
|
||||||
ssize_t index = calcIndexAt(x, y);
|
ptrdiff_t index = calcIndexAt(x, y);
|
||||||
setCaret(index);
|
setCaret(index);
|
||||||
extendSelection(index);
|
extendSelection(index);
|
||||||
resetMaxLocalCaret();
|
resetMaxLocalCaret();
|
||||||
@ -452,7 +455,7 @@ void TextBox::stepDefaultUp(bool shiftPressed, bool breakSelection) {
|
|||||||
uint offset = std::min(size_t(maxLocalCaret), getLineLength(caretLine-1)-1);
|
uint offset = std::min(size_t(maxLocalCaret), getLineLength(caretLine-1)-1);
|
||||||
setCaret(label->getTextLineOffset(caretLine-1) + offset);
|
setCaret(label->getTextLineOffset(caretLine-1) + offset);
|
||||||
} else {
|
} else {
|
||||||
setCaret(0UL);
|
setCaret(static_cast<size_t>(0));
|
||||||
}
|
}
|
||||||
if (shiftPressed) {
|
if (shiftPressed) {
|
||||||
if (selectionStart == selectionEnd) {
|
if (selectionStart == selectionEnd) {
|
||||||
@ -652,11 +655,11 @@ void TextBox::setCaret(size_t position) {
|
|||||||
if (realoffset-width > 0) {
|
if (realoffset-width > 0) {
|
||||||
setTextOffset(textOffset + realoffset-width);
|
setTextOffset(textOffset + realoffset-width);
|
||||||
} else if (realoffset < 0) {
|
} else if (realoffset < 0) {
|
||||||
setTextOffset(std::max(textOffset + realoffset, 0LU));
|
setTextOffset(std::max(textOffset + realoffset, static_cast<size_t>(0)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::setCaret(ssize_t position) {
|
void TextBox::setCaret(ptrdiff_t position) {
|
||||||
if (position < 0) {
|
if (position < 0) {
|
||||||
setCaret(static_cast<size_t>(input.length() + position + 1));
|
setCaret(static_cast<size_t>(input.length() + position + 1));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -120,7 +120,7 @@ namespace gui {
|
|||||||
|
|
||||||
/// @brief Set caret position in the text
|
/// @brief Set caret position in the text
|
||||||
/// @param position integer in range [-text.length(), text.length()]
|
/// @param position integer in range [-text.length(), text.length()]
|
||||||
virtual void setCaret(ssize_t position);
|
virtual void setCaret(ptrdiff_t position);
|
||||||
|
|
||||||
/// @brief Select part of the text
|
/// @brief Select part of the text
|
||||||
/// @param start index of the first selected character
|
/// @param start index of the first selected character
|
||||||
|
|||||||
@ -13,6 +13,9 @@ UINode::~UINode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool UINode::isVisible() const {
|
bool UINode::isVisible() const {
|
||||||
|
if (visible && parent) {
|
||||||
|
return parent->isVisible();
|
||||||
|
}
|
||||||
return visible;
|
return visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +110,7 @@ bool UINode::isInside(glm::vec2 point) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<UINode> UINode::getAt(glm::vec2 point, std::shared_ptr<UINode> self) {
|
std::shared_ptr<UINode> UINode::getAt(glm::vec2 point, std::shared_ptr<UINode> self) {
|
||||||
if (!interactive || !enabled) {
|
if (!isInteractive() || !enabled) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return isInside(point) ? self : nullptr;
|
return isInside(point) ? self : nullptr;
|
||||||
@ -129,6 +132,22 @@ bool UINode::isResizing() const {
|
|||||||
return resizing;
|
return resizing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UINode::setTooltip(const std::wstring& text) {
|
||||||
|
this->tooltip = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::wstring UINode::getTooltip() const {
|
||||||
|
return tooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UINode::setTooltipDelay(float delay) {
|
||||||
|
tooltipDelay = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
float UINode::getTooltipDelay() const {
|
||||||
|
return tooltipDelay;
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec2 UINode::calcPos() const {
|
glm::vec2 UINode::calcPos() const {
|
||||||
if (parent) {
|
if (parent) {
|
||||||
return pos + parent->calcPos() + parent->contentOffset();
|
return pos + parent->calcPos() + parent->contentOffset();
|
||||||
@ -315,8 +334,18 @@ void UINode::setGravity(Gravity gravity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UINode::isSubnodeOf(const UINode* node) {
|
||||||
|
if (parent == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (parent == node) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return parent->isSubnodeOf(node);
|
||||||
|
}
|
||||||
|
|
||||||
void UINode::getIndices(
|
void UINode::getIndices(
|
||||||
std::shared_ptr<UINode> node,
|
const std::shared_ptr<UINode> node,
|
||||||
std::unordered_map<std::string, std::shared_ptr<UINode>>& map
|
std::unordered_map<std::string, std::shared_ptr<UINode>>& map
|
||||||
) {
|
) {
|
||||||
const std::string& id = node->getId();
|
const std::string& id = node->getId();
|
||||||
@ -330,3 +359,19 @@ void UINode::getIndices(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::shared_ptr<UINode> UINode::find(
|
||||||
|
const std::shared_ptr<UINode> node,
|
||||||
|
const std::string& id
|
||||||
|
) {
|
||||||
|
if (node->getId() == id) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
if (auto container = std::dynamic_pointer_cast<Container>(node)) {
|
||||||
|
for (auto subnode : container->getNodes()) {
|
||||||
|
if (auto found = UINode::find(subnode, id)) {
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|||||||
@ -109,6 +109,10 @@ namespace gui {
|
|||||||
ActionsSet actions;
|
ActionsSet actions;
|
||||||
/// @brief 'ondoubleclick' callbacks
|
/// @brief 'ondoubleclick' callbacks
|
||||||
ActionsSet doubleClickCallbacks;
|
ActionsSet doubleClickCallbacks;
|
||||||
|
/// @brief element tooltip text
|
||||||
|
std::wstring tooltip;
|
||||||
|
/// @brief element tooltip delay
|
||||||
|
float tooltipDelay = 0.5f;
|
||||||
|
|
||||||
UINode(glm::vec2 size);
|
UINode(glm::vec2 size);
|
||||||
public:
|
public:
|
||||||
@ -197,6 +201,12 @@ namespace gui {
|
|||||||
virtual void setResizing(bool flag);
|
virtual void setResizing(bool flag);
|
||||||
virtual bool isResizing() const;
|
virtual bool isResizing() const;
|
||||||
|
|
||||||
|
virtual void setTooltip(const std::wstring& text);
|
||||||
|
virtual const std::wstring getTooltip() const;
|
||||||
|
|
||||||
|
virtual void setTooltipDelay(float delay);
|
||||||
|
virtual float getTooltipDelay() const;
|
||||||
|
|
||||||
virtual glm::vec4 calcColor() const;
|
virtual glm::vec4 calcColor() const;
|
||||||
|
|
||||||
/// @brief Get inner content offset. Used for scroll
|
/// @brief Get inner content offset. Used for scroll
|
||||||
@ -235,11 +245,18 @@ namespace gui {
|
|||||||
|
|
||||||
virtual void setGravity(Gravity gravity);
|
virtual void setGravity(Gravity gravity);
|
||||||
|
|
||||||
|
bool isSubnodeOf(const UINode* node);
|
||||||
|
|
||||||
/// @brief collect all nodes having id
|
/// @brief collect all nodes having id
|
||||||
static void getIndices(
|
static void getIndices(
|
||||||
std::shared_ptr<UINode> node,
|
const std::shared_ptr<UINode> node,
|
||||||
std::unordered_map<std::string, std::shared_ptr<UINode>>& map
|
std::unordered_map<std::string, std::shared_ptr<UINode>>& map
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static std::shared_ptr<UINode> find(
|
||||||
|
const std::shared_ptr<UINode> node,
|
||||||
|
const std::string& id
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -143,6 +143,13 @@ static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& no
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (element->has("tooltip")) {
|
||||||
|
node.setTooltip(util::str2wstr_utf8(element->attr("tooltip").getText()));
|
||||||
|
}
|
||||||
|
if (element->has("tooltip-delay")) {
|
||||||
|
node.setTooltipDelay(element->attr("tooltip-delay").asFloat());
|
||||||
|
}
|
||||||
|
|
||||||
if (auto onclick = create_action(reader, element, "onclick")) {
|
if (auto onclick = create_action(reader, element, "onclick")) {
|
||||||
node.listenAction(onclick);
|
node.listenAction(onclick);
|
||||||
}
|
}
|
||||||
@ -245,6 +252,9 @@ static std::shared_ptr<UINode> readLabel(UiXmlReader& reader, xml::xmlelement el
|
|||||||
reader.getFilename()
|
reader.getFilename()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if (element->has("autoresize")) {
|
||||||
|
label->setAutoResize(element->attr("autoresize").asBool());
|
||||||
|
}
|
||||||
if (element->has("multiline")) {
|
if (element->has("multiline")) {
|
||||||
label->setMultiline(element->attr("multiline").asBool());
|
label->setMultiline(element->attr("multiline").asBool());
|
||||||
if (!element->has("valign")) {
|
if (!element->has("valign")) {
|
||||||
|
|||||||
@ -21,7 +21,7 @@ void LightSolver::add(int x, int y, int z, int emission) {
|
|||||||
addqueue.push(lightentry {x, y, z, ubyte(emission)});
|
addqueue.push(lightentry {x, y, z, ubyte(emission)});
|
||||||
|
|
||||||
Chunk* chunk = chunks->getChunkByVoxel(x, y, z);
|
Chunk* chunk = chunks->getChunkByVoxel(x, y, z);
|
||||||
chunk->setModified(true);
|
chunk->flags.modified = true;
|
||||||
chunk->lightmap.set(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel, emission);
|
chunk->lightmap.set(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel, emission);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ void LightSolver::solve(){
|
|||||||
if (chunk) {
|
if (chunk) {
|
||||||
int lx = x - chunk->x * CHUNK_W;
|
int lx = x - chunk->x * CHUNK_W;
|
||||||
int lz = z - chunk->z * CHUNK_D;
|
int lz = z - chunk->z * CHUNK_D;
|
||||||
chunk->setModified(true);
|
chunk->flags.modified = true;
|
||||||
|
|
||||||
ubyte light = chunk->lightmap.get(lx,y,lz, channel);
|
ubyte light = chunk->lightmap.get(lx,y,lz, channel);
|
||||||
if (light != 0 && light == entry.light-1){
|
if (light != 0 && light == entry.light-1){
|
||||||
@ -96,7 +96,7 @@ void LightSolver::solve(){
|
|||||||
if (chunk) {
|
if (chunk) {
|
||||||
int lx = x - chunk->x * CHUNK_W;
|
int lx = x - chunk->x * CHUNK_W;
|
||||||
int lz = z - chunk->z * CHUNK_D;
|
int lz = z - chunk->z * CHUNK_D;
|
||||||
chunk->setModified(true);
|
chunk->flags.modified = true;
|
||||||
|
|
||||||
ubyte light = chunk->lightmap.get(lx, y, lz, channel);
|
ubyte light = chunk->lightmap.get(lx, y, lz, channel);
|
||||||
voxel& v = chunk->voxels[vox_index(lx, y, lz)];
|
voxel& v = chunk->voxels[vox_index(lx, y, lz)];
|
||||||
|
|||||||
@ -71,7 +71,7 @@ void BlocksController::updateSides(int x, int y, int z) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BlocksController::breakBlock(Player* player, const Block* def, int x, int y, int z) {
|
void BlocksController::breakBlock(Player* player, const Block* def, int x, int y, int z) {
|
||||||
chunks->set(x,y,z, 0, 0);
|
chunks->set(x,y,z, 0, {});
|
||||||
lighting->onBlockSet(x,y,z, 0);
|
lighting->onBlockSet(x,y,z, 0);
|
||||||
if (def->rt.funcsset.onbroken) {
|
if (def->rt.funcsset.onbroken) {
|
||||||
scripting::on_block_broken(player, def, x, y, z);
|
scripting::on_block_broken(player, def, x, y, z);
|
||||||
@ -113,8 +113,9 @@ void BlocksController::onBlocksTick(int tickid, int parts) {
|
|||||||
if ((id + tickid) % parts != 0)
|
if ((id + tickid) % parts != 0)
|
||||||
continue;
|
continue;
|
||||||
auto def = indices->getBlockDef(id);
|
auto def = indices->getBlockDef(id);
|
||||||
if (def->rt.funcsset.onblockstick) {
|
auto interval = def->tickInterval;
|
||||||
scripting::on_blocks_tick(def, tickRate);
|
if (def->rt.funcsset.onblockstick && tickid / parts % interval == 0) {
|
||||||
|
scripting::on_blocks_tick(def, tickRate / interval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,7 +133,7 @@ void BlocksController::randomTick(int tickid, int parts) {
|
|||||||
if ((index + tickid) % parts != 0)
|
if ((index + tickid) % parts != 0)
|
||||||
continue;
|
continue;
|
||||||
auto& chunk = chunks->chunks[index];
|
auto& chunk = chunks->chunks[index];
|
||||||
if (chunk == nullptr || !chunk->isLighted())
|
if (chunk == nullptr || !chunk->flags.lighted)
|
||||||
continue;
|
continue;
|
||||||
for (int s = 0; s < segments; s++) {
|
for (int s = 0; s < segments; s++) {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
|
|||||||
@ -61,7 +61,7 @@ bool ChunksController::loadVisible(){
|
|||||||
int index = z * w + x;
|
int index = z * w + x;
|
||||||
auto& chunk = chunks->chunks[index];
|
auto& chunk = chunks->chunks[index];
|
||||||
if (chunk != nullptr){
|
if (chunk != nullptr){
|
||||||
if (chunk->isLoaded() && !chunk->isLighted()) {
|
if (chunk->flags.loaded && !chunk->flags.lighted) {
|
||||||
if (buildLights(chunk)) {
|
if (buildLights(chunk)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -99,12 +99,12 @@ bool ChunksController::buildLights(std::shared_ptr<Chunk> chunk) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (surrounding == MIN_SURROUNDING) {
|
if (surrounding == MIN_SURROUNDING) {
|
||||||
bool lightsCache = chunk->isLoadedLights();
|
bool lightsCache = chunk->flags.loadedLights;
|
||||||
if (!lightsCache) {
|
if (!lightsCache) {
|
||||||
lighting->buildSkyLight(chunk->x, chunk->z);
|
lighting->buildSkyLight(chunk->x, chunk->z);
|
||||||
}
|
}
|
||||||
lighting->onChunkLoaded(chunk->x, chunk->z, !lightsCache);
|
lighting->onChunkLoaded(chunk->x, chunk->z, !lightsCache);
|
||||||
chunk->setLighted(true);
|
chunk->flags.lighted = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -114,20 +114,20 @@ void ChunksController::createChunk(int x, int z) {
|
|||||||
auto chunk = level->chunksStorage->create(x, z);
|
auto chunk = level->chunksStorage->create(x, z);
|
||||||
chunks->putChunk(chunk);
|
chunks->putChunk(chunk);
|
||||||
|
|
||||||
if (!chunk->isLoaded()) {
|
if (!chunk->flags.loaded) {
|
||||||
generator->generate(
|
generator->generate(
|
||||||
chunk->voxels, x, z,
|
chunk->voxels, x, z,
|
||||||
level->getWorld()->getSeed()
|
level->getWorld()->getSeed()
|
||||||
);
|
);
|
||||||
chunk->setUnsaved(true);
|
chunk->flags.unsaved = true;
|
||||||
}
|
}
|
||||||
chunk->updateHeights();
|
chunk->updateHeights();
|
||||||
|
|
||||||
if (!chunk->isLoadedLights()) {
|
if (!chunk->flags.loadedLights) {
|
||||||
Lighting::prebuildSkyLight(
|
Lighting::prebuildSkyLight(
|
||||||
chunk.get(), level->content->getIndices()
|
chunk.get(), level->content->getIndices()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
chunk->setLoaded(true);
|
chunk->flags.loaded = true;
|
||||||
chunk->setReady(true);
|
chunk->flags.ready = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user