diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 14805655..ed214cd0 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: include: - - os: ubuntu-latest + - os: ubuntu-22.04 runs-on: ${{ matrix.os }} @@ -23,7 +23,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y build-essential libglfw3-dev libglfw3 libglew-dev \ + sudo apt-get install -y build-essential libglfw3-dev libglfw3 libglew-dev libglew2.2 \ libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev \ libcurl4-openssl-dev libgtest-dev cmake squashfs-tools valgrind # fix luajit paths diff --git a/Dockerfile b/Dockerfile index 83a4a05c..f52496de 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ -# Build docker container: docker build -t voxel-engine . -# Build project: docker run --rm -it -v$(pwd):/project voxel-engine bash -c "cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && cmake --build build" -# Run project in docker: docker run --rm -it -v$(pwd):/project -v/tmp/.X11-unix:/tmp/.X11-unix -v${XAUTHORITY}:/home/user/.Xauthority:ro -eDISPLAY --network=host voxel-engine ./build/VoxelEngine +# Build docker container: docker build -t voxelcore . +# Build project: docker run --rm -it -v$(pwd):/project voxelcore bash -c "cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE -Bbuild && cmake --build build" +# Run project in docker: docker run --rm -it -v$(pwd):/project -v/tmp/.X11-unix:/tmp/.X11-unix -v${XAUTHORITY}:/home/user/.Xauthority:ro -eDISPLAY --network=host voxelcore ./build/VoxelEngine -FROM debian:bullseye-slim -LABEL Description="Docker container for building VoxelEngine for Linux" +FROM debian:bookworm-slim +LABEL Description="Docker container for building VoxelCore for Linux" # Install dependencies RUN apt-get update && apt-get install --no-install-recommends -y \ @@ -17,6 +17,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ libglfw3-dev \ libglfw3 \ libglew-dev \ + libglew2.2 \ libglm-dev \ libpng-dev \ libopenal-dev \ diff --git a/dev/AppImageBuilder.yml b/dev/AppImageBuilder.yml index 69e687e4..f4ffe233 100644 --- a/dev/AppImageBuilder.yml +++ b/dev/AppImageBuilder.yml @@ -11,19 +11,19 @@ AppDir: apt: arch: amd64 sources: - - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse + - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy main restricted universe multiverse key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x871920D1991BC93C' - - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse - - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse - - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse + - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted universe multiverse + - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-backports main restricted universe multiverse + - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-security main restricted universe multiverse include: - libbz2-1.0 - libexpat1 - libfam0 - libgcrypt20 - libglfw3 - - libglew2.1 + - libglew2.2 - libpng16-16 - libopenal1 - libasound2 diff --git a/doc/ru/scripting/extensions.md b/doc/ru/scripting/extensions.md index ca165b0c..32798e43 100644 --- a/doc/ru/scripting/extensions.md +++ b/doc/ru/scripting/extensions.md @@ -52,6 +52,47 @@ table.shuffle(t: table) -> table Перемешивает значения в таблице. +```lua +table.merge(t1: table, t2: table) -> table +``` + +Добавляет в таблицу **t1** значения из таблицы **t2**. Если в таблице **t2** присутствует ключ из **t1**, то значение ключа не будет изменено. + +```lua +table.map(t: table, func: function(indx, value) ) -> table +``` + +Проходится по таблице и применяет ко всем её элементам **func**, которая возвращает новое значение элемента. + +```lua +table.filter(t: table, func: function(indx, value) ) -> table +``` + +Проходится по таблице с помощью **func**, которая возвращает **true** если элемент надо сохранить и **false**, если его надо удалить. + +```lua +table.set_default(t: table, key: number | string, default: any) -> any | default +``` + +Позволяет безопасно получать значение по указанному ключу. Если ключ существует в таблице, метод вернет его значение. Если ключ отсутствует, метод установит его со значением **default** и вернет его. + +```lua +table.flat(t: table) -> table +``` + +Возвращает "плоскую" версию исходной таблицы. + +```lua +table.deep_flat(t: table) -> table +``` + +Возвращает глубокую "плоскую" версию исходной таблицы. + +```lua +table.sub(arr: table, start: number | nil, stop: number | nil) -> table +``` + +Возвращает обрезанную версию таблицы с индекса **start** до индекса **stop** включительно, при этом пары ключ-значение не сохраняются в новой таблице. При значениях **nil** начинает с **1** и заканчивает **#arr** соответственно. ```lua table.tostring(t: table) -> string @@ -139,6 +180,24 @@ string.escape(str: string) -> string Экранирует строку. Является псевдонимом `utf8.escape`. +```lua +string.pad(str: string, size: number, [опционально] char: string) -> string +``` + +Добавляет **char** слева и справа от строки, пока её размер не будет равен **size**. По стандарту **char** равен символу пробела + +```lua +string.left_pad(str: string, size: number, [опционально] char: string) -> string +``` + +Добавляет **char** слева от строки, пока её размер не будет равен **size**. По стандарту **char** равен символу пробела + +```lua +string.right_pad(str: string, size: number, [опционально] char: string) -> string +``` + +Добавляет **char** справа от строки, пока её размер не будет равен **size**. По стандарту **char** равен символу пробела + ## Расширения для math ```lua @@ -165,6 +224,12 @@ math.round(num: number, [опционально] places: num) -> number Возвращает округлённое значение num до указанного количества знаков после запятой places. +```lua +math.sum(x: number, ... | t: table) -> number +``` + +Возвращает сумму всех принимаемых аргументов. Если в качестве аргумента была передана таблица, метод вернёт сумму всех её элементов. + ## Дополнительные глобальные функции В этом же скрипте также определены и другие глобальные функции которые доступны для использования. Ниже их список diff --git a/res/config/defaults.toml b/res/config/defaults.toml index 53de523f..dd2bd314 100644 --- a/res/config/defaults.toml +++ b/res/config/defaults.toml @@ -1 +1,2 @@ generator = "core:default" +player-entity = "" diff --git a/res/content/base/config/defaults.toml b/res/content/base/config/defaults.toml index d292d2ce..a099c198 100644 --- a/res/content/base/config/defaults.toml +++ b/res/content/base/config/defaults.toml @@ -1 +1,2 @@ generator = "base:demo" +player-entity = "base:player" diff --git a/res/scripts/stdmin.lua b/res/scripts/stdmin.lua index 5da1b347..5ebf0176 100644 --- a/res/scripts/stdmin.lua +++ b/res/scripts/stdmin.lua @@ -64,6 +64,23 @@ function math.round(num, places) return math.floor(num * mult + 0.5) / mult end +function math.sum(...) + local numbers = nil + local sum = 0 + + if type(...) == "table" then + numbers = ... + else + numbers = {...} + end + + for _, v in ipairs(numbers) do + sum = sum + v + end + + return sum +end + ---------------------------------------------- function table.copy(t) @@ -113,6 +130,85 @@ function table.shuffle(t) return t end +function table.merge(t1, t2) + for i, v in pairs(t2) do + if type(i) == "number" then + t1[#t1 + 1] = v + elseif t1[i] == nil then + t1[i] = v + end + end + + return t1 +end + +function table.map(t, func) + for i, v in pairs(t) do + t[i] = func(i, v) + end + + return t +end + +function table.filter(t, func) + for i, v in pairs(t) do + if not func(i, v) then + t[i] = nil + end + end + + return t +end + +function table.set_default(t, key, default) + if t[key] == nil then + t[key] = default + return default + end + + return t[key] +end + +function table.flat(t) + local flat = {} + + for _, v in pairs(t) do + if type(v) == "table" then + table.merge(flat, v) + else + table.insert(flat, v) + end + end + + return flat +end + +function table.deep_flat(t) + local flat = {} + + for _, v in pairs(t) do + if type(v) == "table" then + table.merge(flat, table.deep_flat(v)) + else + table.insert(flat, v) + end + end + + return flat +end + +function table.sub(arr, start, stop) + local res = {} + start = start or 1 + stop = stop or #arr + + for i = start, stop do + table.insert(res, arr[i]) + end + + return res +end + ---------------------------------------------- local pattern_escape_replacements = { @@ -196,6 +292,29 @@ function string.trim_left(s, char) return string.match(s, "^" .. char .. "*(.+)$") or s end +function string.pad(str, size, char) + char = char == nil and " " or char + + local padding = math.floor((size - #str) / 2) + local extra_padding = (size - #str) % 2 + + return string.rep(char, padding) .. str .. string.rep(char, padding + extra_padding) +end + +function string.left_pad(str, size, char) + char = char == nil and " " or char + + local left_padding = size - #str + return string.rep(char, left_padding) .. str +end + +function string.right_pad(str, size, char) + char = char == nil and " " or char + + local right_padding = size - #str + return str .. string.rep(char, right_padding) +end + string.lower = utf8.lower string.upper = utf8.upper string.escape = utf8.escape diff --git a/src/content/Content.cpp b/src/content/Content.cpp index 68e9cec3..1cc2fdd7 100644 --- a/src/content/Content.cpp +++ b/src/content/Content.cpp @@ -34,12 +34,14 @@ Content::Content( UptrsMap packs, UptrsMap blockMaterials, UptrsMap skeletons, - ResourceIndicesSet resourceIndices + ResourceIndicesSet resourceIndices, + dv::value defaults ) : indices(std::move(indices)), packs(std::move(packs)), blockMaterials(std::move(blockMaterials)), skeletons(std::move(skeletons)), + defaults(std::move(defaults)), blocks(std::move(blocks)), items(std::move(items)), entities(std::move(entities)), diff --git a/src/content/Content.hpp b/src/content/Content.hpp index 3a836c4e..b95ef247 100644 --- a/src/content/Content.hpp +++ b/src/content/Content.hpp @@ -201,6 +201,7 @@ class Content { UptrsMap packs; UptrsMap blockMaterials; UptrsMap skeletons; + dv::value defaults = nullptr; public: ContentUnitDefs blocks; ContentUnitDefs items; @@ -219,7 +220,8 @@ public: UptrsMap packs, UptrsMap blockMaterials, UptrsMap skeletons, - ResourceIndicesSet resourceIndices + ResourceIndicesSet resourceIndices, + dv::value defaults ); ~Content(); @@ -231,6 +233,10 @@ public: return resourceIndices[static_cast(type)]; } + inline const dv::value& getDefaults() const { + return defaults; + } + const rigging::SkeletonConfig* getSkeleton(const std::string& id) const; const BlockMaterial* findBlockMaterial(const std::string& id) const; const ContentPackRuntime* getPackRuntime(const std::string& id) const; diff --git a/src/content/ContentBuilder.cpp b/src/content/ContentBuilder.cpp index 49433dfd..c57a7ad8 100644 --- a/src/content/ContentBuilder.cpp +++ b/src/content/ContentBuilder.cpp @@ -84,7 +84,8 @@ std::unique_ptr ContentBuilder::build() { std::move(packs), std::move(blockMaterials), std::move(skeletons), - std::move(resourceIndices) + std::move(resourceIndices), + std::move(defaults) ); // Now, it's time to resolve foreign keys diff --git a/src/content/ContentBuilder.hpp b/src/content/ContentBuilder.hpp index cc35838c..7d3df1f6 100644 --- a/src/content/ContentBuilder.hpp +++ b/src/content/ContentBuilder.hpp @@ -73,6 +73,7 @@ public: ContentUnitBuilder entities {allNames, ContentType::ENTITY}; ContentUnitBuilder generators {allNames, ContentType::GENERATOR}; ResourceIndicesSet resourceIndices {}; + dv::value defaults = nullptr; ~ContentBuilder(); diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index d3df18f1..52f4ffa0 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -23,6 +23,7 @@ #include "data/dv_util.hpp" #include "data/StructLayout.hpp" #include "presets/ParticlesPreset.hpp" +#include "io/engine_paths.hpp" namespace fs = std::filesystem; using namespace data; @@ -760,6 +761,10 @@ void ContentLoader::load() { auto folder = pack->folder; + builder.defaults = paths.readCombinedObject( + EnginePaths::CONFIG_DEFAULTS.string() + ); + // Load world generators io::path generatorsDir = folder / "generators"; foreach_file(generatorsDir, [this](const io::path& file) { diff --git a/src/io/engine_paths.hpp b/src/io/engine_paths.hpp index 65e5e067..6bf62010 100644 --- a/src/io/engine_paths.hpp +++ b/src/io/engine_paths.hpp @@ -39,8 +39,7 @@ public: static std::tuple parsePath(std::string_view view); - static inline auto CONFIG_DEFAULTS = - std::filesystem::u8path("config/defaults.toml"); + static inline io::path CONFIG_DEFAULTS = "config/defaults.toml"; private: std::filesystem::path userFilesFolder {"."}; std::filesystem::path resourcesFolder {"res"}; diff --git a/src/logic/scripting/lua/libs/libgeneration.cpp b/src/logic/scripting/lua/libs/libgeneration.cpp index 855700a9..721803f3 100644 --- a/src/logic/scripting/lua/libs/libgeneration.cpp +++ b/src/logic/scripting/lua/libs/libgeneration.cpp @@ -6,6 +6,7 @@ #include "world/Level.hpp" #include "world/generator/VoxelFragment.hpp" #include "content/ContentLoader.hpp" +#include "content/Content.hpp" #include "engine/Engine.hpp" #include "../lua_custom_types.hpp" @@ -69,8 +70,9 @@ static int l_get_generators(lua::State* L) { /// @brief Get the default world generator /// @return The ID of the default world generator static int l_get_default_generator(lua::State* L) { + // content is not initialized yet auto combined = engine->getResPaths()->readCombinedObject( - EnginePaths::CONFIG_DEFAULTS.u8string() + EnginePaths::CONFIG_DEFAULTS.string() ); return lua::pushstring(L, combined["generator"].asString()); } @@ -81,4 +83,5 @@ const luaL_Reg generationlib[] = { {"load_fragment", lua::wrap}, {"get_generators", lua::wrap}, {"get_default_generator", lua::wrap}, - {NULL, NULL}}; + {NULL, NULL} +}; diff --git a/src/objects/Entities.cpp b/src/objects/Entities.cpp index 32200cf8..c3357c24 100644 --- a/src/objects/Entities.cpp +++ b/src/objects/Entities.cpp @@ -31,8 +31,8 @@ static inline std::string SAVED_DATA_VARNAME = "SAVED_DATA"; void Transform::refresh() { combined = glm::mat4(1.0f); combined = glm::translate(combined, pos); - combined = glm::scale(combined, size); combined = combined * glm::mat4(rot); + combined = glm::scale(combined, size); displayPos = pos; displaySize = size; dirty = false; diff --git a/src/objects/Player.cpp b/src/objects/Player.cpp index 9058717c..cbedd676 100644 --- a/src/objects/Player.cpp +++ b/src/objects/Player.cpp @@ -63,10 +63,14 @@ Player::~Player() = default; void Player::updateEntity() { if (eid == ENTITY_AUTO) { - auto& def = level.content.entities.require("base:player"); - eid = level.entities->spawn(def, getPosition()); - if (auto entity = level.entities->get(eid)) { - entity->setPlayer(id); + const auto& defaults = level.content.getDefaults(); + const auto& defName = defaults["player-entity"].asString(); + if (!defName.empty()) { + auto& def = level.content.entities.require(defName); + eid = level.entities->spawn(def, getPosition()); + if (auto entity = level.entities->get(eid)) { + entity->setPlayer(id); + } } } else if (auto entity = level.entities->get(eid)) { position = entity->getTransform().pos;