Merge branch 'main' into blocks_meta

This commit is contained in:
MihailRis
2024-06-06 12:23:20 +03:00
88 changed files with 1476 additions and 802 deletions
+44
View File
@@ -0,0 +1,44 @@
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: Create DMG
run: |
mkdir VoxelEngineDmgContent
cp -r build/res VoxelEngineDmgContent/
cp -r build/VoxelEngine VoxelEngineDmgContent/
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
View 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/*'
+15
View File
@@ -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)
+104 -211
View File
@@ -2,11 +2,7 @@
В качестве языка сценариев используется LuaJIT В качестве языка сценариев используется LuaJIT
## Функции, доступные в скриптах
```lua ```lua
load_script("контентпак:scripts/имя_скрипта.lua") -- загружает скрипт, если ещё не загружен
load_script("контентпак:scripts/имя_скрипта.lua", true) -- перезагружает скрипт
require "контентпак:имя_модуля" -- загружает lua модуль из папки modules (расширение не указывается) require "контентпак:имя_модуля" -- загружает lua модуль из папки modules (расширение не указывается)
``` ```
@@ -77,8 +73,23 @@ player.set_noclip(bool)
Геттер и сеттер noclip режима (выключенная коллизия игрока) Геттер и сеттер 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
``` ```
@@ -103,6 +114,12 @@ world.get_seed() -> int
Возвращает зерно мира. Возвращает зерно мира.
```python
world.exists() -> bool
```
Проверяет существование мира по имени.
## Библиотека pack ## Библиотека pack
```python ```python
@@ -123,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:
@@ -134,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
Библиотека функций для работы с инвентарем. Библиотека функций для работы с инвентарем.
@@ -211,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
``` ```
@@ -373,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
@@ -580,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
View 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 передается таблица значений именованных аргументов.
Проверку и приведение типов интерпретатор команд производит автоматически.
@@ -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
View 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)
```
Вызывается при выходе из мира, перед его сохранением.
@@ -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}/...` возможна потеря данных при перезаписи мира.
@@ -1,4 +1,5 @@
devtools.console="key:grave-accent" devtools.console="key:grave-accent"
chunks.reload="key:f5"
movement.forward="key:w" movement.forward="key:w"
movement.back="key:s" movement.back="key:s"
movement.left="key:a" movement.left="key:a"
+1
View File
@@ -0,0 +1 @@
base
+7 -7
View File
@@ -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
+1
View File
@@ -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
+3 -4
View File
@@ -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>")
+1 -1
View File
@@ -16,7 +16,7 @@ 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) 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", {
+10 -7
View File
@@ -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
View File
@@ -0,0 +1,4 @@
<button
onclick='core.set_setting("ui.language", "%{id}") menu:back()'>
%{name}
</button>
+1 -1
View File
@@ -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>
+2
View File
@@ -1,2 +1,4 @@
print("WARNING: toml is replaced with built-in library, just remove 'require \"core:toml\"'") print("WARNING: toml is replaced with built-in library, just remove 'require \"core:toml\"'")
toml.serialize = toml.tostring
toml.deserialize = toml.parse
return toml return toml
+31 -23
View File
@@ -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=Улева
+5
View File
@@ -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
+5
View File
@@ -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=Назад
-2
View File
@@ -2,8 +2,6 @@
#define CODERS_TOML_HPP_ #define CODERS_TOML_HPP_
#include "../data/dynamic.hpp" #include "../data/dynamic.hpp"
#include "commons.hpp"
#include <string> #include <string>
class SettingsHandler; class SettingsHandler;
+4
View File
@@ -212,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;
+2 -2
View File
@@ -25,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;
+1 -1
View File
@@ -27,7 +27,7 @@ void corecontent::setup(EnginePaths* paths, ContentBuilder* builder) {
auto bindsFile = paths->getResources()/fs::path("bindings.toml"); auto bindsFile = paths->getResources()/fs::path("bindings.toml");
if (fs::is_regular_file(bindsFile)) { if (fs::is_regular_file(bindsFile)) {
Events::loadBindingsToml( Events::loadBindings(
bindsFile.u8string(), files::read_string(bindsFile) bindsFile.u8string(), files::read_string(bindsFile)
); );
} }
+1
View File
@@ -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";
+1 -1
View File
@@ -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;
} }
+2 -1
View File
@@ -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;
} }
+29 -8
View File
@@ -58,7 +58,7 @@ 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)
@@ -71,6 +71,7 @@ Engine::Engine(EngineSettings& settings, SettingsHandler& settingsHandler, Engin
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);
@@ -94,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() {
@@ -103,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);
}
} }
} }
@@ -252,6 +267,16 @@ 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;
@@ -274,14 +299,10 @@ void Engine::loadContent() {
ContentLoader loader(&pack); ContentLoader loader(&pack);
loader.load(contentBuilder); loader.load(contentBuilder);
auto configFolder = pack.folder/fs::path("config"); load_configs(pack.folder);
auto bindsFile = configFolder/fs::path("bindings.toml");
if (fs::is_regular_file(bindsFile)) {
Events::loadBindingsToml(
bindsFile.u8string(), files::read_string(bindsFile)
);
}
} }
load_configs(paths->getResources());
content = contentBuilder.build(); content = contentBuilder.build();
resPaths = std::make_unique<ResPaths>(resdir, resRoots); resPaths = std::make_unique<ResPaths>(resdir, resRoots);
+2 -1
View File
@@ -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();
+1 -1
View File
@@ -364,7 +364,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);
} }
+9 -2
View File
@@ -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) {
+2 -1
View File
@@ -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 -1
View 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);
+18 -8
View File
@@ -20,6 +20,7 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <bitset>
using namespace gui; using namespace gui;
@@ -72,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());
@@ -139,8 +149,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);
} }
{ {
+1 -1
View File
@@ -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;
+4 -3
View File
@@ -1,5 +1,6 @@
#include "LevelScreen.hpp" #include "LevelScreen.hpp"
#include "../../core_defs.hpp"
#include "../hud.hpp" #include "../hud.hpp"
#include "../LevelFrontend.hpp" #include "../LevelFrontend.hpp"
#include "../../audio/audio.hpp" #include "../../audio/audio.hpp"
@@ -47,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());
@@ -114,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) {
+11 -10
View File
@@ -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;
} }
+2 -2
View File
@@ -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);
+23 -16
View File
@@ -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;
} }
+18 -11
View File
@@ -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);
-1
View File
@@ -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 {
+11 -6
View File
@@ -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)));
+15 -10
View File
@@ -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:
+24 -7
View File
@@ -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;
+2 -5
View File
@@ -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;
+11 -8
View File
@@ -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;
-4
View File
@@ -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;
}; };
+3 -5
View File
@@ -68,11 +68,12 @@ void GUI::updateTooltip(float delta) {
if (hover == nullptr || !hover->isInside(Events::cursor)) { if (hover == nullptr || !hover->isInside(Events::cursor)) {
return resetTooltip(); return resetTooltip();
} }
float mouseDelta = glm::length(Events::delta);
if (mouseDelta < 1.0f || tooltipTimer >= hover->getTooltipDelay()) {
if (tooltipTimer + delta >= hover->getTooltipDelay()) { if (tooltipTimer + delta >= hover->getTooltipDelay()) {
auto label = std::dynamic_pointer_cast<gui::Label>(get("tooltip.label")); auto label = std::dynamic_pointer_cast<gui::Label>(get("tooltip.label"));
const auto& text = hover->getTooltip(); const auto& text = hover->getTooltip();
if (text.empty() && tooltip->isVisible()) {
return resetTooltip();
}
if (label && !text.empty()) { if (label && !text.empty()) {
tooltip->setVisible(true); tooltip->setVisible(true);
label->setText(langs::get(text)); label->setText(langs::get(text));
@@ -86,9 +87,6 @@ void GUI::updateTooltip(float delta) {
} }
} }
tooltipTimer += delta; tooltipTimer += delta;
} else {
resetTooltip();
}
} }
/// @brief Mouse related input and logic handling /// @brief Mouse related input and logic handling
+5
View File
@@ -50,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);
}
}; };
} }
+8
View File
@@ -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);
+1
View File
@@ -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);
+3
View File
@@ -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;
+3 -3
View File
@@ -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)];
+5 -4
View File
@@ -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++) {
+8 -8
View File
@@ -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;
} }
+12 -11
View File
@@ -166,11 +166,10 @@ void CameraControl::update(const PlayerInput& input, float delta, Chunks* chunks
} }
} }
glm::vec3 PlayerController::selectedBlockPosition;
glm::vec3 PlayerController::selectedPointPosition; glm::vec3 PlayerController::selectedPointPosition;
glm::ivec3 PlayerController::selectedBlockNormal; glm::ivec3 PlayerController::selectedBlockNormal;
int PlayerController::selectedBlockId = -1; int PlayerController::selectedBlockId = -1;
int PlayerController::selectedBlockStates = 0; int PlayerController::selectedBlockRotation = 0;
PlayerController::PlayerController( PlayerController::PlayerController(
Level* level, Level* level,
@@ -250,7 +249,7 @@ void PlayerController::update(float delta, bool input, bool pause) {
updateInteraction(); updateInteraction();
} else { } else {
selectedBlockId = -1; selectedBlockId = -1;
selectedBlockStates = 0; selectedBlockRotation = 0;
} }
} }
@@ -365,8 +364,8 @@ void PlayerController::updateInteraction(){
if (vox != nullptr) { if (vox != nullptr) {
player->selectedVoxel = *vox; player->selectedVoxel = *vox;
selectedBlockId = vox->id; selectedBlockId = vox->id;
selectedBlockStates = vox->states; selectedBlockRotation = vox->state.rotation;
selectedBlockPosition = iend; player->selectedBlockPosition = iend;
selectedPointPosition = end; selectedPointPosition = end;
selectedBlockNormal = norm; selectedBlockNormal = norm;
int x = iend.x; int x = iend.x;
@@ -374,7 +373,8 @@ void PlayerController::updateInteraction(){
int z = iend.z; int z = iend.z;
Block* def = indices->getBlockDef(item->rt.placingBlock); Block* def = indices->getBlockDef(item->rt.placingBlock);
uint8_t states = determine_rotation(def, norm, camera->dir); blockstate state {};
state.rotation = determine_rotation(def, norm, camera->dir);
if (lclick && !input.shift && item->rt.funcsset.on_block_break_by) { if (lclick && !input.shift && item->rt.funcsset.on_block_break_by) {
if (scripting::on_item_break_block(player.get(), item, x, y, z)) if (scripting::on_item_break_block(player.get(), item, x, y, z))
@@ -411,13 +411,13 @@ void PlayerController::updateInteraction(){
z = (iend.z)+(norm.z); z = (iend.z)+(norm.z);
} else { } else {
if (def->rotations.name == "pipe") { if (def->rotations.name == "pipe") {
states = BLOCK_DIR_UP; state.rotation = BLOCK_DIR_UP;
} }
} }
vox = chunks->get(x, y, z); vox = chunks->get(x, y, z);
blockid_t chosenBlock = def->rt.id; blockid_t chosenBlock = def->rt.id;
if (vox && (target = indices->getBlockDef(vox->id))->replaceable) { if (vox && (target = indices->getBlockDef(vox->id))->replaceable) {
if (!level->physics->isBlockInside(x,y,z,def,states, player->hitbox.get()) if (!level->physics->isBlockInside(x,y,z,def,state, player->hitbox.get())
|| !def->obstacle){ || !def->obstacle){
if (def->grounded && !chunks->isSolidBlock(x, y-1, z)) { if (def->grounded && !chunks->isSolidBlock(x, y-1, z)) {
chosenBlock = 0; chosenBlock = 0;
@@ -427,7 +427,7 @@ void PlayerController::updateInteraction(){
glm::ivec3(x, y, z), def, glm::ivec3(x, y, z), def,
BlockInteraction::placing BlockInteraction::placing
); );
chunks->set(x, y, z, chosenBlock, states); chunks->set(x, y, z, chosenBlock, state);
lighting->onBlockSet(x,y,z, chosenBlock); lighting->onBlockSet(x,y,z, chosenBlock);
if (def->rt.funcsset.onplaced) { if (def->rt.funcsset.onplaced) {
scripting::on_block_placed(player.get(), def, x, y, z); scripting::on_block_placed(player.get(), def, x, y, z);
@@ -442,14 +442,15 @@ void PlayerController::updateInteraction(){
} }
} else { } else {
selectedBlockId = -1; selectedBlockId = -1;
selectedBlockStates = 0; selectedBlockRotation = 0;
} player->selectedVoxel.id = BLOCK_VOID;
if (rclick) { if (rclick) {
if (item->rt.funcsset.on_use) { if (item->rt.funcsset.on_use) {
scripting::on_item_use(player.get(), item); scripting::on_item_use(player.get(), item);
} }
} }
} }
}
Player* PlayerController::getPlayer() { Player* PlayerController::getPlayer() {
return player.get(); return player.get();
+1 -2
View File
@@ -77,11 +77,10 @@ class PlayerController {
void onFootstep(); void onFootstep();
void updateFootsteps(float delta); void updateFootsteps(float delta);
public: public:
static glm::vec3 selectedBlockPosition;
static glm::ivec3 selectedBlockNormal; static glm::ivec3 selectedBlockNormal;
static glm::vec3 selectedPointPosition; static glm::vec3 selectedPointPosition;
static int selectedBlockId; static int selectedBlockId;
static int selectedBlockStates; static int selectedBlockRotation;
PlayerController( PlayerController(
Level* level, Level* level,
+36 -18
View File
@@ -16,7 +16,7 @@
int l_block_name(lua_State* L) { int l_block_name(lua_State* L) {
auto indices = scripting::content->getIndices(); auto indices = scripting::content->getIndices();
lua_Integer id = lua_tointeger(L, 1); lua_Integer id = lua_tointeger(L, 1);
if (id < 0 || size_t(id) >= indices->countBlockDefs()) { if (static_cast<size_t>(id) >= indices->countBlockDefs()) {
return 0; return 0;
} }
auto def = indices->getBlockDef(id); auto def = indices->getBlockDef(id);
@@ -27,7 +27,7 @@ int l_block_name(lua_State* L) {
int l_block_material(lua_State* L) { int l_block_material(lua_State* L) {
auto indices = scripting::content->getIndices(); auto indices = scripting::content->getIndices();
lua_Integer id = lua_tointeger(L, 1); lua_Integer id = lua_tointeger(L, 1);
if (id < 0 || size_t(id) >= indices->countBlockDefs()) { if (static_cast<size_t>(id) >= indices->countBlockDefs()) {
return 0; return 0;
} }
auto def = indices->getBlockDef(id); auto def = indices->getBlockDef(id);
@@ -60,18 +60,19 @@ int l_set_block(lua_State* L) {
lua_Integer y = lua_tointeger(L, 2); lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3); lua_Integer z = lua_tointeger(L, 3);
lua_Integer id = lua_tointeger(L, 4); lua_Integer id = lua_tointeger(L, 4);
lua_Integer states = lua_tointeger(L, 5); lua_Integer state = lua_tointeger(L, 5);
bool noupdate = lua_toboolean(L, 6); bool noupdate = lua_toboolean(L, 6);
if (id < 0 || size_t(id) >= scripting::indices->countBlockDefs()) { if (static_cast<size_t>(id) >= scripting::indices->countBlockDefs()) {
return 0; return 0;
} }
if (!scripting::level->chunks->get(x, y, z)) { if (!scripting::level->chunks->get(x, y, z)) {
return 0; return 0;
} }
scripting::level->chunks->set(x, y, z, id, states); scripting::level->chunks->set(x, y, z, id, int2blockstate(state));
scripting::level->lighting->onBlockSet(x,y,z, id); scripting::level->lighting->onBlockSet(x,y,z, id);
if (!noupdate) if (!noupdate) {
scripting::blocks->updateSides(x, y, z); scripting::blocks->updateSides(x, y, z);
}
return 0; return 0;
} }
@@ -97,7 +98,7 @@ int l_get_block_x(lua_State* L) {
if (!def->rotatable) { if (!def->rotatable) {
return lua::pushivec3(L, 1, 0, 0); return lua::pushivec3(L, 1, 0, 0);
} else { } else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()]; const CoordSystem& rot = def->rotations.variants[vox->state.rotation];
return lua::pushivec3(L, rot.axisX.x, rot.axisX.y, rot.axisX.z); return lua::pushivec3(L, rot.axisX.x, rot.axisX.y, rot.axisX.z);
} }
} }
@@ -114,7 +115,7 @@ int l_get_block_y(lua_State* L) {
if (!def->rotatable) { if (!def->rotatable) {
return lua::pushivec3(L, 0, 1, 0); return lua::pushivec3(L, 0, 1, 0);
} else { } else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()]; const CoordSystem& rot = def->rotations.variants[vox->state.rotation];
return lua::pushivec3(L, rot.axisY.x, rot.axisY.y, rot.axisY.z); return lua::pushivec3(L, rot.axisY.x, rot.axisY.y, rot.axisY.z);
} }
} }
@@ -131,7 +132,7 @@ int l_get_block_z(lua_State* L) {
if (!def->rotatable) { if (!def->rotatable) {
return lua::pushivec3(L, 0, 0, 1); return lua::pushivec3(L, 0, 0, 1);
} else { } else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()]; const CoordSystem& rot = def->rotations.variants[vox->state.rotation];
return lua::pushivec3(L, rot.axisZ.x, rot.axisZ.y, rot.axisZ.z); return lua::pushivec3(L, rot.axisZ.x, rot.axisZ.y, rot.axisZ.z);
} }
} }
@@ -141,7 +142,7 @@ int l_get_block_rotation(lua_State* L) {
lua_Integer y = lua_tointeger(L, 2); lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3); lua_Integer z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z); voxel* vox = scripting::level->chunks->get(x, y, z);
int rotation = vox == nullptr ? 0 : vox->rotation(); int rotation = vox == nullptr ? 0 : vox->state.rotation;
lua_pushinteger(L, rotation); lua_pushinteger(L, rotation);
return 1; return 1;
} }
@@ -155,8 +156,8 @@ int l_set_block_rotation(lua_State* L) {
if (vox == nullptr) { if (vox == nullptr) {
return 0; return 0;
} }
vox->setRotation(value); vox->state.rotation = value;
scripting::level->chunks->getChunkByVoxel(x, y, z)->setModified(true); scripting::level->chunks->getChunkByVoxel(x, y, z)->setModifiedAndUnsaved();
return 0; return 0;
} }
@@ -165,7 +166,7 @@ int l_get_block_states(lua_State* L) {
lua_Integer y = lua_tointeger(L, 2); lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3); lua_Integer z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z); voxel* vox = scripting::level->chunks->get(x, y, z);
int states = vox == nullptr ? 0 : vox->states; int states = vox == nullptr ? 0 : blockstate2int(vox->state);
lua_pushinteger(L, states); lua_pushinteger(L, states);
return 1; return 1;
} }
@@ -181,8 +182,8 @@ int l_set_block_states(lua_State* L) {
return 0; return 0;
} }
voxel* vox = scripting::level->chunks->get(x, y, z); voxel* vox = scripting::level->chunks->get(x, y, z);
vox->states = states; vox->state = int2blockstate(states);
chunk->setModified(true); chunk->setModifiedAndUnsaved();
return 0; return 0;
} }
@@ -199,7 +200,7 @@ int l_get_block_user_bits(lua_State* L) {
return 1; return 1;
} }
uint mask = ((1 << bits) - 1) << offset; uint mask = ((1 << bits) - 1) << offset;
uint data = (vox->states & mask) >> offset; uint data = (blockstate2int(vox->state) & mask) >> offset;
lua_pushinteger(L, data); lua_pushinteger(L, data);
return 1; return 1;
} }
@@ -208,17 +209,22 @@ int l_set_block_user_bits(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1); lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2); lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3); lua_Integer z = lua_tointeger(L, 3);
lua_Integer offset = lua_tointeger(L, 4) + VOXEL_USER_BITS_OFFSET; lua_Integer offset = lua_tointeger(L, 4);
lua_Integer bits = lua_tointeger(L, 5); lua_Integer bits = lua_tointeger(L, 5);
size_t mask = ((1 << bits) - 1) << offset; size_t mask = ((1 << bits) - 1) << offset;
lua_Integer value = (lua_tointeger(L, 6) << offset) & mask; lua_Integer value = (lua_tointeger(L, 6) << offset) & mask;
Chunk* chunk = scripting::level->chunks->getChunkByVoxel(x, y, z);
if (chunk == nullptr) {
return 0;
}
voxel* vox = scripting::level->chunks->get(x, y, z); voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) { if (vox == nullptr) {
return 0; return 0;
} }
vox->states = (vox->states & (~mask)) | value; vox->state.userbits = (vox->state.userbits & (~mask)) | value;
chunk->setModifiedAndUnsaved();
return 0; return 0;
} }
@@ -231,10 +237,22 @@ int l_is_replaceable_at(lua_State* L) {
return 1; return 1;
} }
int l_block_caption(lua_State* L) {
auto indices = scripting::content->getIndices();
lua_Integer id = lua_tointeger(L, 1);
if (static_cast<size_t>(id) >= indices->countBlockDefs()) {
return 0;
}
auto def = indices->getBlockDef(id);
lua_pushstring(L, def->caption.c_str());
return 1;
}
const luaL_Reg blocklib [] = { const luaL_Reg blocklib [] = {
{"index", lua_wrap_errors<l_block_index>}, {"index", lua_wrap_errors<l_block_index>},
{"name", lua_wrap_errors<l_block_name>}, {"name", lua_wrap_errors<l_block_name>},
{"material", lua_wrap_errors<l_block_material>}, {"material", lua_wrap_errors<l_block_material>},
{"caption", lua_wrap_errors<l_block_caption>},
{"defs_count", lua_wrap_errors<l_blocks_count>}, {"defs_count", lua_wrap_errors<l_blocks_count>},
{"is_solid_at", lua_wrap_errors<l_is_solid_at>}, {"is_solid_at", lua_wrap_errors<l_is_solid_at>},
{"is_replaceable_at", lua_wrap_errors<l_is_replaceable_at>}, {"is_replaceable_at", lua_wrap_errors<l_is_replaceable_at>},
-14
View File
@@ -100,19 +100,6 @@ static int l_reconfig_packs(lua_State* L) {
return 0; return 0;
} }
static int l_get_bindings(lua_State* L) {
auto& bindings = Events::bindings;
lua_createtable(L, bindings.size(), 0);
int i = 0;
for (auto& entry : bindings) {
lua_pushstring(L, entry.first.c_str());
lua_rawseti(L, -2, i + 1);
i++;
}
return 1;
}
static int l_get_setting(lua_State* L) { static int l_get_setting(lua_State* L) {
auto name = lua_tostring(L, 1); auto name = lua_tostring(L, 1);
const auto value = scripting::engine->getSettingsHandler().getValue(name); const auto value = scripting::engine->getSettingsHandler().getValue(name);
@@ -186,7 +173,6 @@ const luaL_Reg corelib [] = {
{"close_world", lua_wrap_errors<l_close_world>}, {"close_world", lua_wrap_errors<l_close_world>},
{"delete_world", lua_wrap_errors<l_delete_world>}, {"delete_world", lua_wrap_errors<l_delete_world>},
{"reconfig_packs", lua_wrap_errors<l_reconfig_packs>}, {"reconfig_packs", lua_wrap_errors<l_reconfig_packs>},
{"get_bindings", lua_wrap_errors<l_get_bindings>},
{"get_setting", lua_wrap_errors<l_get_setting>}, {"get_setting", lua_wrap_errors<l_get_setting>},
{"set_setting", lua_wrap_errors<l_set_setting>}, {"set_setting", lua_wrap_errors<l_set_setting>},
{"str_setting", lua_wrap_errors<l_str_setting>}, {"str_setting", lua_wrap_errors<l_str_setting>},
+52 -39
View File
@@ -1,5 +1,6 @@
#include "lua_commons.hpp" #include "lua_commons.hpp"
#include "api_lua.hpp" #include "api_lua.hpp"
#include "LuaState.hpp"
#include "../scripting.hpp" #include "../scripting.hpp"
#include "../../../engine.hpp" #include "../../../engine.hpp"
#include "../../../files/files.hpp" #include "../../../files/files.hpp"
@@ -11,24 +12,41 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
static fs::path resolve_path(lua_State*, const std::string& path) { namespace scripting {
return scripting::engine->getPaths()->resolve(path); extern lua::LuaState* state;
}
using namespace scripting;
static fs::path resolve_path(const std::string& path) {
return engine->getPaths()->resolve(path);
}
static fs::path resolve_path_soft(const std::string& path) {
if (path.find(':') == std::string::npos) {
return path;
}
return engine->getPaths()->resolve(path, false);
} }
static int l_file_find(lua_State* L) { static int l_file_find(lua_State* L) {
std::string path = lua_tostring(L, 1); std::string path = state->requireString(1);
lua_pushstring(L, scripting::engine->getResPaths()->findRaw(path).c_str()); try {
lua_pushstring(L, engine->getResPaths()->findRaw(path).c_str());
return 1; return 1;
} catch (const std::runtime_error& err) {
return 0;
}
} }
static int l_file_resolve(lua_State* L) { static int l_file_resolve(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1)); fs::path path = resolve_path(state->requireString(1));
lua_pushstring(L, path.u8string().c_str()); lua_pushstring(L, path.u8string().c_str());
return 1; return 1;
} }
static int l_file_read(lua_State* L) { static int l_file_read(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1)); fs::path path = resolve_path(state->requireString(1));
if (fs::is_regular_file(path)) { if (fs::is_regular_file(path)) {
lua_pushstring(L, files::read_string(path).c_str()); lua_pushstring(L, files::read_string(path).c_str());
return 1; return 1;
@@ -36,55 +54,50 @@ static int l_file_read(lua_State* L) {
throw std::runtime_error("file does not exists "+util::quote(path.u8string())); throw std::runtime_error("file does not exists "+util::quote(path.u8string()));
} }
static int l_file_write(lua_State* L) { static int l_file_write(lua_State*) {
fs::path path = resolve_path(L, lua_tostring(L, 1)); fs::path path = resolve_path(state->requireString(1));
const char* text = lua_tostring(L, 2); auto text = state->requireString(2);
files::write_string(path, text); files::write_string(path, text);
return 1; return 1;
} }
static int l_file_remove(lua_State* L) { static int l_file_remove(lua_State*) {
std::string rawpath = lua_tostring(L, 1); std::string rawpath = state->requireString(1);
fs::path path = resolve_path(L, rawpath); fs::path path = resolve_path(rawpath);
auto entryPoint = rawpath.substr(0, rawpath.find(':')); auto entryPoint = rawpath.substr(0, rawpath.find(':'));
if (entryPoint != "world") { if (entryPoint != "world") {
throw std::runtime_error("access denied"); throw std::runtime_error("access denied");
} }
lua_pushboolean(L, fs::remove(path)); return state->pushboolean(fs::remove(path));
return 1;
} }
static int l_file_remove_tree(lua_State* L) { static int l_file_remove_tree(lua_State*) {
std::string rawpath = lua_tostring(L, 1); std::string rawpath = state->requireString(1);
fs::path path = resolve_path(L, rawpath); fs::path path = resolve_path(rawpath);
auto entryPoint = rawpath.substr(0, rawpath.find(':')); auto entryPoint = rawpath.substr(0, rawpath.find(':'));
if (entryPoint != "world") { if (entryPoint != "world") {
throw std::runtime_error("access denied"); throw std::runtime_error("access denied");
} }
lua_pushinteger(L, fs::remove_all(path)); return state->pushinteger(fs::remove_all(path));
return 1;
} }
static int l_file_exists(lua_State* L) { static int l_file_exists(lua_State*) {
fs::path path = resolve_path(L, lua_tostring(L, 1)); fs::path path = resolve_path_soft(state->requireString(1));
lua_pushboolean(L, fs::exists(path)); return state->pushboolean(fs::exists(path));
return 1;
} }
static int l_file_isfile(lua_State* L) { static int l_file_isfile(lua_State*) {
fs::path path = resolve_path(L, lua_tostring(L, 1)); fs::path path = resolve_path_soft(state->requireString(1));
lua_pushboolean(L, fs::is_regular_file(path)); return state->pushboolean(fs::is_regular_file(path));
return 1;
} }
static int l_file_isdir(lua_State* L) { static int l_file_isdir(lua_State*) {
fs::path path = resolve_path(L, lua_tostring(L, 1)); fs::path path = resolve_path_soft(state->requireString(1));
lua_pushboolean(L, fs::is_directory(path)); return state->pushboolean(fs::is_directory(path));
return 1;
} }
static int l_file_length(lua_State* L) { static int l_file_length(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1)); fs::path path = resolve_path(state->requireString(1));
if (fs::exists(path)){ if (fs::exists(path)){
lua_pushinteger(L, fs::file_size(path)); lua_pushinteger(L, fs::file_size(path));
} else { } else {
@@ -94,19 +107,19 @@ static int l_file_length(lua_State* L) {
} }
static int l_file_mkdir(lua_State* L) { static int l_file_mkdir(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1)); fs::path path = resolve_path(state->requireString(1));
lua_pushboolean(L, fs::create_directory(path)); lua_pushboolean(L, fs::create_directory(path));
return 1; return 1;
} }
static int l_file_mkdirs(lua_State* L) { static int l_file_mkdirs(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1)); fs::path path = resolve_path(state->requireString(1));
lua_pushboolean(L, fs::create_directories(path)); lua_pushboolean(L, fs::create_directories(path));
return 1; return 1;
} }
static int l_file_read_bytes(lua_State* L) { static int l_file_read_bytes(lua_State* L) {
fs::path path = resolve_path(L, lua_tostring(L, 1)); fs::path path = resolve_path(state->requireString(1));
if (fs::is_regular_file(path)) { if (fs::is_regular_file(path)) {
size_t length = static_cast<size_t>(fs::file_size(path)); size_t length = static_cast<size_t>(fs::file_size(path));
@@ -148,7 +161,7 @@ static int l_file_write_bytes(lua_State* L) {
throw std::runtime_error("string expected"); throw std::runtime_error("string expected");
} }
fs::path path = resolve_path(L, lua_tostring(L, pathIndex)); fs::path path = resolve_path(state->requireString(pathIndex));
std::vector<ubyte> bytes; std::vector<ubyte> bytes;
@@ -163,7 +176,7 @@ static int l_file_write_bytes(lua_State* L) {
} }
static int l_file_list_all_res(lua_State* L, const std::string& path) { static int l_file_list_all_res(lua_State* L, const std::string& path) {
auto files = scripting::engine->getResPaths()->listdirRaw(path); auto files = engine->getResPaths()->listdirRaw(path);
lua_createtable(L, files.size(), 0); lua_createtable(L, files.size(), 0);
for (size_t i = 0; i < files.size(); i++) { for (size_t i = 0; i < files.size(); i++) {
lua_pushstring(L, files[i].c_str()); lua_pushstring(L, files[i].c_str());
@@ -173,11 +186,11 @@ static int l_file_list_all_res(lua_State* L, const std::string& path) {
} }
static int l_file_list(lua_State* L) { static int l_file_list(lua_State* L) {
std::string dirname = lua_tostring(L, 1); std::string dirname = state->requireString(1);
if (dirname.find(':') == std::string::npos) { if (dirname.find(':') == std::string::npos) {
return l_file_list_all_res(L, dirname); return l_file_list_all_res(L, dirname);
} }
fs::path path = resolve_path(L, dirname); fs::path path = resolve_path(dirname);
if (!fs::is_directory(path)) { if (!fs::is_directory(path)) {
throw std::runtime_error(util::quote(path.u8string())+" is not a directory"); throw std::runtime_error(util::quote(path.u8string())+" is not a directory");
} }
+38 -2
View File
@@ -93,6 +93,18 @@ static int l_container_add(lua_State* L) {
return 0; return 0;
} }
static int l_node_destruct(lua_State* L) {
auto docnode = getDocumentNode(L);
auto node = std::dynamic_pointer_cast<Container>(docnode.node);
engine->getGUI()->postRunnable([node]() {
auto parent = node->getParent();
if (auto container = dynamic_cast<Container*>(parent)) {
container->remove(node);
}
});
return 0;
}
static int l_container_clear(lua_State* L) { static int l_container_clear(lua_State* L) {
auto node = getDocumentNode(L, 1); auto node = getDocumentNode(L, 1);
if (auto container = std::dynamic_pointer_cast<Container>(node.node)) { if (auto container = std::dynamic_pointer_cast<Container>(node.node)) {
@@ -101,6 +113,17 @@ static int l_container_clear(lua_State* L) {
return 0; return 0;
} }
static int l_container_set_interval(lua_State* L) {
auto node = getDocumentNode(L, 1);
auto interval = state->tointeger(2) / 1000.0f;
if (auto container = std::dynamic_pointer_cast<Container>(node.node)) {
state->pushvalue(3);
auto runnable = state->createRunnable();
container->listenInterval(interval, runnable);
}
return 0;
}
static int l_move_into(lua_State* L) { static int l_move_into(lua_State* L) {
auto node = getDocumentNode(L, 1); auto node = getDocumentNode(L, 1);
auto dest = getDocumentNode(L, 2); auto dest = getDocumentNode(L, 2);
@@ -243,14 +266,25 @@ static int p_get_src(UINode* node) {
static int p_get_add(UINode* node) { static int p_get_add(UINode* node) {
if (dynamic_cast<Container*>(node)) { if (dynamic_cast<Container*>(node)) {
return state->pushcfunction(l_container_add); return state->pushcfunction(lua_wrap_errors<l_container_add>);
} }
return 0; return 0;
} }
static int p_get_destruct(UINode*) {
return state->pushcfunction(lua_wrap_errors<l_node_destruct>);
}
static int p_get_clear(UINode* node) { static int p_get_clear(UINode* node) {
if (dynamic_cast<Container*>(node)) { if (dynamic_cast<Container*>(node)) {
return state->pushcfunction(l_container_clear); return state->pushcfunction(lua_wrap_errors<l_container_clear>);
}
return 0;
}
static int p_set_interval(UINode* node) {
if (dynamic_cast<Container*>(node)) {
return state->pushcfunction(lua_wrap_errors<l_container_set_interval>);
} }
return 0; return 0;
} }
@@ -316,7 +350,9 @@ static int l_gui_getattr(lua_State* L) {
{"enabled", p_is_enabled}, {"enabled", p_is_enabled},
{"move_into", p_move_into}, {"move_into", p_move_into},
{"add", p_get_add}, {"add", p_get_add},
{"destruct", p_get_destruct},
{"clear", p_get_clear}, {"clear", p_get_clear},
{"setInterval", p_set_interval},
{"placeholder", p_get_placeholder}, {"placeholder", p_get_placeholder},
{"valid", p_is_valid}, {"valid", p_is_valid},
{"caret", p_get_caret}, {"caret", p_get_caret},
+24 -2
View File
@@ -25,16 +25,23 @@ static int l_keycode(lua_State* L) {
return 1; return 1;
} }
static int l_add_callback(lua_State* L) { static int l_mousecode(lua_State* L) {
const char* name = state->requireString(1);
lua_pushinteger(L, static_cast<int>(input_util::mousecode_from(name)));
return 1;
}
static int l_add_callback(lua_State*) {
auto bindname = state->requireString(1); auto bindname = state->requireString(1);
const auto& bind = Events::bindings.find(bindname); const auto& bind = Events::bindings.find(bindname);
if (bind == Events::bindings.end()) { if (bind == Events::bindings.end()) {
throw std::runtime_error("unknown binding "+util::quote(bindname)); throw std::runtime_error("unknown binding "+util::quote(bindname));
} }
state->pushvalue(2); state->pushvalue(2);
runnable actual_callback = state->createRunnable();
runnable callback = [=]() { runnable callback = [=]() {
if (!scripting::engine->getGUI()->isFocusCaught()) { if (!scripting::engine->getGUI()->isFocusCaught()) {
state->createRunnable(); actual_callback();
} }
}; };
if (hud) { if (hud) {
@@ -49,10 +56,25 @@ static int l_get_mouse_pos(lua_State* L) {
return lua::pushvec2_arr(L, Events::cursor); return lua::pushvec2_arr(L, Events::cursor);
} }
static int l_get_bindings(lua_State* L) {
auto& bindings = Events::bindings;
lua_createtable(L, bindings.size(), 0);
int i = 0;
for (auto& entry : bindings) {
lua_pushstring(L, entry.first.c_str());
lua_rawseti(L, -2, i + 1);
i++;
}
return 1;
}
const luaL_Reg inputlib [] = { const luaL_Reg inputlib [] = {
{"keycode", lua_wrap_errors<l_keycode>}, {"keycode", lua_wrap_errors<l_keycode>},
{"mousecode", lua_wrap_errors<l_mousecode>},
{"add_callback", lua_wrap_errors<l_add_callback>}, {"add_callback", lua_wrap_errors<l_add_callback>},
{"get_mouse_pos", lua_wrap_errors<l_get_mouse_pos>}, {"get_mouse_pos", lua_wrap_errors<l_get_mouse_pos>},
{"get_bindings", lua_wrap_errors<l_get_bindings>},
{NULL, NULL} {NULL, NULL}
}; };
+2 -2
View File
@@ -23,14 +23,14 @@ static int l_json_stringify(lua_State* L) {
} }
static int l_json_parse(lua_State* L) { static int l_json_parse(lua_State* L) {
auto string = lua_tostring(L, 1); auto string = scripting::state->requireString(1);
auto element = json::parse("<string>", string); auto element = json::parse("<string>", string);
scripting::state->pushvalue(element); scripting::state->pushvalue(element);
return 1; return 1;
} }
const luaL_Reg jsonlib [] = { const luaL_Reg jsonlib [] = {
{"stringify", lua_wrap_errors<l_json_stringify>}, {"tostring", lua_wrap_errors<l_json_stringify>},
{"parse", lua_wrap_errors<l_json_parse>}, {"parse", lua_wrap_errors<l_json_parse>},
{NULL, NULL} {NULL, NULL}
}; };
+15
View File
@@ -132,6 +132,20 @@ static int l_player_set_noclip(lua_State* L) {
return 0; return 0;
} }
static int l_player_get_selected_block(lua_State* L) {
if (auto player = get_player(L, 1)) {
if (player->selectedVoxel.id == BLOCK_VOID) {
return 0;
}
const glm::ivec3 pos = player->selectedBlockPosition;
lua_pushinteger(L, pos.x);
lua_pushinteger(L, pos.y);
lua_pushinteger(L, pos.z);
return 3;
}
return 0;
}
const luaL_Reg playerlib [] = { const luaL_Reg playerlib [] = {
{"get_pos", lua_wrap_errors<l_player_get_pos>}, {"get_pos", lua_wrap_errors<l_player_get_pos>},
{"set_pos", lua_wrap_errors<l_player_set_pos>}, {"set_pos", lua_wrap_errors<l_player_set_pos>},
@@ -144,5 +158,6 @@ const luaL_Reg playerlib [] = {
{"set_flight", lua_wrap_errors<l_player_set_flight>}, {"set_flight", lua_wrap_errors<l_player_set_flight>},
{"is_noclip", lua_wrap_errors<l_player_is_noclip>}, {"is_noclip", lua_wrap_errors<l_player_is_noclip>},
{"set_noclip", lua_wrap_errors<l_player_set_noclip>}, {"set_noclip", lua_wrap_errors<l_player_set_noclip>},
{"get_selected_block", lua_wrap_errors<l_player_get_selected_block>},
{NULL, NULL} {NULL, NULL}
}; };
+2 -2
View File
@@ -31,7 +31,7 @@ static int l_toml_parse(lua_State*) {
} }
const luaL_Reg tomllib [] = { const luaL_Reg tomllib [] = {
{"serialize", lua_wrap_errors<l_toml_stringify>}, {"tostring", lua_wrap_errors<l_toml_stringify>},
{"deserialize", lua_wrap_errors<l_toml_parse>}, {"parse", lua_wrap_errors<l_toml_parse>},
{NULL, NULL} {NULL, NULL}
}; };
+2 -1
View File
@@ -44,8 +44,9 @@ public:
std::shared_ptr<Camera> currentCamera; std::shared_ptr<Camera> currentCamera;
std::unique_ptr<Hitbox> hitbox; std::unique_ptr<Hitbox> hitbox;
bool debug = false; bool debug = false;
voxel selectedVoxel {0, 0}; voxel selectedVoxel {0, {}};
glm::vec3 cam {}; glm::vec3 cam {};
glm::ivec3 selectedBlockPosition {};
Player(glm::vec3 position, float speed, std::shared_ptr<Inventory> inv); Player(glm::vec3 position, float speed, std::shared_ptr<Inventory> inv);
~Player(); ~Player();
+10 -8
View File
@@ -33,6 +33,7 @@ void PhysicsSolver::step(
hitbox->grounded = false; hitbox->grounded = false;
for (uint i = 0; i < substeps; i++) { for (uint i = 0; i < substeps; i++) {
float px = pos.x; float px = pos.x;
float py = pos.y;
float pz = pos.z; float pz = pos.z;
vel += gravity * dt * gravityScale; vel += gravity * dt * gravityScale;
@@ -44,6 +45,9 @@ void PhysicsSolver::step(
vel.z *= glm::max(0.0f, 1.0f - dt * linear_damping); vel.z *= glm::max(0.0f, 1.0f - dt * linear_damping);
pos += vel * dt + gravity * gravityScale * dt * dt * 0.5f; pos += vel * dt + gravity * gravityScale * dt * dt * 0.5f;
if (hitbox->grounded) {
pos.y = py;
}
if (shifting && hitbox->grounded){ if (shifting && hitbox->grounded){
float y = (pos.y-half.y-E); float y = (pos.y-half.y-E);
@@ -219,21 +223,19 @@ bool PhysicsSolver::isBlockInside(int x, int y, int z, Hitbox* hitbox) {
y >= floor(pos.y-half.y) && y <= floor(pos.y+half.y); y >= floor(pos.y-half.y) && y <= floor(pos.y+half.y);
} }
bool PhysicsSolver::isBlockInside(int x, int y, int z, Block* def, blockstate_t states, Hitbox* hitbox) { bool PhysicsSolver::isBlockInside(int x, int y, int z, Block* def, blockstate state, Hitbox* hitbox) {
const float E = 0.001f; // inaccuracy
const glm::vec3& pos = hitbox->position; const glm::vec3& pos = hitbox->position;
const glm::vec3& half = hitbox->halfsize; const glm::vec3& half = hitbox->halfsize;
voxel v {};
v.states = states;
const auto& boxes = def->rotatable const auto& boxes = def->rotatable
? def->rt.hitboxes[v.rotation()] ? def->rt.hitboxes[state.rotation]
: def->hitboxes; : def->hitboxes;
for (const auto& block_hitbox : boxes) { for (const auto& block_hitbox : boxes) {
glm::vec3 min = block_hitbox.min(); glm::vec3 min = block_hitbox.min();
glm::vec3 max = block_hitbox.max(); glm::vec3 max = block_hitbox.max();
// 0.00001 - inaccuracy if (min.x < pos.x+half.x-x-E && max.x > pos.x-half.x-x+E &&
if (min.x < pos.x+half.x-x-0.00001f && max.x > pos.x-half.x-x+0.00001f && min.z < pos.z+half.z-z-E && max.z > pos.z-half.z-z+E &&
min.z < pos.z+half.z-z-0.00001f && max.z > pos.z-half.z-z+0.00001f && min.y < pos.y+half.y-y-E && max.y > pos.y-half.y-y+E)
min.y < pos.y+half.y-y-0.00001f && max.y > pos.y-half.y-y+0.00001f)
return true; return true;
} }
return false; return false;
+2 -1
View File
@@ -2,6 +2,7 @@
#define PHYSICS_PHYSICSSOLVER_HPP_ #define PHYSICS_PHYSICSSOLVER_HPP_
#include "../typedefs.hpp" #include "../typedefs.hpp"
#include "../voxels/voxel.hpp"
#include <glm/glm.hpp> #include <glm/glm.hpp>
@@ -31,7 +32,7 @@ public:
float stepHeight float stepHeight
); );
bool isBlockInside(int x, int y, int z, Hitbox* hitbox); bool isBlockInside(int x, int y, int z, Hitbox* hitbox);
bool isBlockInside(int x, int y, int z, Block* def, blockstate_t states, Hitbox* hitbox); bool isBlockInside(int x, int y, int z, Block* def, blockstate state, Hitbox* hitbox);
}; };
#endif // PHYSICS_PHYSICSSOLVER_HPP_ #endif // PHYSICS_PHYSICSSOLVER_HPP_
+1 -1
View File
@@ -57,7 +57,7 @@ struct GraphicsSettings {
/// 1.0 is linear, 2.0 is quadratic /// 1.0 is linear, 2.0 is quadratic
NumberSetting fogCurve {1.6f, 1.0f, 6.0f}; NumberSetting fogCurve {1.6f, 1.0f, 6.0f};
/// @brief Lighting gamma /// @brief Lighting gamma
NumberSetting gamma {1.0f, 0.5f, 2.0f}; NumberSetting gamma {1.0f, 0.4f, 1.0f};
/// @brief Enable blocks backlight to prevent complete darkness /// @brief Enable blocks backlight to prevent complete darkness
FlagSetting backlight {true}; FlagSetting backlight {true};
/// @brief Enable chunks frustum culling /// @brief Enable chunks frustum culling
-2
View File
@@ -5,7 +5,6 @@
#include "util/platform.hpp" #include "util/platform.hpp"
#include "util/command_line.hpp" #include "util/command_line.hpp"
#include "debug/Logger.hpp" #include "debug/Logger.hpp"
#include "objects/Player.hpp"
#include <stdexcept> #include <stdexcept>
@@ -13,7 +12,6 @@ static debug::Logger logger("main");
int main(int argc, char** argv) { int main(int argc, char** argv) {
debug::Logger::init("latest.log"); debug::Logger::init("latest.log");
std::cout << sizeof(PlayerInput) << std::endl;
EnginePaths paths; EnginePaths paths;
if (!parse_cmdline(argc, argv, paths)) if (!parse_cmdline(argc, argv, paths))
+3
View File
@@ -162,6 +162,9 @@ public:
/// @brief Block inventory size. 0 - no inventory /// @brief Block inventory size. 0 - no inventory
uint inventorySize = 0; uint inventorySize = 0;
// @brief Block tick interval (1 - 20tps, 2 - 10tps)
uint tickInterval = 1;
/// @brief Runtime indices (content indexing results) /// @brief Runtime indices (content indexing results)
struct { struct {
/// @brief block runtime integer id /// @brief block runtime integer id
+7 -9
View File
@@ -9,10 +9,6 @@
Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos){ Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos){
bottom = 0; bottom = 0;
top = CHUNK_H; top = CHUNK_H;
for (uint i = 0; i < CHUNK_VOL; i++) {
voxels[i].id = 2;
voxels[i].states = 0;
}
} }
bool Chunk::isEmpty(){ bool Chunk::isEmpty(){
@@ -46,12 +42,12 @@ void Chunk::updateHeights() {
void Chunk::addBlockInventory(std::shared_ptr<Inventory> inventory, void Chunk::addBlockInventory(std::shared_ptr<Inventory> inventory,
uint x, uint y, uint z) { uint x, uint y, uint z) {
inventories[vox_index(x, y, z)] = inventory; inventories[vox_index(x, y, z)] = inventory;
setUnsaved(true); flags.unsaved = true;
} }
void Chunk::removeBlockInventory(uint x, uint y, uint z) { void Chunk::removeBlockInventory(uint x, uint y, uint z) {
if (inventories.erase(vox_index(x, y, z))) { if (inventories.erase(vox_index(x, y, z))) {
setUnsaved(true); flags.unsaved = true;
} }
} }
@@ -97,8 +93,10 @@ std::unique_ptr<ubyte[]> Chunk::encode() const {
for (uint i = 0; i < CHUNK_VOL; i++) { for (uint i = 0; i < CHUNK_VOL; i++) {
buffer[i] = voxels[i].id >> 8; buffer[i] = voxels[i].id >> 8;
buffer[CHUNK_VOL+i] = voxels[i].id & 0xFF; buffer[CHUNK_VOL+i] = voxels[i].id & 0xFF;
buffer[CHUNK_VOL*2 + i] = voxels[i].states >> 8;
buffer[CHUNK_VOL*3 + i] = voxels[i].states & 0xFF; blockstate_t state = blockstate2int(voxels[i].state);
buffer[CHUNK_VOL*2 + i] = state >> 8;
buffer[CHUNK_VOL*3 + i] = state & 0xFF;
} }
return buffer; return buffer;
} }
@@ -114,7 +112,7 @@ bool Chunk::decode(const ubyte* data) {
ubyte bst2 = data[CHUNK_VOL*3 + i]; ubyte bst2 = data[CHUNK_VOL*3 + i];
vox.id = (blockid_t(bid1) << 8) | (blockid_t(bid2)); vox.id = (blockid_t(bid1) << 8) | (blockid_t(bid2));
vox.states = (blockstate_t(bst1) << 8) | (blockstate_t(bst2)); vox.state = int2blockstate((blockstate_t(bst1) << 8) | (blockstate_t(bst2)));
} }
return true; return true;
} }
+13 -41
View File
@@ -9,14 +9,6 @@
#include "voxel.hpp" #include "voxel.hpp"
#include "../lighting/Lightmap.hpp" #include "../lighting/Lightmap.hpp"
struct ChunkFlag {
static const int MODIFIED = 0x1;
static const int READY = 0x2;
static const int LOADED = 0x4;
static const int LIGHTED = 0x8;
static const int UNSAVED = 0x10;
static const int LOADED_LIGHTS = 0x20;
};
inline constexpr int CHUNK_DATA_LEN = CHUNK_VOL*4; inline constexpr int CHUNK_DATA_LEN = CHUNK_VOL*4;
class Lightmap; class Lightmap;
@@ -29,9 +21,16 @@ class Chunk {
public: public:
int x, z; int x, z;
int bottom, top; int bottom, top;
voxel voxels[CHUNK_VOL]; voxel voxels[CHUNK_VOL] {};
Lightmap lightmap; Lightmap lightmap;
int flags = 0; struct {
bool modified: 1;
bool ready: 1;
bool loaded: 1;
bool lighted: 1;
bool unsaved: 1;
bool loadedLights: 1;
} flags {};
/* Block inventories map where key is index of block in voxels array */ /* Block inventories map where key is index of block in voxels array */
chunk_inventories_map inventories; chunk_inventories_map inventories;
@@ -45,14 +44,6 @@ public:
// unused // unused
std::unique_ptr<Chunk> clone() const; std::unique_ptr<Chunk> clone() const;
// flags getters/setters below
inline void setFlags(int mask, bool value){
if (value)
flags |= mask;
else
flags &= ~(mask);
}
/* Creates new block inventory given size /* Creates new block inventory given size
@return inventory id or 0 if block does not exists */ @return inventory id or 0 if block does not exists */
void addBlockInventory(std::shared_ptr<Inventory> inventory, void addBlockInventory(std::shared_ptr<Inventory> inventory,
@@ -63,29 +54,10 @@ public:
/* @return inventory bound to the given block or nullptr */ /* @return inventory bound to the given block or nullptr */
std::shared_ptr<Inventory> getBlockInventory(uint x, uint y, uint z) const; std::shared_ptr<Inventory> getBlockInventory(uint x, uint y, uint z) const;
inline bool isUnsaved() const {return flags & ChunkFlag::UNSAVED;} inline void setModifiedAndUnsaved() {
flags.modified = true;
inline bool isModified() const {return flags & ChunkFlag::MODIFIED;} flags.unsaved = true;
}
inline bool isLighted() const {return flags & ChunkFlag::LIGHTED;}
inline bool isLoaded() const {return flags & ChunkFlag::LOADED;}
inline bool isLoadedLights() const {return flags & ChunkFlag::LOADED_LIGHTS;}
inline bool isReady() const {return flags & ChunkFlag::READY;}
inline void setUnsaved(bool newState) {setFlags(ChunkFlag::UNSAVED, newState);}
inline void setModified(bool newState) {setFlags(ChunkFlag::MODIFIED, newState);}
inline void setLoaded(bool newState) {setFlags(ChunkFlag::LOADED, newState);}
inline void setLoadedLights(bool newState) {setFlags(ChunkFlag::LOADED_LIGHTS, newState);}
inline void setLighted(bool newState) {setFlags(ChunkFlag::LIGHTED, newState);}
inline void setReady(bool newState) {setFlags(ChunkFlag::READY, newState);}
std::unique_ptr<ubyte[]> encode() const; std::unique_ptr<ubyte[]> encode() const;
+13 -15
View File
@@ -68,7 +68,7 @@ const AABB* Chunks::isObstacleAt(float x, float y, float z){
const Block* def = contentIds->getBlockDef(v->id); const Block* def = contentIds->getBlockDef(v->id);
if (def->obstacle) { if (def->obstacle) {
const auto& boxes = def->rotatable const auto& boxes = def->rotatable
? def->rt.hitboxes[v->rotation()] ? def->rt.hitboxes[v->state.rotation]
: def->hitboxes; : def->hitboxes;
for (const auto& hitbox : boxes) { for (const auto& hitbox : boxes) {
if (hitbox.contains({x - ix, y - iy, z - iz})) { if (hitbox.contains({x - ix, y - iy, z - iz})) {
@@ -158,7 +158,7 @@ Chunk* Chunks::getChunk(int x, int z){
return chunks[z * w + x].get(); return chunks[z * w + x].get();
} }
void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, uint8_t states) { void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state) {
if (y < 0 || y >= CHUNK_H) if (y < 0 || y >= CHUNK_H)
return; return;
x -= ox * CHUNK_W; x -= ox * CHUNK_W;
@@ -178,24 +178,22 @@ void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, uint8_t states) {
if (def->inventorySize == 0) if (def->inventorySize == 0)
chunk->removeBlockInventory(lx, y, lz); chunk->removeBlockInventory(lx, y, lz);
vox.id = id; vox.id = id;
vox.states = states; vox.state = state;
chunk->setModifiedAndUnsaved();
chunk->setUnsaved(true);
chunk->setModified(true);
if (y < chunk->bottom) chunk->bottom = y; if (y < chunk->bottom) chunk->bottom = y;
else if (y + 1 > chunk->top) chunk->top = y + 1; else if (y + 1 > chunk->top) chunk->top = y + 1;
else if (id == 0) chunk->updateHeights(); else if (id == 0) chunk->updateHeights();
if (lx == 0 && (chunk = getChunk(cx+ox-1, cz+oz))) if (lx == 0 && (chunk = getChunk(cx+ox-1, cz+oz)))
chunk->setModified(true); chunk->flags.modified = true;
if (lz == 0 && (chunk = getChunk(cx+ox, cz+oz-1))) if (lz == 0 && (chunk = getChunk(cx+ox, cz+oz-1)))
chunk->setModified(true); chunk->flags.modified = true;
if (lx == CHUNK_W-1 && (chunk = getChunk(cx+ox+1, cz+oz))) if (lx == CHUNK_W-1 && (chunk = getChunk(cx+ox+1, cz+oz)))
chunk->setModified(true); chunk->flags.modified = true;
if (lz == CHUNK_D-1 && (chunk = getChunk(cx+ox, cz+oz+1))) if (lz == CHUNK_D-1 && (chunk = getChunk(cx+ox, cz+oz+1)))
chunk->setModified(true); chunk->flags.modified = true;
} }
voxel* Chunks::rayCast( voxel* Chunks::rayCast(
@@ -255,7 +253,7 @@ voxel* Chunks::rayCast(
if (!def->rt.solid) { if (!def->rt.solid) {
const std::vector<AABB>& hitboxes = def->rotatable const std::vector<AABB>& hitboxes = def->rotatable
? def->rt.hitboxes[voxel->rotation()] ? def->rt.hitboxes[voxel->state.rotation]
: def->hitboxes; : def->hitboxes;
scalar_t distance = maxDist; scalar_t distance = maxDist;
@@ -365,7 +363,7 @@ glm::vec3 Chunks::rayCastToObstacle(glm::vec3 start, glm::vec3 dir, float maxDis
if (def->obstacle) { if (def->obstacle) {
if (!def->rt.solid) { if (!def->rt.solid) {
const std::vector<AABB>& hitboxes = def->rotatable const std::vector<AABB>& hitboxes = def->rotatable
? def->rt.hitboxes[voxel->rotation()] ? def->rt.hitboxes[voxel->state.rotation]
: def->modelBoxes; : def->modelBoxes;
scalar_t distance; scalar_t distance;
@@ -499,12 +497,12 @@ void Chunks::saveAndClear(){
for (size_t i = 0; i < volume; i++){ for (size_t i = 0; i < volume; i++){
Chunk* chunk = chunks[i].get(); Chunk* chunk = chunks[i].get();
chunks[i] = nullptr; chunks[i] = nullptr;
if (chunk == nullptr || !chunk->isLighted()) if (chunk == nullptr || !chunk->flags.lighted)
continue; continue;
bool lightsUnsaved = !chunk->isLoadedLights() && bool lightsUnsaved = !chunk->flags.loadedLights &&
worldFiles->doesWriteLights(); worldFiles->doesWriteLights();
if (!chunk->isUnsaved() && !lightsUnsaved) if (!chunk->flags.unsaved && !lightsUnsaved)
continue; continue;
regions.put(chunk); regions.put(chunk);
} }
+3 -2
View File
@@ -5,6 +5,8 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "voxel.hpp"
#include "../typedefs.hpp" #include "../typedefs.hpp"
class VoxelRenderer; class VoxelRenderer;
@@ -13,7 +15,6 @@ struct AABB;
class Content; class Content;
class ContentIndices; class ContentIndices;
class Chunk; class Chunk;
struct voxel;
class WorldFiles; class WorldFiles;
class LevelEvents; class LevelEvents;
@@ -42,7 +43,7 @@ public:
voxel* get(int32_t x, int32_t y, int32_t z); voxel* get(int32_t x, int32_t y, int32_t z);
light_t getLight(int32_t x, int32_t y, int32_t z); light_t getLight(int32_t x, int32_t y, int32_t z);
ubyte getLight(int32_t x, int32_t y, int32_t z, int channel); ubyte getLight(int32_t x, int32_t y, int32_t z, int channel);
void set(int32_t x, int32_t y, int32_t z, uint32_t id, uint8_t states); void set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state);
voxel* rayCast( voxel* rayCast(
glm::vec3 start, glm::vec3 start,
+2 -2
View File
@@ -61,7 +61,7 @@ std::shared_ptr<Chunk> ChunksStorage::create(int x, int z) {
chunk->decode(data.get()); chunk->decode(data.get());
auto invs = regions.fetchInventories(chunk->x, chunk->z); auto invs = regions.fetchInventories(chunk->x, chunk->z);
chunk->setBlockInventories(std::move(invs)); chunk->setBlockInventories(std::move(invs));
chunk->setLoaded(true); chunk->flags.loaded = true;
for(auto& entry : chunk->inventories) { for(auto& entry : chunk->inventories) {
level->inventories->store(entry.second); level->inventories->store(entry.second);
} }
@@ -71,7 +71,7 @@ std::shared_ptr<Chunk> ChunksStorage::create(int x, int z) {
auto lights = regions.getLights(chunk->x, chunk->z); auto lights = regions.getLights(chunk->x, chunk->z);
if (lights) { if (lights) {
chunk->lightmap.set(lights.get()); chunk->lightmap.set(lights.get());
chunk->setLoadedLights(true); chunk->flags.loadedLights = true;
} }
return chunk; return chunk;
} }
+4 -4
View File
@@ -163,7 +163,7 @@ void DefaultWorldGenerator::generate(voxel* voxels, int cx, int cz, int seed){
for (int cur_y = 0; cur_y < CHUNK_H; cur_y++){ for (int cur_y = 0; cur_y < CHUNK_H; cur_y++){
// int cur_y = y; // int cur_y = y;
int id = cur_y < SEA_LEVEL ? idWater : BLOCK_AIR; int id = cur_y < SEA_LEVEL ? idWater : BLOCK_AIR;
int states = 0; blockstate state {};
if ((cur_y == (int)height) && (SEA_LEVEL-2 < cur_y)) { if ((cur_y == (int)height) && (SEA_LEVEL-2 < cur_y)) {
id = idGrassBlock; id = idGrassBlock;
} else if (cur_y < (height - 6)){ } else if (cur_y < (height - 6)){
@@ -177,7 +177,7 @@ void DefaultWorldGenerator::generate(voxel* voxels, int cx, int cz, int seed){
treesTile, idWood, idLeaves); treesTile, idWood, idLeaves);
if (tree) { if (tree) {
id = tree; id = tree;
states = BLOCK_DIR_UP; state.rotation = BLOCK_DIR_UP;
} }
} }
float sand = fmax(heights.get(MAPS::SAND, cur_x, cur_z), heights.get(MAPS::CLIFF, cur_x, cur_z)); float sand = fmax(heights.get(MAPS::SAND, cur_x, cur_z), heights.get(MAPS::CLIFF, cur_x, cur_z));
@@ -198,10 +198,10 @@ void DefaultWorldGenerator::generate(voxel* voxels, int cx, int cz, int seed){
} }
if ((height > SEA_LEVEL+1) && ((int)(height + 1) == cur_y) && ((unsigned short)randomgrass.rand() > 65533)){ if ((height > SEA_LEVEL+1) && ((int)(height + 1) == cur_y) && ((unsigned short)randomgrass.rand() > 65533)){
id = idWood; id = idWood;
states = BLOCK_DIR_UP; state.rotation = BLOCK_DIR_UP;
} }
voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].id = id; voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].id = id;
voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].states = states; voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].state = state;
} }
} }
} }
+2 -2
View File
@@ -10,7 +10,7 @@ void FlatWorldGenerator::generate(voxel* voxels, int cx, int cz, int seed) {
for (int x = 0; x < CHUNK_W; x++) { for (int x = 0; x < CHUNK_W; x++) {
for (int cur_y = 0; cur_y < CHUNK_H; cur_y++){ for (int cur_y = 0; cur_y < CHUNK_H; cur_y++){
int id = BLOCK_AIR; int id = BLOCK_AIR;
int states = 0; blockstate state {};
if(cur_y == 2) { if(cur_y == 2) {
id = idBazalt; id = idBazalt;
@@ -21,7 +21,7 @@ void FlatWorldGenerator::generate(voxel* voxels, int cx, int cz, int seed) {
} }
voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].id = id; voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].id = id;
voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].states = states; voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].state = state;
} }
} }
} }
+25 -13
View File
@@ -10,22 +10,34 @@ inline constexpr int BLOCK_DIR_EAST = 0x3;
inline constexpr int BLOCK_DIR_UP = 0x4; inline constexpr int BLOCK_DIR_UP = 0x4;
inline constexpr int BLOCK_DIR_DOWN = 0x5; inline constexpr int BLOCK_DIR_DOWN = 0x5;
// limited to 8 block orientations struct blockstate {
inline constexpr int BLOCK_ROT_MASK = 0b0000'0111; uint8_t rotation : 3;
// reserved bits uint8_t segment : 2; // planned to 0.22
inline constexpr int BLOCK_RESERVED_MASK = 0b1111'1000; uint8_t reserved : 3;
uint8_t userbits : 8;
};
static_assert (sizeof(blockstate) == 2);
inline constexpr blockstate_t blockstate2int(blockstate b) {
return static_cast<blockstate_t>(b.rotation) |
static_cast<blockstate_t>(b.segment) << 3 |
static_cast<blockstate_t>(b.reserved) << 5 |
static_cast<blockstate_t>(b.userbits) << 8;
}
inline constexpr blockstate int2blockstate(blockstate_t i) {
return {
static_cast<uint8_t>(i & 0b111),
static_cast<uint8_t>((i >> 3) & 0b11),
static_cast<uint8_t>((i >> 5) & 0b111),
static_cast<uint8_t>((i >> 8) & 0xFF)
};
}
struct voxel { struct voxel {
blockid_t id; blockid_t id;
blockstate_t states; blockstate state;
inline uint8_t rotation() const {
return states & BLOCK_ROT_MASK;
}
inline void setRotation(uint8_t rotation) {
states = (states & (~BLOCK_ROT_MASK)) | (rotation & BLOCK_ROT_MASK);
}
}; };
static_assert(sizeof(voxel) == 4);
#endif // VOXELS_VOXEL_HPP_ #endif // VOXELS_VOXEL_HPP_
+23 -8
View File
@@ -98,6 +98,14 @@ void Events::pollEvents() {
} }
} }
Binding& Events::getBinding(const std::string& name) {
auto found = bindings.find(name);
if (found == bindings.end()) {
throw std::runtime_error("binding '"+name+"' does not exists");
}
return found->second;
}
void Events::bind(const std::string& name, inputtype type, keycode code) { void Events::bind(const std::string& name, inputtype type, keycode code) {
bind(name, type, static_cast<int>(code)); bind(name, type, static_cast<int>(code));
} }
@@ -110,6 +118,10 @@ void Events::bind(const std::string& name, inputtype type, int code) {
bindings.emplace(name, Binding(type, code)); bindings.emplace(name, Binding(type, code));
} }
void Events::rebind(const std::string& name, inputtype type, int code) {
bindings[name] = Binding(type, code);
}
bool Events::active(const std::string& name) { bool Events::active(const std::string& name) {
const auto& found = bindings.find(name); const auto& found = bindings.find(name);
if (found == bindings.end()) { if (found == bindings.end()) {
@@ -155,19 +167,22 @@ std::string Events::writeBindings() {
dynamic::Map obj; dynamic::Map obj;
for (auto& entry : Events::bindings) { for (auto& entry : Events::bindings) {
const auto& binding = entry.second; const auto& binding = entry.second;
std::string value;
auto& jentry = obj.putMap(entry.first);
switch (binding.type) { switch (binding.type) {
case inputtype::keyboard: jentry.put("type", "keyboard"); break; case inputtype::keyboard:
case inputtype::mouse: jentry.put("type", "mouse"); break; value = "key:"+input_util::get_name(static_cast<keycode>(binding.code));
break;
case inputtype::mouse:
value = "mouse:"+input_util::get_name(static_cast<mousecode>(binding.code));
break;
default: throw std::runtime_error("unsupported control type"); default: throw std::runtime_error("unsupported control type");
} }
jentry.put("code", binding.code); obj.put(entry.first, value);
} }
return json::stringify(&obj, true, " "); return toml::stringify(obj);
} }
void Events::loadBindings(const std::string& filename, const std::string& source) { void Events::loadBindingsOld(const std::string& filename, const std::string& source) {
auto obj = json::parse(filename, source); auto obj = json::parse(filename, source);
for (auto& entry : Events::bindings) { for (auto& entry : Events::bindings) {
auto& binding = entry.second; auto& binding = entry.second;
@@ -192,7 +207,7 @@ void Events::loadBindings(const std::string& filename, const std::string& source
} }
} }
void Events::loadBindingsToml(const std::string& filename, const std::string& source) { void Events::loadBindings(const std::string& filename, const std::string& source) {
auto map = toml::parse(filename, source); auto map = toml::parse(filename, source);
for (auto& entry : map->values) { for (auto& entry : map->values) {
if (auto value = std::get_if<std::string>(&entry.second)) { if (auto value = std::get_if<std::string>(&entry.second)) {
+3 -1
View File
@@ -38,9 +38,11 @@ public:
static void toggleCursor(); static void toggleCursor();
static Binding& getBinding(const std::string& name);
static void bind(const std::string& name, inputtype type, keycode code); static void bind(const std::string& name, inputtype type, keycode code);
static void bind(const std::string& name, inputtype type, mousecode code); static void bind(const std::string& name, inputtype type, mousecode code);
static void bind(const std::string& name, inputtype type, int code); static void bind(const std::string& name, inputtype type, int code);
static void rebind(const std::string& name, inputtype type, int code);
static bool active(const std::string& name); static bool active(const std::string& name);
static bool jactive(const std::string& name); static bool jactive(const std::string& name);
@@ -51,7 +53,7 @@ public:
static std::string writeBindings(); static std::string writeBindings();
static void loadBindings(const std::string& filename, const std::string& source); static void loadBindings(const std::string& filename, const std::string& source);
static void loadBindingsToml(const std::string& filename, const std::string& source); static void loadBindingsOld(const std::string& filename, const std::string& source); // TODO: remove in 0.22
}; };
#endif // WINDOW_EVENTS_HPP_ #endif // WINDOW_EVENTS_HPP_
+23 -1
View File
@@ -40,6 +40,25 @@ static std::unordered_map<std::string, int> mousecodes {
{"middle", GLFW_MOUSE_BUTTON_3}, {"middle", GLFW_MOUSE_BUTTON_3},
}; };
static std::unordered_map<int, std::string> keynames {};
std::string input_util::get_name(mousecode code) {
switch (code) {
case mousecode::BUTTON_1: return "left";
case mousecode::BUTTON_2: return "right";
case mousecode::BUTTON_3: return "middle";
default: return "unknown";
}
}
std::string input_util::get_name(keycode code) {
auto found = keynames.find(static_cast<int>(code));
if (found == keynames.end()) {
return "unknown";
}
return found->second;
}
void Binding::reset(inputtype type, int code) { void Binding::reset(inputtype type, int code) {
this->type = type; this->type = type;
this->code = code; this->code = code;
@@ -58,11 +77,14 @@ void input_util::initialize() {
keycodes[std::to_string(i)] = GLFW_KEY_0+i; keycodes[std::to_string(i)] = GLFW_KEY_0+i;
} }
for (int i = 0; i < 25; i++) { for (int i = 0; i < 25; i++) {
keycodes["f"+std::to_string(i)] = GLFW_KEY_F1+i; keycodes["f"+std::to_string(i+1)] = GLFW_KEY_F1+i;
} }
for (char i = 'a'; i <= 'z'; i++) { for (char i = 'a'; i <= 'z'; i++) {
keycodes[std::string({i})] = GLFW_KEY_A-'a'+i; keycodes[std::string({i})] = GLFW_KEY_A-'a'+i;
} }
for (const auto& entry : keycodes) {
keynames[entry.second] = entry.first;
}
} }
keycode input_util::keycode_from(const std::string& name) { keycode input_util::keycode_from(const std::string& name) {
+5
View File
@@ -122,6 +122,11 @@ namespace input_util {
std::string to_string(keycode code); std::string to_string(keycode code);
/// @return Mouse button label by keycode /// @return Mouse button label by keycode
std::string to_string(mousecode code); std::string to_string(mousecode code);
/// @return Key name by keycode
std::string get_name(keycode code);
/// @return Mouse button name by keycode
std::string get_name(mousecode code);
} }
enum class inputtype { enum class inputtype {
-9
View File
@@ -1,9 +0,0 @@
## Key Names
- space, backspace, tab, enter, caps-lock, escape
- left-ctrl, left-shift, left-alt, left-super
- right-ctrl, right-shift, right-alt, right-alt
- delete, home, end, insert, page-up, page-down
- left, right, down, up
- a..z
- 0..9
- f1..f25
+1 -1
View File
@@ -58,8 +58,8 @@ public:
std::shared_ptr<T> tObj = std::make_shared<T>(args...); std::shared_ptr<T> tObj = std::make_shared<T>(args...);
std::shared_ptr<Object> obj = std::dynamic_pointer_cast<Object, T>(tObj); std::shared_ptr<Object> obj = std::dynamic_pointer_cast<Object, T>(tObj);
objects.push_back(obj);
obj->objectUID = objects.size(); obj->objectUID = objects.size();
objects.push_back(obj);
obj->spawned(); obj->spawned();
return tObj; return tObj;
} }
+12 -10
View File
@@ -12,7 +12,6 @@
#include "../voxels/Chunk.hpp" #include "../voxels/Chunk.hpp"
#include "../voxels/Chunks.hpp" #include "../voxels/Chunks.hpp"
#include "../voxels/ChunksStorage.hpp" #include "../voxels/ChunksStorage.hpp"
#include "../window/Camera.hpp"
#include "../world/WorldGenerators.hpp" #include "../world/WorldGenerators.hpp"
#include <memory> #include <memory>
@@ -58,11 +57,11 @@ void World::write(Level* level) {
for (size_t i = 0; i < chunks->volume; i++) { for (size_t i = 0; i < chunks->volume; i++) {
auto chunk = chunks->chunks[i]; auto chunk = chunks->chunks[i];
if (chunk == nullptr || !chunk->isLighted()) if (chunk == nullptr || !chunk->flags.lighted)
continue; continue;
bool lightsUnsaved = !chunk->isLoadedLights() && bool lightsUnsaved = !chunk->flags.loadedLights &&
settings.debug.doWriteLights.get(); settings.debug.doWriteLights.get();
if (!chunk->isUnsaved() && !lightsUnsaved) if (!chunk->flags.unsaved && !lightsUnsaved)
continue; continue;
regions.put(chunk.get()); regions.put(chunk.get());
} }
@@ -135,7 +134,6 @@ std::unique_ptr<Level> World::load(
} }
} }
} }
(void)world.release();
return level; return level;
} }
@@ -194,19 +192,20 @@ void World::deserialize(dynamic::Map* root) {
if (generator == "") { if (generator == "") {
generator = WorldGenerators::getDefaultGeneratorID(); generator = WorldGenerators::getDefaultGeneratorID();
} }
auto verobj = root->map("version"); if (auto verobj = root->map("version")) {
if (verobj) {
int major=0, minor=-1; int major=0, minor=-1;
verobj->num("major", major); verobj->num("major", major);
verobj->num("minor", minor); verobj->num("minor", minor);
std::cout << "world version: " << major << "." << minor << std::endl; logger.info() << "world version: " << major << "." << minor;
} }
auto timeobj = root->map("time"); if (auto timeobj = root->map("time")) {
if (timeobj) {
timeobj->num("day-time", daytime); timeobj->num("day-time", daytime);
timeobj->num("day-time-speed", daytimeSpeed); timeobj->num("day-time-speed", daytimeSpeed);
timeobj->num("total-time", totalTime); timeobj->num("total-time", totalTime);
} }
if (auto weatherobj = root->map("weather")) {
weatherobj->num("fog", fog);
}
nextInventoryId = root->get("next-inventory-id", 2); nextInventoryId = root->get("next-inventory-id", 2);
} }
@@ -226,6 +225,9 @@ std::unique_ptr<dynamic::Map> World::serialize() const {
timeobj.put("day-time-speed", daytimeSpeed); timeobj.put("day-time-speed", daytimeSpeed);
timeobj.put("total-time", totalTime); timeobj.put("total-time", totalTime);
auto& weatherobj = root->putMap("weather");
weatherobj.put("fog", fog);
root->put("next-inventory-id", nextInventoryId); root->put("next-inventory-id", nextInventoryId);
return root; return root;
} }
+3
View File
@@ -49,6 +49,9 @@ public:
/// @brief total time passed in the world (not depending on daytimeSpeed) /// @brief total time passed in the world (not depending on daytimeSpeed)
double totalTime = 0.0; double totalTime = 0.0;
/// @brief will be replaced with weather in future
float fog = 0.0f;
World( World(
std::string name, std::string name,
std::string generator, std::string generator,