Compare commits

...

55 Commits

Author SHA1 Message Date
MihailRis
06f6550624 fix the stupid
Some checks failed
Build / Build (push) Failing after 17s
MSVC Build / build-windows (windows-latest) (push) Has been cancelled
2025-12-08 19:21:50 +03:00
MihailRis
00f269ca7e debug it 2025-12-08 19:21:50 +03:00
MihailRis
42248d67eb update appimage.yml 2025-12-08 19:21:50 +03:00
MihailRis
257a293bf4 fix platform::detect_locale 2025-12-08 19:21:50 +03:00
MihailRis
a375af9ca1 update appimage.yml 2025-12-08 19:21:50 +03:00
MihailRis
289347dc91 update appimage workflow 2025-12-08 19:21:50 +03:00
MihailRis
dd40780334 add 'network' permission 2025-12-08 19:21:50 +03:00
MihailRis
56d808e3e2 add 'write-to-user' permission & refactor checking for writeability 2025-12-08 19:21:50 +03:00
MihailRis
8831d676d4 feat: project permissions loading 2025-12-08 19:21:50 +03:00
MihailRis
6fca6eab56 start 0.31 development 2025-12-08 19:21:50 +03:00
MihailRis
df1ce1ae53 fix window title if VC_BUILD_NAME is empty 2025-12-08 19:21:50 +03:00
MihailRis
213e9150dd fix libpng error handling 2025-12-08 19:21:50 +03:00
MihailRis
43f54c38ec fix corrupted voxel reset 2025-12-08 19:21:50 +03:00
MihailRis
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
MihailRis
149f418bed update macos.yml 2025-12-08 19:21:50 +03:00
MihailRis
4893705ff4 fix overriden content units scripts overriding 2025-12-08 19:21:50 +03:00
MihailRis
b36d8d5852 fix block ticks 2025-12-08 19:21:50 +03:00
MihailRis
17503674e8 update doc/*/block-properties.md 2025-12-08 19:21:50 +03:00
MihailRis
db09672e50 document tick-interval 2025-12-08 19:21:50 +03:00
MihailRis
f1d9f1bf60 fix release pipeline 2025-12-08 19:21:50 +03:00
MihailRis
f4adcf58b2 simplify release.yml 2025-12-08 19:21:50 +03:00
MihailRis
2c1d783e0c cleanup 2025-12-08 19:21:49 +03:00
MihailRis
6bd1103f88 fix 2025-12-08 19:21:49 +03:00
MihailRis
6becd2f5b5 make windows-clang.yml reusable 2025-12-08 19:21:49 +03:00
MihailRis
9d05d7c725 fix 2025-12-08 19:21:49 +03:00
MihailRis
5971e6b76b restore jobs 2025-12-08 19:21:49 +03:00
MihailRis
80852ed368 fix 2025-12-08 19:21:49 +03:00
MihailRis
ddf3babac9 fix 2025-12-08 19:21:49 +03:00
MihailRis
082b5cd080 update release.yml 2025-12-08 19:21:49 +03:00
MihailRis
a15961af8f update release.yml 2025-12-08 19:21:49 +03:00
MihailRis
678c42a825 add more steps 2025-12-08 19:21:49 +03:00
MihailRis
85258ff036 temporary disable windows-clang.yml pull_request trigger 2025-12-08 19:21:49 +03:00
MihailRis
fa2b933856 update release.yml 2025-12-08 19:21:49 +03:00
MihailRis
8ad578e109 temporary disable workflows 2025-12-08 19:21:49 +03:00
MihailRis
63cbf12507 update windows.yml 2025-12-08 19:21:49 +03:00
MihailRis
6f9c3a1389 add publish_release job 2025-12-08 19:21:49 +03:00
MihailRis
3de1dbed0b update release.yml 2025-12-08 19:21:49 +03:00
MihailRis
5f1569a8be update release.yml 2025-12-08 19:21:49 +03:00
MihailRis
56cb79f9e2 update release.yml 2025-12-08 19:21:49 +03:00
MihailRis
092fe59c81 add release workflow 2025-12-08 19:21:49 +03:00
MihailRis
4697969bdb remove old unused release pipeline 2025-12-08 19:21:49 +03:00
MihailRis
be420352eb increase moon sprite distance 2025-12-08 19:21:49 +03:00
MihailRis
32189b5fa2 fix nil coords passed to on_block_tick 2025-12-08 19:21:49 +03:00
MihailRis
bc1ff634a3 fix: incomplete size transform support by entities 2025-12-08 19:21:49 +03:00
MihailRis
98a3971e13 fix exception if model having invalid variable texture passed to modelviewer 2025-12-08 19:21:49 +03:00
MihailRis
417521e94f temporary fix improvement 2025-12-08 19:21:49 +03:00
MihailRis
fbc6d072e8 fix canvas:set_data with table argument 2025-12-08 19:21:49 +03:00
MihailRis
e2e1bd6d76 cleanup 2025-12-08 19:21:49 +03:00
MihailRis
65ee464941 fix generated item's script 2025-12-08 19:21:49 +03:00
MihailRis
9bd6b39952 temporary fix 2025-12-08 19:21:49 +03:00
MihailRis
d7f3bf9c7c fix ui elements overriding 2025-12-08 19:21:49 +03:00
MihailRis
5ae34c2dc2 fix: pack environment not passed to components 2025-12-08 19:21:49 +03:00
MihailRis
59df377fde fix temporary 2025-12-08 19:21:49 +03:00
MihailRis
15b3e4d549 make parsing error messages while assets loading more verbose 2025-12-08 19:21:49 +03:00
MihailRis
b7751cf053 fix 'unexpected end' while parsing .obj 2025-12-08 19:21:49 +03:00
59 changed files with 461 additions and 194 deletions

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

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

View File

@ -1,43 +1,74 @@
# 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 || '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
- 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@v4
with:
name: VoxelEngine
- name: Pack artifacts
path: ./artifacts
- name: Show Artifacts
run: |
chmod +x VoxelEngine
zip -r VoxelEngine.zip res VoxelEngine
- name: Grab and store version
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
run: |
tag_name=$(echo ${{ github.ref }} | grep -oE "v[^/]+$")
echo "VERSION=$tag_name" >> $GITHUB_ENV
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- name: Create release
uses: softprops/action-gh-release@v1
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
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag_name: ${{ github.ref }}
name: VoxelEngine ${{ env.VERSION }}
tag_name: v${{ env.RELEASE_VERSION }}
draft: true
prerelease: false
files: |
VoxelEngine.zip
./release/*
generate_release_notes: true

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-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: |

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

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.

View File

@ -1,6 +1,9 @@
# Documentation
Documentation for 0.30.
Documentation for 0.31.
> [!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)
## Sections

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)

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 равному одной секунде.
## Методы
Методы используются для управлением перезаписью свойств при расширении блока другими паками.

View File

@ -1,6 +1,9 @@
# Документация
Документация версии 0.30.
Документация версии 0.31.
> [!WARNING]
> Версия находится в разработке. Перейдите к [документации для 0.30.](https://github.com/MihailRis/voxelcore/blob/release-0.30/doc/ru/main-page.md)
## Разделы

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)

View File

@ -1,6 +1,6 @@
{
"id": "base",
"title": "Base",
"version": "0.30",
"version": "0.31",
"description": "basic content package"
}

View File

@ -1,3 +1,6 @@
# default project
name = "default"
base_packs = ["base"]
permissions = [
"network"
]

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

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

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

View File

@ -46,6 +46,7 @@ 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
@ -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)), data.size)
self:_set_data(tostring(_ffi.cast("uintptr_t", canvas_ffi_buffer)), size)
end
local ipairs_mt_supported = false

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(

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) {

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);

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";
/// @brief world regions format version
inline constexpr uint REGION_FORMAT_VERSION = 3;

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()

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;
}
if (root.has("script-name") || def.scriptFile.empty()) {
def.scriptFile = pack.id + ":scripts/" + def.scriptName + ".lua";
}
}

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;
}

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();
}

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();

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>();
if (project->permissions.has(Permissions::NETWORK)) {
network = network::Network::create(settings.network);
}
if (!params.debugServerString.empty()) {
try {
@ -232,7 +236,9 @@ void Engine::run() {
}
void Engine::postUpdate() {
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();

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() {

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) {

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();
};

View File

@ -36,9 +36,17 @@ WindowControl::Result WindowControl::initialize() {
if (!title.empty()) {
title += " - ";
}
title += "VoxelCore v" +
std::to_string(ENGINE_VERSION_MAJOR) + "." +
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]";
}

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 {

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;

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,10 +88,10 @@ 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();
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) +
@ -98,6 +99,7 @@ std::shared_ptr<UINode> create_debug_panel(
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());
}));
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();

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)
);
}

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));

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) {

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);

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(

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;

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";

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");
}

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;
}

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;

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>},

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);
}

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

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)) {

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());
}

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
);
}
}

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;
}

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;

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 {

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;
}
};

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;

View File

@ -33,7 +33,9 @@ namespace util {
std::shared_ptr<T> create(Args&&... args) {
std::lock_guard lock(mutex);
if (freeObjects.empty()) {
allocateNew();
if (!allocateNew()) {
return std::make_shared<T>(std::forward<Args>(args)...);
}
}
auto ptr = freeObjects.front();
freeObjects.pop();
@ -49,7 +51,7 @@ namespace util {
std::queue<void*> freeObjects;
std::mutex mutex;
void allocateNew() {
bool allocateNew() {
std::unique_ptr<void, AlignedDeleter> ptr(
#if defined(_WIN32)
_aligned_malloc(sizeof(T), alignof(T))
@ -57,8 +59,12 @@ namespace util {
std::aligned_alloc(alignof(T), sizeof(T))
#endif
);
if (ptr == nullptr) {
return false;
}
freeObjects.push(ptr.get());
objects.push_back(std::move(ptr));
return true;
}
};
}

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;
}

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] = {};
}
}
}

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>