Compare commits
2 Commits
main
...
macOS-issu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f62574f588 | ||
|
|
a28f630878 |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
custom: ['https://boosty.to/mihailris']
|
||||
13
.github/workflows/appimage.yml
vendored
13
.github/workflows/appimage.yml
vendored
@ -5,17 +5,9 @@ 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:
|
||||
# Only run on GitHub, skip on Gitea
|
||||
if: github.server_url == 'https://github.com'
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
@ -44,14 +36,13 @@ 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 -DVC_BUILD_NAME="${{ inputs.build_name }}"
|
||||
run: cmake -S . -B build -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_APPDIR=1 -DVOXELENGINE_BUILD_TESTS=ON
|
||||
- name: Build
|
||||
run: cmake --build build -t install
|
||||
- name: Run tests
|
||||
run: ctest --test-dir build
|
||||
- name: Run engine tests
|
||||
timeout-minutes: 3
|
||||
continue-on-error: true
|
||||
timeout-minutes: 1
|
||||
run: |
|
||||
chmod +x build/VoxelEngine
|
||||
chmod +x AppDir/usr/bin/vctest
|
||||
|
||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -8,8 +8,6 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# Only run on GitHub, skip on Gitea
|
||||
if: github.server_url == 'https://github.com'
|
||||
name: Build
|
||||
uses: ./.github/workflows/cmake.yml
|
||||
with:
|
||||
|
||||
2
.github/workflows/cmake.yml
vendored
2
.github/workflows/cmake.yml
vendored
@ -19,8 +19,6 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# Only run on GitHub, skip on Gitea
|
||||
if: github.server_url == 'https://github.com'
|
||||
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
|
||||
# You can convert this to a matrix build if you need cross-platform coverage.
|
||||
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||
|
||||
15
.github/workflows/macos.yml
vendored
15
.github/workflows/macos.yml
vendored
@ -5,17 +5,9 @@ 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:
|
||||
# Only run on GitHub, skip on Gitea
|
||||
if: github.server_url == 'https://github.com'
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
@ -28,7 +20,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 -DVC_BUILD_NAME="${{ inputs.build_name }}"
|
||||
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_TESTS=ON -DVOXELENGINE_BUILD_APPDIR=1
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build -t install
|
||||
@ -43,12 +35,11 @@ jobs:
|
||||
run: ctest --output-on-failure --test-dir build
|
||||
|
||||
- name: Run engine tests
|
||||
timeout-minutes: 3
|
||||
continue-on-error: true
|
||||
timeout-minutes: 1
|
||||
run: |
|
||||
chmod +x build/VoxelEngine
|
||||
chmod +x AppDir/usr/bin/vctest
|
||||
AppDir/usr/bin/vctest -e build/VoxelEngine -d dev/tests -u build --output-always
|
||||
AppDir/usr/bin/vctest -e build/VoxelEngine -d dev/tests -u build
|
||||
- name: Create DMG
|
||||
run: |
|
||||
mkdir VoxelEngineDmgContent
|
||||
|
||||
113
.github/workflows/release.yml
vendored
113
.github/workflows/release.yml
vendored
@ -1,100 +1,43 @@
|
||||
# adopted from https://github.com/PrismLauncher/PrismLauncher
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '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' }}
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
# Gitea job - create draft release on tag push
|
||||
gitea-draft-release:
|
||||
if: github.server_url != 'https://github.com'
|
||||
build_release:
|
||||
name: Build Release
|
||||
uses: ./.github/workflows/cmake.yml
|
||||
with:
|
||||
build_type: Release
|
||||
upload_artifacts: true
|
||||
|
||||
create_release:
|
||||
needs: build_release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create Draft Release on Gitea
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.ref_name }}
|
||||
name: VoxelCore ${{ github.ref_name }}
|
||||
draft: true
|
||||
body: |
|
||||
## VoxelCore Release ${{ github.ref_name }}
|
||||
|
||||
### Downloads
|
||||
Артефакты будут загружены вручную после сборки на GitHub.
|
||||
|
||||
---
|
||||
**Full Changelog**: https://git.pyserve.org/PulseStudio/VoxelEngine/commits/tag/${{ github.ref_name }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# GitHub jobs - full build and release
|
||||
prepare:
|
||||
# Only run on GitHub, skip on Gitea
|
||||
if: github.server_url == 'https://github.com'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- 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
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./artifacts
|
||||
- name: Show Artifacts
|
||||
name: VoxelEngine
|
||||
- name: Pack 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
|
||||
chmod +x VoxelEngine
|
||||
zip -r VoxelEngine.zip res VoxelEngine
|
||||
- name: Grab and store version
|
||||
run: |
|
||||
git config --local user.email "action@github.com"
|
||||
git config --local user.name "GitHub Action"
|
||||
tag_name=$(echo ${{ github.ref }} | grep -oE "v[^/]+$")
|
||||
echo "VERSION=$tag_name" >> $GITHUB_ENV
|
||||
|
||||
TAG_NAME="v${RELEASE_VERSION}"
|
||||
git tag -a "${TAG_NAME}" -m "Automated release tag ${TAG_NAME}"
|
||||
git push origin "${TAG_NAME}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Create Release Draft
|
||||
uses: softprops/action-gh-release@v2
|
||||
- name: Create release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: v${{ env.RELEASE_VERSION }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag_name: ${{ github.ref }}
|
||||
name: VoxelEngine ${{ env.VERSION }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
files: |
|
||||
./release/*
|
||||
generate_release_notes: true
|
||||
VoxelEngine.zip
|
||||
|
||||
10
.github/workflows/windows-clang.yml
vendored
10
.github/workflows/windows-clang.yml
vendored
@ -5,17 +5,9 @@ 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-windows:
|
||||
# Only run on GitHub, skip on Gitea
|
||||
if: github.server_url == 'https://github.com'
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
@ -55,7 +47,7 @@ jobs:
|
||||
export VCPKG_ROOT=$(pwd)/vcpkg
|
||||
mkdir build
|
||||
cd build
|
||||
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 -G "MinGW Makefiles" -DVCPKG_TARGET_TRIPLET=x64-mingw-static -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake ..
|
||||
cmake --build . --config Release
|
||||
- name: Package for Windows
|
||||
run: |
|
||||
|
||||
1
.github/workflows/windows.yml
vendored
1
.github/workflows/windows.yml
vendored
@ -8,7 +8,6 @@ on:
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
if: github.server_url == 'https://github.com'
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
|
||||
@ -10,8 +10,6 @@ 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
|
||||
@ -42,7 +40,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
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/res $<TARGET_FILE_DIR:VoxelEngine>/res)
|
||||
|
||||
if(VOXELENGINE_BUILD_TESTS)
|
||||
|
||||
@ -1,297 +0,0 @@
|
||||
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.")
|
||||
@ -159,8 +159,6 @@ 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*
|
||||
@ -218,6 +216,10 @@ 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.
|
||||
@ -314,16 +316,6 @@ 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.
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
# Documentation
|
||||
|
||||
Documentation for 0.31.12.
|
||||
|
||||
> [!WARNING]
|
||||
> Version is in development. Proceed to [Documentation for 0.30.](https://github.com/MihailRis/voxelcore/blob/release-0.30/doc/en/main-page.md)
|
||||
Documentation for 0.30.
|
||||
|
||||
## Sections
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ Called on random block update (grass growth)
|
||||
function on_blocks_tick(tps: int)
|
||||
```
|
||||
|
||||
Called tps (20 / tick-interval) times per second. Use 1/tps instead of `time.delta()`.
|
||||
Called tps (20) times per second. Use 1/tps instead of `time.delta()`.
|
||||
|
||||
```lua
|
||||
function on_block_tick(x, y, z, tps: number)
|
||||
|
||||
@ -168,8 +168,6 @@
|
||||
- **optional** - отсечение граней среди блоков одной группы отрисовки можно отключить через настройку `graphics.dense-render` (Плотный рендер блоков).
|
||||
- **disabled** - отсечение граней среди блоков одной группы отрисовки отключено.
|
||||
|
||||
В режиме `optional` при отключении `graphics.dense-render` будет использоваться `*_opaque` вариант текстуры (при наличии).
|
||||
|
||||
## Физика
|
||||
|
||||
### Препятствие - *obstacle*
|
||||
@ -228,6 +226,11 @@
|
||||
|
||||
Пример: блок `door:door_open` скрыт (hidden) поэтому указывается `picking-item: "door:door.item"`
|
||||
|
||||
### Имя скрипта - *script-name*
|
||||
|
||||
Позволяет указать название скрипта блока. Свойство обеспечивает возможность использования одного скрипта для нескольких блоков.
|
||||
Название указывается без `пак:scripts/` и расширения.
|
||||
|
||||
### Имя макета UI - *ui-layout*
|
||||
|
||||
Позволяет указать id XML-макета интерфейса блока. По-умолчанию используется строковый id блока.
|
||||
@ -322,17 +325,6 @@
|
||||
|
||||
Для генерации лута следует использовать функцию `block_loot(block_id: int)` в модуле `base:util`.
|
||||
|
||||
## Другое
|
||||
|
||||
### Имя скрипта - *script-name*
|
||||
|
||||
Позволяет указать название скрипта блока. Свойство обеспечивает возможность использования одного скрипта для нескольких блоков.
|
||||
Название указывается без `пак:scripts/` и расширения.
|
||||
|
||||
### Интервал тактов - *tick-interval*
|
||||
|
||||
Интервал в тактах мира (1/20 секуды). Значение 20 приводит к интервалу вызова on_block_tick равному одной секунде.
|
||||
|
||||
## Методы
|
||||
|
||||
Методы используются для управлением перезаписью свойств при расширении блока другими паками.
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
# Документация
|
||||
|
||||
Документация версии 0.31.12.
|
||||
|
||||
> [!WARNING]
|
||||
> Версия находится в разработке. Перейдите к [документации для 0.30.](https://github.com/MihailRis/voxelcore/blob/release-0.30/doc/ru/main-page.md)
|
||||
Документация версии 0.30.
|
||||
|
||||
## Разделы
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ function on_random_update(x, y, z)
|
||||
function on_blocks_tick(tps: int)
|
||||
```
|
||||
|
||||
Вызывается tps (20 / tick-interval) раз в секунду. Используйте 1/tps вместо `time.delta()`.
|
||||
Вызывается tps (20) раз в секунду. Используйте 1/tps вместо `time.delta()`.
|
||||
|
||||
```lua
|
||||
function on_block_tick(x, y, z, tps: number)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"id": "base",
|
||||
"title": "Base",
|
||||
"version": "0.31.12",
|
||||
"version": "0.30",
|
||||
"description": "basic content package"
|
||||
}
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
# default project
|
||||
name = "default"
|
||||
base_packs = ["base"]
|
||||
permissions = [
|
||||
"network"
|
||||
]
|
||||
|
||||
@ -7,7 +7,7 @@ function on_menu_clear()
|
||||
end
|
||||
end
|
||||
|
||||
local function setup_backround()
|
||||
function on_menu_setup()
|
||||
local controller = {}
|
||||
function controller.resize_menu_bg()
|
||||
local w, h = unpack(gui.get_viewport())
|
||||
@ -17,16 +17,11 @@ local function setup_backround()
|
||||
end
|
||||
return w, h
|
||||
end
|
||||
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]
|
||||
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
|
||||
controller.resize_menu_bg()
|
||||
end
|
||||
|
||||
function on_menu_setup()
|
||||
setup_backround()
|
||||
menu.page = "main"
|
||||
menu.visible = true
|
||||
end
|
||||
|
||||
@ -182,9 +182,6 @@ 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
|
||||
|
||||
@ -13,7 +13,6 @@ 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
|
||||
|
||||
@ -46,7 +46,6 @@ local _ffi = ffi
|
||||
function __vc_Canvas_set_data(self, data)
|
||||
if type(data) == "cdata" then
|
||||
self:_set_data(tostring(_ffi.cast("uintptr_t", data.bytes)), data.size)
|
||||
return
|
||||
end
|
||||
local width = self.width
|
||||
local height = self.height
|
||||
@ -61,7 +60,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)), size)
|
||||
self:_set_data(tostring(_ffi.cast("uintptr_t", canvas_ffi_buffer)), data.size)
|
||||
end
|
||||
|
||||
local ipairs_mt_supported = false
|
||||
|
||||
@ -14,15 +14,6 @@ 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)
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
#include <utility>
|
||||
|
||||
#include "coders/imageio.hpp"
|
||||
#include "coders/commons.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "content/ContentPack.hpp"
|
||||
@ -72,26 +71,20 @@ 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);
|
||||
} 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));
|
||||
}
|
||||
} 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));
|
||||
}
|
||||
}
|
||||
|
||||
static void add_layouts(
|
||||
|
||||
@ -10,21 +10,20 @@ 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 if (hasNext()) {
|
||||
} else {
|
||||
uint indices[3] {};
|
||||
uint i = 0;
|
||||
do {
|
||||
char next = peekInLine();
|
||||
if (is_digit(next)) {
|
||||
indices[i] = parseSimpleInt(10);
|
||||
if (hasNext() && peekInLine() == '/') {
|
||||
if (peekInLine() == '/') {
|
||||
pos++;
|
||||
}
|
||||
} else if (next == '/') {
|
||||
@ -32,13 +31,13 @@ class ObjParser : BasicParser<char> {
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (hasNext() && peekInLine() != '\n' && ++i < 3);
|
||||
} while (peekInLine() != '\n' && ++i < 3);
|
||||
|
||||
vertices.push_back(Vertex {
|
||||
coords[indices[0]], uvs[indices[1]], normals[indices[2]]});
|
||||
}
|
||||
}
|
||||
if (hasNext() && peekInLine() != '\n') {
|
||||
if (peekInLine() != '\n' && hasNext()) {
|
||||
skipLine();
|
||||
}
|
||||
if (vertices.size() >= 3) {
|
||||
|
||||
@ -164,22 +164,12 @@ 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, png_error_handler, nullptr
|
||||
);
|
||||
pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||
if (pngPtr == nullptr) {
|
||||
throw std::runtime_error("failed png_create_read_struct");
|
||||
}
|
||||
@ -190,11 +180,6 @@ 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);
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include <string>
|
||||
|
||||
inline constexpr int ENGINE_VERSION_MAJOR = 0;
|
||||
inline constexpr int ENGINE_VERSION_MINOR = 31;
|
||||
inline constexpr int ENGINE_VERSION_MINOR = 30;
|
||||
|
||||
#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.31.12";
|
||||
inline const std::string ENGINE_VERSION_STRING = "0.30";
|
||||
|
||||
/// @brief world regions format version
|
||||
inline constexpr uint REGION_FORMAT_VERSION = 3;
|
||||
|
||||
@ -289,7 +289,6 @@ 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];
|
||||
@ -493,7 +492,6 @@ 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;
|
||||
|
||||
@ -502,10 +500,9 @@ void ContentLoader::loadScripts(Content& content) {
|
||||
|
||||
// Load entity components
|
||||
io::path componentsDir = folder / "scripts/components";
|
||||
foreach_file(componentsDir, [&pack, env](const io::path& file) {
|
||||
foreach_file(componentsDir, [&pack](const io::path& file) {
|
||||
auto name = pack.id + ":" + file.stem();
|
||||
scripting::load_entity_component(
|
||||
env,
|
||||
name,
|
||||
file,
|
||||
pack.id + ":scripts/components/" + file.name()
|
||||
|
||||
@ -247,7 +247,5 @@ template<> void ContentUnitLoader<Block>::loadUnit(
|
||||
if (def.hidden && def.pickingItem == def.name + BLOCK_ITEM_SUFFIX) {
|
||||
def.pickingItem = CORE_EMPTY;
|
||||
}
|
||||
if (root.has("script-name") || def.scriptFile.empty()) {
|
||||
def.scriptFile = pack.id + ":scripts/" + def.scriptName + ".lua";
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,17 +94,12 @@ bool ClientConnection::alive() const {
|
||||
static network::Server& create_tcp_server(
|
||||
DebuggingServer& dbgServer, Engine& engine, int port
|
||||
) {
|
||||
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(
|
||||
auto& network = engine.getNetwork();
|
||||
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 << ": "
|
||||
@ -113,7 +108,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);
|
||||
@ -307,10 +302,8 @@ void DebuggingServer::sendValue(
|
||||
}
|
||||
|
||||
void DebuggingServer::setClient(u64id_t client) {
|
||||
auto network = engine.getNetwork();
|
||||
assert (network != nullptr);
|
||||
connection =
|
||||
std::make_unique<ClientConnection>(*network, client);
|
||||
std::make_unique<ClientConnection>(engine.getNetwork(), client);
|
||||
connectionEstablished = false;
|
||||
}
|
||||
|
||||
|
||||
@ -11,15 +11,10 @@ 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)}
|
||||
});
|
||||
}
|
||||
|
||||
@ -27,17 +22,6 @@ 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() {
|
||||
@ -59,7 +43,3 @@ 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();
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
@ -12,22 +11,12 @@ 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();
|
||||
|
||||
|
||||
@ -134,14 +134,10 @@ 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>();
|
||||
|
||||
if (project->permissions.has(Permissions::NETWORK)) {
|
||||
network = network::Network::create(settings.network);
|
||||
}
|
||||
|
||||
if (!params.debugServerString.empty()) {
|
||||
try {
|
||||
@ -236,9 +232,7 @@ void Engine::run() {
|
||||
}
|
||||
|
||||
void Engine::postUpdate() {
|
||||
if (network) {
|
||||
network->update();
|
||||
}
|
||||
postRunnables.run();
|
||||
scripting::process_post_runnables();
|
||||
|
||||
@ -271,8 +265,6 @@ void Engine::nextFrame(bool waitForRefresh) {
|
||||
}
|
||||
|
||||
void Engine::startPauseLoop() {
|
||||
assert (network != nullptr);
|
||||
|
||||
bool initialCursorLocked = false;
|
||||
if (!isHeadless()) {
|
||||
initialCursorLocked = input->isCursorLocked();
|
||||
|
||||
@ -3,7 +3,9 @@
|
||||
#include "CoreParameters.hpp"
|
||||
#include "PostRunnables.hpp"
|
||||
#include "Time.hpp"
|
||||
#include "delegates.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "util/ObjectsKeeper.hpp"
|
||||
|
||||
#include <memory>
|
||||
@ -159,8 +161,8 @@ public:
|
||||
return *window;
|
||||
}
|
||||
|
||||
network::Network* getNetwork() {
|
||||
return network.get();
|
||||
network::Network& getNetwork() {
|
||||
return *network;
|
||||
}
|
||||
|
||||
cmd::CommandsInterpreter& getCmd() {
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
#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"
|
||||
@ -44,10 +43,7 @@ static std::string generate_random_base64() {
|
||||
EnginePaths::EnginePaths(CoreParameters& params)
|
||||
: resourcesFolder(params.resFolder),
|
||||
userFilesFolder(params.userFolder),
|
||||
projectFolder(params.projectFolder),
|
||||
initiallyWriteables({
|
||||
"world", "export", "config"
|
||||
}) {
|
||||
projectFolder(params.projectFolder) {
|
||||
if (!params.scriptFile.empty()) {
|
||||
scriptFolder = params.scriptFile.parent_path();
|
||||
io::set_device("script", std::make_shared<io::StdfsDevice>(*scriptFolder));
|
||||
@ -243,22 +239,6 @@ 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) {
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <set>
|
||||
|
||||
struct PathsRoot {
|
||||
std::string name;
|
||||
@ -43,8 +42,6 @@ private:
|
||||
std::vector<PathsRoot> roots;
|
||||
};
|
||||
|
||||
struct Project;
|
||||
|
||||
class EnginePaths {
|
||||
public:
|
||||
ResPaths resPaths;
|
||||
@ -68,10 +65,6 @@ 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);
|
||||
@ -88,7 +81,6 @@ 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();
|
||||
};
|
||||
|
||||
@ -36,17 +36,9 @@ WindowControl::Result WindowControl::initialize() {
|
||||
if (!title.empty()) {
|
||||
title += " - ";
|
||||
}
|
||||
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) + "." +
|
||||
title += "VoxelCore v" +
|
||||
std::to_string(ENGINE_VERSION_MAJOR) + "." +
|
||||
std::to_string(ENGINE_VERSION_MINOR);
|
||||
} else {
|
||||
title += buildName;
|
||||
}
|
||||
if (ENGINE_DEBUG_BUILD) {
|
||||
title += " [debug]";
|
||||
}
|
||||
|
||||
@ -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.lock();
|
||||
return found->second;
|
||||
}
|
||||
|
||||
const uidocscript& UiDocument::getScript() const {
|
||||
|
||||
@ -19,7 +19,7 @@ struct uidocscript {
|
||||
bool onclose : 1;
|
||||
};
|
||||
|
||||
using UINodesMap = std::unordered_map<std::string, std::weak_ptr<gui::UINode>>;
|
||||
using UINodesMap = std::unordered_map<std::string, std::shared_ptr<gui::UINode>>;
|
||||
|
||||
class UiDocument {
|
||||
std::string id;
|
||||
|
||||
@ -59,7 +59,6 @@ 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
|
||||
@ -88,10 +87,10 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
fpsMax = fps;
|
||||
});
|
||||
|
||||
if (network) {
|
||||
panel->listenInterval(1.0f, [network]() {
|
||||
size_t totalDownload = network->getTotalDownload();
|
||||
size_t totalUpload = network->getTotalUpload();
|
||||
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) +
|
||||
@ -99,7 +98,6 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
lastTotalDownload = totalDownload;
|
||||
lastTotalUpload = totalUpload;
|
||||
});
|
||||
}
|
||||
|
||||
panel->add(create_label(gui, []() { return L"fps: "+fpsString;}));
|
||||
|
||||
@ -118,9 +116,7 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
panel->add(create_label(gui, []() {
|
||||
return L"lua-stack: " + std::to_wstring(scripting::get_values_on_stack());
|
||||
}));
|
||||
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();
|
||||
|
||||
@ -28,13 +28,6 @@ void HandsRenderer::renderHands(
|
||||
const auto& config = *skeleton.config;
|
||||
|
||||
modelBatch.setLightsOffset(camera.position);
|
||||
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)
|
||||
);
|
||||
config.update(skeleton, glm::mat4(1.0f), glm::vec3());
|
||||
config.render(assets, modelBatch, skeleton, glm::mat3(1.0f), glm::vec3());
|
||||
}
|
||||
|
||||
@ -134,16 +134,16 @@ void Skybox::draw(
|
||||
DrawContext ctx = pctx.sub();
|
||||
ctx.setBlendMode(BlendMode::addition);
|
||||
|
||||
auto shader = assets.get<Shader>("ui3d");
|
||||
shader->use();
|
||||
shader->uniformMatrix("u_projview", camera.getProjView(false));
|
||||
shader->uniformMatrix("u_apply", glm::mat4(1.0f));
|
||||
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));
|
||||
batch3d->begin();
|
||||
|
||||
float angle = daytime * glm::pi<float>() * 2.0f;
|
||||
float opacity = glm::pow(1.0f - fog, 7.0f);
|
||||
|
||||
float depthScale = 2e3;
|
||||
float depthScale = 1e3;
|
||||
for (auto& sprite : sprites) {
|
||||
batch3d->texture(assets.get<Texture>(sprite.texture));
|
||||
|
||||
|
||||
@ -79,33 +79,6 @@ 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();
|
||||
@ -131,10 +104,26 @@ 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) {
|
||||
auto region = determine_texture_region(assets, mesh.texture);
|
||||
|
||||
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");
|
||||
}
|
||||
batch->texture(region.texture);
|
||||
batch->setRegion(region.region);
|
||||
for (const auto& vertex : mesh.vertices) {
|
||||
|
||||
@ -385,18 +385,10 @@ bool UINode::isSubnodeOf(const UINode* node) {
|
||||
|
||||
void UINode::getIndices(
|
||||
const std::shared_ptr<UINode>& node,
|
||||
std::unordered_map<std::string, std::weak_ptr<UINode>>& map
|
||||
std::unordered_map<std::string, std::shared_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);
|
||||
|
||||
@ -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::weak_ptr<UINode>>& map
|
||||
std::unordered_map<std::string, std::shared_ptr<UINode>>& map
|
||||
);
|
||||
|
||||
static std::shared_ptr<UINode> find(
|
||||
|
||||
@ -2,10 +2,9 @@
|
||||
|
||||
#include "util/stringutil.hpp"
|
||||
|
||||
ItemDef::ItemDef(const std::string& name)
|
||||
: name(name),
|
||||
caption(util::id_to_caption(name)),
|
||||
scriptName(name.substr(name.find(':') + 1)) {
|
||||
ItemDef::ItemDef(const std::string& name) : name(name) {
|
||||
caption = util::id_to_caption(name);
|
||||
description = "";
|
||||
}
|
||||
void ItemDef::cloneTo(ItemDef& dst) {
|
||||
dst.caption = caption;
|
||||
|
||||
@ -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;
|
||||
std::string scriptName = name.substr(name.find(':') + 1);
|
||||
|
||||
std::string modelName = name + ".model";
|
||||
|
||||
|
||||
@ -15,11 +15,7 @@ using namespace scripting;
|
||||
static int l_start_debug_instance(lua::State* L) {
|
||||
int port = lua::tointeger(L, 1);
|
||||
if (port == 0) {
|
||||
auto network = engine->getNetwork();
|
||||
if (network == nullptr) {
|
||||
throw std::runtime_error("project has no network permission");
|
||||
}
|
||||
port = network->findFreePort();
|
||||
port = engine->getNetwork().findFreePort();
|
||||
if (port == -1) {
|
||||
throw std::runtime_error("could not find free port");
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#include "libentity.hpp"
|
||||
|
||||
#include "content/Content.hpp"
|
||||
#include "content/ContentPack.hpp"
|
||||
#include "engine/Engine.hpp"
|
||||
#include "engine/EnginePaths.hpp"
|
||||
#include "objects/Entities.hpp"
|
||||
@ -237,14 +236,7 @@ static int l_reload_component(lua::State* L) {
|
||||
}
|
||||
auto filename = name.substr(0, pos + 1) + "scripts/components/" +
|
||||
name.substr(pos + 1) + ".lua";
|
||||
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
|
||||
);
|
||||
scripting::load_entity_component(name, filename, filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -39,7 +39,18 @@ 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;
|
||||
@ -47,7 +58,7 @@ static bool is_writeable(const std::string& entryPoint) {
|
||||
if (dynamic_cast<io::MemoryDevice*>(device.get())) {
|
||||
return true;
|
||||
}
|
||||
if (engine->getPaths().isWriteable(entryPoint)) {
|
||||
if (writeable_entry_points.find(entryPoint) != writeable_entry_points.end()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -133,7 +133,7 @@ static int l_post(lua::State* L, network::Network& network) {
|
||||
auto headers = read_headers(L, 3);
|
||||
int currentRequestId = request_id++;
|
||||
|
||||
network.post(
|
||||
engine->getNetwork().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 = network.getConnection(id, false);
|
||||
auto connection = engine->getNetwork().getConnection(id, false);
|
||||
|
||||
if (connection == nullptr || connection->getTransportType() != network::TransportType::TCP) {
|
||||
return 0;
|
||||
@ -519,21 +519,11 @@ 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 {
|
||||
auto network = engine->getNetwork();
|
||||
if (network == nullptr) {
|
||||
throw std::runtime_error(
|
||||
"network subsystem is not available in the project"
|
||||
);
|
||||
}
|
||||
result = func(L, *network);
|
||||
result = func(L, engine->getNetwork());
|
||||
}
|
||||
// transform exception with description into lua_error
|
||||
catch (std::exception& e) {
|
||||
@ -553,7 +543,6 @@ 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>},
|
||||
|
||||
@ -708,15 +708,12 @@ void scripting::load_content_script(
|
||||
}
|
||||
|
||||
void scripting::load_entity_component(
|
||||
const scriptenv& env,
|
||||
const std::string& name,
|
||||
const io::path& file,
|
||||
const std::string& fileName
|
||||
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, *env, src, fileName);
|
||||
lua::loadbuffer(L, 0, src, fileName);
|
||||
lua::store_in(L, lua::CHUNKS_TABLE, name);
|
||||
}
|
||||
|
||||
|
||||
@ -186,12 +186,10 @@ 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
|
||||
|
||||
@ -14,10 +14,6 @@ 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)) {
|
||||
|
||||
@ -194,6 +194,5 @@ 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());
|
||||
}
|
||||
|
||||
@ -302,7 +302,6 @@ 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(
|
||||
@ -359,9 +358,7 @@ void Entities::renderDebug(
|
||||
if (frustum && !frustum->isBoxVisible(pos - size, pos + size)) {
|
||||
continue;
|
||||
}
|
||||
batch.box(
|
||||
hitbox.position, hitbox.getHalfSize() * 2.0f, glm::vec4(1.0f)
|
||||
);
|
||||
batch.box(hitbox.position, hitbox.halfsize * 2.0f, glm::vec4(1.0f));
|
||||
|
||||
for (auto& sensor : rigidbody.sensors) {
|
||||
if (sensor.type != SensorType::AABB) continue;
|
||||
@ -413,14 +410,10 @@ void Entities::render(
|
||||
}
|
||||
const auto& pos = transform.pos;
|
||||
const auto& size = transform.size;
|
||||
if (frustum && !frustum->isBoxVisible(pos - size, pos + size)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!frustum || frustum->isBoxVisible(pos - size, pos + size)) {
|
||||
const auto* rigConfig = skeleton.config;
|
||||
rigConfig->render(
|
||||
assets, batch, skeleton, transform.rot, pos, size
|
||||
);
|
||||
rigConfig->render(assets, batch, skeleton, transform.rot, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -23,19 +23,19 @@ struct Transform {
|
||||
|
||||
void refresh();
|
||||
|
||||
inline void setRot(const glm::mat3& m) {
|
||||
inline void setRot(glm::mat3 m) {
|
||||
rot = m;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
inline void setSize(const glm::vec3& v) {
|
||||
inline void setSize(glm::vec3 v) {
|
||||
if (glm::distance2(displaySize, v) >= EPSILON) {
|
||||
dirty = true;
|
||||
}
|
||||
size = v;
|
||||
}
|
||||
|
||||
inline void setPos(const glm::vec3& v) {
|
||||
inline void setPos(glm::vec3 v) {
|
||||
if (glm::distance2(displayPos, v) >= EPSILON) {
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@ -122,21 +122,15 @@ size_t SkeletonConfig::update(
|
||||
return count;
|
||||
}
|
||||
|
||||
static glm::mat4 build_matrix(
|
||||
const glm::mat3& rot, const glm::vec3& pos, const glm::vec3& scale
|
||||
) {
|
||||
static glm::mat4 build_matrix(const glm::mat3& rot, const glm::vec3& pos) {
|
||||
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,
|
||||
const glm::vec3& scale
|
||||
Skeleton& skeleton, const glm::mat3& rotation, const glm::vec3& position
|
||||
) const {
|
||||
if (skeleton.interpolation.isEnabled()) {
|
||||
const auto& interpolation = skeleton.interpolation;
|
||||
@ -144,10 +138,10 @@ void SkeletonConfig::update(
|
||||
0,
|
||||
skeleton,
|
||||
root.get(),
|
||||
build_matrix(rotation, interpolation.getCurrent(), scale)
|
||||
build_matrix(rotation, interpolation.getCurrent())
|
||||
);
|
||||
} else {
|
||||
update(0, skeleton, root.get(), build_matrix(rotation, position, scale));
|
||||
update(0, skeleton, root.get(), build_matrix(rotation, position));
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,10 +150,9 @@ void SkeletonConfig::render(
|
||||
ModelBatch& batch,
|
||||
Skeleton& skeleton,
|
||||
const glm::mat3& rotation,
|
||||
const glm::vec3& position,
|
||||
const glm::vec3& scale
|
||||
const glm::vec3& position
|
||||
) const {
|
||||
update(skeleton, rotation, position, scale);
|
||||
update(skeleton, rotation, position);
|
||||
|
||||
if (!skeleton.visible) {
|
||||
return;
|
||||
|
||||
@ -121,8 +121,7 @@ namespace rigging {
|
||||
void update(
|
||||
Skeleton& skeleton,
|
||||
const glm::mat3& rotation,
|
||||
const glm::vec3& position,
|
||||
const glm::vec3& scale
|
||||
const glm::vec3& position
|
||||
) const;
|
||||
|
||||
void render(
|
||||
@ -130,8 +129,7 @@ namespace rigging {
|
||||
ModelBatch& batch,
|
||||
Skeleton& skeleton,
|
||||
const glm::mat3& rotation,
|
||||
const glm::vec3& position,
|
||||
const glm::vec3& scale
|
||||
const glm::vec3& position
|
||||
) const;
|
||||
|
||||
Skeleton instance() const {
|
||||
|
||||
@ -52,7 +52,6 @@ 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;
|
||||
@ -65,8 +64,4 @@ struct Hitbox {
|
||||
AABB getAABB() const {
|
||||
return AABB(position-halfsize, position+halfsize);
|
||||
}
|
||||
|
||||
glm::vec3 getHalfSize() const {
|
||||
return halfsize * scale;
|
||||
}
|
||||
};
|
||||
|
||||
@ -11,10 +11,11 @@
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/gtx/norm.hpp>
|
||||
|
||||
inline const float E = 0.03f;
|
||||
inline const float MAX_FIX = 0.1f;
|
||||
const float E = 0.03f;
|
||||
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,
|
||||
@ -27,7 +28,7 @@ void PhysicsSolver::step(
|
||||
float linearDamping = hitbox.linearDamping * hitbox.friction;
|
||||
float s = 2.0f/BLOCK_AABB_GRID;
|
||||
|
||||
auto half = hitbox.getHalfSize();
|
||||
const glm::vec3& half = hitbox.halfsize;
|
||||
glm::vec3& pos = hitbox.position;
|
||||
glm::vec3& vel = hitbox.velocity;
|
||||
float gravityScale = hitbox.gravityScale;
|
||||
@ -90,8 +91,8 @@ void PhysicsSolver::step(
|
||||
}
|
||||
|
||||
AABB aabb;
|
||||
aabb.a = hitbox.position - hitbox.getHalfSize();
|
||||
aabb.b = hitbox.position + hitbox.getHalfSize();
|
||||
aabb.a = hitbox.position - hitbox.halfsize;
|
||||
aabb.b = hitbox.position + hitbox.halfsize;
|
||||
for (size_t i = 0; i < sensors.size(); i++) {
|
||||
auto& sensor = *sensors[i];
|
||||
if (sensor.entity == entity) {
|
||||
@ -266,7 +267,7 @@ void PhysicsSolver::colisionCalc(
|
||||
|
||||
bool PhysicsSolver::isBlockInside(int x, int y, int z, Hitbox* hitbox) {
|
||||
const glm::vec3& pos = hitbox->position;
|
||||
auto half = hitbox->getHalfSize();
|
||||
const glm::vec3& half = hitbox->halfsize;
|
||||
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);
|
||||
@ -275,7 +276,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;
|
||||
auto half = hitbox->getHalfSize();
|
||||
const glm::vec3& half = hitbox->halfsize;
|
||||
const auto& boxes = def->rotatable
|
||||
? def->rt.hitboxes[state.rotation]
|
||||
: def->hitboxes;
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <new>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <malloc.h>
|
||||
@ -35,11 +36,7 @@ namespace util {
|
||||
std::shared_ptr<T> create(Args&&... args) {
|
||||
std::lock_guard lock(mutex);
|
||||
if (freeObjects.empty()) {
|
||||
try {
|
||||
allocateNew();
|
||||
} catch (const std::bad_alloc&) {
|
||||
return std::make_shared<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
auto ptr = freeObjects.front();
|
||||
freeObjects.pop();
|
||||
@ -56,6 +53,7 @@ namespace util {
|
||||
std::mutex mutex;
|
||||
|
||||
void allocateNew() {
|
||||
// Use posix_memalign on POSIX systems as aligned_alloc has stricter requirements
|
||||
constexpr size_t alignment = alignof(T) < sizeof(void*) ? sizeof(void*) : alignof(T);
|
||||
constexpr size_t size = sizeof(T);
|
||||
void* rawPtr = nullptr;
|
||||
|
||||
@ -102,7 +102,7 @@ std::string platform::detect_locale() {
|
||||
if (programLocaleName && preferredLocaleName) {
|
||||
setlocale(LC_ALL, programLocaleName);
|
||||
|
||||
return std::string(preferredLocaleName);
|
||||
return std::string(preferredLocaleName, 5);
|
||||
}
|
||||
return langs::FALLBACK_DEFAULT;
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ static void check_voxels(const ContentIndices& indices, Chunk& chunk) {
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
chunk.voxels[i] = {};
|
||||
chunk.voxels[i].id = BLOCK_AIR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,6 +160,12 @@ 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>
|
||||
|
||||
@ -15,7 +15,7 @@ target_link_libraries(VoxelEngineTest PRIVATE VoxelEngineSrc GTest::gtest_main)
|
||||
add_custom_command(
|
||||
TARGET VoxelEngineTest
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different
|
||||
${CMAKE_SOURCE_DIR}/res ${CMAKE_CURRENT_BINARY_DIR}/res)
|
||||
|
||||
include(GoogleTest)
|
||||
|
||||
@ -11,19 +11,9 @@ namespace fs = std::filesystem;
|
||||
|
||||
TEST(YAML, EncodeDecode) {
|
||||
io::set_device("root", std::make_shared<io::StdfsDevice>(fs::u8path("../../")));
|
||||
auto filename = "root:res/project.toml";
|
||||
auto filename = "root:.github/workflows/windows-clang.yml";
|
||||
try {
|
||||
// Test basic YAML parsing with a simple inline string
|
||||
auto value = yaml::parse(R"(
|
||||
name: test
|
||||
version: 1.0
|
||||
settings:
|
||||
debug: true
|
||||
values:
|
||||
- one
|
||||
- two
|
||||
- three
|
||||
)");
|
||||
auto value = yaml::parse(io::read_string(filename));
|
||||
std::cout << yaml::stringify(value) << std::endl;
|
||||
} catch (const parsing_error& error) {
|
||||
std::cerr << error.errorLog() << std::endl;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user