Merge branch 'main' into dev
This commit is contained in:
commit
289e0f597c
117
README.md
117
README.md
@ -5,6 +5,8 @@
|
|||||||
- [Download](https://github.com/MihailRis/VoxelCore/releases/latest) | [Скачать](https://github.com/MihailRis/VoxelCore/releases/latest)
|
- [Download](https://github.com/MihailRis/VoxelCore/releases/latest) | [Скачать](https://github.com/MihailRis/VoxelCore/releases/latest)
|
||||||
- [Documentation](https://github.com/MihailRis/VoxelCore/blob/release-0.28/doc/en/main-page.md) | [Документация](https://github.com/MihailRis/VoxelCore/blob/release-0.28/doc/ru/main-page.md)
|
- [Documentation](https://github.com/MihailRis/VoxelCore/blob/release-0.28/doc/en/main-page.md) | [Документация](https://github.com/MihailRis/VoxelCore/blob/release-0.28/doc/ru/main-page.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Build project in Linux
|
## Build project in Linux
|
||||||
|
|
||||||
### Install libraries
|
### Install libraries
|
||||||
@ -13,13 +15,14 @@
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/skypjack/entt.git
|
git clone https://github.com/skypjack/entt.git
|
||||||
cd entt/build
|
cd entt
|
||||||
cmake -DCMAKE_BUILD_TYPE=Release -DENTT_INSTALL=on ..
|
mkdir build && cd build
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Release -DENTT_INSTALL=ON ..
|
||||||
sudo make install
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> If you are using ALT Linux, you should not use this EnTT installation method
|
> If you are using ALT Linux, do **not** use this EnTT installation method.
|
||||||
|
|
||||||
#### ALT Linux based distros
|
#### ALT Linux based distros
|
||||||
|
|
||||||
@ -31,11 +34,11 @@ apt-get install entt-devel libglfw3-devel libGLEW-devel libglm-devel libpng-deve
|
|||||||
#### Debian based distros
|
#### Debian based distros
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo apt install libglfw3-dev libglfw3 libglew-dev libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev libcurl4-openssl-dev
|
sudo apt install libglfw3 libglfw3-dev libglew-dev libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev libcurl4-openssl-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> CMake missing LUA_INCLUDE_DIR and LUA_LIBRARIES fix:
|
> CMake missing `LUA_INCLUDE_DIR` and `LUA_LIBRARIES` fix:
|
||||||
>
|
>
|
||||||
> ```sh
|
> ```sh
|
||||||
> sudo ln -s /usr/lib/x86_64-linux-gnu/libluajit-5.1.a /usr/lib/x86_64-linux-gnu/liblua5.1.a
|
> sudo ln -s /usr/lib/x86_64-linux-gnu/libluajit-5.1.a /usr/lib/x86_64-linux-gnu/liblua5.1.a
|
||||||
@ -45,24 +48,24 @@ sudo apt install libglfw3-dev libglfw3 libglew-dev libglm-dev libpng-dev libopen
|
|||||||
#### RHEL based distros
|
#### RHEL based distros
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo dnf install glfw-devel glfw glew-devel glm-devel libpng-devel libvorbis-devel openal-devel luajit-devel libcurl-devel
|
sudo dnf install glfw-devel glew-devel glm-devel libpng-devel libvorbis-devel openal-soft-devel luajit-devel libcurl-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Arch based distros
|
#### Arch based distros
|
||||||
|
|
||||||
If you use X11
|
If you use X11:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo pacman -S glfw-x11 glew glm libpng libvorbis openal luajit libcurl
|
sudo pacman -S glfw-x11 glew glm libpng libvorbis openal luajit libcurl
|
||||||
```
|
```
|
||||||
|
|
||||||
If you use Wayland
|
If you use Wayland:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo pacman -S glfw-wayland glew glm libpng libvorbis openal luajit libcurl
|
sudo pacman -S glfw-wayland glew glm libpng libvorbis openal luajit libcurl
|
||||||
```
|
```
|
||||||
|
|
||||||
And you need entt. In yay you can use
|
And install EnTT:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yay -S entt
|
yay -S entt
|
||||||
@ -76,9 +79,14 @@ cd VoxelCore
|
|||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||||
cmake --build .
|
cmake --build . --parallel
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Use `--parallel` to utilize all CPU cores during build.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Building project in macOS
|
## Building project in macOS
|
||||||
|
|
||||||
### Install libraries
|
### Install libraries
|
||||||
@ -88,9 +96,7 @@ brew install glfw3 glew glm libpng libvorbis lua luajit libcurl openal-soft skyp
|
|||||||
```
|
```
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> If homebrew for some reason could not install the necessary packages:
|
> If Homebrew fails to install `lua`, `luajit`, or `openal-soft`, download, compile, and install them manually.
|
||||||
> ```lua luajit openal-soft```, then download, install and compile them manually
|
|
||||||
> (Lua, LuaJIT and OpenAL).
|
|
||||||
|
|
||||||
### Building engine with CMake
|
### Building engine with CMake
|
||||||
|
|
||||||
@ -100,90 +106,109 @@ cd VoxelCore
|
|||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||||
cmake --build .
|
cmake --build . --parallel
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Building in Windows
|
## Building in Windows
|
||||||
|
|
||||||
>[!NOTE]
|
> [!NOTE]
|
||||||
> Requirement:
|
> Requirements: **vcpkg**, **CMake**, **Git**, and **Visual Studio** (with C++ tools).
|
||||||
>
|
|
||||||
> vcpkg, CMake, Git
|
|
||||||
There are two options to use vcpkg:
|
There are two options to use vcpkg:
|
||||||
1. If you have Visual Studio installed, most likely the **VCPKG_ROOT** environment variable will already exist in **Developer Command Prompt for VS**
|
|
||||||
2. If you want use **vcpkg**, install **vcpkg** from git to you system:
|
1. If you have Visual Studio installed, the **VCPKG_ROOT** environment variable is often already set in the **Developer Command Prompt for VS**.
|
||||||
```PowerShell
|
2. Otherwise, install **vcpkg** manually:
|
||||||
cd C:/
|
|
||||||
|
```powershell
|
||||||
|
cd C:\
|
||||||
git clone https://github.com/microsoft/vcpkg.git
|
git clone https://github.com/microsoft/vcpkg.git
|
||||||
cd vcpkg
|
cd vcpkg
|
||||||
.\bootstrap-vcpkg.bat
|
.\bootstrap-vcpkg.bat
|
||||||
```
|
```
|
||||||
After installing **vcpkg**, setup env variable **VCPKG_ROOT** and add it to **PATH**:
|
|
||||||
```PowerShell
|
Then set the `VCPKG_ROOT` environment variable and add it to `PATH`:
|
||||||
$env:VCPKG_ROOT = "C:\path\to\vcpkg"
|
|
||||||
|
```powershell
|
||||||
|
$env:VCPKG_ROOT = "C:\vcpkg"
|
||||||
$env:PATH = "$env:VCPKG_ROOT;$env:PATH"
|
$env:PATH = "$env:VCPKG_ROOT;$env:PATH"
|
||||||
```
|
```
|
||||||
>[!TIP]
|
|
||||||
>For troubleshooting you can read full [documentation](https://learn.microsoft.com/ru-ru/vcpkg/get_started/get-started?pivots=shell-powershell) for **vcpkg**
|
|
||||||
|
|
||||||
After installing **vcpkg** you can build project:
|
> [!TIP]
|
||||||
```PowerShell
|
> For troubleshooting, refer to the official [vcpkg documentation](https://learn.microsoft.com/ru-ru/vcpkg/get_started/get-started?pivots=shell-powershell).
|
||||||
|
|
||||||
|
After installing **vcpkg**, build the project:
|
||||||
|
|
||||||
|
```powershell
|
||||||
git clone --recursive https://github.com/MihailRis/VoxelCore.git
|
git clone --recursive https://github.com/MihailRis/VoxelCore.git
|
||||||
cd VoxelCore
|
cd VoxelCore
|
||||||
cmake --preset default-vs-msvc-windows
|
cmake --preset default-vs-msvc-windows
|
||||||
cmake --build --preset default-vs-msvc-windows
|
cmake --build --preset default-vs-msvc-windows
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Make sure your `CMakeUserPresets.json` (if used) contains the correct `VCPKG_ROOT` path.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Build using Docker
|
## Build using Docker
|
||||||
|
|
||||||
### Step 0. Install docker on your system
|
> [!NOTE]
|
||||||
|
> First, install Docker Engine: [https://docs.docker.com/engine/install](https://docs.docker.com/engine/install)
|
||||||
|
|
||||||
See <https://docs.docker.com/engine/install>
|
### On Linux
|
||||||
|
|
||||||
### Do you have Linux
|
#### Step 1. Build Docker image
|
||||||
|
|
||||||
### Step 1. Build docker container
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker build -t voxel-engine .
|
docker build -t voxel-engine .
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 2. Build project using the docker container
|
#### Step 2. Build project inside container
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker run --rm -it -v$(pwd):/project voxel-engine bash -c "cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && cmake --build build"
|
docker run --rm -it -v "$(pwd):/project" voxel-engine bash -c "cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && cmake --build build --parallel"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 3. Run project using the docker container
|
#### Step 3. Run the application (requires X11 forwarding)
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker run --rm -it -v$(pwd):/project -v/tmp/.X11-unix:/tmp/.X11-unix -v${XAUTHORITY}:/home/user/.Xauthority:ro -eDISPLAY --network=host voxel-engine ./build/VoxelEngine
|
docker run --rm -it \
|
||||||
|
-v "$(pwd):/project" \
|
||||||
|
-v /tmp/.X11-unix:/tmp/.X11-unix \
|
||||||
|
-v "$XAUTHORITY:/home/user/.Xauthority:ro" \
|
||||||
|
-e DISPLAY="$DISPLAY" \
|
||||||
|
--network=host \
|
||||||
|
voxel-engine ./build/VoxelEngine
|
||||||
```
|
```
|
||||||
|
|
||||||
### Do you have Windows
|
### On Windows
|
||||||
|
|
||||||
### Step 1. You need to install VcXsrv
|
> [!NOTE]
|
||||||
|
> You need an X server like **VcXsrv** to display the GUI.
|
||||||
|
|
||||||
### Step 2. Run VcXsrv with the command
|
#### Step 1. Install and run VcXsrv
|
||||||
|
|
||||||
|
Launch with:
|
||||||
```powershell
|
```powershell
|
||||||
.\vcxsrv.exe :0 -multiwindow -ac
|
.\vcxsrv.exe :0 -multiwindow -ac
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 3. Build docker container
|
#### Step 2. Build Docker image
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
docker build -t voxel-engine .
|
docker build -t voxel-engine .
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 4. Build project using the docker container
|
#### Step 3. Build project
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
docker run --rm -it -v "${PWD}:/project" voxel-engine bash -c "cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && cmake --build build"
|
docker run --rm -it -v "${PWD}:/project" voxel-engine bash -c "cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && cmake --build build --parallel"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 5. Run project using the docker container
|
#### Step 4. Run the application
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
docker run --rm -it -v "${PWD}:/project" -e DISPLAY=host.docker.internal:0.0 --network host voxel-engine ./build/VoxelEngine
|
docker run --rm -it -v "${PWD}:/project" -e DISPLAY=host.docker.internal:0.0 --network=host voxel-engine ./build/VoxelEngine
|
||||||
```
|
```
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
for i=1,3 do
|
for i=1,3 do
|
||||||
print(string.format("iteration %s", i + 1))
|
print(string.format("iteration %s", i))
|
||||||
local text = ""
|
local text = ""
|
||||||
local complete = false
|
local complete = false
|
||||||
|
|
||||||
|
|||||||
35
dev/tests/network_udp.lua
Normal file
35
dev/tests/network_udp.lua
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
math.randomseed(43172)
|
||||||
|
for i = 1, 15 do
|
||||||
|
debug.log(string.format("iteration %s", i))
|
||||||
|
local complete = false
|
||||||
|
|
||||||
|
local server = network.udp_open(8645 + i, function (address, port, data, srv)
|
||||||
|
debug.log(string.format("server received %s byte(s) from %s:%s", #data, address, port))
|
||||||
|
srv:send(address, port, "pong")
|
||||||
|
end)
|
||||||
|
|
||||||
|
app.tick()
|
||||||
|
network.udp_connect("localhost", 8645 + i, function (data)
|
||||||
|
debug.log(string.format("client received %s byte(s) from server", #data))
|
||||||
|
complete = true
|
||||||
|
end, function (socket)
|
||||||
|
debug.log("udp socket opened")
|
||||||
|
start_coroutine(function()
|
||||||
|
debug.log("udp data-sender started")
|
||||||
|
for k = 1, 15 do
|
||||||
|
local payload = ""
|
||||||
|
for j = 1, 16 do
|
||||||
|
payload = payload .. math.random(0, 9)
|
||||||
|
end
|
||||||
|
socket:send(payload)
|
||||||
|
debug.log(string.format("sent packet %s (%s bytes)", k, #payload))
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
app.sleep_until(function () return complete end, nil, 5)
|
||||||
|
socket:close()
|
||||||
|
end, "udp-data-sender")
|
||||||
|
end)
|
||||||
|
|
||||||
|
app.sleep_until(function () return complete end, nil, 5)
|
||||||
|
server:close()
|
||||||
|
end
|
||||||
@ -86,9 +86,9 @@ body:get_size() -> vec3
|
|||||||
body:set_size(size: vec3)
|
body:set_size(size: vec3)
|
||||||
|
|
||||||
-- Returns the gravity multiplier
|
-- Returns the gravity multiplier
|
||||||
body:get_gravity_scale() -> vec3
|
body:get_gravity_scale() -> number
|
||||||
-- Sets the gravity multiplier
|
-- Sets the gravity multiplier
|
||||||
body:set_gravity_scale(scale: vec3)
|
body:set_gravity_scale(scale: number)
|
||||||
|
|
||||||
-- Returns the linear velocity attenuation multiplier (used to simulate air resistance and friction)
|
-- Returns the linear velocity attenuation multiplier (used to simulate air resistance and friction)
|
||||||
body:get_linear_damping() -> number
|
body:get_linear_damping() -> number
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
- [Модуль core:bit_converter](scripting/modules/core_bit_converter.md)
|
- [Модуль core:bit_converter](scripting/modules/core_bit_converter.md)
|
||||||
- [Модуль core:data_buffer](scripting/modules/core_data_buffer.md)
|
- [Модуль core:data_buffer](scripting/modules/core_data_buffer.md)
|
||||||
- [Модули core:vector2, core:vector3](scripting/modules/core_vector2_vector3.md)
|
- [Модули core:vector2, core:vector3](scripting/modules/core_vector2_vector3.md)
|
||||||
|
- [Встроенные компоненты сущностей](scripting/core_components.md)
|
||||||
|
|
||||||
## Аннотации типов данных
|
## Аннотации типов данных
|
||||||
|
|
||||||
|
|||||||
89
doc/ru/scripting/core_components.md
Normal file
89
doc/ru/scripting/core_components.md
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# Встроенные компоненты
|
||||||
|
|
||||||
|
## *core:pathfinding*
|
||||||
|
|
||||||
|
Компонент для построение путей движения мобов.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local pathfinding = entity:require_component("core:pathfinding")
|
||||||
|
|
||||||
|
-- Устанавливает цель движения, не сбрасывая текущий маршрут
|
||||||
|
pathfinding.set_target(target: vec3)
|
||||||
|
|
||||||
|
-- Возвращает текущую цель движения
|
||||||
|
pathfinding.get_target() --> vec3
|
||||||
|
|
||||||
|
-- Устанавливает высоту преодолимого прыжком препятствия
|
||||||
|
pathfinding.set_jump_height(height: number)
|
||||||
|
|
||||||
|
-- Возвращает текущий построенный маршрут или nil
|
||||||
|
pathfinding.get_route()
|
||||||
|
|
||||||
|
-- Сбрасывает текущий построенный маршрут
|
||||||
|
pathfinding.reset_route()
|
||||||
|
|
||||||
|
-- Возвращает следующую точку маршрута, по текущим координатам.
|
||||||
|
-- (следует использовать компонент core:mob - функция mob.follow_waypoints)
|
||||||
|
pathfinding.next_waypoint() --> vec3 или nil
|
||||||
|
|
||||||
|
-- Устанавливает интервал перестройки маршрута в тактах обновления.
|
||||||
|
pathfinding.set_refresh_interval(interval: number)
|
||||||
|
```
|
||||||
|
|
||||||
|
## *core:mob*
|
||||||
|
|
||||||
|
Компонент для управления движением (включая полёт) и вращением мобов.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local mob = entity:require_component("core:mob")
|
||||||
|
|
||||||
|
-- Выполняет прыжок с силой jump_force * multiplier
|
||||||
|
mob.jump([опционально] multiplier: number = 1.0)
|
||||||
|
|
||||||
|
|
||||||
|
-- Вертикальное движение (работает в полёте или в плавании (в будущем))
|
||||||
|
mob.move_vertical(
|
||||||
|
-- Скорость вертикального движения
|
||||||
|
speed: number,
|
||||||
|
-- Текущая скорость сущности (для минимизации вызовов rigidbody:get_vel())
|
||||||
|
[опционально] current_velocity
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Горизонтальное движение
|
||||||
|
mob.go(
|
||||||
|
-- 2D вектор направления движения
|
||||||
|
dir: vec2,
|
||||||
|
-- Множитель скорости
|
||||||
|
speed_multiplier: number,
|
||||||
|
-- Бег
|
||||||
|
sprint: bool,
|
||||||
|
-- Присядь
|
||||||
|
crouch: bool,
|
||||||
|
-- Текущая скорость сущности (для минимизации вызовов rigidbody:get_vel())
|
||||||
|
[опционально] current_velocity
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Меняет направление взгляда сущности, направляя на указанную точку
|
||||||
|
mob.look_at(
|
||||||
|
-- Целевая точка
|
||||||
|
point: vec3,
|
||||||
|
-- Менять ли направление всей сущности
|
||||||
|
change_dir: bool = false
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Движение по построенному маршруту.
|
||||||
|
-- Если не указан pathfinding, требуется наличие у сущности компонента core:pathfinding
|
||||||
|
mob.follow_waypoints(
|
||||||
|
-- Возможная замена компонента pathfinding
|
||||||
|
[опционально] pathfinding
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Устанавливает направление всей сущности
|
||||||
|
mob.set_dir(dir: vec3)
|
||||||
|
|
||||||
|
-- Проверяет, включён ли режим полёта
|
||||||
|
mob.is_flight() --> bool
|
||||||
|
|
||||||
|
-- Включает/выключает режим полёта
|
||||||
|
mob.set_flight(flag: bool)
|
||||||
|
```
|
||||||
@ -86,9 +86,9 @@ body:get_size() -> vec3
|
|||||||
body:set_size(size: vec3)
|
body:set_size(size: vec3)
|
||||||
|
|
||||||
-- Возвращает множитель гравитации
|
-- Возвращает множитель гравитации
|
||||||
body:get_gravity_scale() -> vec3
|
body:get_gravity_scale() -> number
|
||||||
-- Устанавливает множитель гравитации
|
-- Устанавливает множитель гравитации
|
||||||
body:set_gravity_scale(scale: vec3)
|
body:set_gravity_scale(scale: number)
|
||||||
|
|
||||||
-- Возвращает множитель затухания линейной скорости (используется для имитации сопротивления воздуха и трения)
|
-- Возвращает множитель затухания линейной скорости (используется для имитации сопротивления воздуха и трения)
|
||||||
body:get_linear_damping() -> number
|
body:get_linear_damping() -> number
|
||||||
|
|||||||
@ -22,6 +22,11 @@
|
|||||||
|
|
||||||
На данный момент существует два вида примитивов: box и rect, а также, part (описывает часть примитива, такую как, например, сторона куба).
|
На данный момент существует два вида примитивов: box и rect, а также, part (описывает часть примитива, такую как, например, сторона куба).
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> По-умолчанию текстурные координаты определяются размерами примитивов.
|
||||||
|
> При размерах более 1.0 результат не определён и может измениться в последующих обновлениях.
|
||||||
|
> Используйте `region` или `region-scale` для ручной настройки.
|
||||||
|
|
||||||
### Свойства `rect`
|
### Свойства `rect`
|
||||||
|
|
||||||
- `from` - точка начала примитива. Пример: `from (0,0.5,0.125)`
|
- `from` - точка начала примитива. Пример: `from (0,0.5,0.125)`
|
||||||
|
|||||||
@ -31,11 +31,11 @@
|
|||||||
size='32' margin='0,0,425,64' gravity='bottom-right'
|
size='32' margin='0,0,425,64' gravity='bottom-right'
|
||||||
color='#FFFFFF50' hover-color='#FFFFFF10'/>
|
color='#FFFFFF50' hover-color='#FFFFFF10'/>
|
||||||
|
|
||||||
<panel id='packs_add' pos='485,34' size='440,507' color='0' max-length='455' scrollable='true'>
|
<panel id='packs_add' pos='485,34' size='440,455' color='0' max-length='455' scrollable='true'>
|
||||||
<!-- content is generated in script -->
|
<!-- content is generated in script -->
|
||||||
</panel>
|
</panel>
|
||||||
|
|
||||||
<panel id='packs_cur' pos='15,34' size='440,507' color='0' max-length='455' scrollable='true'>
|
<panel id='packs_cur' pos='15,34' size='440,455' color='0' max-length='455' scrollable='true'>
|
||||||
<!-- content is generated in script -->
|
<!-- content is generated in script -->
|
||||||
</panel>
|
</panel>
|
||||||
</container>
|
</container>
|
||||||
@ -255,30 +255,33 @@ function check_dependencies(packinfo)
|
|||||||
if packinfo.dependencies == nil then
|
if packinfo.dependencies == nil then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
for i,dep in ipairs(packinfo.dependencies) do
|
for i, dep in ipairs(packinfo.dependencies) do
|
||||||
local depid, depver = unpack(string.split(dep:sub(2,-1), "@"))
|
local depid, depver = unpack(string.split(dep:sub(2,-1), "@"))
|
||||||
|
|
||||||
if dep:sub(1,1) == '!' then
|
if dep:sub(1,1) ~= '!' then
|
||||||
if not table.has(packs_all, depid) then
|
goto continue
|
||||||
return string.format(
|
|
||||||
"%s (%s)", gui.str("error.dependency-not-found"), depid
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local dep_pack = pack.get_info(depid);
|
|
||||||
|
|
||||||
if not compare_version(depver, dep_pack.version) then
|
|
||||||
local op, ver = Version.parse(depver);
|
|
||||||
|
|
||||||
print(string.format("%s: %s !%s %s (%s)", gui.str("error.dependency-version-not-met"), dep_pack.version, op, ver, depid));
|
|
||||||
return string.format("%s: %s != %s (%s)", gui.str("error.dependency-version-not-met"), dep_pack.version, ver, depid);
|
|
||||||
end
|
|
||||||
|
|
||||||
if table.has(packs_installed, packinfo.id) then
|
|
||||||
table.insert(required, depid)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
if not table.has(packs_all, depid) then
|
||||||
|
return string.format(
|
||||||
|
"%s (%s)", gui.str("error.dependency-not-found"), depid
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
local dep_pack = pack.get_info(depid);
|
||||||
|
|
||||||
|
if not compare_version(depver, dep_pack.version) then
|
||||||
|
local op, ver = Version.parse(depver)
|
||||||
|
return string.format(
|
||||||
|
"%s: %s != %s (%s)",
|
||||||
|
gui.str("error.dependency-version-not-met"),
|
||||||
|
dep_pack.version, ver, depid
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
if table.has(packs_installed, packinfo.id) then
|
||||||
|
table.insert(required, depid)
|
||||||
|
end
|
||||||
|
::continue::
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,35 +0,0 @@
|
|||||||
local Random = {}
|
|
||||||
|
|
||||||
local M = 2 ^ 31
|
|
||||||
local A = 1103515245
|
|
||||||
local C = 12345
|
|
||||||
|
|
||||||
function Random.randint(self)
|
|
||||||
self._seed = (A * self._seed + C) % M
|
|
||||||
return self._seed
|
|
||||||
end
|
|
||||||
|
|
||||||
function Random.random(self, a, b)
|
|
||||||
local num = self:randint() % M / M
|
|
||||||
if b then
|
|
||||||
return math.floor(num * (b - a + 1) + a)
|
|
||||||
elseif a then
|
|
||||||
return math.floor(num * a + 1)
|
|
||||||
else
|
|
||||||
return num
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Random.seed(self, number)
|
|
||||||
if type(number) ~= "number" then
|
|
||||||
error("number expected")
|
|
||||||
end
|
|
||||||
self._seed = number
|
|
||||||
end
|
|
||||||
|
|
||||||
return function(seed)
|
|
||||||
if seed and type(seed) ~= "number" then
|
|
||||||
error("number expected")
|
|
||||||
end
|
|
||||||
return setmetatable({_seed = seed or random.random(M)}, {__index = Random})
|
|
||||||
end
|
|
||||||
@ -144,7 +144,11 @@ network.udp_connect = function (address, port, datagramHandler, openCallback)
|
|||||||
socket.id = network.__connect_udp(address, port)
|
socket.id = network.__connect_udp(address, port)
|
||||||
|
|
||||||
_udp_client_datagram_callbacks[socket.id] = datagramHandler
|
_udp_client_datagram_callbacks[socket.id] = datagramHandler
|
||||||
_udp_client_open_callbacks[socket.id] = openCallback
|
if openCallback then
|
||||||
|
_udp_client_open_callbacks[socket.id] = function()
|
||||||
|
openCallback(socket)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return socket
|
return socket
|
||||||
end
|
end
|
||||||
@ -225,8 +229,6 @@ block.__process_register_events = function()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
print(type, id, x, y, z)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -256,9 +258,15 @@ network.__process_events = function()
|
|||||||
end
|
end
|
||||||
elseif etype == DATAGRAM then
|
elseif etype == DATAGRAM then
|
||||||
if side == ON_CLIENT then
|
if side == ON_CLIENT then
|
||||||
_udp_client_datagram_callbacks[cid](data)
|
local callback = _udp_client_datagram_callbacks[cid]
|
||||||
|
if callback then
|
||||||
|
callback(data)
|
||||||
|
end
|
||||||
elseif side == ON_SERVER then
|
elseif side == ON_SERVER then
|
||||||
_udp_server_callbacks[sid](addr, port, data)
|
local callback = _udp_server_callbacks[sid]
|
||||||
|
if callback then
|
||||||
|
callback(addr, port, data)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
elseif etype == RESPONSE then
|
elseif etype == RESPONSE then
|
||||||
if event[2] / 100 == 2 then
|
if event[2] / 100 == 2 then
|
||||||
|
|||||||
@ -51,6 +51,7 @@ end
|
|||||||
|
|
||||||
function move_vertical(speed, vel)
|
function move_vertical(speed, vel)
|
||||||
vel = vel or body:get_vel()
|
vel = vel or body:get_vel()
|
||||||
|
speed = speed or 1.0
|
||||||
vel[2] = vel[2] * 0.2 + props.movement_speed * speed * 0.8
|
vel[2] = vel[2] * 0.2 + props.movement_speed * speed * 0.8
|
||||||
body:set_vel(vel)
|
body:set_vel(vel)
|
||||||
end
|
end
|
||||||
@ -145,6 +146,10 @@ function set_dir(new_dir)
|
|||||||
dir = new_dir
|
dir = new_dir
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function get_dir()
|
||||||
|
return dir
|
||||||
|
end
|
||||||
|
|
||||||
function is_flight() return flight end
|
function is_flight() return flight end
|
||||||
|
|
||||||
function set_flight(flag) flight = flag end
|
function set_flight(flag) flight = flag end
|
||||||
@ -154,7 +159,7 @@ local prev_angle = (vec2.angle({dir[3], dir[1]})) % 360
|
|||||||
function on_physics_update(delta)
|
function on_physics_update(delta)
|
||||||
local grounded = body:is_grounded()
|
local grounded = body:is_grounded()
|
||||||
body:set_vdamping(flight)
|
body:set_vdamping(flight)
|
||||||
body:set_gravity_scale({0, flight and 0.0 or props.gravity_scale, 0})
|
body:set_gravity_scale(flight and 0.0 or props.gravity_scale)
|
||||||
body:set_linear_damping(
|
body:set_linear_damping(
|
||||||
(flight or not grounded) and props.air_damping or props.ground_damping
|
(flight or not grounded) and props.air_damping or props.ground_damping
|
||||||
)
|
)
|
||||||
|
|||||||
@ -25,6 +25,10 @@ function get_route()
|
|||||||
return route
|
return route
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function reset_route()
|
||||||
|
route = nil
|
||||||
|
end
|
||||||
|
|
||||||
function next_waypoint()
|
function next_waypoint()
|
||||||
if not route or #route == 0 then
|
if not route or #route == 0 then
|
||||||
return
|
return
|
||||||
|
|||||||
@ -4,13 +4,22 @@ local mob = entity:require_component("core:mob")
|
|||||||
|
|
||||||
local cheat_speed_mul = 10.0
|
local cheat_speed_mul = 10.0
|
||||||
|
|
||||||
local function process_player_inputs(pid, delta)
|
local function get_player_rotation(pid)
|
||||||
|
local rx, ry, rz = player.get_rot(pid)
|
||||||
|
local matrix = mat4.rotate({0, 1, 0}, rx)
|
||||||
|
mat4.rotate(matrix, {1, 0, 0}, ry, matrix)
|
||||||
|
mat4.rotate(matrix, {0, 0, 1}, rz, matrix)
|
||||||
|
return matrix
|
||||||
|
end
|
||||||
|
|
||||||
|
local function process_player_inputs(pid, rot, delta)
|
||||||
if not hud or hud.is_inventory_open() or menu.page ~= "" then
|
if not hud or hud.is_inventory_open() or menu.page ~= "" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local cam = cameras.get("core:first-person")
|
|
||||||
local front = cam:get_front()
|
local front = mat4.mul(rot, {0, 0, -1})
|
||||||
local right = cam:get_right()
|
local right = mat4.mul(rot, {1, 0, 0})
|
||||||
|
|
||||||
front[2] = 0.0
|
front[2] = 0.0
|
||||||
vec3.normalize(front, front)
|
vec3.normalize(front, front)
|
||||||
|
|
||||||
@ -22,8 +31,6 @@ local function process_player_inputs(pid, delta)
|
|||||||
local isback = input.is_active('movement.back')
|
local isback = input.is_active('movement.back')
|
||||||
local isleft = input.is_active('movement.left')
|
local isleft = input.is_active('movement.left')
|
||||||
local isright = input.is_active('movement.right')
|
local isright = input.is_active('movement.right')
|
||||||
mob.set_flight(player.is_flight(pid))
|
|
||||||
body:set_body_type(player.is_noclip(pid) and "kinematic" or "dynamic")
|
|
||||||
body:set_crouching(iscrouch)
|
body:set_crouching(iscrouch)
|
||||||
|
|
||||||
local vel = body:get_vel()
|
local vel = body:get_vel()
|
||||||
@ -53,10 +60,19 @@ end
|
|||||||
|
|
||||||
function on_physics_update(delta)
|
function on_physics_update(delta)
|
||||||
local pid = entity:get_player()
|
local pid = entity:get_player()
|
||||||
if pid ~= -1 then
|
if pid == -1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
mob.set_flight(player.is_flight(pid))
|
||||||
|
body:set_body_type(player.is_noclip(pid) and "kinematic" or "dynamic")
|
||||||
|
|
||||||
|
if hud and pid == hud.get_player() then
|
||||||
local pos = tsf:get_pos()
|
local pos = tsf:get_pos()
|
||||||
local cam = cameras.get("core:first-person")
|
local rot = get_player_rotation(pid)
|
||||||
process_player_inputs(pid, delta)
|
local front = mat4.mul(rot, {0, 0, -1})
|
||||||
mob.look_at(vec3.add(pos, cam:get_front()))
|
|
||||||
|
process_player_inputs(pid, rot, delta)
|
||||||
|
mob.look_at(vec3.add(pos, front))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -669,4 +669,41 @@ end
|
|||||||
bit.compile = require "core:bitwise/compiler"
|
bit.compile = require "core:bitwise/compiler"
|
||||||
bit.execute = require "core:bitwise/executor"
|
bit.execute = require "core:bitwise/executor"
|
||||||
|
|
||||||
random.Random = require "core:internal/random_generator"
|
function __vc_create_random_methods(random_methods)
|
||||||
|
local index = 1
|
||||||
|
local buffer = nil
|
||||||
|
local buffer_size = 64
|
||||||
|
|
||||||
|
local seed_func = random_methods.seed
|
||||||
|
local random_func = random_methods.random
|
||||||
|
|
||||||
|
function random_methods:bytes(n)
|
||||||
|
local bytes = Bytearray(n)
|
||||||
|
for i=1,n do
|
||||||
|
bytes[i] = self:random(255)
|
||||||
|
end
|
||||||
|
return bytes
|
||||||
|
end
|
||||||
|
|
||||||
|
function random_methods:seed(x)
|
||||||
|
seed_func(self, x)
|
||||||
|
buffer = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function random_methods:random(a, b)
|
||||||
|
if not buffer or index > #buffer then
|
||||||
|
buffer = random_func(self, buffer_size)
|
||||||
|
index = 1
|
||||||
|
end
|
||||||
|
local value = buffer[index]
|
||||||
|
if b then
|
||||||
|
value = math.floor(value * (b - a + 1) + a)
|
||||||
|
elseif a then
|
||||||
|
value = math.floor(value * a + 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
index = index + 4
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
return random_methods
|
||||||
|
end
|
||||||
|
|||||||
@ -43,7 +43,7 @@ float calc_shadow(
|
|||||||
// TODO: add array textures support
|
// TODO: add array textures support
|
||||||
float calc_shadow(vec4 modelPos, vec3 realnormal, float distance) {
|
float calc_shadow(vec4 modelPos, vec3 realnormal, float distance) {
|
||||||
#ifdef ENABLE_SHADOWS
|
#ifdef ENABLE_SHADOWS
|
||||||
float s = pow(abs(cos(u_dayTime * PI2)), 0.25) * u_shadowsOpacity;
|
float s = u_shadowsOpacity;
|
||||||
vec3 normalOffset = realnormal * (distance > 64.0 ? 0.2 : 0.04);
|
vec3 normalOffset = realnormal * (distance > 64.0 ? 0.2 : 0.04);
|
||||||
|
|
||||||
// as slow as mix(...)
|
// as slow as mix(...)
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
#include <constants>
|
#include <constants>
|
||||||
|
|
||||||
vec3 pick_sky_color(samplerCube cubemap) {
|
vec3 pick_sky_color(samplerCube cubemap) {
|
||||||
vec3 skyLightColor = texture(cubemap, vec3(0.8f, 0.01f, 0.4f)).rgb;
|
vec3 skyLightColor = texture(cubemap, vec3(0.4f, 0.05f, 0.4f)).rgb;
|
||||||
skyLightColor *= SKY_LIGHT_TINT;
|
skyLightColor *= SKY_LIGHT_TINT;
|
||||||
skyLightColor = min(vec3(1.0f), skyLightColor * SKY_LIGHT_MUL);
|
skyLightColor = min(vec3(1.0f), skyLightColor * SKY_LIGHT_MUL);
|
||||||
skyLightColor = max(MIN_SKY_LIGHT, skyLightColor);
|
skyLightColor = max(MIN_SKY_LIGHT, skyLightColor);
|
||||||
|
|||||||
@ -268,7 +268,11 @@ void main() {
|
|||||||
camera_vector, // the camera vector (ray direction of this pixel)
|
camera_vector, // the camera vector (ray direction of this pixel)
|
||||||
1e12f, // max dist, essentially the scene depth
|
1e12f, // max dist, essentially the scene depth
|
||||||
vec3(0.0f), // scene color, the color of the current pixel being rendered
|
vec3(0.0f), // scene color, the color of the current pixel being rendered
|
||||||
vec3(u_lightDir.x, pow(u_lightDir.y, 3.0), u_lightDir.z), // light direction
|
vec3(
|
||||||
|
u_lightDir.x,
|
||||||
|
u_lightDir.y,
|
||||||
|
u_lightDir.z
|
||||||
|
), // light direction
|
||||||
vec3(40.0*fog), // light intensity, 40 looks nice
|
vec3(40.0*fog), // light intensity, 40 looks nice
|
||||||
PLANET_POS, // position of the planet
|
PLANET_POS, // position of the planet
|
||||||
PLANET_RADIUS, // radius of the planet in meters
|
PLANET_RADIUS, // radius of the planet in meters
|
||||||
|
|||||||
@ -32,7 +32,7 @@ protected:
|
|||||||
void goBack(size_t count = 1);
|
void goBack(size_t count = 1);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
int64_t parseSimpleInt(int base);
|
int64_t parseSimpleInt(int base, size_t maxLength = 0xFFFFFFFF);
|
||||||
dv::value parseNumber(int sign);
|
dv::value parseNumber(int sign);
|
||||||
dv::value parseNumber();
|
dv::value parseNumber();
|
||||||
StringT parseString(CharT chr, bool closeRequired = true);
|
StringT parseString(CharT chr, bool closeRequired = true);
|
||||||
|
|||||||
@ -349,7 +349,10 @@ std::basic_string<CharT> BasicParser<CharT>::parseXmlName() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename CharT>
|
template <typename CharT>
|
||||||
int64_t BasicParser<CharT>::parseSimpleInt(int base) {
|
int64_t BasicParser<CharT>::parseSimpleInt(int base, size_t maxLength) {
|
||||||
|
if (maxLength == 0) return 0;
|
||||||
|
|
||||||
|
size_t start = pos;
|
||||||
CharT c = peek();
|
CharT c = peek();
|
||||||
int index = hexchar2int(c);
|
int index = hexchar2int(c);
|
||||||
if (index == -1 || index >= base) {
|
if (index == -1 || index >= base) {
|
||||||
@ -357,7 +360,7 @@ int64_t BasicParser<CharT>::parseSimpleInt(int base) {
|
|||||||
}
|
}
|
||||||
int64_t value = index;
|
int64_t value = index;
|
||||||
pos++;
|
pos++;
|
||||||
while (hasNext()) {
|
while (hasNext() && pos - start < maxLength) {
|
||||||
c = source[pos];
|
c = source[pos];
|
||||||
while (c == '_') {
|
while (c == '_') {
|
||||||
c = source[++pos];
|
c = source[++pos];
|
||||||
@ -476,7 +479,7 @@ std::basic_string<CharT> BasicParser<CharT>::parseString(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c == 'u' || c == 'x') {
|
if (c == 'u' || c == 'x') {
|
||||||
int codepoint = parseSimpleInt(16);
|
int codepoint = parseSimpleInt(16, c == 'u' ? 4 : 2);
|
||||||
ubyte bytes[4];
|
ubyte bytes[4];
|
||||||
int size = util::encode_utf8(codepoint, bytes);
|
int size = util::encode_utf8(codepoint, bytes);
|
||||||
CharT chars[4];
|
CharT chars[4];
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
#define VC_ENABLE_REFLECTION
|
||||||
#include "ContentPack.hpp"
|
#include "ContentPack.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -146,7 +147,7 @@ ContentPack ContentPack::read(const io::path& folder) {
|
|||||||
std::uint8_t op_size = 0;
|
std::uint8_t op_size = 0;
|
||||||
|
|
||||||
// Two symbol operators
|
// Two symbol operators
|
||||||
if (op == ">=" || op == "=>" || op == "<=" || op == "=<") {
|
if (op == ">=" || op == "<=") {
|
||||||
op_size = 2;
|
op_size = 2;
|
||||||
depVerOperator = op;
|
depVerOperator = op;
|
||||||
}
|
}
|
||||||
@ -169,7 +170,16 @@ ContentPack ContentPack::read(const io::path& folder) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pack.dependencies.push_back({level, depName, depVer, depVerOperator});
|
VersionOperator versionOperator;
|
||||||
|
if (VersionOperatorMeta.getItem(depVerOperator, versionOperator)) {
|
||||||
|
pack.dependencies.push_back(
|
||||||
|
{level, depName, depVer, versionOperator}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw contentpack_error(
|
||||||
|
pack.id, folder, "invalid version operator"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "typedefs.hpp"
|
||||||
|
#include "content_fwd.hpp"
|
||||||
|
#include "io/io.hpp"
|
||||||
|
#include "util/EnumMetadata.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "typedefs.hpp"
|
|
||||||
#include "content_fwd.hpp"
|
|
||||||
#include "io/io.hpp"
|
|
||||||
|
|
||||||
class EnginePaths;
|
class EnginePaths;
|
||||||
|
|
||||||
class contentpack_error : public std::runtime_error {
|
class contentpack_error : public std::runtime_error {
|
||||||
@ -25,11 +26,19 @@ public:
|
|||||||
io::path getFolder() const;
|
io::path getFolder() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DependencyVersionOperator {
|
enum class VersionOperator {
|
||||||
EQUAL, GREATHER, LESS,
|
EQUAL, GREATHER, LESS,
|
||||||
GREATHER_OR_EQUAL, LESS_OR_EQUAL
|
GREATHER_OR_EQUAL, LESS_OR_EQUAL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
VC_ENUM_METADATA(VersionOperator)
|
||||||
|
{"=", VersionOperator::EQUAL},
|
||||||
|
{">", VersionOperator::GREATHER},
|
||||||
|
{"<", VersionOperator::LESS},
|
||||||
|
{">=", VersionOperator::GREATHER_OR_EQUAL},
|
||||||
|
{"<=", VersionOperator::LESS_OR_EQUAL},
|
||||||
|
VC_ENUM_END
|
||||||
|
|
||||||
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
|
||||||
@ -41,7 +50,7 @@ struct DependencyPack {
|
|||||||
DependencyLevel level;
|
DependencyLevel level;
|
||||||
std::string id;
|
std::string id;
|
||||||
std::string version;
|
std::string version;
|
||||||
std::string op;
|
VersionOperator op;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ContentPackStats {
|
struct ContentPackStats {
|
||||||
|
|||||||
@ -26,26 +26,11 @@ Version::Version(const std::string& version) {
|
|||||||
if (parts.size() > 2) patch = parts[2];
|
if (parts.size() > 2) patch = parts[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
DependencyVersionOperator Version::string_to_operator(const std::string& op) {
|
|
||||||
if (op == "=")
|
|
||||||
return DependencyVersionOperator::EQUAL;
|
|
||||||
else if (op == ">")
|
|
||||||
return DependencyVersionOperator::GREATHER;
|
|
||||||
else if (op == "<")
|
|
||||||
return DependencyVersionOperator::LESS;
|
|
||||||
else if (op == ">=" || op == "=>")
|
|
||||||
return DependencyVersionOperator::GREATHER_OR_EQUAL;
|
|
||||||
else if (op == "<=" || op == "=<")
|
|
||||||
return DependencyVersionOperator::LESS_OR_EQUAL;
|
|
||||||
else
|
|
||||||
return DependencyVersionOperator::EQUAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNumber(const std::string& s) {
|
bool isNumber(const std::string& s) {
|
||||||
return !s.empty() && std::all_of(s.begin(), s.end(), ::is_digit);
|
return !s.empty() && std::all_of(s.begin(), s.end(), ::is_digit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Version::matches_pattern(const std::string& version) {
|
bool Version::matchesPattern(const std::string& version) {
|
||||||
for (char c : version) {
|
for (char c : version) {
|
||||||
if (!isdigit(c) && c != '.') {
|
if (!isdigit(c) && c != '.') {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -33,25 +33,22 @@ public:
|
|||||||
return !(*this > other);
|
return !(*this > other);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool process_operator(const std::string& op, const Version& other) const {
|
bool processOperator(VersionOperator op, const Version& other) const {
|
||||||
auto dep_op = Version::string_to_operator(op);
|
switch (op) {
|
||||||
|
case VersionOperator::EQUAL:
|
||||||
switch (dep_op) {
|
|
||||||
case DependencyVersionOperator::EQUAL:
|
|
||||||
return *this == other;
|
return *this == other;
|
||||||
case DependencyVersionOperator::GREATHER:
|
case VersionOperator::GREATHER:
|
||||||
return *this > other;
|
return *this > other;
|
||||||
case DependencyVersionOperator::LESS:
|
case VersionOperator::LESS:
|
||||||
return *this < other;
|
return *this < other;
|
||||||
case DependencyVersionOperator::LESS_OR_EQUAL:
|
case VersionOperator::LESS_OR_EQUAL:
|
||||||
return *this <= other;
|
return *this <= other;
|
||||||
case DependencyVersionOperator::GREATHER_OR_EQUAL:
|
case VersionOperator::GREATHER_OR_EQUAL:
|
||||||
return *this >= other;
|
return *this >= other;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static DependencyVersionOperator string_to_operator(const std::string& op);
|
static bool matchesPattern(const std::string& version);
|
||||||
static bool matches_pattern(const std::string& version);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
#define VC_ENABLE_REFLECTION
|
||||||
#include "PacksManager.hpp"
|
#include "PacksManager.hpp"
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
@ -109,9 +110,9 @@ static bool resolve_dependencies(
|
|||||||
|
|
||||||
auto dep_pack = found -> second;
|
auto dep_pack = found -> second;
|
||||||
|
|
||||||
if (Version::matches_pattern(dep.version) && Version::matches_pattern(dep_pack.version)
|
if (Version::matchesPattern(dep.version) && Version::matchesPattern(dep_pack.version)
|
||||||
&& Version(dep_pack.version)
|
&& Version(dep_pack.version)
|
||||||
.process_operator(dep.op, Version(dep.version))
|
.processOperator(dep.op, Version(dep.version))
|
||||||
) {
|
) {
|
||||||
// dependency pack version meets the required one
|
// dependency pack version meets the required one
|
||||||
continue;
|
continue;
|
||||||
@ -120,7 +121,11 @@ static bool resolve_dependencies(
|
|||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
throw contentpack_error(
|
throw contentpack_error(
|
||||||
dep.id, io::path(), "does not meet required version '" + dep.op + dep.version +"' of '" + pack->id + "'"
|
dep.id,
|
||||||
|
io::path(),
|
||||||
|
"does not meet required version '" +
|
||||||
|
VersionOperatorMeta.getNameString(dep.op) + dep.version +
|
||||||
|
"' of '" + pack->id + "'"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -96,12 +96,16 @@ void Shadows::setup(Shader& shader, const Weather& weather) {
|
|||||||
if (shadows) {
|
if (shadows) {
|
||||||
const auto& worldInfo = level.getWorld()->getInfo();
|
const auto& worldInfo = level.getWorld()->getInfo();
|
||||||
float cloudsIntensity = glm::max(worldInfo.fog, weather.clouds());
|
float cloudsIntensity = glm::max(worldInfo.fog, weather.clouds());
|
||||||
|
float shadowsOpacity = 1.0f - cloudsIntensity;
|
||||||
|
shadowsOpacity *= glm::sqrt(glm::abs(
|
||||||
|
glm::mod((worldInfo.daytime + 0.5f) * 2.0f, 1.0f) * 2.0f - 1.0f
|
||||||
|
));
|
||||||
shader.uniform1i("u_screen", 0);
|
shader.uniform1i("u_screen", 0);
|
||||||
shader.uniformMatrix("u_shadowsMatrix[0]", shadowCamera.getProjView());
|
shader.uniformMatrix("u_shadowsMatrix[0]", shadowCamera.getProjView());
|
||||||
shader.uniformMatrix("u_shadowsMatrix[1]", wideShadowCamera.getProjView());
|
shader.uniformMatrix("u_shadowsMatrix[1]", wideShadowCamera.getProjView());
|
||||||
shader.uniform3f("u_sunDir", shadowCamera.front);
|
shader.uniform3f("u_sunDir", shadowCamera.front);
|
||||||
shader.uniform1i("u_shadowsRes", shadowMap->getResolution());
|
shader.uniform1i("u_shadowsRes", shadowMap->getResolution());
|
||||||
shader.uniform1f("u_shadowsOpacity", 1.0f - cloudsIntensity); // TODO: make it configurable
|
shader.uniform1f("u_shadowsOpacity", shadowsOpacity); // TODO: make it configurable
|
||||||
shader.uniform1f("u_shadowsSoftness", 1.0f + cloudsIntensity * 4); // TODO: make it configurable
|
shader.uniform1f("u_shadowsSoftness", 1.0f + cloudsIntensity * 4); // TODO: make it configurable
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + TARGET_SHADOWS0);
|
glActiveTexture(GL_TEXTURE0 + TARGET_SHADOWS0);
|
||||||
|
|||||||
@ -22,7 +22,7 @@ namespace markdown {
|
|||||||
Result<wchar_t> process(std::wstring_view source, bool eraseMarkdown);
|
Result<wchar_t> process(std::wstring_view source, bool eraseMarkdown);
|
||||||
|
|
||||||
template <typename CharT>
|
template <typename CharT>
|
||||||
inline std::basic_string<CharT> escape(std::string_view source) {
|
inline std::basic_string<CharT> escape(std::basic_string_view<CharT> source) {
|
||||||
std::basic_stringstream<CharT> ss;
|
std::basic_stringstream<CharT> ss;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
while (pos < source.size()) {
|
while (pos < source.size()) {
|
||||||
|
|||||||
@ -54,7 +54,12 @@ static int l_get_gravity_scale(lua::State* L) {
|
|||||||
|
|
||||||
static int l_set_gravity_scale(lua::State* L) {
|
static int l_set_gravity_scale(lua::State* L) {
|
||||||
if (auto entity = get_entity(L, 1)) {
|
if (auto entity = get_entity(L, 1)) {
|
||||||
entity->getRigidbody().hitbox.gravityScale = lua::tovec3(L, 2).y;
|
auto& hitbox = entity->getRigidbody().hitbox;
|
||||||
|
if (lua::istable(L, 2)) {
|
||||||
|
hitbox.gravityScale = lua::tovec3(L, 2).y;
|
||||||
|
} else {
|
||||||
|
hitbox.gravityScale = lua::tonumber(L, 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,4 @@
|
|||||||
#include <algorithm>
|
#define VC_ENABLE_REFLECTION
|
||||||
#include <filesystem>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include "assets/AssetsLoader.hpp"
|
#include "assets/AssetsLoader.hpp"
|
||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
@ -19,6 +15,12 @@
|
|||||||
#include "world/World.hpp"
|
#include "world/World.hpp"
|
||||||
#include "api_lua.hpp"
|
#include "api_lua.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
using namespace scripting;
|
using namespace scripting;
|
||||||
|
|
||||||
static int l_pack_get_folder(lua::State* L) {
|
static int l_pack_get_folder(lua::State* L) {
|
||||||
@ -114,8 +116,16 @@ static int l_pack_get_info(
|
|||||||
default:
|
default:
|
||||||
throw std::runtime_error("");
|
throw std::runtime_error("");
|
||||||
}
|
}
|
||||||
|
auto opString = VersionOperatorMeta.getNameString(dpack.op);
|
||||||
|
|
||||||
lua::pushfstring(L, "%s%s@%s%s", prefix.c_str(), dpack.id.c_str(), dpack.op.c_str(), dpack.version.c_str());
|
lua::pushfstring(
|
||||||
|
L,
|
||||||
|
"%s%s@%s%s",
|
||||||
|
prefix.c_str(),
|
||||||
|
dpack.id.c_str(),
|
||||||
|
(dpack.op == VersionOperator::EQUAL ? "" : opString).c_str(),
|
||||||
|
dpack.version.c_str()
|
||||||
|
);
|
||||||
lua::rawseti(L, i + 1);
|
lua::rawseti(L, i + 1);
|
||||||
}
|
}
|
||||||
lua::setfield(L, "dependencies");
|
lua::setfield(L, "dependencies");
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include "lua_commons.hpp"
|
#include "lua_commons.hpp"
|
||||||
|
|
||||||
@ -114,4 +115,20 @@ namespace lua {
|
|||||||
std::shared_ptr<ImageData> mData;
|
std::shared_ptr<ImageData> mData;
|
||||||
};
|
};
|
||||||
static_assert(!std::is_abstract<LuaCanvas>());
|
static_assert(!std::is_abstract<LuaCanvas>());
|
||||||
|
|
||||||
|
class LuaRandom : public Userdata {
|
||||||
|
public:
|
||||||
|
std::mt19937 rng;
|
||||||
|
|
||||||
|
explicit LuaRandom(uint64_t seed) : rng(seed) {}
|
||||||
|
virtual ~LuaRandom() override = default;
|
||||||
|
|
||||||
|
const std::string& getTypeName() const override {
|
||||||
|
return TYPENAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int createMetatable(lua::State*);
|
||||||
|
inline static std::string TYPENAME = "__vc_Random";
|
||||||
|
};
|
||||||
|
static_assert(!std::is_abstract<LuaRandom>());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -169,5 +169,13 @@ State* lua::create_state(const EnginePaths& paths, StateType stateType) {
|
|||||||
auto file = "res:scripts/stdmin.lua";
|
auto file = "res:scripts/stdmin.lua";
|
||||||
auto src = io::read_string(file);
|
auto src = io::read_string(file);
|
||||||
lua::pop(L, lua::execute(L, 0, src, "core:scripts/stdmin.lua"));
|
lua::pop(L, lua::execute(L, 0, src, "core:scripts/stdmin.lua"));
|
||||||
|
|
||||||
|
newusertype<LuaRandom>(L);
|
||||||
|
if (getglobal(L, "random")) {
|
||||||
|
if (getglobal(L, "__vc_Random")) {
|
||||||
|
setfield(L, "Random");
|
||||||
|
}
|
||||||
|
pop(L);
|
||||||
|
}
|
||||||
return L;
|
return L;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -275,6 +275,15 @@ namespace lua {
|
|||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline T& require_userdata(lua::State* L, int idx) {
|
||||||
|
if (void* rawptr = lua_touserdata(L, idx)) {
|
||||||
|
return *static_cast<T*>(rawptr);
|
||||||
|
}
|
||||||
|
throw std::runtime_error("invalid 'self' value");
|
||||||
|
}
|
||||||
|
|
||||||
template <class T, typename... Args>
|
template <class T, typename... Args>
|
||||||
inline int newuserdata(lua::State* L, Args&&... args) {
|
inline int newuserdata(lua::State* L, Args&&... args) {
|
||||||
const auto& found = usertypeNames.find(typeid(T));
|
const auto& found = usertypeNames.find(typeid(T));
|
||||||
|
|||||||
56
src/logic/scripting/lua/usertypes/lua_type_random.cpp
Normal file
56
src/logic/scripting/lua/usertypes/lua_type_random.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "../lua_custom_types.hpp"
|
||||||
|
#include "../lua_util.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
using namespace lua;
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
static int l_random(lua::State* L) {
|
||||||
|
std::uniform_int_distribution<> dist(0, std::numeric_limits<int>::max());
|
||||||
|
|
||||||
|
auto& rng = require_userdata<LuaRandom>(L, 1).rng;
|
||||||
|
size_t n = touinteger(L, 2);
|
||||||
|
createtable(L, n, 0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
pushnumber(L, dist(rng) / (double)std::numeric_limits<int>::max());
|
||||||
|
rawseti(L, i + 1);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_seed(lua::State* L) {
|
||||||
|
require_userdata<LuaRandom>(L, 1).rng = std::mt19937(lua::touinteger(L, 2));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_meta_meta_call(lua::State* L) {
|
||||||
|
integer_t seed;
|
||||||
|
if (lua::isnoneornil(L, 1)) {
|
||||||
|
seed = system_clock::now().time_since_epoch().count();
|
||||||
|
} else {
|
||||||
|
seed = tointeger(L, 1);
|
||||||
|
}
|
||||||
|
return newuserdata<LuaRandom>(L, seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
int LuaRandom::createMetatable(lua::State* L) {
|
||||||
|
createtable(L, 0, 3);
|
||||||
|
|
||||||
|
requireglobal(L, "__vc_create_random_methods");
|
||||||
|
createtable(L, 0, 0);
|
||||||
|
pushcfunction(L, wrap<l_random>);
|
||||||
|
setfield(L, "random");
|
||||||
|
pushcfunction(L, wrap<l_seed>);
|
||||||
|
setfield(L, "seed");
|
||||||
|
call(L, 1, 1);
|
||||||
|
|
||||||
|
setfield(L, "__index");
|
||||||
|
|
||||||
|
createtable(L, 0, 1);
|
||||||
|
pushcfunction(L, wrap<l_meta_meta_call>);
|
||||||
|
setfield(L, "__call");
|
||||||
|
setmetatable(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@ -620,6 +620,26 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static sockaddr_in resolve_address_dgram(const std::string& address, int port) {
|
||||||
|
sockaddr_in serverAddr{};
|
||||||
|
addrinfo hints {};
|
||||||
|
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
|
||||||
|
addrinfo* addrinfo = nullptr;
|
||||||
|
if (int res = getaddrinfo(
|
||||||
|
address.c_str(), nullptr, &hints, &addrinfo
|
||||||
|
)) {
|
||||||
|
throw std::runtime_error(gai_strerror(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(&serverAddr, addrinfo->ai_addr, sizeof(sockaddr_in));
|
||||||
|
serverAddr.sin_port = htons(port);
|
||||||
|
freeaddrinfo(addrinfo);
|
||||||
|
return serverAddr;
|
||||||
|
}
|
||||||
|
|
||||||
class SocketUdpConnection : public UdpConnection {
|
class SocketUdpConnection : public UdpConnection {
|
||||||
u64id_t id;
|
u64id_t id;
|
||||||
SOCKET descriptor;
|
SOCKET descriptor;
|
||||||
@ -652,13 +672,7 @@ public:
|
|||||||
throw std::runtime_error("could not create udp socket");
|
throw std::runtime_error("could not create udp socket");
|
||||||
}
|
}
|
||||||
|
|
||||||
sockaddr_in serverAddr{};
|
sockaddr_in serverAddr = resolve_address_dgram(address, port);
|
||||||
serverAddr.sin_family = AF_INET;
|
|
||||||
if (inet_pton(AF_INET, address.c_str(), &serverAddr.sin_addr) <= 0) {
|
|
||||||
closesocket(descriptor);
|
|
||||||
throw std::runtime_error("invalid udp address: " + address);
|
|
||||||
}
|
|
||||||
serverAddr.sin_port = htons(port);
|
|
||||||
|
|
||||||
if (::connect(descriptor, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
|
if (::connect(descriptor, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
|
||||||
auto err = handle_socket_error("udp connect failed");
|
auto err = handle_socket_error("udp connect failed");
|
||||||
@ -683,6 +697,7 @@ public:
|
|||||||
while (open) {
|
while (open) {
|
||||||
int size = recv(descriptor, buffer.data(), buffer.size(), 0);
|
int size = recv(descriptor, buffer.data(), buffer.size(), 0);
|
||||||
if (size <= 0) {
|
if (size <= 0) {
|
||||||
|
logger.error() <<id <<"udp connection " << id << handle_socket_error(" recv error").what();
|
||||||
if (!open) break;
|
if (!open) break;
|
||||||
closesocket(descriptor);
|
closesocket(descriptor);
|
||||||
state = ConnectionState::CLOSED;
|
state = ConnectionState::CLOSED;
|
||||||
@ -697,11 +712,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int send(const char* buffer, size_t length) override {
|
int send(const char* buffer, size_t length) override {
|
||||||
int len = sendto(descriptor, buffer, length, 0,
|
int len = ::send(descriptor, buffer, length, 0);
|
||||||
(sockaddr*)&addr, sizeof(addr));
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
|
auto err = handle_socket_error(" send failed");
|
||||||
closesocket(descriptor);
|
closesocket(descriptor);
|
||||||
state = ConnectionState::CLOSED;
|
state = ConnectionState::CLOSED;
|
||||||
|
logger.error() << "udp connection " << id << err.what();
|
||||||
} else totalUpload += len;
|
} else totalUpload += len;
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
@ -710,6 +726,7 @@ public:
|
|||||||
void close(bool discardAll=false) override {
|
void close(bool discardAll=false) override {
|
||||||
if (!open) return;
|
if (!open) return;
|
||||||
open = false;
|
open = false;
|
||||||
|
logger.info() << "closing udp connection "<< id;
|
||||||
|
|
||||||
if (state != ConnectionState::CLOSED) {
|
if (state != ConnectionState::CLOSED) {
|
||||||
shutdown(descriptor, 2);
|
shutdown(descriptor, 2);
|
||||||
@ -789,13 +806,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sendTo(const std::string& addr, int port, const char* buffer, size_t length) override {
|
void sendTo(const std::string& addr, int port, const char* buffer, size_t length) override {
|
||||||
sockaddr_in client{};
|
sockaddr_in client = resolve_address_dgram(addr, port);
|
||||||
client.sin_family = AF_INET;
|
if (sendto(descriptor, buffer, length, 0,
|
||||||
inet_pton(AF_INET, addr.c_str(), &client.sin_addr);
|
reinterpret_cast<sockaddr*>(&client), sizeof(client)) < 0) {
|
||||||
client.sin_port = htons(port);
|
logger.error() << handle_socket_error("sendto").what();
|
||||||
|
}
|
||||||
sendto(descriptor, buffer, length, 0,
|
|
||||||
reinterpret_cast<sockaddr*>(&client), sizeof(client));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void close() override {
|
void close() override {
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
#include "command_line.hpp"
|
#include "command_line.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "io/engine_paths.hpp"
|
#include "io/engine_paths.hpp"
|
||||||
#include "util/ArgsReader.hpp"
|
#include "util/ArgsReader.hpp"
|
||||||
@ -8,45 +11,69 @@
|
|||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
class ArgC {
|
||||||
|
public:
|
||||||
|
std::string keyword;
|
||||||
|
std::function<bool()> execute;
|
||||||
|
std::string help;
|
||||||
|
ArgC(const std::string& keyword, std::function<bool()> execute, const std::string& help) {
|
||||||
|
this->keyword = keyword;
|
||||||
|
this->execute = execute;
|
||||||
|
this->help = help;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static bool perform_keyword(
|
static bool perform_keyword(
|
||||||
util::ArgsReader& reader, const std::string& keyword, CoreParameters& params
|
util::ArgsReader& reader, const std::string& keyword, CoreParameters& params
|
||||||
) {
|
) {
|
||||||
if (keyword == "--res") {
|
static const std::vector<ArgC> argumentsCommandline = {
|
||||||
params.resFolder = reader.next();
|
ArgC("--res", [¶ms, &reader]() -> bool {
|
||||||
} else if (keyword == "--dir") {
|
params.resFolder = reader.next();
|
||||||
params.userFolder = reader.next();
|
return true;
|
||||||
} else if (keyword == "--project") {
|
}, "<path> - set resources directory."),
|
||||||
params.projectFolder = reader.next();
|
ArgC("--dir", [¶ms, &reader]() -> bool {
|
||||||
} else if (keyword == "--help" || keyword == "-h") {
|
params.userFolder = reader.next();
|
||||||
std::cout << "VoxelCore v" << ENGINE_VERSION_STRING << "\n\n";
|
return true;
|
||||||
std::cout << "command-line arguments:\n";
|
}, "<path> - set userfiles directory."),
|
||||||
std::cout << " --help - display this help\n";
|
ArgC("--project", [¶ms, &reader]() -> bool {
|
||||||
std::cout << " --version - display engine version\n";
|
params.projectFolder = reader.next();
|
||||||
std::cout << " --res <path> - set resources directory\n";
|
return true;
|
||||||
std::cout << " --dir <path> - set userfiles directory\n";
|
}, "<path> - set project directory."),
|
||||||
std::cout << " --project <path> - set project directory\n";
|
ArgC("--test", [¶ms, &reader]() -> bool {
|
||||||
std::cout << " --headless - run in headless mode\n";
|
params.testMode = true;
|
||||||
std::cout << " --test <path> - test script file\n";
|
params.scriptFile = reader.next();
|
||||||
std::cout << " --script <path> - main script file\n";
|
return true;
|
||||||
std::cout << std::endl;
|
}, "<path> - test script file."),
|
||||||
return false;
|
ArgC("--script", [¶ms, &reader]() -> bool {
|
||||||
} else if (keyword == "--version") {
|
params.testMode = false;
|
||||||
std::cout << ENGINE_VERSION_STRING << std::endl;
|
params.scriptFile = reader.next();
|
||||||
return false;
|
return true;
|
||||||
} else if (keyword == "--headless") {
|
}, "<path> - main script file."),
|
||||||
params.headless = true;
|
ArgC("--headless", [¶ms]() -> bool {
|
||||||
} else if (keyword == "--test") {
|
params.headless = true;
|
||||||
auto token = reader.next();
|
return true;
|
||||||
params.testMode = true;
|
}, "- run in headless mode."),
|
||||||
params.scriptFile = token;
|
ArgC("--version", []() -> bool {
|
||||||
} else if (keyword == "--script") {
|
std::cout << ENGINE_VERSION_STRING << std::endl;
|
||||||
auto token = reader.next();
|
return false;
|
||||||
params.testMode = false;
|
}, "- display the engine version."),
|
||||||
params.scriptFile = token;
|
ArgC("--help", []() -> bool {
|
||||||
} else {
|
std::cout << "VoxelCore v" << ENGINE_VERSION_STRING << "\n\n";
|
||||||
throw std::runtime_error("unknown argument " + keyword);
|
std::cout << "Command-line arguments:\n";
|
||||||
|
for (auto& a : argumentsCommandline) {
|
||||||
|
std::cout << a.keyword << " " << a.help << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
return false;
|
||||||
|
}, "- display this help.")
|
||||||
|
};
|
||||||
|
for (auto& a : argumentsCommandline) {
|
||||||
|
if (a.keyword == keyword) {
|
||||||
|
return a.execute();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
throw std::runtime_error("unknown argument " + keyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_cmdline(int argc, char** argv, CoreParameters& params) {
|
bool parse_cmdline(int argc, char** argv, CoreParameters& params) {
|
||||||
|
|||||||
@ -40,7 +40,7 @@ std::string util::escape(std::string_view s, bool escapeUnicode) {
|
|||||||
uint cpsize;
|
uint cpsize;
|
||||||
int codepoint = decode_utf8(cpsize, s.data() + pos);
|
int codepoint = decode_utf8(cpsize, s.data() + pos);
|
||||||
if (escapeUnicode) {
|
if (escapeUnicode) {
|
||||||
ss << "\\u" << std::hex << codepoint;
|
ss << "\\u" << std::setw(4) << std::setfill('0') << std::hex << codepoint;
|
||||||
} else {
|
} else {
|
||||||
ss << std::string(s.data() + pos, cpsize);
|
ss << std::string(s.data() + pos, cpsize);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
static debug::Logger logger("window");
|
static debug::Logger logger("window");
|
||||||
|
|
||||||
static std::unordered_set<std::string> supported_gl_extensions;
|
static std::unordered_set<std::string> supported_gl_extensions;
|
||||||
|
static void window_size_callback(GLFWwindow* window, int width, int height);
|
||||||
|
|
||||||
static void init_gl_extensions_list() {
|
static void init_gl_extensions_list() {
|
||||||
GLint numExtensions = 0;
|
GLint numExtensions = 0;
|
||||||
@ -418,7 +419,7 @@ public:
|
|||||||
if (fullscreen) {
|
if (fullscreen) {
|
||||||
glfwGetWindowPos(window, &posX, &posY);
|
glfwGetWindowPos(window, &posX, &posY);
|
||||||
glfwSetWindowMonitor(
|
glfwSetWindowMonitor(
|
||||||
window, monitor, 0, 0, mode->width, mode->height, GLFW_DONT_CARE
|
window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
glfwSetWindowMonitor(
|
glfwSetWindowMonitor(
|
||||||
@ -430,6 +431,7 @@ public:
|
|||||||
settings->height.get(),
|
settings->height.get(),
|
||||||
GLFW_DONT_CARE
|
GLFW_DONT_CARE
|
||||||
);
|
);
|
||||||
|
window_size_callback(window, settings->width.get(), settings->height.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
double xPos, yPos;
|
double xPos, yPos;
|
||||||
@ -596,6 +598,17 @@ static void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) {
|
|||||||
handler->input.setCursorPosition(xpos, ypos);
|
handler->input.setCursorPosition(xpos, ypos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void iconify_callback(GLFWwindow* window, int iconified) {
|
||||||
|
auto handler = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||||
|
if (handler->isFullscreen() && iconified == 0) {
|
||||||
|
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
||||||
|
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
|
||||||
|
glfwSetWindowMonitor(
|
||||||
|
window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void create_standard_cursors() {
|
static void create_standard_cursors() {
|
||||||
for (int i = 0; i <= static_cast<int>(CursorShape::LAST); i++) {
|
for (int i = 0; i <= static_cast<int>(CursorShape::LAST); i++) {
|
||||||
int cursor = GLFW_ARROW_CURSOR + i;
|
int cursor = GLFW_ARROW_CURSOR + i;
|
||||||
@ -615,6 +628,7 @@ static void setup_callbacks(GLFWwindow* window) {
|
|||||||
glfwSetWindowSizeCallback(window, window_size_callback);
|
glfwSetWindowSizeCallback(window, window_size_callback);
|
||||||
glfwSetCharCallback(window, character_callback);
|
glfwSetCharCallback(window, character_callback);
|
||||||
glfwSetScrollCallback(window, scroll_callback);
|
glfwSetScrollCallback(window, scroll_callback);
|
||||||
|
glfwSetWindowIconifyCallback(window, iconify_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<
|
std::tuple<
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
|
#include "coders/BasicParser.hpp"
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
@ -16,6 +17,25 @@ TEST(stringutil, utf8) {
|
|||||||
EXPECT_EQ(str, str2);
|
EXPECT_EQ(str, str2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::wstring gen_random_unicode_wstring(int n) {
|
||||||
|
std::wstring str;
|
||||||
|
str.resize(n);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
// wstring is 16 bit in some systems
|
||||||
|
str[i] = rand() & 0xFFFF;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(stringutil, utf8_random) {
|
||||||
|
srand(5436324);
|
||||||
|
|
||||||
|
auto str = gen_random_unicode_wstring(10'000);
|
||||||
|
auto utf8str = util::wstr2str_utf8(str);
|
||||||
|
auto back = util::str2wstr_utf8(utf8str);
|
||||||
|
EXPECT_EQ(str, back);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(stringutil, base64) {
|
TEST(stringutil, base64) {
|
||||||
srand(2019);
|
srand(2019);
|
||||||
for (size_t size = 0; size < 30; size++) {
|
for (size_t size = 0; size < 30; size++) {
|
||||||
@ -47,3 +67,37 @@ TEST(stringutil, base64_urlsafe) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StringParser : BasicParser<char> {
|
||||||
|
public:
|
||||||
|
StringParser(std::string_view source) : BasicParser("<string>", source) {}
|
||||||
|
|
||||||
|
std::string parse() {
|
||||||
|
++pos;
|
||||||
|
return parseString(source[0], true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(stringutil, escape_cases) {
|
||||||
|
auto escaped = util::escape("тест5", true);
|
||||||
|
auto expected = "\"\\u0442\\u0435\\u0441\\u04425\"";
|
||||||
|
ASSERT_EQ(expected, escaped);
|
||||||
|
|
||||||
|
srand(345873458);
|
||||||
|
for (int i = 0; i < 36; i++) {
|
||||||
|
rand();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto str = gen_random_unicode_wstring(40);
|
||||||
|
auto utf8str = util::wstr2str_utf8(str);
|
||||||
|
escaped = util::escape(utf8str, true);
|
||||||
|
|
||||||
|
StringParser parser(escaped);
|
||||||
|
auto restored = parser.parse();
|
||||||
|
for (int i = 0; i < utf8str.length(); i++) {
|
||||||
|
if (utf8str[i] != restored[i]) {
|
||||||
|
std::cout << i << ": " << (int)utf8str[i] << " " << (int)restored[i] << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_EQ(utf8str, restored);
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user