86 Commits
Author SHA1 Message Date
ShiftyX1 5507e17402 fix: replace copy_directory_if_different with copy_directory
Build and Release / prepare (push) Successful in 0s
Build / Build (push) Has been cancelled
Build and Release / build_linux (push) Failing after 9m9s
Build and Release / build_macos (push) Failing after 5s
Build and Release / build_windows (push) Failing after 5s
Build and Release / publish_release (push) Has been skipped
MSVC Build / build-windows (windows-latest) (push) Has been cancelled
- copy_directory_if_different doesn't exist in CMake 3.22
- Use standard copy_directory command instead
2025-12-08 20:52:57 +03:00
ShiftyX1 b68e5567b8 fix: create OpenAL::OpenAL target alias for Linux
Build / Build (push) Successful in 9m28s
Build and Release / prepare (push) Successful in 1s
Build and Release / build_linux (push) Failing after 8m58s
Build and Release / build_macos (push) Failing after 11s
Build and Release / build_windows (push) Failing after 12s
Build and Release / publish_release (push) Has been skipped
MSVC Build / build-windows (windows-latest) (push) Has been cancelled
- FindOpenAL on Linux creates OPENAL_LIBRARY/OPENAL_INCLUDE_DIR
- But code expects OpenAL::OpenAL target
- Add compatibility layer to create proper target
2025-12-08 20:25:59 +03:00
ShiftyX1 42dcf7c888 fix: adapt CI/CD for Gitea compatibility
Build / Build (push) Successful in 9m29s
Build and Release / prepare (push) Successful in 1s
Build and Release / build_linux (push) Failing after 43s
Build and Release / build_macos (push) Failing after 11s
Build and Release / build_windows (push) Failing after 14s
Build and Release / publish_release (push) Has been skipped
MSVC Build / build-windows (windows-latest) (push) Has been cancelled
- Replace upload/download-artifact v4 with v3 (v4 not supported on Gitea)
- Fix ObjectsPool::allocateNew() usage (returns void, not bool)
- Add cmake and build-essential to dependencies
- Update release workflow to use softprops/action-gh-release
2025-12-08 20:09:54 +03:00
ShiftyX1 403dbc7791 fixed error: could not convert from ‘void’ to ‘bool’
Build / Build (push) Failing after 9m39s
MSVC Build / build-windows (windows-latest) (push) Has been cancelled
2025-12-08 19:58:00 +03:00
ShiftyX1 5255fd3a77 ci: add cmake and build-essential to dependencies
Build / Build (push) Failing after 7m57s
MSVC Build / build-windows (windows-latest) (push) Has been cancelled
2025-12-08 19:44:30 +03:00
ShiftyX1 0107cf13c3 ci: adapt workflows for Gitea Actions
Build / Build (push) Failing after 32s
MSVC Build / build-windows (windows-latest) (push) Has been cancelled
- Update release.yml to use softprops/action-gh-release (Gitea compatible)
- Add push trigger for version tags
- Fix apt-get install requiring confirmation with -y flag
- Remove complex API calls in favor of standard actions
2025-12-08 19:43:15 +03:00
ShiftyX1 ee7b1d4299 refactor: update release workflow for improved tagging and asset management
Build / Build (push) Failing after 17s
MSVC Build / build-windows (windows-latest) (push) Has been cancelled
2025-12-08 19:41:32 +03:00
Shifty d3f8942fbf Merge pull request 'lua-zip-test' (#1) from lua-zip-test into main
Build / Build (push) Failing after 30s
MSVC Build / build-windows (windows-latest) (push) Has been cancelled
Reviewed-on: https://git.pyserve.org/PulseStudio/VoxelEngine/pulls/1
2025-12-08 16:32:26 +00:00
ShiftyX1 5997cbd714 fixed macOS segfault correct way
Build / Build (push) Failing after 17s
MSVC Build / build-windows (windows-latest) (push) Has been cancelled
2025-12-08 19:23:57 +03:00
MihailRisandShiftyX1 06f6550624 fix the stupid
Build / Build (push) Failing after 17s
MSVC Build / build-windows (windows-latest) (push) Has been cancelled
2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 00f269ca7e debug it 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 42248d67eb update appimage.yml 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 257a293bf4 fix platform::detect_locale 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 a375af9ca1 update appimage.yml 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 289347dc91 update appimage workflow 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 dd40780334 add 'network' permission 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 56d808e3e2 add 'write-to-user' permission & refactor checking for writeability 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 8831d676d4 feat: project permissions loading 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 6fca6eab56 start 0.31 development 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 df1ce1ae53 fix window title if VC_BUILD_NAME is empty 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 213e9150dd fix libpng error handling 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 43f54c38ec fix corrupted voxel reset 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 f5868b65f0 add build info to release (#725)
* attempt to add VC_BUILD_NAME

* fix

* fix

* update macos.yml

* fix

* update macos.yml

* update macos.yml

* add debug step

* update

* update

* fix release.yml

* update cmake

* update WindowControl.cpp

* update workflows

* update release.yml

* add --output-always

* cleanup
2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 149f418bed update macos.yml 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 4893705ff4 fix overriden content units scripts overriding 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 b36d8d5852 fix block ticks 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 17503674e8 update doc/*/block-properties.md 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 db09672e50 document tick-interval 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 f1d9f1bf60 fix release pipeline 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 f4adcf58b2 simplify release.yml 2025-12-08 19:21:50 +03:00
MihailRisandShiftyX1 2c1d783e0c cleanup 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 6bd1103f88 fix 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 6becd2f5b5 make windows-clang.yml reusable 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 9d05d7c725 fix 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 5971e6b76b restore jobs 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 80852ed368 fix 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 ddf3babac9 fix 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 082b5cd080 update release.yml 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 a15961af8f update release.yml 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 678c42a825 add more steps 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 85258ff036 temporary disable windows-clang.yml pull_request trigger 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 fa2b933856 update release.yml 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 8ad578e109 temporary disable workflows 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 63cbf12507 update windows.yml 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 6f9c3a1389 add publish_release job 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 3de1dbed0b update release.yml 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 5f1569a8be update release.yml 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 56cb79f9e2 update release.yml 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 092fe59c81 add release workflow 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 4697969bdb remove old unused release pipeline 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 be420352eb increase moon sprite distance 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 32189b5fa2 fix nil coords passed to on_block_tick 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 bc1ff634a3 fix: incomplete size transform support by entities 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 98a3971e13 fix exception if model having invalid variable texture passed to modelviewer 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 417521e94f temporary fix improvement 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 fbc6d072e8 fix canvas:set_data with table argument 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 e2e1bd6d76 cleanup 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 65ee464941 fix generated item's script 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 9bd6b39952 temporary fix 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 d7f3bf9c7c fix ui elements overriding 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 5ae34c2dc2 fix: pack environment not passed to components 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 59df377fde fix temporary 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 15b3e4d549 make parsing error messages while assets loading more verbose 2025-12-08 19:21:49 +03:00
MihailRisandShiftyX1 b7751cf053 fix 'unexpected end' while parsing .obj 2025-12-08 19:21:49 +03:00
ShiftyX1 a7713d2c44 chore: update .gitignore to include build artifacts and configuration files
x86-64 AppImage / build-appimage (ubuntu-22.04) (pull_request) Failing after 33s
Build / Build (pull_request) Failing after 17s
MSVC Build / build-windows (windows-latest) (pull_request) Has been cancelled
Macos Build / build-dmg (pull_request) Has been cancelled
Windows Build (CLang) / build-windows (clang, windows-latest) (pull_request) Has been cancelled
2025-12-08 19:09:22 +03:00
ShiftyX1 7fc1c37258 upd gitignore
x86-64 AppImage / build-appimage (ubuntu-22.04) (push) Failing after 1m23s
Build / Build (push) Failing after 17s
MSVC Build / build-windows (windows-latest) (push) Has been cancelled
Macos Build / build-dmg (push) Has been cancelled
Windows Build (CLang) / build-windows (clang, windows-latest) (push) Has been cancelled
2025-12-08 19:04:50 +03:00
ShiftyX1 e257a7f462 qa: added lua autotest for ZIP filesystem operations 2025-12-01 21:29:28 +03:00
MihailRisandGitHub ecba496f12 Merge pull request #711 from MihailRis/fixes
0.30.1 fixes
2025-12-01 02:04:03 +03:00
MihailRis 7c74eece99 fix: bad_alloc if canvas element size is negative 2025-11-30 14:01:59 +03:00
MihailRisandGitHub 3a999c6b19 Merge pull request #712 from MihailRis/revert-702-improve-gl-errors
Revert "Improve gl errors"
2025-11-29 19:14:39 +03:00
MihailRisandGitHub a04ea83c48 Revert "Improve gl errors" 2025-11-29 18:54:08 +03:00
MihailRis bcfcd9ca76 fix headless mode fatal error in some systems 2025-11-29 18:29:04 +03:00
MihailRis 618b3d7f61 fix world generator 2025-11-29 16:15:19 +03:00
MihailRisandGitHub 1f9b10db6e Merge pull request #710 from MihailRis/release-0.30
Release 0.30
2025-11-27 20:01:49 +03:00
MihailRis 59d005c527 Merge branch 'main' into release-0.30 2025-11-26 23:05:17 +03:00
MihailRisandGitHub 41a45a961f Merge pull request #709 from MihailRis/fix-canvas-set-data
fix canvas:set_data
2025-11-26 23:04:51 +03:00
MihailRis 66bb734a4e fix canvas:set_data 2025-11-26 22:46:43 +03:00
MihailRis 53cf3c17b7 update CHANGELOG.md 2025-11-26 12:16:40 +03:00
MihailRis c128643cbd Merge branch 'main' into release-0.30 2025-11-26 00:22:03 +03:00
MihailRis 8110377e7d update CHANGELOG.md to 0.30 2025-11-25 22:34:04 +03:00
MihailRis 011774a8ba Merge branch 'main' into release-0.30 2025-11-25 22:32:54 +03:00
MihailRis 933d9b6299 fix CHANGELOG.md release date 2025-11-25 20:21:20 +03:00
MihailRis 64ac93b9d2 update CHANGELOG.md 2025-11-25 20:20:02 +03:00
MihailRis a70b9f9093 Merge branch 'main' into release-0.30 2025-11-25 18:29:32 +03:00
MihailRis 7fc9bde6f5 update README.md 2025-11-25 12:26:15 +03:00
MihailRis 3cdf43ecb7 update doc/*/main-page.md 2025-11-25 12:25:11 +03:00
76 changed files with 966 additions and 400 deletions
-1
View File
@@ -1 +0,0 @@
custom: ['https://boosty.to/mihailris']
+8 -2
View File
@@ -5,6 +5,12 @@ on:
branches: [ "main", "release-**"]
pull_request:
branches: [ "main", "dev" ]
workflow_call:
inputs:
build_name:
required: true
type: string
description: 'Build name passed as VC_BUILD_NAME define'
jobs:
build-appimage:
@@ -36,7 +42,7 @@ jobs:
sudo make install
cd ../..
- name: Configure
run: cmake -S . -B build -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_APPDIR=1 -DVOXELENGINE_BUILD_TESTS=ON
run: cmake -S . -B build -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_APPDIR=1 -DVOXELENGINE_BUILD_TESTS=ON -DVC_BUILD_NAME="${{ inputs.build_name }}"
- name: Build
run: cmake --build build -t install
- name: Run tests
@@ -53,7 +59,7 @@ jobs:
UPDATE_INFO: gh-releases-zsync|MihailRis|VoxelEngine-Cpp|latest|*x86_64.AppImage.zsync
with:
recipe: dev/AppImageBuilder.yml
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
with:
name: AppImage
path: './*.AppImage*'
+2 -2
View File
@@ -39,7 +39,7 @@ jobs:
# make && make install INSTALL_INC=/usr/include/lua
run: |
sudo apt-get update
sudo apt-get install libglfw3-dev libglfw3 libglew-dev libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev libgtest-dev libcurl4-openssl-dev
sudo apt-get install -y cmake build-essential libglfw3-dev libglfw3 libglew-dev libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev libgtest-dev libcurl4-openssl-dev
# fix luajit paths
sudo ln -s /usr/lib/x86_64-linux-gnu/libluajit-5.1.a /usr/lib/x86_64-linux-gnu/liblua-5.1.a
sudo ln -s /usr/include/luajit-2.1 /usr/include/lua
@@ -68,7 +68,7 @@ jobs:
run: ctest --test-dir ${{github.workspace}}/build
- name: Upload artifacts
if: ${{ inputs.upload_artifacts }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: VoxelEngine
path: |
+9 -3
View File
@@ -5,6 +5,12 @@ on:
branches: [ "main", "release-**"]
pull_request:
branches: [ "main", "dev" ]
workflow_call:
inputs:
build_name:
required: true
type: string
description: 'Build name passed as VC_BUILD_NAME define'
jobs:
build-dmg:
@@ -20,7 +26,7 @@ jobs:
brew install glfw3 glew libpng openal-soft luajit libvorbis skypjack/entt/entt googletest glm
- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_TESTS=ON -DVOXELENGINE_BUILD_APPDIR=1
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_TESTS=ON -DVOXELENGINE_BUILD_APPDIR=1 -DVC_BUILD_NAME="${{ inputs.build_name }}"
- name: Build
run: cmake --build build -t install
@@ -39,7 +45,7 @@ jobs:
run: |
chmod +x build/VoxelEngine
chmod +x AppDir/usr/bin/vctest
AppDir/usr/bin/vctest -e build/VoxelEngine -d dev/tests -u build
AppDir/usr/bin/vctest -e build/VoxelEngine -d dev/tests -u build --output-always
- name: Create DMG
run: |
mkdir VoxelEngineDmgContent
@@ -49,7 +55,7 @@ jobs:
hdiutil create VoxelEngineMacApp.dmg -volname "VoxelEngine" -srcfolder VoxelEngineDmgContent -ov -format UDZO
- name: Upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: VoxelEngineMacOs
path: VoxelEngineMacApp.dmg
+85 -36
View File
@@ -1,43 +1,92 @@
# adopted from https://github.com/PrismLauncher/PrismLauncher
name: Release
name: Build and Release
run-name: ${{ github.actor }} preparing release
on:
push:
tags:
- "v*"
- 'v*'
workflow_dispatch:
inputs:
version:
description: 'Engine release version'
required: true
default: "0.0.0"
env:
RELEASE_VERSION: ${{ github.event.inputs.version || github.ref_name || 'testrelease' }}
BRANCH_NAME: ${{ github.event_name == 'workflow_dispatch' && github.ref_name || 'main' }}
jobs:
build_release:
name: Build Release
uses: ./.github/workflows/cmake.yml
with:
build_type: Release
upload_artifacts: true
create_release:
needs: build_release
prepare:
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: VoxelEngine
- name: Pack artifacts
run: |
chmod +x VoxelEngine
zip -r VoxelEngine.zip res VoxelEngine
- name: Grab and store version
run: |
tag_name=$(echo ${{ github.ref }} | grep -oE "v[^/]+$")
echo "VERSION=$tag_name" >> $GITHUB_ENV
- run: echo "exists just for outputs"
outputs:
build_name: '${{ env.RELEASE_VERSION }}'
build_linux:
needs: [prepare]
uses: ./.github/workflows/appimage.yml
with:
build_name: '${{ needs.prepare.outputs.build_name }}'
build_macos:
needs: [prepare]
uses: ./.github/workflows/macos.yml
with:
build_name: '${{ needs.prepare.outputs.build_name }}'
build_windows:
needs: [prepare]
uses: ./.github/workflows/windows-clang.yml
with:
build_name: '${{ needs.prepare.outputs.build_name }}'
publish_release:
runs-on: ubuntu-latest
needs: [build_linux, build_macos, build_windows]
steps:
- name: Checkout Release Branch
uses: actions/checkout@v4
with:
ref: ${{ env.BRANCH_NAME }}
- name: Download Build Artifact
uses: actions/download-artifact@v3
with:
path: ./artifacts
- name: Show Artifacts
run: |
mkdir release
mv ./artifacts/AppImage/VoxelCore-latest-x86_64.AppImage \
./release/voxelcore-${RELEASE_VERSION}_x86-64.AppImage
mv ./artifacts/VoxelEngineMacOs/VoxelEngineMacApp.dmg \
./release/voxelcore-${RELEASE_VERSION}_macos.dmg
(cd ./artifacts/Windows-Build && zip -r ../../release/voxelcore-${RELEASE_VERSION}_win64.zip .)
ls -la ./release
tree ./release
- name: Create Tag
if: github.event_name == 'workflow_dispatch'
run: |
git config --local user.email "action@gitea.com"
git config --local user.name "Gitea Action"
TAG_NAME="v${RELEASE_VERSION}"
git tag -a "${TAG_NAME}" -m "Automated release tag ${TAG_NAME}"
git push origin "${TAG_NAME}"
- name: Create Release with assets
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ env.RELEASE_VERSION }}
name: VoxelCore v${{ env.RELEASE_VERSION }}
body: |
## VoxelCore Release ${{ env.RELEASE_VERSION }}
### Downloads
- **Linux**: voxelcore-${{ env.RELEASE_VERSION }}_x86-64.AppImage
- **macOS**: voxelcore-${{ env.RELEASE_VERSION }}_macos.dmg
- **Windows**: voxelcore-${{ env.RELEASE_VERSION }}_win64.zip
### Installation
Download the appropriate file for your platform and run it.
---
**Full Changelog**: https://git.pyserve.org/PulseStudio/VoxelEngine/compare/v0.0.0...v${{ env.RELEASE_VERSION }}
draft: true
prerelease: false
files: |
./release/*
token: ${{ secrets.GITHUB_TOKEN }}
- name: Create release
uses: softprops/action-gh-release@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag_name: ${{ github.ref }}
name: VoxelEngine ${{ env.VERSION }}
draft: true
prerelease: false
files: |
VoxelEngine.zip
+9 -3
View File
@@ -4,7 +4,13 @@ on:
push:
branches: [ "main", "release-**"]
pull_request:
branches: [ "main", "dev" ]
branches: [ "main", "dev" ]
workflow_call:
inputs:
build_name:
required: true
type: string
description: 'Build name passed as VC_BUILD_NAME define'
jobs:
build-windows:
@@ -47,7 +53,7 @@ jobs:
export VCPKG_ROOT=$(pwd)/vcpkg
mkdir build
cd build
cmake -G "MinGW Makefiles" -DVCPKG_TARGET_TRIPLET=x64-mingw-static -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake ..
cmake -G "MinGW Makefiles" -DVCPKG_TARGET_TRIPLET=x64-mingw-static -DVC_BUILD_NAME="${{ inputs.build_name }}" -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake ..
cmake --build . --config Release
- name: Package for Windows
run: |
@@ -58,7 +64,7 @@ jobs:
cp build/*.dll packaged/
cp -r build/res/* packaged/res/
mv packaged/VoxelEngine.exe packaged/VoxelCore.exe
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
with:
name: Windows-Build
path: 'packaged/*'
+1 -1
View File
@@ -47,7 +47,7 @@ jobs:
cp C:/Windows/System32/msvcp140.dll packaged/msvcp140.dll
mv packaged/VoxelEngine.exe packaged/VoxelCore.exe
working-directory: ${{ github.workspace }}
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
with:
name: Windows-Build
path: 'packaged/*'
+11
View File
@@ -49,3 +49,14 @@ appimage-build/
# libs
/libs/
/vcpkg_installed/
CMakeCache.txt
cmake_install.cmake
CMakeFiles/
Makefile
compile_commands.json
VoxelEngine
libVoxelEngineSrc.a
vctest
.vctest/settings.toml
+121 -110
View File
@@ -1,6 +1,6 @@
# 0.29 - 2025.09.20
# 0.30 - 2025.11.27
[Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/tree/release-0.29/doc/en/main-page.md) for 0.29
[Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/tree/release-0.30/doc/en/main-page.md) for 0.30
Table of contents:
@@ -11,121 +11,132 @@ Table of contents:
## Added
- pathfinding
- components:
- core:pathfinding
- core:player
- core:mob
- audio recording
- in-memory filesystems
- `:block` placement (generator)
- `on_block_present`, `on_block_removed` events
- debugging server
- `rotate` and `origin` vcm modifiers (rotation)
- custom audio streams in lua (audio.PCMStream class)
- add I16view, I32view, U16view, I32view lua classes
- libraries:
- random
- gfx.skeletons
- (documented) assets
- udp support
- schedules
- events:
- on_physics_update (components)
- on_block_tick(x, y, z, tps) (blocks)
- custom hand controller
- http headers
- named pipes
- optimizations:
- speed up block.set
- speed up vectors
- items description
- item properties methods
- tab + shift+tab
- blocks, items tags
- pack dependencies versions
- ~~allow to disable autospawn position~~ use player.set_spawnpoint
- entity.spawn command
- project script
- gui.root document
- time.schedules.world.common: Schedule
- compression
- audio.input
- editing atlas textures feature
- add non_reset_packs argument to app.reset_content
- freeze debug panel values on cursor unlock
- project:content content source
- project start application script
- uinode.exists property
- uinode events:
- `onrightclick`
- `onmouseover`
- `onmouseout`
- frameless window mode
- settings:
- `display.adaptive-menu-fps` experimental flag
- `graphics.soft-lighting`
- command-line arguments:
- `--tps` command line argument for headless mode
- `--dbg-server` command line argument
- added error callback argument to network.tcp_connect
- go back in menu on Escape pressed
- publish `hud.exchange-slot` element
- add `istoplevel` argument to input.add_callback
- engine pause mode (debugging)
- rebuild mip-maps on texture reload
- documentation:
- documented player.set_camera and related
- documented `on_hud_render` event
- update app library docs
- updated content-packs docs (added full pack structure)
### Changes
- app.sleep_until - added 'timeout argument'
- network.get / post - added 'data' argument to error callback
- autorefresh model preview
- move player controls to lua
- move hand control to lua
- optimization:
- fixed major chunks loading performance issue
- reduced headless mode chunks memory consumption
- vecn functions optimization is not experimental now
- pass pack environment to menu page script
- canvas element autoresize
- disable mouse camera control if non-standard camera used
- events without prefix are forbidden now
- player.* functions now throw exception in headless mode if player id not specified
### Functions
- block.model_name
- block.has_tag
- item.has_tag
- item.description
- base64.encode_urlsafe
- base64.decode_urlsafe
- vec2.rotate
- vecn.distance
- vecn.mix
- rigidbody:get_vdamping
- rigidbody:set_vdamping
- entity:require_component
- network.udp_connect
- random.random
- random.bytes
- random.uuid
- Random:random
- Random:seed
- hud.hand_controller
- inventory.get_caption
- inventory.set_caption
- inventory.get_description
- inventory.set_description
- pathfinding.create_agent
- pathfinding.remove_agent
- pathfinding.set_enabled
- pathfinding.is_enabled
- pathfinding.make_route
- pathfinding.make_route_async
- pathfinding.pull_route
- pathfinding.set_max_visited
- pathfinding.avoid_tag
- gfx.skeletons.get
- Skeleton:index
- Skeleton:get_model
- Skeleton:set_model
- Skeleton:get_matrix
- Skeleton:set_matrix
- Skeleton:get_texture
- Skeleton:set_texture
- Skeleton:is_visible
- Skeleton:set_visible
- Skeleton:get_color
- Skeleton:set_color
- Schedule:set_timeout(time_ms, callback)
- Schedule:set_interval(interval_ms, callback, [optional] repetions): int
- Schedule:remove_interval(id)
- ScheduleGroup:publish(schedule: Schedule)
- app.create_memory_device
- app.focus
- app.get_content_sources
- app.open_url
- app.set_content_sources
- app.start_debug_instance
- assets.to_canvas
- audio.get_all_input_devices_names
- audio.get_input_info
- audio.input.fetch
- audio.input.request_open
- canvas:add
- canvas:encode
- canvas:get_data
- canvas:mul
- canvas:rect
- canvas:sub
- canvas:unbind_texture
- Canvas.decode
- compression.decode
- compression.encode
- debug.get_pack_by_frame
- file.create_memory_device
- gui.ask
- gui.set_syntax_styles
- gui.show_message
- hud.is_open
- input.get_mouse_delta
- network.find_free_port
- PCMStream:create_sound
- PCMStream:feed
- PCMStream:share
- player.get_all
- player.get_all_in_radius
- player.get_dir
- player.get_interaction_distance
- player.get_nearest
- player.set_interaction_distance
- socket:is_nodelay
- socket:recv_async
- socket:set_nodelay
- string.escape_xml
- textbox:indexByPos
- textbox:lineY
- utf8.escape_xml
## Fixes
- fix 3d text position / culling
- fix fragment:place rotation (#593)
- fix server socket creation in macos
- fix: base packs not scanned for app scripts
- fix lua::getfield and events registering
- fix UIDocument::rebuildIndices
- fix input library in headless mode
- fix rigidbody:set_gravity_scale
- fix extended blocks destruction particles spawn spread, offset
- fix shaders recompiling
- fix: C++ vecn functions precision loss
- fix coroutines errors handling
- fix: viewport size on toggle fullscreen
- fix: fullscreen monitor refresh rate
- fix: content menu panel height
- fix generation.create_fragment (#596)
- fix bytearray:insert (#594)
- fix: script overriding
- fix: hud.close after hud.show_overlay bug
- fix: 'cannot resume dead coroutine' (#569)
- fix: skybox is not visible behind translucent blocks
- fix: sampler arrays inbdexed with non-constant / uniform-based expressions are forbidden
- fix initial weather intensity
- fix drop count (560)
- fix BasicParser::parseNumber() out of range (560)
- fix rotation interpolation (#557)
- [fix: "Bytearray expected, got function"](https://github.com/MihailRis/voxelcore/commit/2d1c69ee7e7248d8e86e00c4a2f5cead490cd278)
- [fix zero frames texture animation fatal error](https://github.com/MihailRis/voxelcore/commit/e9222976efa67e2fe541962aabb6485363a12354)
- [fix non-local players interpolation and head direction](https://github.com/MihailRis/voxelcore/commit/75ef603df0b1958e0c9eb95c2474dc7f3ec34057)
- [fix std::bad_alloc caused by corrupted regions](https://github.com/MihailRis/voxelcore/commit/47cdc0213723c74be3e41b39702b656a2db0448d)
- [fix 'align' ui property reading](https://github.com/MihailRis/voxelcore/commit/c8ba5b5dbb7980a6576444fed9f7ea66ae1ed32a)
- [fix incorrect textbox horizontal scroll](https://github.com/MihailRis/voxelcore/commit/bc86a3d8da4301ea6ce94c52715bd7cf863b0c37)
- [fix: wrong environment used in modules imported by require(...)](https://github.com/MihailRis/voxelcore/commit/5626163f17a252212607dc63bfcd726df44bf290)
- [fix: some container attributes not available in panel](https://github.com/MihailRis/voxelcore/commit/8a858beeb421495247a8dfae064672bcf6eb4190)
- [fix generation.load_fragment](https://github.com/MihailRis/voxelcore/commit/b4ba2da95524025991f07be87b61ecc015f12656)
- [fix: byteutil.unpack 'b' is equivalent of 'B'](https://github.com/MihailRis/voxelcore/commit/2a9507b54e58f852b558d7bc9b2cc88397d37a34)
- [fix: missing yaml null literals](https://github.com/MihailRis/voxelcore/commit/5755c616f35cc1c1fc5e94ecbc9c38a5a7f52275)
- [fix yaml array parsing](https://github.com/MihailRis/voxelcore/commit/026ae756cf4ad4a4febbef58ce2f007b2a0fc974)
- [fix mouse click textbox caret set](https://github.com/MihailRis/voxelcore/commit/a1f0c2c2527b91d3a1d4f47eb2c043ebdef60119)
- [fix wrapped textbox selection render](https://github.com/MihailRis/voxelcore/commit/76b54a890c35b6edb6d5018078c865f31e966965)
- [fix broken dependencies management](https://github.com/MihailRis/voxelcore/commit/ee6f006b797d1a560baa9e333c99ee0181f548b6)
- [fix assets.parse_model with 'xml' format](https://github.com/MihailRis/voxelcore/commit/ec94abccbc4604e5d945d2bb8d1a63561797092b)
- [fix correct line generation algorithm and bounds calculation](https://github.com/MihailRis/voxelcore/commit/ed9cf8800aea07c169719a3efddae7020e6be7e9)
- [fix enable per-variant custom model caching](https://github.com/MihailRis/voxelcore/commit/2a1d2f9354ee2ab623aca9d0059c0a676395d6d0)
- [fix: stream stops and dies on underflow](https://github.com/MihailRis/voxelcore/commit/cf561e78a81810fcb70975c7b785938af37b4b64)
- [fix Schedule:set_timeout](https://github.com/MihailRis/voxelcore/commit/1e16ab5464b80d258fd955cf0485ebf596298ab3)
- [fix major chunks loading performance issue](https://github.com/MihailRis/voxelcore/commit/957f9f59983790583fb57c9e9a3661631f380153)
- [fix: undo/redo also available when textbox is not editable](https://github.com/MihailRis/voxelcore/commit/0df5684adf3117f4018e4b34868f6c41ee7125e3)
- [fix player library docs](https://github.com/MihailRis/voxelcore/commit/51f07450d89781ce35bd630e07ea8cf33b912b93)
- [fix: root node id overriding](https://github.com/MihailRis/voxelcore/commit/91cb5ab7d8ca5376d87e1ad69b8f2cb05278d73d)
- [fix extended block placement across chunk borders](https://github.com/MihailRis/voxelcore/commit/b85c5e367a2adea57ab0c3111e3d3b0cc924322b)
- [fix modelviewer fbo creation](https://github.com/MihailRis/voxelcore/commit/be6710bc831f700bd9099860c704b3571d1d90fa)
- [fix: panel width differs to size specified in xml](https://github.com/MihailRis/voxelcore/commit/8cc51a107e27e1cb5ae8343fa0151db9c9a66852)
+3 -1
View File
@@ -10,6 +10,8 @@ execute_process(COMMAND ${CMAKE_COMMAND} --version)
option(VOXELENGINE_BUILD_APPDIR "Pack linux build" OFF)
option(VOXELENGINE_BUILD_TESTS "Build tests" OFF)
add_compile_definitions(VC_BUILD_NAME="${VC_BUILD_NAME}")
# Need for static compilation on Windows with MSVC clang TODO: Make single build
# on Windows to avoid dependence on combinations of platforms and compilers and
# make it independent
@@ -40,7 +42,7 @@ target_link_options(VoxelEngine PRIVATE $<$<CXX_COMPILER_ID:GNU>:-no-pie>)
add_custom_command(
TARGET VoxelEngine
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/res $<TARGET_FILE_DIR:VoxelEngine>/res)
if(VOXELENGINE_BUILD_TESTS)
+1 -1
View File
@@ -3,7 +3,7 @@
## Latest release
- [Download](https://github.com/MihailRis/VoxelCore/releases/latest) | [Скачать](https://github.com/MihailRis/VoxelCore/releases/latest)
- [Documentation](https://github.com/MihailRis/VoxelCore/blob/release-0.29/doc/en/main-page.md) | [Документация](https://github.com/MihailRis/VoxelCore/blob/release-0.29/doc/ru/main-page.md)
- [Documentation](https://github.com/MihailRis/VoxelCore/blob/release-0.30/doc/en/main-page.md) | [Документация](https://github.com/MihailRis/VoxelCore/blob/release-0.30/doc/ru/main-page.md)
---
+297
View File
@@ -0,0 +1,297 @@
debug.log("=== ZIP Filesystem Tests ===")
-- Helper function to create test directory structure
local function setup_test_directory()
debug.log("Setting up test directory structure")
file.mkdirs("config:zip_test/subdir/deep")
file.write("config:zip_test/root_file.txt", "This is a root level file")
file.write("config:zip_test/subdir/file_in_subdir.txt", "File in subdirectory")
file.write("config:zip_test/subdir/deep/deep_file.txt", "File in deep subdirectory")
file.write("config:zip_test/unicode.txt", "Привет мир! Hello World! 你好世界!")
local bytes = {0x00, 0x01, 0x02, 0xFF, 0xFE, 0xFD}
file.write_bytes("config:zip_test/binary.bin", bytes)
debug.log("Test directory structure created")
end
-- Helper function to cleanup
local function cleanup()
debug.log("Cleaning up test files")
if file.exists("config:zip_test") then
file.remove_tree("config:zip_test")
end
if file.exists("config:test_archive.zip") then
file.remove("config:test_archive.zip")
end
end
-- Track found bugs
local bugs_found = {}
local function report_bug(name, description)
table.insert(bugs_found, {name = name, description = description})
debug.log("!!! BUG FOUND: " .. name)
debug.log(" " .. description)
end
cleanup()
debug.log("\n[Test 1] Create test directory structure")
setup_test_directory()
assert(file.isdir("config:zip_test"))
assert(file.isfile("config:zip_test/root_file.txt"))
assert(file.isfile("config:zip_test/subdir/file_in_subdir.txt"))
assert(file.isfile("config:zip_test/subdir/deep/deep_file.txt"))
debug.log("\n[Test 2] Create ZIP archive")
file.create_zip("config:zip_test", "config:test_archive.zip")
assert(file.exists("config:test_archive.zip"), "ZIP archive was not created")
assert(file.isfile("config:test_archive.zip"), "ZIP archive is not a file")
local zip_size = file.length("config:test_archive.zip")
assert(zip_size > 0, "ZIP archive is empty")
debug.log("ZIP archive created, size: " .. tostring(zip_size) .. " bytes")
debug.log("\n[Test 3] Mount ZIP archive")
local entry_point = file.mount("config:test_archive.zip")
assert(entry_point ~= nil, "Mount returned nil")
assert(#entry_point > 0, "Mount returned empty entry point")
debug.log("ZIP mounted at entry point: " .. entry_point)
debug.log("\n[Test 4] Check mounted ZIP is read-only")
assert(not file.is_writeable(entry_point .. ":"), "Mounted ZIP should not be writeable")
-- Check root directory consistency (exists vs isdir methods check)
debug.log("\n[Test 5] Check root directory consistency")
local root_path = entry_point .. ":"
local root_isdir = file.isdir(root_path)
local root_exists = file.exists(root_path)
debug.log("file.isdir('" .. root_path .. "') = " .. tostring(root_isdir))
debug.log("file.exists('" .. root_path .. "') = " .. tostring(root_exists))
if root_isdir and not root_exists then
report_bug("ROOT_EXISTS_INCONSISTENCY",
"file.isdir() returns true for ZIP root but file.exists() returns false. " ..
"ZipFileDevice::exists() should handle empty path like ZipFileDevice::isdir() does.")
end
debug.log("\n[Test 6] List root directory")
local root_entries = file.list(root_path)
debug.log("Root entries count: " .. #root_entries)
for i, entry in ipairs(root_entries) do
debug.log(" [" .. i .. "] '" .. entry .. "'")
end
-- Check path format in ZIP archive (leading slash bug)
debug.log("\n[Test 7] Check path format in ZIP archive")
local test_paths = {
{path = entry_point .. ":root_file.txt", desc = "without leading '/'"},
{path = entry_point .. ":/root_file.txt", desc = "with leading '/'"},
{path = entry_point .. ":subdir", desc = "subdir without leading '/'"},
{path = entry_point .. ":/subdir", desc = "subdir with leading '/'"},
}
local path_without_slash_works = false
local path_with_slash_works = false
local working_prefix = ""
for _, test in ipairs(test_paths) do
local exists = file.exists(test.path)
local isfile = file.isfile(test.path)
local isdir = file.isdir(test.path)
debug.log("Path: '" .. test.path .. "' (" .. test.desc .. ")")
debug.log(" exists=" .. tostring(exists) .. ", isfile=" .. tostring(isfile) .. ", isdir=" .. tostring(isdir))
if test.desc == "without leading '/'" and exists then
path_without_slash_works = true
working_prefix = ""
elseif test.desc == "with leading '/'" and exists then
path_with_slash_works = true
working_prefix = "/"
end
end
if not path_without_slash_works and path_with_slash_works then
report_bug("LEADING_SLASH_IN_ZIP_PATHS",
"file.create_zip generates paths with leading '/' (e.g., '/root_file.txt' instead of 'root_file.txt'). " ..
"This breaks file.list() for root directory and requires paths like 'entry:/file.txt' instead of 'entry:file.txt'. " ..
"The bug is in write_zip() where name = entry.pathPart().substr(root.length()) produces '/file.txt' " ..
"because root doesn't include the trailing slash.")
end
-- Set the working path format
local function make_path(relative_path)
if #working_prefix > 0 then
return entry_point .. ":" .. working_prefix .. relative_path
else
return entry_point .. ":" .. relative_path
end
end
debug.log("\n[Test 8] Read text file (with correct path format)")
local root_file_path = make_path("root_file.txt")
debug.log("Trying to read: " .. root_file_path)
if file.exists(root_file_path) then
local content = file.read(root_file_path)
debug.log("Content: '" .. content .. "'")
assert(content == "This is a root level file", "Content mismatch")
else
debug.log("File does not exist with path: " .. root_file_path)
end
debug.log("\n[Test 9] Check subdirectory")
local subdir_path = make_path("subdir")
debug.log("Checking: " .. subdir_path)
local subdir_exists = file.exists(subdir_path)
local subdir_isdir = file.isdir(subdir_path)
debug.log("exists=" .. tostring(subdir_exists) .. ", isdir=" .. tostring(subdir_isdir))
debug.log("\n[Test 10] Check file in subdirectory")
local subdir_file_path = make_path("subdir/file_in_subdir.txt")
debug.log("Checking: " .. subdir_file_path)
local subdir_file_exists = file.exists(subdir_file_path)
debug.log("exists=" .. tostring(subdir_file_exists))
if subdir_file_exists then
local content = file.read(subdir_file_path)
debug.log("Content: '" .. content .. "'")
end
debug.log("\n[Test 11] List subdirectory")
if file.isdir(subdir_path) then
local subdir_entries = file.list(subdir_path)
debug.log("Subdirectory entries count: " .. #subdir_entries)
for i, entry in ipairs(subdir_entries) do
debug.log(" [" .. i .. "] '" .. entry .. "'")
end
for i, entry in ipairs(subdir_entries) do
local expected_prefix = entry_point .. ":"
if string.sub(entry, 1, #expected_prefix) ~= expected_prefix then
report_bug("LIST_MISSING_ENTRY_POINT",
"file.list() returns paths without entry point prefix. " ..
"Expected '" .. expected_prefix .. "...' but got '" .. entry .. "'")
break
end
end
local subdir_path_slash = subdir_path .. "/"
if file.isdir(subdir_path_slash) then
local subdir_entries_slash = file.list(subdir_path_slash)
debug.log("Subdirectory entries (with trailing '/') count: " .. #subdir_entries_slash)
if #subdir_entries ~= #subdir_entries_slash then
report_bug("TRAILING_SLASH_CHANGES_LIST_RESULT",
"file.list() returns different results for paths with and without trailing slash")
end
end
else
debug.log("Subdirectory does not exist, skipping list test")
end
debug.log("\n[Test 12] Deep nested structure")
local deep_dir = make_path("subdir/deep")
local deep_file = make_path("subdir/deep/deep_file.txt")
debug.log("Deep dir: " .. deep_dir .. " exists=" .. tostring(file.exists(deep_dir)))
debug.log("Deep file: " .. deep_file .. " exists=" .. tostring(file.exists(deep_file)))
debug.log("\n[Test 13] Binary file")
local binary_path = make_path("binary.bin")
debug.log("Binary file: " .. binary_path)
if file.exists(binary_path) then
local read_bytes = file.read_bytes(binary_path)
local expected_bytes = {0x00, 0x01, 0x02, 0xFF, 0xFE, 0xFD}
debug.log("Read " .. #read_bytes .. " bytes, expected " .. #expected_bytes)
local bytes_match = (#read_bytes == #expected_bytes)
if bytes_match then
for i, b in ipairs(expected_bytes) do
if read_bytes[i] ~= b then
bytes_match = false
break
end
end
end
debug.log("Binary content matches: " .. tostring(bytes_match))
end
debug.log("\n[Test 14] Unicode content")
local unicode_path = make_path("unicode.txt")
if file.exists(unicode_path) then
local content = file.read(unicode_path)
local expected = "Привет мир! Hello World! 你好世界!"
debug.log("Unicode content matches: " .. tostring(content == expected))
end
debug.log("\n[Test 15] file.parent() for ZIP paths")
local test_file = make_path("subdir/file_in_subdir.txt")
local parent = file.parent(test_file)
debug.log("file.parent('" .. test_file .. "') = '" .. parent .. "'")
local expected_parent = entry_point .. ":" .. working_prefix .. "subdir"
if parent ~= expected_parent then
debug.log("Expected: '" .. expected_parent .. "'")
-- This might be a problem with path normalization
end
debug.log("\n[Test 16] Navigate up using file.parent()")
local path = make_path("subdir/deep/deep_file.txt")
debug.log("Starting: " .. path)
local steps = {}
for i = 1, 5 do
path = file.parent(path)
table.insert(steps, path)
debug.log(" Step " .. i .. ": " .. path)
if path == entry_point .. ":" or path == "" then
break
end
end
debug.log("\n[Test 17] Unmount ZIP archive")
file.unmount(entry_point)
debug.log("Unmounted")
local after_unmount_exists = file.exists(root_file_path)
debug.log("After unmount, file.exists('" .. root_file_path .. "') = " .. tostring(after_unmount_exists))
if after_unmount_exists then
report_bug("UNMOUNT_FILES_STILL_ACCESSIBLE",
"Files are still accessible after file.unmount()")
end
-- Cleanup
debug.log("\n[Cleanup]")
cleanup()
-- Summary
debug.log("\n=== Test Summary ===")
if #bugs_found == 0 then
debug.log("No bugs found!")
else
debug.log("Found " .. #bugs_found .. " bug(s):")
for i, bug in ipairs(bugs_found) do
debug.log(" " .. i .. ". " .. bug.name)
debug.log(" " .. bug.description)
end
end
-- Final assertions to ensure critical functionality works
-- (these will fail the test if the workaround path format doesn't work)
debug.log("\n=== Final Assertions ===")
cleanup()
setup_test_directory()
file.create_zip("config:zip_test", "config:test_archive.zip")
local ep = file.mount("config:test_archive.zip")
-- Critical: Files should be readable from mounted ZIP (with workaround)
local test_content = file.read(ep .. ":/root_file.txt")
assert(test_content == "This is a root level file", "CRITICAL: Cannot read files from mounted ZIP")
-- Critical: Subdirectories should be listable
local test_list = file.list(ep .. ":/subdir")
assert(#test_list > 0, "CRITICAL: Cannot list subdirectories in mounted ZIP")
-- Critical: Deep nested files should be accessible
local deep_content = file.read(ep .. ":/subdir/deep/deep_file.txt")
assert(deep_content == "File in deep subdirectory", "CRITICAL: Cannot read deep nested files")
file.unmount(ep)
cleanup()
debug.log("\n=== ZIP Filesystem Tests Completed ===")
debug.log("Note: " .. #bugs_found .. " non-critical bug(s) detected, see summary above.")
+12 -4
View File
@@ -159,6 +159,8 @@ Face culling mode:
- **optional** - face culling among blocks of the same rendering group can be disabled via the `graphics.dense-render` setting.
- **disabled** - face culling among blocks of the same rendering group disabled.
In `optional` mode, disabling `graphics.dense-render` will use the `*_opaque` texture variant (if available).
## Physics
### *obstacle*
@@ -216,10 +218,6 @@ Item will be chosen on MMB click on the block.
Example: block `door:door_open` is hidden, so you need to specify `picking-item: "door:door.item"` to bind it to not hidden `door:door` block item.
### *script-name*
Used to specify block script name (to reuse one script to multiple blocks). Name must not contain `packid:scripts/` and extension. Just name.
### *ui-layout*
Block UI XML layout name. Default: string block id.
@@ -316,6 +314,16 @@ Example: `base:dirt.item`.
To generate loot, the function `block_loot(block_id: int)` in the `base:util` module should be used.
## Other properties
### *script-name*
Used to specify block script name (to reuse one script to multiple blocks). Name must not contain `packid:scripts/` and extension. Just name.
### Tick Interval - *tick-interval*
The interval in ticks (1/20th of a second). A value of 20 results in an on_block_tick call interval of one second.
## Methods
Methods are used to manage the overwriting of properties when extending a block with other packs.
+2 -2
View File
@@ -1,9 +1,9 @@
# Documentation
Documentation for 0.30.
Documentation for 0.31.1.
> [!WARNING]
> Version is in development. Proceed to [Documentation for 0.29.](https://github.com/MihailRis/voxelcore/blob/release-0.29/doc/en/main-page.md)
> Version is in development. Proceed to [Documentation for 0.30.](https://github.com/MihailRis/voxelcore/blob/release-0.30/doc/en/main-page.md)
## Sections
+1 -1
View File
@@ -48,7 +48,7 @@ Called on random block update (grass growth)
function on_blocks_tick(tps: int)
```
Called tps (20) times per second. Use 1/tps instead of `time.delta()`.
Called tps (20 / tick-interval) times per second. Use 1/tps instead of `time.delta()`.
```lua
function on_block_tick(x, y, z, tps: number)
+13 -5
View File
@@ -168,6 +168,8 @@
- **optional** - отсечение граней среди блоков одной группы отрисовки можно отключить через настройку `graphics.dense-render` (Плотный рендер блоков).
- **disabled** - отсечение граней среди блоков одной группы отрисовки отключено.
В режиме `optional` при отключении `graphics.dense-render` будет использоваться `*_opaque` вариант текстуры (при наличии).
## Физика
### Препятствие - *obstacle*
@@ -226,11 +228,6 @@
Пример: блок `door:door_open` скрыт (hidden) поэтому указывается `picking-item: "door:door.item"`
### Имя скрипта - *script-name*
Позволяет указать название скрипта блока. Свойство обеспечивает возможность использования одного скрипта для нескольких блоков.
Название указывается без `пак:scripts/` и расширения.
### Имя макета UI - *ui-layout*
Позволяет указать id XML-макета интерфейса блока. По-умолчанию используется строковый id блока.
@@ -325,6 +322,17 @@
Для генерации лута следует использовать функцию `block_loot(block_id: int)` в модуле `base:util`.
## Другое
### Имя скрипта - *script-name*
Позволяет указать название скрипта блока. Свойство обеспечивает возможность использования одного скрипта для нескольких блоков.
Название указывается без `пак:scripts/` и расширения.
### Интервал тактов - *tick-interval*
Интервал в тактах мира (1/20 секуды). Значение 20 приводит к интервалу вызова on_block_tick равному одной секунде.
## Методы
Методы используются для управлением перезаписью свойств при расширении блока другими паками.
+2 -2
View File
@@ -1,9 +1,9 @@
# Документация
Документация версии 0.30.
Документация версии 0.31.1.
> [!WARNING]
> Версия находится в разработке. Перейдите к [документации для 0.29.](https://github.com/MihailRis/voxelcore/blob/release-0.29/doc/ru/main-page.md)
> Версия находится в разработке. Перейдите к [документации для 0.30.](https://github.com/MihailRis/voxelcore/blob/release-0.30/doc/ru/main-page.md)
## Разделы
+1 -1
View File
@@ -48,7 +48,7 @@ function on_random_update(x, y, z)
function on_blocks_tick(tps: int)
```
Вызывается tps (20) раз в секунду. Используйте 1/tps вместо `time.delta()`.
Вызывается tps (20 / tick-interval) раз в секунду. Используйте 1/tps вместо `time.delta()`.
```lua
function on_block_tick(x, y, z, tps: number)
+1 -1
View File
@@ -1,6 +1,6 @@
{
"id": "base",
"title": "Base",
"version": "0.30",
"version": "0.31.1",
"description": "basic content package"
}
+3
View File
@@ -1,3 +1,6 @@
# default project
name = "default"
base_packs = ["base"]
permissions = [
"network"
]
+10 -5
View File
@@ -7,7 +7,7 @@ function on_menu_clear()
end
end
function on_menu_setup()
local function setup_backround()
local controller = {}
function controller.resize_menu_bg()
local w, h = unpack(gui.get_viewport())
@@ -17,11 +17,16 @@ function on_menu_setup()
end
return w, h
end
gui.root.root:add(
"<image id='menubg' src='gui/menubg' size-func='DATA.resize_menu_bg' "..
"z-index='-1' interactive='true'/>", controller)
menubg = gui.root.menubg
local bgid = random.uuid()
gui.root.root:add(string.format(
"<image id='%s' src='gui/menubg' size-func='DATA.resize_menu_bg' "..
"z-index='-1' interactive='true'/>", bgid), controller)
menubg = gui.root[bgid]
controller.resize_menu_bg()
end
function on_menu_setup()
setup_backround()
menu.page = "main"
menu.visible = true
end
+3
View File
@@ -182,6 +182,9 @@ local function clean(iterable, checkFun, ...)
end
network.__process_events = function()
if not network.is_available() then
return
end
local CLIENT_CONNECTED = 1
local CONNECTED_TO_SERVER = 2
local DATAGRAM = 3
+1
View File
@@ -13,6 +13,7 @@ block.__perform_ticks = function(delta)
goto continue
end
entry.timer = 0.0
entry.pointer = entry.pointer % #entry
local event = entry.event
local tps = entry.tps
for i=1, steps do
+3 -2
View File
@@ -45,7 +45,8 @@ local canvas_ffi_buffer_size = 0
local _ffi = ffi
function __vc_Canvas_set_data(self, data)
if type(data) == "cdata" then
self:_set_data(tostring(_ffi.cast("uintptr_t", data)))
self:_set_data(tostring(_ffi.cast("uintptr_t", data.bytes)), data.size)
return
end
local width = self.width
local height = self.height
@@ -60,7 +61,7 @@ function __vc_Canvas_set_data(self, data)
for i=0, size - 1 do
canvas_ffi_buffer[i] = data[i + 1]
end
self:_set_data(tostring(_ffi.cast("uintptr_t", canvas_ffi_buffer)))
self:_set_data(tostring(_ffi.cast("uintptr_t", canvas_ffi_buffer)), size)
end
local ipairs_mt_supported = false
+9
View File
@@ -14,6 +14,15 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
find_package(OpenAL CONFIG REQUIRED)
else()
find_package(OpenAL REQUIRED)
# Create OpenAL::OpenAL alias if not exists
if(NOT TARGET OpenAL::OpenAL AND TARGET OpenAL::AL)
add_library(OpenAL::OpenAL ALIAS OpenAL::AL)
elseif(NOT TARGET OpenAL::OpenAL AND OPENAL_FOUND)
add_library(OpenAL::OpenAL INTERFACE IMPORTED)
set_target_properties(OpenAL::OpenAL PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${OPENAL_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${OPENAL_LIBRARY}")
endif()
endif()
find_package(ZLIB REQUIRED)
find_package(PNG REQUIRED)
+15 -8
View File
@@ -5,6 +5,7 @@
#include <utility>
#include "coders/imageio.hpp"
#include "coders/commons.hpp"
#include "constants.hpp"
#include "content/Content.hpp"
#include "content/ContentPack.hpp"
@@ -71,20 +72,26 @@ aloader_func AssetsLoader::getLoader(AssetType tag) {
void AssetsLoader::loadNext() {
const aloader_entry& entry = entries.front();
logger.info() << "loading " << entry.filename << " as " << entry.alias;
std::string error {};
try {
aloader_func loader = getLoader(entry.tag);
auto postfunc =
loader(this, paths, entry.filename, entry.alias, entry.config);
postfunc(&assets);
entries.pop();
} catch (std::runtime_error& err) {
logger.error() << err.what();
auto type = entry.tag;
std::string filename = entry.filename;
std::string reason = err.what();
entries.pop();
throw assetload::error(type, std::move(filename), std::move(reason));
} catch (const parsing_error& err) {
error = err.errorLog();
} catch (const std::runtime_error& err) {
error = err.what();
}
if (!error.empty()) {
logger.error() << error;
auto tag = entry.tag;
auto filename = entry.filename;
entries.pop();
throw assetload::error(tag, std::move(filename), std::move(error));
}
entries.pop();
}
static void add_layouts(
+5 -4
View File
@@ -10,20 +10,21 @@ class ObjParser : BasicParser<char> {
std::vector<glm::vec2> uvs {{0, 0}};
std::vector<glm::vec3> normals {{0, 1, 0}};
// TODO: refactor
void parseFace(Mesh& mesh) {
std::vector<Vertex> vertices;
while (hasNext()) {
auto c = peekInLine();
if (c == '\n') {
break;
} else {
} else if (hasNext()) {
uint indices[3] {};
uint i = 0;
do {
char next = peekInLine();
if (is_digit(next)) {
indices[i] = parseSimpleInt(10);
if (peekInLine() == '/') {
if (hasNext() && peekInLine() == '/') {
pos++;
}
} else if (next == '/') {
@@ -31,13 +32,13 @@ class ObjParser : BasicParser<char> {
} else {
break;
}
} while (peekInLine() != '\n' && ++i < 3);
} while (hasNext() && peekInLine() != '\n' && ++i < 3);
vertices.push_back(Vertex {
coords[indices[0]], uvs[indices[1]], normals[indices[2]]});
}
}
if (peekInLine() != '\n' && hasNext()) {
if (hasNext() && peekInLine() != '\n') {
skipLine();
}
if (vertices.size() >= 3) {
+16 -1
View File
@@ -164,12 +164,22 @@ static void read_in_memory(png_structp pngPtr, png_bytep dst, png_size_t toread)
reader.offset += toread;
}
void png_error_handler(png_structp pngPtr, png_const_charp errorMessage) {
logger.error() << "libpng error: " << errorMessage;
if (pngPtr) {
longjmp(png_jmpbuf(pngPtr), 1);
}
abort(); // Should not be reached if longjmp works
}
std::unique_ptr<ImageData> png::load_image(const ubyte* bytes, size_t size) {
if (size < 8 || !png_check_sig(bytes, 8)) {
throw std::runtime_error("invalid png signature");
}
png_structp pngPtr = nullptr;
pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
pngPtr = png_create_read_struct(
PNG_LIBPNG_VER_STRING, nullptr, png_error_handler, nullptr
);
if (pngPtr == nullptr) {
throw std::runtime_error("failed png_create_read_struct");
}
@@ -180,6 +190,11 @@ std::unique_ptr<ImageData> png::load_image(const ubyte* bytes, size_t size) {
throw std::runtime_error("failed png_create_info_struct");
}
if (setjmp(png_jmpbuf(pngPtr))) {
png_destroy_read_struct(&pngPtr, &infoPtr, nullptr);
throw std::runtime_error("failed to decode png");
}
InMemoryReader reader {bytes, size, 0};
png_set_read_fn(pngPtr, &reader, read_in_memory);
+2 -2
View File
@@ -6,7 +6,7 @@
#include <string>
inline constexpr int ENGINE_VERSION_MAJOR = 0;
inline constexpr int ENGINE_VERSION_MINOR = 30;
inline constexpr int ENGINE_VERSION_MINOR = 31;
#ifdef NDEBUG
inline constexpr bool ENGINE_DEBUG_BUILD = false;
@@ -14,7 +14,7 @@ inline constexpr bool ENGINE_DEBUG_BUILD = false;
inline constexpr bool ENGINE_DEBUG_BUILD = true;
#endif // NDEBUG
inline const std::string ENGINE_VERSION_STRING = "0.30";
inline const std::string ENGINE_VERSION_STRING = "0.31.1";
/// @brief world regions format version
inline constexpr uint REGION_FORMAT_VERSION = 3;
+2 -2
View File
@@ -12,7 +12,7 @@
#include "logic/scripting/scripting.hpp"
#include "core_defs.hpp"
static void load_configs(Input& input, const io::path& root) {
static void load_configs(Input* input, const io::path& root) {
auto configFolder = root / "config";
}
@@ -26,7 +26,7 @@ static std::vector<io::path> default_content_sources {
ContentControl::ContentControl(
const Project& project,
EnginePaths& paths,
Input& input,
Input* input,
std::function<void()> postContent
)
: paths(paths),
+2 -2
View File
@@ -19,7 +19,7 @@ public:
ContentControl(
const Project& project,
EnginePaths& paths,
Input& input,
Input* input,
std::function<void()> postContent
);
~ContentControl();
@@ -49,7 +49,7 @@ public:
const std::vector<io::path>& getContentSources() const;
private:
EnginePaths& paths;
Input& input;
Input* input;
std::unique_ptr<Content> content;
std::function<void()> postContent;
std::vector<std::string> basePacks;
+4 -1
View File
@@ -289,6 +289,7 @@ void ContentLoader::loadContent(const dv::value& root) {
item.icon = def.name;
item.placingBlock = def.name;
item.tags = def.tags;
item.scriptFile = def.name + BLOCK_ITEM_SUFFIX + ".lua";
for (uint j = 0; j < 4; j++) {
item.emission[j] = def.emission[j];
@@ -492,6 +493,7 @@ void ContentLoader::loadScripts(Content& content) {
load_scripts(content, content.items);
for (const auto& [packid, runtime] : content.getPacks()) {
auto env = runtime->getEnvironment();
const auto& pack = runtime->getInfo();
const auto& folder = pack.folder;
@@ -500,9 +502,10 @@ void ContentLoader::loadScripts(Content& content) {
// Load entity components
io::path componentsDir = folder / "scripts/components";
foreach_file(componentsDir, [&pack](const io::path& file) {
foreach_file(componentsDir, [&pack, env](const io::path& file) {
auto name = pack.id + ":" + file.stem();
scripting::load_entity_component(
env,
name,
file,
pack.id + ":scripts/components/" + file.name()
+3 -1
View File
@@ -247,5 +247,7 @@ template<> void ContentUnitLoader<Block>::loadUnit(
if (def.hidden && def.pickingItem == def.name + BLOCK_ITEM_SUFFIX) {
def.pickingItem = CORE_EMPTY;
}
def.scriptFile = pack.id + ":scripts/" + def.scriptName + ".lua";
if (root.has("script-name") || def.scriptFile.empty()) {
def.scriptFile = pack.id + ":scripts/" + def.scriptName + ".lua";
}
}
+3 -3
View File
@@ -10,7 +10,7 @@
#include "coders/toml.hpp"
// All in-game definitions (blocks, items, etc..)
void corecontent::setup(Input& input, ContentBuilder& builder) {
void corecontent::setup(Input* input, ContentBuilder& builder) {
{
Block& block = builder.blocks.create(CORE_AIR);
block.replaceable = true;
@@ -28,8 +28,8 @@ void corecontent::setup(Input& input, ContentBuilder& builder) {
}
auto bindsFile = "res:bindings.toml";
if (io::is_regular_file(bindsFile)) {
input.getBindings().read(
if (input && io::is_regular_file(bindsFile)) {
input->getBindings().read(
toml::parse(bindsFile, io::read_string(bindsFile)), BindType::BIND
);
}
+1 -1
View File
@@ -32,5 +32,5 @@ class Input;
class ContentBuilder;
namespace corecontent {
void setup(Input& input, ContentBuilder& builder);
void setup(Input* input, ContentBuilder& builder);
}
+12 -5
View File
@@ -94,12 +94,17 @@ bool ClientConnection::alive() const {
static network::Server& create_tcp_server(
DebuggingServer& dbgServer, Engine& engine, int port
) {
auto& network = engine.getNetwork();
u64id_t serverId = network.openTcpServer(
auto network = engine.getNetwork();
if (network == nullptr) {
throw std::runtime_error(
"unable to create tcp server: project has no network permission"
);
}
u64id_t serverId = network->openTcpServer(
port,
[&network, &dbgServer](u64id_t sid, u64id_t id) {
auto& connection = dynamic_cast<network::ReadableConnection&>(
*network.getConnection(id, true)
*network->getConnection(id, true)
);
connection.setPrivate(true);
logger.info() << "connected client " << id << ": "
@@ -108,7 +113,7 @@ static network::Server& create_tcp_server(
dbgServer.setClient(id);
}
);
auto& server = *network.getServer(serverId, true);
auto& server = *network->getServer(serverId, true);
server.setPrivate(true);
auto& tcpServer = dynamic_cast<network::TcpServer&>(server);
@@ -302,8 +307,10 @@ void DebuggingServer::sendValue(
}
void DebuggingServer::setClient(u64id_t client) {
auto network = engine.getNetwork();
assert (network != nullptr);
connection =
std::make_unique<ClientConnection>(engine.getNetwork(), client);
std::make_unique<ClientConnection>(*network, client);
connectionEstablished = false;
}
+20
View File
@@ -11,10 +11,15 @@ static debug::Logger logger("project");
Project::~Project() = default;
dv::value Project::serialize() const {
auto permissionsList = dv::list();
for (const auto& perm : permissions.permissions) {
permissionsList.add(perm);
}
return dv::object({
{"name", name},
{"title", title},
{"base_packs", dv::to_value(basePacks)},
{"permissions", std::move(permissionsList)}
});
}
@@ -22,6 +27,17 @@ void Project::deserialize(const dv::value& src) {
src.at("name").get(name);
src.at("title").get(title);
dv::get(src, "base_packs", basePacks);
if (src.has("permissions")) {
std::vector<std::string> perms;
dv::get(src, "permissions", perms);
permissions.permissions =
std::set<std::string>(perms.begin(), perms.end());
}
logger.info() << "permissions: ";
for (const auto& perm : permissions.permissions) {
logger.info() << " - " << perm;
}
}
void Project::loadProjectClientScript() {
@@ -43,3 +59,7 @@ void Project::loadProjectStartScript() {
logger.warning() << "project start script does not exists";
}
}
bool Permissions::has(const std::string& name) const {
return permissions.find(name) != permissions.end();
}
+11
View File
@@ -1,5 +1,6 @@
#pragma once
#include <set>
#include <string>
#include <vector>
#include <memory>
@@ -11,12 +12,22 @@ namespace scripting {
class IClientProjectScript;
}
struct Permissions {
static inline std::string WRITE_TO_USER = "write-to-user";
static inline std::string NETWORK = "network";
std::set<std::string> permissions;
bool has(const std::string& name) const;
};
struct Project : Serializable {
std::string name;
std::string title;
std::vector<std::string> basePacks;
std::unique_ptr<scripting::IClientProjectScript> clientScript;
std::unique_ptr<Process> setupCoroutine;
Permissions permissions;
~Project();
+13 -5
View File
@@ -134,10 +134,14 @@ void Engine::initialize(CoreParameters coreParameters) {
}
paths = std::make_unique<EnginePaths>(params);
loadProject();
paths->setupProject(*project);
editor = std::make_unique<devtools::Editor>(*this);
cmd = std::make_unique<cmd::CommandsInterpreter>();
network = network::Network::create(settings.network);
if (project->permissions.has(Permissions::NETWORK)) {
network = network::Network::create(settings.network);
}
if (!params.debugServerString.empty()) {
try {
@@ -163,9 +167,9 @@ void Engine::initialize(CoreParameters coreParameters) {
langs::locale_by_envlocale(platform::detect_locale())
);
}
content = std::make_unique<ContentControl>(*project, *paths, *input, [this]() {
onContentLoad();
});
content = std::make_unique<ContentControl>(
*project, *paths, input.get(), [this]() { onContentLoad(); }
);
scripting::initialize(this);
if (!isHeadless()) {
@@ -232,7 +236,9 @@ void Engine::run() {
}
void Engine::postUpdate() {
network->update();
if (network) {
network->update();
}
postRunnables.run();
scripting::process_post_runnables();
@@ -265,6 +271,8 @@ void Engine::nextFrame(bool waitForRefresh) {
}
void Engine::startPauseLoop() {
assert (network != nullptr);
bool initialCursorLocked = false;
if (!isHeadless()) {
initialCursorLocked = input->isCursorLocked();
+2 -4
View File
@@ -3,9 +3,7 @@
#include "CoreParameters.hpp"
#include "PostRunnables.hpp"
#include "Time.hpp"
#include "delegates.hpp"
#include "settings.hpp"
#include "typedefs.hpp"
#include "util/ObjectsKeeper.hpp"
#include <memory>
@@ -161,8 +159,8 @@ public:
return *window;
}
network::Network& getNetwork() {
return *network;
network::Network* getNetwork() {
return network.get();
}
cmd::CommandsInterpreter& getCmd() {
+21 -1
View File
@@ -6,6 +6,7 @@
#include "io/devices/ZipFileDevice.hpp"
#include "maths/util.hpp"
#include "typedefs.hpp"
#include "devtools/Project.hpp"
#include "util/platform.hpp"
#include "util/random.hpp"
#include "util/stringutil.hpp"
@@ -43,7 +44,10 @@ static std::string generate_random_base64() {
EnginePaths::EnginePaths(CoreParameters& params)
: resourcesFolder(params.resFolder),
userFilesFolder(params.userFolder),
projectFolder(params.projectFolder) {
projectFolder(params.projectFolder),
initiallyWriteables({
"world", "export", "config"
}) {
if (!params.scriptFile.empty()) {
scriptFolder = params.scriptFile.parent_path();
io::set_device("script", std::make_shared<io::StdfsDevice>(*scriptFolder));
@@ -239,6 +243,22 @@ void EnginePaths::setEntryPoints(std::vector<PathsRoot> entryPoints) {
this->entryPoints = std::move(entryPoints);
}
void EnginePaths::setupProject(const Project& project) {
if (project.permissions.has(Permissions::WRITE_TO_USER)) {
initiallyWriteables.insert("user");
}
}
bool EnginePaths::isWriteable(const std::string& entryPoint) const {
if (entryPoint.length() < 2) {
return false;
}
if (entryPoint.substr(0, 2) == "W.") {
return true;
}
return initiallyWriteables.find(entryPoint) != initiallyWriteables.end();
}
std::tuple<std::string, std::string> EnginePaths::parsePath(std::string_view path) {
size_t separator = path.find(':');
if (separator == std::string::npos) {
+8
View File
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
#include <tuple>
#include <set>
struct PathsRoot {
std::string name;
@@ -42,6 +43,8 @@ private:
std::vector<PathsRoot> roots;
};
struct Project;
class EnginePaths {
public:
ResPaths resPaths;
@@ -65,6 +68,10 @@ public:
void setEntryPoints(std::vector<PathsRoot> entryPoints);
void setupProject(const Project& project);
bool isWriteable(const std::string& entryPoint) const;
std::vector<io::path> scanForWorlds() const;
static std::tuple<std::string, std::string> parsePath(std::string_view view);
@@ -81,6 +88,7 @@ private:
std::vector<PathsRoot> entryPoints;
std::unordered_map<std::string, std::string> writeables;
std::vector<std::string> mounted;
std::set<std::string> initiallyWriteables;
void cleanup();
};
+11 -3
View File
@@ -36,9 +36,17 @@ WindowControl::Result WindowControl::initialize() {
if (!title.empty()) {
title += " - ";
}
title += "VoxelCore v" +
std::to_string(ENGINE_VERSION_MAJOR) + "." +
std::to_string(ENGINE_VERSION_MINOR);
std::string buildName;
#ifdef VC_BUILD_NAME
buildName = VC_BUILD_NAME;
#endif
title += "VoxelCore v";
if (buildName.empty()) {
title += std::to_string(ENGINE_VERSION_MAJOR) + "." +
std::to_string(ENGINE_VERSION_MINOR);
} else {
title += buildName;
}
if (ENGINE_DEBUG_BUILD) {
title += " [debug]";
}
+1 -1
View File
@@ -45,7 +45,7 @@ std::shared_ptr<gui::UINode> UiDocument::get(const std::string& id) const {
if (found == map.end()) {
return nullptr;
}
return found->second;
return found->second.lock();
}
const uidocscript& UiDocument::getScript() const {
+1 -1
View File
@@ -19,7 +19,7 @@ struct uidocscript {
bool onclose : 1;
};
using UINodesMap = std::unordered_map<std::string, std::shared_ptr<gui::UINode>>;
using UINodesMap = std::unordered_map<std::string, std::weak_ptr<gui::UINode>>;
class UiDocument {
std::string id;
+16 -12
View File
@@ -59,6 +59,7 @@ std::shared_ptr<UINode> create_debug_panel(
Player& player,
bool allowDebugCheats
) {
auto network = engine.getNetwork();
auto& gui = engine.getGUI();
auto panel = std::make_shared<Panel>(
gui, glm::vec2(300, 200), glm::vec4(5.0f), 2.0f
@@ -87,17 +88,18 @@ std::shared_ptr<UINode> create_debug_panel(
fpsMax = fps;
});
panel->listenInterval(1.0f, [&engine]() {
const auto& network = engine.getNetwork();
size_t totalDownload = network.getTotalDownload();
size_t totalUpload = network.getTotalUpload();
netSpeedString =
L"download: " + std::to_wstring(totalDownload - lastTotalDownload) +
L" B/s upload: " + std::to_wstring(totalUpload - lastTotalUpload) +
L" B/s";
lastTotalDownload = totalDownload;
lastTotalUpload = totalUpload;
});
if (network) {
panel->listenInterval(1.0f, [network]() {
size_t totalDownload = network->getTotalDownload();
size_t totalUpload = network->getTotalUpload();
netSpeedString =
L"download: " + std::to_wstring(totalDownload - lastTotalDownload) +
L" B/s upload: " + std::to_wstring(totalUpload - lastTotalUpload) +
L" B/s";
lastTotalDownload = totalDownload;
lastTotalUpload = totalUpload;
});
}
panel->add(create_label(gui, []() { return L"fps: "+fpsString;}));
@@ -116,7 +118,9 @@ std::shared_ptr<UINode> create_debug_panel(
panel->add(create_label(gui, []() {
return L"lua-stack: " + std::to_wstring(scripting::get_values_on_stack());
}));
panel->add(create_label(gui, []() { return netSpeedString; }));
if (network) {
panel->add(create_label(gui, []() { return netSpeedString; }));
}
panel->add(create_label(gui, [&engine]() {
auto& settings = engine.getSettings();
bool culling = settings.graphics.frustumCulling.get();
+11 -32
View File
@@ -3,7 +3,6 @@
#include <GL/glew.h>
#include "Texture.hpp"
#include "debug/Logger.hpp"
#include "gl_util.hpp"
static debug::Logger logger("gl-framebuffer");
@@ -20,35 +19,21 @@ Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture)
}
static std::unique_ptr<Texture> create_texture(int width, int height, int format) {
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
format,
width,
height,
0,
format,
GL_UNSIGNED_BYTE,
nullptr
);
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0
);
return std::make_unique<Texture>(texture, width, height);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
return std::make_unique<Texture>(tex, width, height);
}
Framebuffer::Framebuffer(uint width, uint height, bool alpha)
: width(width), height(height)
{
width = std::max<uint>(1, width);
height = std::max<uint>(1, height);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
@@ -60,17 +45,11 @@ Framebuffer::Framebuffer(uint width, uint height, bool alpha)
// Setup depth attachment
glGenRenderbuffers(1, &depth);
glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depth
);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
auto logLine = logger.error();
logLine << "framebuffer is not complete: ";
logLine << gl::to_string(status);
logLine << " (" << status << ")";
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
logger.error() << "framebuffer is not complete!";
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -99,7 +78,7 @@ void Framebuffer::resize(uint width, uint height) {
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
texture = create_texture(width, height, format);
-36
View File
@@ -45,40 +45,4 @@ namespace gl {
}
return 0;
}
/// TODO: extend
inline const char* to_string(GLenum item) {
switch (item) {
case GL_INVALID_ENUM:
return "invalid enum";
case GL_INVALID_VALUE:
return "invalid value";
case GL_INVALID_OPERATION:
return "invalid operation";
case GL_STACK_OVERFLOW:
return "stack overflow";
case GL_STACK_UNDERFLOW:
return "stack underflow";
case GL_OUT_OF_MEMORY:
return "out of memory";
case GL_INVALID_FRAMEBUFFER_OPERATION:
return "invalid framebuffer operation";
case GL_FRAMEBUFFER_UNDEFINED:
return "framebuffer undefined";
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
return "framebuffer incomplete attachment";
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
return "framebuffer incomplete missing attachment";
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
return "framebuffer incomplete draw buffer";
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
return "framebuffer incomplete read buffer";
case GL_FRAMEBUFFER_UNSUPPORTED:
return "framebuffer unsupported";
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
return "framebuffer incomplete multisample";
default:
return "unknown";
}
}
}
+9 -2
View File
@@ -28,6 +28,13 @@ void HandsRenderer::renderHands(
const auto& config = *skeleton.config;
modelBatch.setLightsOffset(camera.position);
config.update(skeleton, glm::mat4(1.0f), glm::vec3());
config.render(assets, modelBatch, skeleton, glm::mat3(1.0f), glm::vec3());
config.update(skeleton, glm::mat4(1.0f), glm::vec3(), glm::vec3(1.0f));
config.render(
assets,
modelBatch,
skeleton,
glm::mat3(1.0f),
glm::vec3(),
glm::vec3(1.0f)
);
}
+5 -5
View File
@@ -134,16 +134,16 @@ void Skybox::draw(
DrawContext ctx = pctx.sub();
ctx.setBlendMode(BlendMode::addition);
auto p_shader = assets.get<Shader>("ui3d");
p_shader->use();
p_shader->uniformMatrix("u_projview", camera.getProjView(false));
p_shader->uniformMatrix("u_apply", glm::mat4(1.0f));
auto shader = assets.get<Shader>("ui3d");
shader->use();
shader->uniformMatrix("u_projview", camera.getProjView(false));
shader->uniformMatrix("u_apply", glm::mat4(1.0f));
batch3d->begin();
float angle = daytime * glm::pi<float>() * 2.0f;
float opacity = glm::pow(1.0f - fog, 7.0f);
float depthScale = 1e3;
float depthScale = 2e3;
for (auto& sprite : sprites) {
batch3d->texture(assets.get<Texture>(sprite.texture));
+1 -1
View File
@@ -22,6 +22,6 @@ void gui::Canvas::draw(const DrawContext& pctx, const Assets& assets) {
void gui::Canvas::setSize(const glm::vec2& size) {
UINode::setSize(size);
data->extend(size.x, size.y);
data->extend(std::max<int>(1, size.x), std::max<int>(1, size.y));
texture->reload(*data);
}
+30 -19
View File
@@ -79,6 +79,33 @@ void ModelViewer::act(float delta) {
camera.position = center - camera.front * distance;
}
static util::TextureRegion determine_texture_region(
const Assets& assets, const std::string& texture
) {
static std::array<std::string, 6> faces {
"blocks:dbg_north",
"blocks:dbg_south",
"blocks:dbg_top",
"blocks:dbg_bottom",
"blocks:dbg_west",
"blocks:dbg_east",
};
if (texture.length() < 2 || texture.at(0) != '$') {
return util::get_texture_region(assets, texture, "blocks:notfound");
}
unsigned char sideIndex = texture.at(1) - '0';
if (sideIndex < faces.size()) {
return util::get_texture_region(
assets,
faces.at(texture.at(1) - '0'),
"blocks:notfound"
);
}
return util::get_texture_region(assets, "blocks:notfound", "");
}
void ModelViewer::draw(const DrawContext& pctx, const Assets& assets) {
camera.setAspectRatio(size.x / size.y);
camera.updateVectors();
@@ -104,26 +131,10 @@ void ModelViewer::draw(const DrawContext& pctx, const Assets& assets) {
ui3dShader.uniformMatrix("u_apply", glm::mat4(1.0f));
ui3dShader.uniformMatrix("u_projview", camera.getProjView());
batch->begin();
for (const auto& mesh : model->meshes) {
util::TextureRegion region;
if (!mesh.texture.empty() && mesh.texture[0] == '$') {
// todo: refactor
static std::array<std::string, 6> faces {
"blocks:dbg_north",
"blocks:dbg_south",
"blocks:dbg_top",
"blocks:dbg_bottom",
"blocks:dbg_west",
"blocks:dbg_east",
};
region = util::get_texture_region(
assets,
faces.at(mesh.texture.at(1) - '0'),
"blocks:notfound"
);
} else {
region = util::get_texture_region(assets, mesh.texture, "blocks:notfound");
}
auto region = determine_texture_region(assets, mesh.texture);
batch->texture(region.texture);
batch->setRegion(region.region);
for (const auto& vertex : mesh.vertices) {
+9 -1
View File
@@ -385,10 +385,18 @@ bool UINode::isSubnodeOf(const UINode* node) {
void UINode::getIndices(
const std::shared_ptr<UINode>& node,
std::unordered_map<std::string, std::shared_ptr<UINode>>& map
std::unordered_map<std::string, std::weak_ptr<UINode>>& map
) {
const std::string& id = node->getId();
if (!id.empty()) {
const auto& found = map.find(id);
if (found != map.end()) {
auto prev = found->second.lock();
if (prev && prev->getParent()) {
return;
}
}
map[id] = node;
}
auto container = std::dynamic_pointer_cast<gui::Container>(node);
+1 -1
View File
@@ -289,7 +289,7 @@ namespace gui {
/// @brief collect all nodes having id
static void getIndices(
const std::shared_ptr<UINode>& node,
std::unordered_map<std::string, std::shared_ptr<UINode>>& map
std::unordered_map<std::string, std::weak_ptr<UINode>>& map
);
static std::shared_ptr<UINode> find(
+4 -3
View File
@@ -2,9 +2,10 @@
#include "util/stringutil.hpp"
ItemDef::ItemDef(const std::string& name) : name(name) {
caption = util::id_to_caption(name);
description = "";
ItemDef::ItemDef(const std::string& name)
: name(name),
caption(util::id_to_caption(name)),
scriptName(name.substr(name.find(':') + 1)) {
}
void ItemDef::cloneTo(ItemDef& dst) {
dst.caption = caption;
+2 -2
View File
@@ -37,7 +37,7 @@ struct ItemDef {
std::string caption;
/// @brief Item description will shown in inventory
std::string description;
std::string description = "";
dv::value properties = nullptr;
@@ -60,7 +60,7 @@ struct ItemDef {
std::string icon = "blocks:notfound";
std::string placingBlock = "core:air";
std::string scriptName = name.substr(name.find(':') + 1);
std::string scriptName;
std::string modelName = name + ".model";
+5 -1
View File
@@ -15,7 +15,11 @@ using namespace scripting;
static int l_start_debug_instance(lua::State* L) {
int port = lua::tointeger(L, 1);
if (port == 0) {
port = engine->getNetwork().findFreePort();
auto network = engine->getNetwork();
if (network == nullptr) {
throw std::runtime_error("project has no network permission");
}
port = network->findFreePort();
if (port == -1) {
throw std::runtime_error("could not find free port");
}
+9 -1
View File
@@ -1,6 +1,7 @@
#include "libentity.hpp"
#include "content/Content.hpp"
#include "content/ContentPack.hpp"
#include "engine/Engine.hpp"
#include "engine/EnginePaths.hpp"
#include "objects/Entities.hpp"
@@ -236,7 +237,14 @@ static int l_reload_component(lua::State* L) {
}
auto filename = name.substr(0, pos + 1) + "scripts/components/" +
name.substr(pos + 1) + ".lua";
scripting::load_entity_component(name, filename, filename);
auto prefix = name.substr(0, pos);
auto runtime = content->getPackRuntime(prefix);
if (runtime == nullptr) {
throw std::runtime_error("pack '" + prefix + "' content is not loaded");
}
scripting::load_entity_component(
runtime->getEnvironment(), name, filename, filename
);
return 0;
}
+1 -12
View File
@@ -39,18 +39,7 @@ static int l_read(lua::State* L) {
);
}
static std::set<std::string> writeable_entry_points {
"world", "export", "config"
};
static bool is_writeable(const std::string& entryPoint) {
if (entryPoint.length() < 2) {
return false;
}
if (entryPoint.substr(0, 2) == "W.") {
return true;
}
// todo: do better
auto device = io::get_device(entryPoint);
if (device == nullptr) {
return false;
@@ -58,7 +47,7 @@ static bool is_writeable(const std::string& entryPoint) {
if (dynamic_cast<io::MemoryDevice*>(device.get())) {
return true;
}
if (writeable_entry_points.find(entryPoint) != writeable_entry_points.end()) {
if (engine->getPaths().isWriteable(entryPoint)) {
return true;
}
return false;
+14 -3
View File
@@ -133,7 +133,7 @@ static int l_post(lua::State* L, network::Network& network) {
auto headers = read_headers(L, 3);
int currentRequestId = request_id++;
engine->getNetwork().post(
network.post(
url,
string,
[currentRequestId](std::vector<char> bytes) {
@@ -240,7 +240,7 @@ static int l_recv(lua::State* L, network::Network& network) {
u64id_t id = lua::tointeger(L, 1);
int length = lua::tointeger(L, 2);
auto connection = engine->getNetwork().getConnection(id, false);
auto connection = network.getConnection(id, false);
if (connection == nullptr || connection->getTransportType() != network::TransportType::TCP) {
return 0;
@@ -519,11 +519,21 @@ static int l_pull_events(lua::State* L, network::Network& network) {
return 1;
}
static int l_is_available(lua::State* L) {
return lua::pushboolean(L, engine->getNetwork() != nullptr);
}
template <int(*func)(lua::State*, network::Network&)>
int wrap(lua_State* L) {
int result = 0;
try {
result = func(L, engine->getNetwork());
auto network = engine->getNetwork();
if (network == nullptr) {
throw std::runtime_error(
"network subsystem is not available in the project"
);
}
result = func(L, *network);
}
// transform exception with description into lua_error
catch (std::exception& e) {
@@ -543,6 +553,7 @@ const luaL_Reg networklib[] = {
{"get_total_upload", wrap<l_get_total_upload>},
{"get_total_download", wrap<l_get_total_download>},
{"find_free_port", wrap<l_find_free_port>},
{"is_available", lua::wrap<l_is_available>},
{"__pull_events", wrap<l_pull_events>},
{"__open_tcp", wrap<l_open_tcp>},
{"__open_udp", wrap<l_open_udp>},
@@ -220,6 +220,14 @@ static int l_set_data(State* L) {
if (lua::isstring(L, 2)) {
auto ptr = reinterpret_cast<ubyte*>(std::stoull(lua::tostring(L, 2)));
int len = lua::touinteger(L, 3);
if (len < image.getDataSize()) {
throw std::runtime_error(
"data size mismatch expected " +
std::to_string(image.getDataSize()) + ", got " +
std::to_string(len)
);
}
std::memcpy(data, ptr, image.getDataSize());
return 0;
}
+5 -2
View File
@@ -708,12 +708,15 @@ void scripting::load_content_script(
}
void scripting::load_entity_component(
const std::string& name, const io::path& file, const std::string& fileName
const scriptenv& env,
const std::string& name,
const io::path& file,
const std::string& fileName
) {
auto L = lua::get_main_state();
std::string src = io::read_string(file);
logger.info() << "script (component) " << file.string();
lua::loadbuffer(L, 0, src, fileName);
lua::loadbuffer(L, *env, src, fileName);
lua::store_in(L, lua::CHUNKS_TABLE, name);
}
+2
View File
@@ -186,10 +186,12 @@ namespace scripting {
);
/// @brief Load component script
/// @param env environment
/// @param name component full name (packid:name)
/// @param file component script file path
/// @param fileName script file path using the engine format
void load_entity_component(
const scriptenv& env,
const std::string& name,
const io::path& file,
const std::string& fileName
+4
View File
@@ -14,6 +14,10 @@ static void sigterm_handler(int signum) {
}
int main(int argc, char** argv) {
#ifdef VC_BUILD_NAME
logger.info() << "build: " << VC_BUILD_NAME;
#endif
CoreParameters coreParameters;
try {
if (!parse_cmdline(argc, argv, coreParameters)) {
+1
View File
@@ -194,5 +194,6 @@ void Network::update() {
}
std::unique_ptr<Network> Network::create(const NetworkSettings& settings) {
logger.info() << "initializing network";
return std::make_unique<Network>(network::create_curl_requests());
}
+11 -4
View File
@@ -302,6 +302,7 @@ void Entities::updatePhysics(float delta) {
hitbox.friction = glm::abs(hitbox.gravityScale <= 1e-7f)
? 8.0f
: (!grounded ? 2.0f : 10.0f);
hitbox.scale = transform.size;
transform.setPos(hitbox.position);
if (hitbox.grounded && !grounded) {
scripting::on_entity_grounded(
@@ -358,7 +359,9 @@ void Entities::renderDebug(
if (frustum && !frustum->isBoxVisible(pos - size, pos + size)) {
continue;
}
batch.box(hitbox.position, hitbox.halfsize * 2.0f, glm::vec4(1.0f));
batch.box(
hitbox.position, hitbox.getHalfSize() * 2.0f, glm::vec4(1.0f)
);
for (auto& sensor : rigidbody.sensors) {
if (sensor.type != SensorType::AABB) continue;
@@ -410,10 +413,14 @@ void Entities::render(
}
const auto& pos = transform.pos;
const auto& size = transform.size;
if (!frustum || frustum->isBoxVisible(pos - size, pos + size)) {
const auto* rigConfig = skeleton.config;
rigConfig->render(assets, batch, skeleton, transform.rot, pos);
if (frustum && !frustum->isBoxVisible(pos - size, pos + size)) {
continue;
}
const auto* rigConfig = skeleton.config;
rigConfig->render(
assets, batch, skeleton, transform.rot, pos, size
);
}
}
+3 -3
View File
@@ -23,19 +23,19 @@ struct Transform {
void refresh();
inline void setRot(glm::mat3 m) {
inline void setRot(const glm::mat3& m) {
rot = m;
dirty = true;
}
inline void setSize(glm::vec3 v) {
inline void setSize(const glm::vec3& v) {
if (glm::distance2(displaySize, v) >= EPSILON) {
dirty = true;
}
size = v;
}
inline void setPos(glm::vec3 v) {
inline void setPos(const glm::vec3& v) {
if (glm::distance2(displayPos, v) >= EPSILON) {
dirty = true;
}
+13 -6
View File
@@ -122,15 +122,21 @@ size_t SkeletonConfig::update(
return count;
}
static glm::mat4 build_matrix(const glm::mat3& rot, const glm::vec3& pos) {
static glm::mat4 build_matrix(
const glm::mat3& rot, const glm::vec3& pos, const glm::vec3& scale
) {
glm::mat4 combined(1.0f);
combined = glm::translate(combined, pos);
combined = combined * glm::mat4(rot);
combined = glm::scale(combined, scale);
return combined;
}
void SkeletonConfig::update(
Skeleton& skeleton, const glm::mat3& rotation, const glm::vec3& position
Skeleton& skeleton,
const glm::mat3& rotation,
const glm::vec3& position,
const glm::vec3& scale
) const {
if (skeleton.interpolation.isEnabled()) {
const auto& interpolation = skeleton.interpolation;
@@ -138,10 +144,10 @@ void SkeletonConfig::update(
0,
skeleton,
root.get(),
build_matrix(rotation, interpolation.getCurrent())
build_matrix(rotation, interpolation.getCurrent(), scale)
);
} else {
update(0, skeleton, root.get(), build_matrix(rotation, position));
update(0, skeleton, root.get(), build_matrix(rotation, position, scale));
}
}
@@ -150,9 +156,10 @@ void SkeletonConfig::render(
ModelBatch& batch,
Skeleton& skeleton,
const glm::mat3& rotation,
const glm::vec3& position
const glm::vec3& position,
const glm::vec3& scale
) const {
update(skeleton, rotation, position);
update(skeleton, rotation, position, scale);
if (!skeleton.visible) {
return;
+4 -2
View File
@@ -121,7 +121,8 @@ namespace rigging {
void update(
Skeleton& skeleton,
const glm::mat3& rotation,
const glm::vec3& position
const glm::vec3& position,
const glm::vec3& scale
) const;
void render(
@@ -129,7 +130,8 @@ namespace rigging {
ModelBatch& batch,
Skeleton& skeleton,
const glm::mat3& rotation,
const glm::vec3& position
const glm::vec3& position,
const glm::vec3& scale
) const;
Skeleton instance() const {
+5
View File
@@ -52,6 +52,7 @@ struct Hitbox {
glm::vec3 position;
glm::vec3 halfsize;
glm::vec3 velocity;
glm::vec3 scale {1.0f, 1.0f, 1.0f};
float linearDamping = 0.5;
float friction = 1.0f;
float verticalDamping = 1.0f;
@@ -64,4 +65,8 @@ struct Hitbox {
AABB getAABB() const {
return AABB(position-halfsize, position+halfsize);
}
glm::vec3 getHalfSize() const {
return halfsize * scale;
}
};
+8 -9
View File
@@ -11,11 +11,10 @@
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/norm.hpp>
const float E = 0.03f;
const float MAX_FIX = 0.1f;
inline const float E = 0.03f;
inline const float MAX_FIX = 0.1f;
PhysicsSolver::PhysicsSolver(glm::vec3 gravity) : gravity(gravity) {
}
PhysicsSolver::PhysicsSolver(glm::vec3 gravity) : gravity(gravity) {}
void PhysicsSolver::step(
const GlobalChunks& chunks,
@@ -28,7 +27,7 @@ void PhysicsSolver::step(
float linearDamping = hitbox.linearDamping * hitbox.friction;
float s = 2.0f/BLOCK_AABB_GRID;
const glm::vec3& half = hitbox.halfsize;
auto half = hitbox.getHalfSize();
glm::vec3& pos = hitbox.position;
glm::vec3& vel = hitbox.velocity;
float gravityScale = hitbox.gravityScale;
@@ -91,8 +90,8 @@ void PhysicsSolver::step(
}
AABB aabb;
aabb.a = hitbox.position - hitbox.halfsize;
aabb.b = hitbox.position + hitbox.halfsize;
aabb.a = hitbox.position - hitbox.getHalfSize();
aabb.b = hitbox.position + hitbox.getHalfSize();
for (size_t i = 0; i < sensors.size(); i++) {
auto& sensor = *sensors[i];
if (sensor.entity == entity) {
@@ -267,7 +266,7 @@ void PhysicsSolver::colisionCalc(
bool PhysicsSolver::isBlockInside(int x, int y, int z, Hitbox* hitbox) {
const glm::vec3& pos = hitbox->position;
const glm::vec3& half = hitbox->halfsize;
auto half = hitbox->getHalfSize();
return x >= floor(pos.x-half.x) && x <= floor(pos.x+half.x) &&
z >= floor(pos.z-half.z) && z <= floor(pos.z+half.z) &&
y >= floor(pos.y-half.y) && y <= floor(pos.y+half.y);
@@ -276,7 +275,7 @@ bool PhysicsSolver::isBlockInside(int x, int y, int z, 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& half = hitbox->halfsize;
auto half = hitbox->getHalfSize();
const auto& boxes = def->rotatable
? def->rt.hitboxes[state.rotation]
: def->hitboxes;
+18 -5
View File
@@ -7,6 +7,8 @@
#if defined(_WIN32)
#include <malloc.h>
#else
#include <cstdlib>
#endif
namespace util {
@@ -33,7 +35,11 @@ namespace util {
std::shared_ptr<T> create(Args&&... args) {
std::lock_guard lock(mutex);
if (freeObjects.empty()) {
allocateNew();
try {
allocateNew();
} catch (const std::bad_alloc&) {
return std::make_shared<T>(std::forward<Args>(args)...);
}
}
auto ptr = freeObjects.front();
freeObjects.pop();
@@ -50,13 +56,20 @@ namespace util {
std::mutex mutex;
void allocateNew() {
std::unique_ptr<void, AlignedDeleter> ptr(
constexpr size_t alignment = alignof(T) < sizeof(void*) ? sizeof(void*) : alignof(T);
constexpr size_t size = sizeof(T);
void* rawPtr = nullptr;
#if defined(_WIN32)
_aligned_malloc(sizeof(T), alignof(T))
rawPtr = _aligned_malloc(size, alignment);
#else
std::aligned_alloc(alignof(T), sizeof(T))
if (posix_memalign(&rawPtr, alignment, size) != 0) {
rawPtr = nullptr;
}
#endif
);
if (rawPtr == nullptr) {
throw std::bad_alloc();
}
std::unique_ptr<void, AlignedDeleter> ptr(rawPtr);
freeObjects.push(ptr.get());
objects.push_back(std::move(ptr));
}
+1 -1
View File
@@ -102,7 +102,7 @@ std::string platform::detect_locale() {
if (programLocaleName && preferredLocaleName) {
setlocale(LC_ALL, programLocaleName);
return std::string(preferredLocaleName, 5);
return std::string(preferredLocaleName);
}
return langs::FALLBACK_DEFAULT;
}
+1 -1
View File
@@ -58,7 +58,7 @@ static void check_voxels(const ContentIndices& indices, Chunk& chunk) {
abort();
#endif
}
chunk.voxels[i].id = BLOCK_AIR;
chunk.voxels[i] = {};
}
}
}
-6
View File
@@ -160,12 +160,6 @@ static void initialize_block(
block_register_events.push_back(BlockRegisterEvent {
static_cast<uint8_t>(bits | 1), def.rt.id, {x, y, z}
});
if (def.rt.funcsset.onblocktick) {
block_register_events.push_back(BlockRegisterEvent {
bits, def.rt.id, {x, y, z}
});
}
}
template <class Storage>
+4 -2
View File
@@ -91,7 +91,7 @@ static inline void generate_pole(
voxel* voxels,
int x, int z
) {
uint y = top;
uint y = std::min<uint>(top, CHUNK_H - 1);
uint layerExtension = 0;
for (const auto& layer : layers.layers) {
// skip layer if can't be generated under sea level
@@ -106,7 +106,9 @@ static inline void generate_pole(
} else {
layerHeight += layerExtension;
}
layerHeight = std::min(static_cast<uint>(layerHeight), y+1);
layerHeight = std::min(
static_cast<uint>(layerHeight), std::min<uint>(CHUNK_H - 1, y + 1)
);
for (uint i = 0; i < layerHeight; i++, y--) {
voxels[vox_index(x, y, z)].id = layer.rt.id;