Merge branch 'dev' into generated-pcm-stream
This commit is contained in:
commit
4f675dde27
@ -48,6 +48,79 @@ Example:
|
|||||||
|
|
||||||
Content pack picture should be added as *icon.png* file. Recommended size: 128x128
|
Content pack picture should be added as *icon.png* file. Recommended size: 128x128
|
||||||
|
|
||||||
See *res/content/base* as an example of content pack structure.
|
# File System
|
||||||
|
|
||||||
|
Every loaded pack is mounted to the internal file system as a new mount point, whose name matches the pack's id.
|
||||||
|
|
||||||
|
This means that accessing pack files does not require the use of additional functions:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
print(file.read("your_pack_id:package.json")) -- will output the contents of the pack's package.json
|
||||||
|
```
|
||||||
|
|
||||||
|
This is also one of the reasons why some ids are reserved and cannot be used.
|
||||||
|
|
||||||
|
Mount points are mounted as read-only. To gain write access, use the `pack.request_writeable` function.
|
||||||
|
|
||||||
|
Read more about the [file](scripting/builtins/libfile.md) library.
|
||||||
|
|
||||||
|
# Content Pack Structure
|
||||||
|
|
||||||
|
Don't be intimidated by the following text, as a minimal pack only requires `package.json`.
|
||||||
|
|
||||||
|
- Content:
|
||||||
|
- `block_materials/` - Block material definitions
|
||||||
|
- `blocks/` - Block definitions
|
||||||
|
- `items/` - Item definitions
|
||||||
|
- `generators/` - World generators
|
||||||
|
- `entities/` - Entity definitions
|
||||||
|
- `skeletons/` - Entity skeleton definitions
|
||||||
|
- `presets/` - Presets (can also be used by packs for their own purposes)
|
||||||
|
- `text3d/` - 3D Text
|
||||||
|
- `weather/` - Weather
|
||||||
|
- Code:
|
||||||
|
- `modules/` - Script modules
|
||||||
|
- `scripts/` - Content scripts, world scripts
|
||||||
|
- `components/` - Entity components
|
||||||
|
- Assets (Client-side resources):
|
||||||
|
- `fonts/` - Fonts
|
||||||
|
- `models/` - 3D Models
|
||||||
|
- `textures/` - Textures
|
||||||
|
- `shaders/` - Shaders
|
||||||
|
- `effects/` - Post-processing effects
|
||||||
|
- `sounds/` - Sounds and Music
|
||||||
|
- `texts/` - Localization files
|
||||||
|
- GUI:
|
||||||
|
- `layouts/` - UI Layouts
|
||||||
|
- `pages/` - Menu page layouts (for the pagebox element)
|
||||||
|
- Configuration:
|
||||||
|
- `config/` - Configuration files
|
||||||
|
- `defaults.toml` - Overrides for standard content bindings, such as the player entity, default generator, etc.
|
||||||
|
- `bindings.toml` - Keyboard/Mouse bindings
|
||||||
|
- `user-props.toml` - User properties for content definitions
|
||||||
|
- `devtools/` - Auxiliary files for internal debugging tools
|
||||||
|
- `content.json` - Automatically generated content lists, used for validating world indices and for conversion when mismatched
|
||||||
|
- `icon.png` - Pack icon
|
||||||
|
- `package.json` - Pack definition file
|
||||||
|
- `preload.json` - Asset preload lists for assets that are not loaded automatically; avoid listing assets unnecessarily
|
||||||
|
- `resources.json` - Definition lists for [resources](resources.md) (not to be confused with assets)
|
||||||
|
- `resource-aliases.json` - Files declaring aliases for [resources](resources.md)
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Manually editing `content.json` is strongly discouraged and will most likely lead to irreversible world corruption.
|
||||||
|
|
||||||
|
# Content Sources
|
||||||
|
|
||||||
|
Content packs are searched for within **content sources**, which are paths in the engine's file system.
|
||||||
|
|
||||||
|
Source priority determines the scan order: if the same pack is found in multiple sources, the one belonging to the source with the highest priority will be selected.
|
||||||
|
|
||||||
|
Content sources in descending order of priority:
|
||||||
|
- `world:content` - Content in the world folder (`world/content/`)
|
||||||
|
- `user:content` - Content in the user folder (`$HOME/.voxeng/content/`)
|
||||||
|
- `project:content` - Content in the project folder (`project/content/`)
|
||||||
|
- `res:content` - Built-in content shipped with the engine core (`res/content/`)
|
||||||
|
|
||||||
|
I.e., if the same pack exists in both `world:content` and `user:content`, the version from `world:content` will be selected.
|
||||||
|
|
||||||
|
The pack version, however, is currently not taken into account.
|
||||||
|
|||||||
@ -20,6 +20,12 @@ hud.open(
|
|||||||
[optional] invid: int
|
[optional] invid: int
|
||||||
) -> int
|
) -> int
|
||||||
|
|
||||||
|
-- Returns true if specified layout is open.
|
||||||
|
hud.is_open(
|
||||||
|
layoutid: str
|
||||||
|
) -> bool
|
||||||
|
|
||||||
|
|
||||||
-- Open block UI and inventory.
|
-- Open block UI and inventory.
|
||||||
-- Throws an exception if block has no UI layout.
|
-- Throws an exception if block has no UI layout.
|
||||||
-- Returns block inventory ID (if *"inventory-size"=0* a virtual
|
-- Returns block inventory ID (if *"inventory-size"=0* a virtual
|
||||||
|
|||||||
@ -50,5 +50,80 @@
|
|||||||
|
|
||||||
Изображение контент-пака добавляется в виде файла *icon.png* в папку пака (не в textures). Рекомендованный размер изображения: 128x128
|
Изображение контент-пака добавляется в виде файла *icon.png* в папку пака (не в textures). Рекомендованный размер изображения: 128x128
|
||||||
|
|
||||||
Новые блоки добавляются в под-папку **blocks**, предметы в **items**, текстуры в **textures**
|
# Файловая система
|
||||||
С примером файловой структуры лучше ознакомиться через базовый пакет (*res/content/base*)
|
|
||||||
|
Каждый загруженный пак монтируется к внутренней файловой системе как новая точка входа, имя которой совпадает с id пака.
|
||||||
|
|
||||||
|
Это значит, что для доступа к файлам пака не требуется использование дополнительных функций:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
print(file.read("пак:package.json")) -- выведет содержимое package.json пака
|
||||||
|
```
|
||||||
|
|
||||||
|
Также это является одной из причин того, что некоторые id зарезервированы от использования.
|
||||||
|
|
||||||
|
Точки входа монтируются как read-only. Для получения доступа к записи существует функция pack.request_writeable.
|
||||||
|
|
||||||
|
Подробнее про библиотеку [file](scripting/builtins/libfile.md).
|
||||||
|
|
||||||
|
# Структура контент-пака
|
||||||
|
|
||||||
|
Пусть вас не пугает следующий текст, ведь минимальный пак содержит только package.json.
|
||||||
|
|
||||||
|
- Контент:
|
||||||
|
- `block_materials/` - определения материалов блоков
|
||||||
|
- `blocks/` - определения блоков
|
||||||
|
- `items/` - определения предметов
|
||||||
|
- `generators/` - генераторы мира
|
||||||
|
- `entities/` - определения сущностей
|
||||||
|
- `skeletons/` - определения скелетов сущностей
|
||||||
|
- `presets/` - пресеты (может использоваться и паками в своих целях)
|
||||||
|
- `text3d/` - 3D текст
|
||||||
|
- `weather/` - погода
|
||||||
|
- Код:
|
||||||
|
- `modules/` - скриптовые модули
|
||||||
|
- `scripts/` - скрипты контента, мира
|
||||||
|
- `components/` - компоненты сущностей
|
||||||
|
- Ассеты (ресурсы клиентской стороны):
|
||||||
|
- `fonts/` - шрифты
|
||||||
|
- `models/` - 3D модели
|
||||||
|
- `textures/` - текстуры
|
||||||
|
- `shaders/` - шейдеры
|
||||||
|
- `effects/` - эффекты пост-обработки
|
||||||
|
- `sounds/` - звуки и музыка
|
||||||
|
- `texts/` - файлы локализации
|
||||||
|
- GUI:
|
||||||
|
- `layouts/` - макеты UI
|
||||||
|
- `pages/` - макеты страниц меню (элемент pagebox)
|
||||||
|
- Конфигурация:
|
||||||
|
- `config/` - файлы конфигурации
|
||||||
|
- `defaults.toml` - переопределения стандартных привязок к контенту, такие как сущность игрока, генератор по-умолчанию и т.д.
|
||||||
|
- `bindings.toml` - привязки к клавишам / мыши
|
||||||
|
- `user-props.toml` - пользовательские свойства определений контента
|
||||||
|
- `devtools/` - вспомогательные файлы внутренних инструментов отладки
|
||||||
|
- `content.json` - генерируемые автоматически списки контента, используемое для проверки корректности индексов в мире и конвертации при несовпадении
|
||||||
|
- `icon.png` - иконка пака
|
||||||
|
- `package.json` - файл опеределения пака
|
||||||
|
- `preload.json` - списки предзагрузки ассетов, которые не загружаются автоматически, не следует указывать ассеты без надобности
|
||||||
|
- `resources.json` - списки определений [ресурсов](resources.md) (не путать с ассетами)
|
||||||
|
- `resource-aliases.json` - файлы объявления псевдонимов для [ресурсов](resources.md)
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Ручное редактирование `content.json` противопоказано и скорее всего приведёт к необратимой поломке миров.
|
||||||
|
|
||||||
|
# Источники контента
|
||||||
|
|
||||||
|
Поиск контент-паков производится среди **источников контента**, являющихся путями в файловой системе движка.
|
||||||
|
|
||||||
|
Приоритет источника определяет порядок сканирования: если один и тот же пак найден в нескольких источниках,
|
||||||
|
будет выбран тот, что принадлежит источнику с наивысшим приоритетом.
|
||||||
|
|
||||||
|
Источники контента в порядке убывания приоритета:
|
||||||
|
- `world:content` - контент папке с миром (`мир/content/`)
|
||||||
|
- `user:content` - контент в папке пользователя (`$HOME/.voxeng/content/`)
|
||||||
|
- `project:content` - контент в папке с проектом (`проект/content/`)
|
||||||
|
- `res:content` - встроенный контент, поставляемый вместе с ядром движка (`res/content/`)
|
||||||
|
|
||||||
|
Т.е. если в `world:content` и в `user:content` есть один и тот же пак, будет выбрана версия из `world:content`.
|
||||||
|
|
||||||
|
Версия пака, при этом, на данный момент, не учитывается.
|
||||||
|
|||||||
@ -20,6 +20,10 @@ hud.open(
|
|||||||
[опционально] invid: int
|
[опционально] invid: int
|
||||||
) -> int
|
) -> int
|
||||||
|
|
||||||
|
-- Возвращает true если указаный макет UI открыт.
|
||||||
|
hud.is_open(
|
||||||
|
layoutid: str
|
||||||
|
) -> bool
|
||||||
|
|
||||||
-- Открывает инвентарь и UI блока.
|
-- Открывает инвентарь и UI блока.
|
||||||
-- Если блок не имеет макета UI - бросается исключение.
|
-- Если блок не имеет макета UI - бросается исключение.
|
||||||
|
|||||||
@ -2,7 +2,14 @@ local events = {
|
|||||||
handlers = {}
|
handlers = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local __parse_path = parse_path
|
||||||
|
local __pack_is_installed = pack.is_installed
|
||||||
|
|
||||||
function events.on(event, func)
|
function events.on(event, func)
|
||||||
|
local prefix = __parse_path(event)
|
||||||
|
if prefix ~= "core" and not __pack_is_installed(prefix) then
|
||||||
|
error("pack prefix required")
|
||||||
|
end
|
||||||
if events.handlers[event] == nil then
|
if events.handlers[event] == nil then
|
||||||
events.handlers[event] = {}
|
events.handlers[event] = {}
|
||||||
end
|
end
|
||||||
|
|||||||
@ -114,7 +114,6 @@ events = require "core:internal/events"
|
|||||||
|
|
||||||
function pack.unload(prefix)
|
function pack.unload(prefix)
|
||||||
events.remove_by_prefix(prefix)
|
events.remove_by_prefix(prefix)
|
||||||
__vc__pack_envs[prefix] = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function __vc_start_app_script(path)
|
function __vc_start_app_script(path)
|
||||||
|
|||||||
@ -230,15 +230,37 @@ function require(path)
|
|||||||
return __load_script(prefix .. ":modules/" .. file .. ".lua", nil, env)
|
return __load_script(prefix .. ":modules/" .. file .. ".lua", nil, env)
|
||||||
end
|
end
|
||||||
|
|
||||||
function __scripts_cleanup()
|
-- TODO: move to string
|
||||||
|
local function join(t, sep)
|
||||||
|
local s = ""
|
||||||
|
for i, v in ipairs(t) do
|
||||||
|
s = s..tostring(v)
|
||||||
|
if i < #t then
|
||||||
|
s = s..sep
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
function __scripts_cleanup(non_reset_packs)
|
||||||
debug.log("cleaning scripts cache")
|
debug.log("cleaning scripts cache")
|
||||||
|
if #non_reset_packs == 0 then
|
||||||
|
debug.log("no non-reset packs")
|
||||||
|
else
|
||||||
|
debug.log("non-reset packs: "..join(non_reset_packs, ", "))
|
||||||
|
end
|
||||||
for k, v in pairs(__cached_scripts) do
|
for k, v in pairs(__cached_scripts) do
|
||||||
local packname, _ = parse_path(k)
|
local packname, _ = parse_path(k)
|
||||||
|
if table.has(non_reset_packs, packname) then
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
if packname ~= "core" then
|
if packname ~= "core" then
|
||||||
debug.log("unloaded "..k)
|
debug.log("unloaded "..k)
|
||||||
__cached_scripts[k] = nil
|
__cached_scripts[k] = nil
|
||||||
package.loaded[k] = nil
|
package.loaded[k] = nil
|
||||||
end
|
end
|
||||||
|
__vc__pack_envs[packname] = nil
|
||||||
|
::continue::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
#include "content/ContentPack.hpp"
|
#include "content/ContentPack.hpp"
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "graphics/core/Texture.hpp"
|
#include "graphics/core/Texture.hpp"
|
||||||
#include "logic/scripting/scripting.hpp"
|
#include "logic/scripting/scripting.hpp"
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
#include "coders/vec3.hpp"
|
#include "coders/vec3.hpp"
|
||||||
#include "constants.hpp"
|
#include "constants.hpp"
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "frontend/UiDocument.hpp"
|
#include "frontend/UiDocument.hpp"
|
||||||
#include "graphics/core/Atlas.hpp"
|
#include "graphics/core/Atlas.hpp"
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "typedefs.hpp"
|
#include "typedefs.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
#include "coders/json.hpp"
|
#include "coders/json.hpp"
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include "ContentControl.hpp"
|
#include "ContentControl.hpp"
|
||||||
|
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "Content.hpp"
|
#include "Content.hpp"
|
||||||
#include "ContentPack.hpp"
|
#include "ContentPack.hpp"
|
||||||
#include "ContentBuilder.hpp"
|
#include "ContentBuilder.hpp"
|
||||||
@ -30,6 +30,7 @@ ContentControl::ContentControl(
|
|||||||
manager->setSources({
|
manager->setSources({
|
||||||
"world:content",
|
"world:content",
|
||||||
"user:content",
|
"user:content",
|
||||||
|
"project:content",
|
||||||
"res:content",
|
"res:content",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -48,10 +49,10 @@ std::vector<std::string>& ContentControl::getBasePacks() {
|
|||||||
return basePacks;
|
return basePacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentControl::resetContent() {
|
void ContentControl::resetContent(const std::vector<std::string>& nonReset) {
|
||||||
paths.setCurrentWorldFolder("");
|
paths.setCurrentWorldFolder("");
|
||||||
|
|
||||||
scripting::cleanup();
|
scripting::cleanup(nonReset);
|
||||||
std::vector<PathsRoot> resRoots;
|
std::vector<PathsRoot> resRoots;
|
||||||
{
|
{
|
||||||
auto pack = ContentPack::createCore();
|
auto pack = ContentPack::createCore();
|
||||||
@ -78,8 +79,6 @@ void ContentControl::loadContent(const std::vector<std::string>& names) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ContentControl::loadContent() {
|
void ContentControl::loadContent() {
|
||||||
scripting::cleanup();
|
|
||||||
|
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
for (auto& pack : contentPacks) {
|
for (auto& pack : contentPacks) {
|
||||||
names.push_back(pack.id);
|
names.push_back(pack.id);
|
||||||
|
|||||||
@ -34,7 +34,7 @@ public:
|
|||||||
std::vector<std::string>& getBasePacks();
|
std::vector<std::string>& getBasePacks();
|
||||||
|
|
||||||
/// @brief Reset content to base packs list
|
/// @brief Reset content to base packs list
|
||||||
void resetContent();
|
void resetContent(const std::vector<std::string>& nonReset);
|
||||||
|
|
||||||
void loadContent(const std::vector<std::string>& names);
|
void loadContent(const std::vector<std::string>& names);
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
#include "objects/rigging.hpp"
|
#include "objects/rigging.hpp"
|
||||||
#include "util/listutil.hpp"
|
#include "util/listutil.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
|
|
||||||
static debug::Logger logger("content-loader");
|
static debug::Logger logger("content-loader");
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
#include "coders/json.hpp"
|
#include "coders/json.hpp"
|
||||||
#include "constants.hpp"
|
#include "constants.hpp"
|
||||||
#include "data/dv.hpp"
|
#include "data/dv.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "coders/commons.hpp"
|
#include "coders/commons.hpp"
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
#include "../ContentPack.hpp"
|
#include "../ContentPack.hpp"
|
||||||
|
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "logic/scripting/scripting.hpp"
|
#include "logic/scripting/scripting.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
#include "world/generator/GeneratorDef.hpp"
|
#include "world/generator/GeneratorDef.hpp"
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
#include "content/ContentBuilder.hpp"
|
#include "content/ContentBuilder.hpp"
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "window/input.hpp"
|
#include "window/input.hpp"
|
||||||
#include "voxels/Block.hpp"
|
#include "voxels/Block.hpp"
|
||||||
#include "coders/toml.hpp"
|
#include "coders/toml.hpp"
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include "Editor.hpp"
|
#include "Editor.hpp"
|
||||||
|
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "coders/syntax_parser.hpp"
|
#include "coders/syntax_parser.hpp"
|
||||||
#include "SyntaxProcessor.hpp"
|
#include "SyntaxProcessor.hpp"
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
#include "Project.hpp"
|
#include "Project.hpp"
|
||||||
|
|
||||||
#include "data/dv_util.hpp"
|
#include "data/dv_util.hpp"
|
||||||
|
#include "debug/Logger.hpp"
|
||||||
|
#include "io/io.hpp"
|
||||||
|
#include "io/path.hpp"
|
||||||
#include "logic/scripting/scripting.hpp"
|
#include "logic/scripting/scripting.hpp"
|
||||||
|
|
||||||
|
static debug::Logger logger("project");
|
||||||
|
|
||||||
Project::~Project() = default;
|
Project::~Project() = default;
|
||||||
|
|
||||||
dv::value Project::serialize() const {
|
dv::value Project::serialize() const {
|
||||||
@ -18,3 +23,23 @@ void Project::deserialize(const dv::value& src) {
|
|||||||
src.at("title").get(title);
|
src.at("title").get(title);
|
||||||
dv::get(src, "base_packs", basePacks);
|
dv::get(src, "base_packs", basePacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Project::loadProjectClientScript() {
|
||||||
|
io::path scriptFile = "project:project_client.lua";
|
||||||
|
if (io::exists(scriptFile)) {
|
||||||
|
logger.info() << "starting project client script";
|
||||||
|
clientScript = scripting::load_client_project_script(scriptFile);
|
||||||
|
} else {
|
||||||
|
logger.warning() << "project client script does not exists";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Project::loadProjectStartScript() {
|
||||||
|
io::path scriptFile = "project:start.lua";
|
||||||
|
if (io::exists(scriptFile)) {
|
||||||
|
logger.info() << "starting project start script";
|
||||||
|
setupCoroutine = scripting::start_app_script(scriptFile);
|
||||||
|
} else {
|
||||||
|
logger.warning() << "project start script does not exists";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "interfaces/Process.hpp"
|
||||||
#include "interfaces/Serializable.hpp"
|
#include "interfaces/Serializable.hpp"
|
||||||
|
|
||||||
namespace scripting {
|
namespace scripting {
|
||||||
@ -15,9 +16,13 @@ struct Project : Serializable {
|
|||||||
std::string title;
|
std::string title;
|
||||||
std::vector<std::string> basePacks;
|
std::vector<std::string> basePacks;
|
||||||
std::unique_ptr<scripting::IClientProjectScript> clientScript;
|
std::unique_ptr<scripting::IClientProjectScript> clientScript;
|
||||||
|
std::unique_ptr<Process> setupCoroutine;
|
||||||
|
|
||||||
~Project();
|
~Project();
|
||||||
|
|
||||||
dv::value serialize() const override;
|
dv::value serialize() const override;
|
||||||
void deserialize(const dv::value& src) override;
|
void deserialize(const dv::value& src) override;
|
||||||
|
|
||||||
|
void loadProjectClientScript();
|
||||||
|
void loadProjectStartScript();
|
||||||
};
|
};
|
||||||
|
|||||||
15
src/engine/CoreParameters.hpp
Normal file
15
src/engine/CoreParameters.hpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
struct CoreParameters {
|
||||||
|
bool headless = false;
|
||||||
|
bool testMode = false;
|
||||||
|
std::filesystem::path resFolder = "res";
|
||||||
|
std::filesystem::path userFolder = ".";
|
||||||
|
std::filesystem::path scriptFile;
|
||||||
|
std::filesystem::path projectFolder;
|
||||||
|
std::string debugServerString;
|
||||||
|
int tps = 20;
|
||||||
|
};
|
||||||
@ -8,8 +8,6 @@
|
|||||||
#include "assets/AssetsLoader.hpp"
|
#include "assets/AssetsLoader.hpp"
|
||||||
#include "audio/audio.hpp"
|
#include "audio/audio.hpp"
|
||||||
#include "coders/GLSLExtension.hpp"
|
#include "coders/GLSLExtension.hpp"
|
||||||
#include "coders/imageio.hpp"
|
|
||||||
#include "coders/json.hpp"
|
|
||||||
#include "coders/toml.hpp"
|
#include "coders/toml.hpp"
|
||||||
#include "coders/commons.hpp"
|
#include "coders/commons.hpp"
|
||||||
#include "devtools/Editor.hpp"
|
#include "devtools/Editor.hpp"
|
||||||
@ -18,28 +16,28 @@
|
|||||||
#include "content/ContentControl.hpp"
|
#include "content/ContentControl.hpp"
|
||||||
#include "core_defs.hpp"
|
#include "core_defs.hpp"
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
|
#include "io/settings_io.hpp"
|
||||||
#include "frontend/locale.hpp"
|
#include "frontend/locale.hpp"
|
||||||
#include "frontend/menu.hpp"
|
#include "frontend/menu.hpp"
|
||||||
#include "frontend/screens/Screen.hpp"
|
#include "frontend/screens/Screen.hpp"
|
||||||
#include "graphics/render/ModelsGenerator.hpp"
|
#include "graphics/render/ModelsGenerator.hpp"
|
||||||
#include "graphics/core/DrawContext.hpp"
|
#include "graphics/core/DrawContext.hpp"
|
||||||
#include "graphics/core/ImageData.hpp"
|
|
||||||
#include "graphics/core/Shader.hpp"
|
#include "graphics/core/Shader.hpp"
|
||||||
#include "graphics/ui/GUI.hpp"
|
#include "graphics/ui/GUI.hpp"
|
||||||
#include "graphics/ui/elements/Menu.hpp"
|
#include "graphics/ui/elements/Menu.hpp"
|
||||||
#include "objects/rigging.hpp"
|
|
||||||
#include "logic/EngineController.hpp"
|
#include "logic/EngineController.hpp"
|
||||||
#include "logic/CommandsInterpreter.hpp"
|
#include "logic/CommandsInterpreter.hpp"
|
||||||
#include "logic/scripting/scripting.hpp"
|
#include "logic/scripting/scripting.hpp"
|
||||||
#include "logic/scripting/scripting_hud.hpp"
|
#include "logic/scripting/scripting_hud.hpp"
|
||||||
#include "network/Network.hpp"
|
#include "network/Network.hpp"
|
||||||
#include "util/platform.hpp"
|
#include "util/platform.hpp"
|
||||||
#include "window/Camera.hpp"
|
|
||||||
#include "window/input.hpp"
|
#include "window/input.hpp"
|
||||||
#include "window/Window.hpp"
|
#include "window/Window.hpp"
|
||||||
#include "world/Level.hpp"
|
#include "world/Level.hpp"
|
||||||
#include "Mainloop.hpp"
|
#include "Mainloop.hpp"
|
||||||
#include "ServerMainloop.hpp"
|
#include "ServerMainloop.hpp"
|
||||||
|
#include "WindowControl.hpp"
|
||||||
|
#include "EnginePaths.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -50,29 +48,6 @@
|
|||||||
|
|
||||||
static debug::Logger logger("engine");
|
static debug::Logger logger("engine");
|
||||||
|
|
||||||
static std::unique_ptr<ImageData> load_icon() {
|
|
||||||
try {
|
|
||||||
auto file = "res:textures/misc/icon.png";
|
|
||||||
if (io::exists(file)) {
|
|
||||||
return imageio::read(file);
|
|
||||||
}
|
|
||||||
} catch (const std::exception& err) {
|
|
||||||
logger.error() << "could not load window icon: " << err.what();
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::unique_ptr<scripting::IClientProjectScript> load_client_project_script() {
|
|
||||||
io::path scriptFile = "project:project_client.lua";
|
|
||||||
if (io::exists(scriptFile)) {
|
|
||||||
logger.info() << "starting project script";
|
|
||||||
return scripting::load_client_project_script(scriptFile);
|
|
||||||
} else {
|
|
||||||
logger.warning() << "project script does not exists";
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Engine::Engine() = default;
|
Engine::Engine() = default;
|
||||||
Engine::~Engine() = default;
|
Engine::~Engine() = default;
|
||||||
|
|
||||||
@ -87,7 +62,7 @@ Engine& Engine::getInstance() {
|
|||||||
|
|
||||||
void Engine::onContentLoad() {
|
void Engine::onContentLoad() {
|
||||||
editor->loadTools();
|
editor->loadTools();
|
||||||
langs::setup(langs::get_current(), paths.resPaths.collectRoots());
|
langs::setup(langs::get_current(), paths->resPaths.collectRoots());
|
||||||
|
|
||||||
if (isHeadless()) {
|
if (isHeadless()) {
|
||||||
return;
|
return;
|
||||||
@ -108,29 +83,9 @@ void Engine::onContentLoad() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Engine::initializeClient() {
|
void Engine::initializeClient() {
|
||||||
std::string title = project->title;
|
windowControl = std::make_unique<WindowControl>(*this);
|
||||||
if (title.empty()) {
|
auto [window, input] = windowControl->initialize();
|
||||||
title = "VoxelCore v" +
|
|
||||||
std::to_string(ENGINE_VERSION_MAJOR) + "." +
|
|
||||||
std::to_string(ENGINE_VERSION_MINOR);
|
|
||||||
}
|
|
||||||
if (ENGINE_DEBUG_BUILD) {
|
|
||||||
title += " [debug]";
|
|
||||||
}
|
|
||||||
if (debuggingServer) {
|
|
||||||
title = "[debugging] " + title;
|
|
||||||
}
|
|
||||||
auto [window, input] = Window::initialize(&settings.display, title);
|
|
||||||
if (!window || !input){
|
|
||||||
throw initialize_error("could not initialize window");
|
|
||||||
}
|
|
||||||
window->setFramerate(settings.display.framerate.get());
|
|
||||||
|
|
||||||
time.set(window->time());
|
|
||||||
if (auto icon = load_icon()) {
|
|
||||||
icon->flipY();
|
|
||||||
window->setIcon(icon.get());
|
|
||||||
}
|
|
||||||
this->window = std::move(window);
|
this->window = std::move(window);
|
||||||
this->input = std::move(input);
|
this->input = std::move(input);
|
||||||
|
|
||||||
@ -171,15 +126,12 @@ void Engine::initialize(CoreParameters coreParameters) {
|
|||||||
|
|
||||||
logger.info() << "engine version: " << ENGINE_VERSION_STRING;
|
logger.info() << "engine version: " << ENGINE_VERSION_STRING;
|
||||||
if (params.headless) {
|
if (params.headless) {
|
||||||
logger.info() << "headless mode is enabled";
|
logger.info() << "engine runs in headless mode";
|
||||||
}
|
}
|
||||||
if (params.projectFolder.empty()) {
|
if (params.projectFolder.empty()) {
|
||||||
params.projectFolder = params.resFolder;
|
params.projectFolder = params.resFolder;
|
||||||
}
|
}
|
||||||
paths.setResourcesFolder(params.resFolder);
|
paths = std::make_unique<EnginePaths>(params);
|
||||||
paths.setUserFilesFolder(params.userFolder);
|
|
||||||
paths.setProjectFolder(params.projectFolder);
|
|
||||||
paths.prepare();
|
|
||||||
loadProject();
|
loadProject();
|
||||||
|
|
||||||
editor = std::make_unique<devtools::Editor>(*this);
|
editor = std::make_unique<devtools::Editor>(*this);
|
||||||
@ -197,10 +149,6 @@ void Engine::initialize(CoreParameters coreParameters) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!params.scriptFile.empty()) {
|
|
||||||
paths.setScriptFolder(params.scriptFile.parent_path());
|
|
||||||
}
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
controller = std::make_unique<EngineController>(*this);
|
controller = std::make_unique<EngineController>(*this);
|
||||||
@ -214,7 +162,7 @@ void Engine::initialize(CoreParameters coreParameters) {
|
|||||||
langs::locale_by_envlocale(platform::detect_locale())
|
langs::locale_by_envlocale(platform::detect_locale())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
content = std::make_unique<ContentControl>(*project, paths, *input, [this]() {
|
content = std::make_unique<ContentControl>(*project, *paths, *input, [this]() {
|
||||||
onContentLoad();
|
onContentLoad();
|
||||||
});
|
});
|
||||||
scripting::initialize(this);
|
scripting::initialize(this);
|
||||||
@ -223,10 +171,13 @@ void Engine::initialize(CoreParameters coreParameters) {
|
|||||||
gui->setPageLoader(scripting::create_page_loader());
|
gui->setPageLoader(scripting::create_page_loader());
|
||||||
}
|
}
|
||||||
keepAlive(settings.ui.language.observe([this](auto lang) {
|
keepAlive(settings.ui.language.observe([this](auto lang) {
|
||||||
langs::setup(lang, paths.resPaths.collectRoots());
|
langs::setup(lang, paths->resPaths.collectRoots());
|
||||||
}, true));
|
}, true));
|
||||||
|
|
||||||
project->clientScript = load_client_project_script();
|
project->loadProjectStartScript();
|
||||||
|
if (!params.headless) {
|
||||||
|
project->loadProjectClientScript();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::loadSettings() {
|
void Engine::loadSettings() {
|
||||||
@ -256,29 +207,17 @@ void Engine::loadControls() {
|
|||||||
|
|
||||||
void Engine::updateHotkeys() {
|
void Engine::updateHotkeys() {
|
||||||
if (input->jpressed(Keycode::F2)) {
|
if (input->jpressed(Keycode::F2)) {
|
||||||
saveScreenshot();
|
windowControl->saveScreenshot();
|
||||||
}
|
}
|
||||||
if (input->pressed(Keycode::LEFT_CONTROL) && input->pressed(Keycode::F3) &&
|
if (input->pressed(Keycode::LEFT_CONTROL) && input->pressed(Keycode::F3) &&
|
||||||
input->jpressed(Keycode::U)) {
|
input->jpressed(Keycode::U)) {
|
||||||
gui->toggleDebug();
|
gui->toggleDebug();
|
||||||
}
|
}
|
||||||
if (input->jpressed(Keycode::F11)) {
|
if (input->jpressed(Keycode::F11)) {
|
||||||
if (settings.display.windowMode.get() != static_cast<int>(WindowMode::FULLSCREEN)) {
|
windowControl->toggleFullscreen();
|
||||||
settings.display.windowMode.set(static_cast<int>(WindowMode::FULLSCREEN));
|
|
||||||
} else {
|
|
||||||
settings.display.windowMode.set(static_cast<int>(WindowMode::WINDOWED));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::saveScreenshot() {
|
|
||||||
auto image = window->takeScreenshot();
|
|
||||||
image->flipY();
|
|
||||||
io::path filename = paths.getNewScreenshotFile("png");
|
|
||||||
imageio::write(filename.string(), image.get());
|
|
||||||
logger.info() << "saved screenshot as " << filename.string();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::run() {
|
void Engine::run() {
|
||||||
if (params.headless) {
|
if (params.headless) {
|
||||||
ServerMainloop(*this).run();
|
ServerMainloop(*this).run();
|
||||||
@ -301,6 +240,12 @@ void Engine::detachDebugger() {
|
|||||||
debuggingServer.reset();
|
debuggingServer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Engine::applicationTick() {
|
||||||
|
if (project->setupCoroutine && project->setupCoroutine->isActive()) {
|
||||||
|
project->setupCoroutine->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Engine::updateFrontend() {
|
void Engine::updateFrontend() {
|
||||||
double delta = time.getDelta();
|
double delta = time.getDelta();
|
||||||
updateHotkeys();
|
updateHotkeys();
|
||||||
@ -310,14 +255,8 @@ void Engine::updateFrontend() {
|
|||||||
gui->postAct();
|
gui->postAct();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::nextFrame() {
|
void Engine::nextFrame(bool waitForRefresh) {
|
||||||
window->setFramerate(
|
windowControl->nextFrame(waitForRefresh);
|
||||||
window->isIconified() && settings.display.limitFpsIconified.get()
|
|
||||||
? 20
|
|
||||||
: settings.display.framerate.get()
|
|
||||||
);
|
|
||||||
window->swapBuffers();
|
|
||||||
input->pollEvents();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::startPauseLoop() {
|
void Engine::startPauseLoop() {
|
||||||
@ -336,7 +275,7 @@ void Engine::startPauseLoop() {
|
|||||||
if (isHeadless()) {
|
if (isHeadless()) {
|
||||||
platform::sleep(1.0 / params.tps * 1000);
|
platform::sleep(1.0 / params.tps * 1000);
|
||||||
} else {
|
} else {
|
||||||
nextFrame();
|
nextFrame(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (initialCursorLocked) {
|
if (initialCursorLocked) {
|
||||||
@ -407,17 +346,18 @@ void Engine::setLevelConsumer(OnWorldOpen levelConsumer) {
|
|||||||
|
|
||||||
void Engine::loadAssets() {
|
void Engine::loadAssets() {
|
||||||
logger.info() << "loading assets";
|
logger.info() << "loading assets";
|
||||||
Shader::preprocessor->setPaths(&paths.resPaths);
|
Shader::preprocessor->setPaths(&paths->resPaths);
|
||||||
|
|
||||||
auto content = this->content->get();
|
auto content = this->content->get();
|
||||||
|
|
||||||
auto new_assets = std::make_unique<Assets>();
|
auto new_assets = std::make_unique<Assets>();
|
||||||
AssetsLoader loader(*this, *new_assets, paths.resPaths);
|
AssetsLoader loader(*this, *new_assets, paths->resPaths);
|
||||||
AssetsLoader::addDefaults(loader, content);
|
AssetsLoader::addDefaults(loader, content);
|
||||||
|
|
||||||
// no need
|
// no need
|
||||||
// correct log messages order is more useful
|
// correct log messages order is more useful
|
||||||
bool threading = false; // look at two upper lines
|
// todo: before setting to true, check if GLSLExtension thread safe
|
||||||
|
bool threading = false; // look at three upper lines
|
||||||
if (threading) {
|
if (threading) {
|
||||||
auto task = loader.startTask([=](){});
|
auto task = loader.startTask([=](){});
|
||||||
task->waitForEnd();
|
task->waitForEnd();
|
||||||
@ -454,6 +394,7 @@ void Engine::setScreen(std::shared_ptr<Screen> screen) {
|
|||||||
}
|
}
|
||||||
if (project->clientScript && this->screen) {
|
if (project->clientScript && this->screen) {
|
||||||
project->clientScript->onScreenChange(this->screen->getName(), true);
|
project->clientScript->onScreenChange(this->screen->getName(), true);
|
||||||
|
window->setShouldRefresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,11 +428,11 @@ Assets* Engine::getAssets() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EnginePaths& Engine::getPaths() {
|
EnginePaths& Engine::getPaths() {
|
||||||
return paths;
|
return *paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResPaths& Engine::getResPaths() {
|
ResPaths& Engine::getResPaths() {
|
||||||
return paths.resPaths;
|
return paths->resPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Screen> Engine::getScreen() {
|
std::shared_ptr<Screen> Engine::getScreen() {
|
||||||
|
|||||||
@ -1,25 +1,27 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "delegates.hpp"
|
#include "CoreParameters.hpp"
|
||||||
#include "typedefs.hpp"
|
|
||||||
#include "settings.hpp"
|
|
||||||
|
|
||||||
#include "io/engine_paths.hpp"
|
|
||||||
#include "io/settings_io.hpp"
|
|
||||||
#include "util/ObjectsKeeper.hpp"
|
|
||||||
#include "PostRunnables.hpp"
|
#include "PostRunnables.hpp"
|
||||||
#include "Time.hpp"
|
#include "Time.hpp"
|
||||||
|
#include "delegates.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
#include "typedefs.hpp"
|
||||||
|
#include "util/ObjectsKeeper.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class Window;
|
|
||||||
class Assets;
|
class Assets;
|
||||||
class Level;
|
|
||||||
class Screen;
|
|
||||||
class ContentControl;
|
class ContentControl;
|
||||||
class EngineController;
|
class EngineController;
|
||||||
|
class EnginePaths;
|
||||||
class Input;
|
class Input;
|
||||||
|
class Level;
|
||||||
|
class ResPaths;
|
||||||
|
class Screen;
|
||||||
|
class SettingsHandler;
|
||||||
|
class Window;
|
||||||
|
class WindowControl;
|
||||||
struct Project;
|
struct Project;
|
||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
@ -44,24 +46,12 @@ public:
|
|||||||
initialize_error(const std::string& message) : std::runtime_error(message) {}
|
initialize_error(const std::string& message) : std::runtime_error(message) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CoreParameters {
|
|
||||||
bool headless = false;
|
|
||||||
bool testMode = false;
|
|
||||||
std::filesystem::path resFolder = "res";
|
|
||||||
std::filesystem::path userFolder = ".";
|
|
||||||
std::filesystem::path scriptFile;
|
|
||||||
std::filesystem::path projectFolder;
|
|
||||||
std::string debugServerString;
|
|
||||||
int tps = 20;
|
|
||||||
};
|
|
||||||
|
|
||||||
using OnWorldOpen = std::function<void(std::unique_ptr<Level>, int64_t)>;
|
using OnWorldOpen = std::function<void(std::unique_ptr<Level>, int64_t)>;
|
||||||
|
|
||||||
class Engine : public util::ObjectsKeeper {
|
class Engine : public util::ObjectsKeeper {
|
||||||
CoreParameters params;
|
CoreParameters params;
|
||||||
EngineSettings settings;
|
EngineSettings settings;
|
||||||
EnginePaths paths;
|
std::unique_ptr<EnginePaths> paths;
|
||||||
|
|
||||||
std::unique_ptr<Project> project;
|
std::unique_ptr<Project> project;
|
||||||
std::unique_ptr<SettingsHandler> settingsHandler;
|
std::unique_ptr<SettingsHandler> settingsHandler;
|
||||||
std::unique_ptr<Assets> assets;
|
std::unique_ptr<Assets> assets;
|
||||||
@ -75,6 +65,7 @@ class Engine : public util::ObjectsKeeper {
|
|||||||
std::unique_ptr<gui::GUI> gui;
|
std::unique_ptr<gui::GUI> gui;
|
||||||
std::unique_ptr<devtools::Editor> editor;
|
std::unique_ptr<devtools::Editor> editor;
|
||||||
std::unique_ptr<devtools::DebuggingServer> debuggingServer;
|
std::unique_ptr<devtools::DebuggingServer> debuggingServer;
|
||||||
|
std::unique_ptr<WindowControl> windowControl;
|
||||||
PostRunnables postRunnables;
|
PostRunnables postRunnables;
|
||||||
Time time;
|
Time time;
|
||||||
OnWorldOpen levelConsumer;
|
OnWorldOpen levelConsumer;
|
||||||
@ -105,9 +96,10 @@ public:
|
|||||||
|
|
||||||
void postUpdate();
|
void postUpdate();
|
||||||
|
|
||||||
|
void applicationTick();
|
||||||
void updateFrontend();
|
void updateFrontend();
|
||||||
void renderFrame();
|
void renderFrame();
|
||||||
void nextFrame();
|
void nextFrame(bool waitForRefresh);
|
||||||
void startPauseLoop();
|
void startPauseLoop();
|
||||||
|
|
||||||
/// @brief Set screen (scene).
|
/// @brief Set screen (scene).
|
||||||
@ -143,8 +135,6 @@ public:
|
|||||||
postRunnables.postRunnable(callback);
|
postRunnables.postRunnable(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveScreenshot();
|
|
||||||
|
|
||||||
EngineController* getController();
|
EngineController* getController();
|
||||||
|
|
||||||
void setLevelConsumer(OnWorldOpen levelConsumer);
|
void setLevelConsumer(OnWorldOpen levelConsumer);
|
||||||
|
|||||||
@ -1,44 +1,56 @@
|
|||||||
#include "engine_paths.hpp"
|
#include "EnginePaths.hpp"
|
||||||
|
|
||||||
|
#include "debug/Logger.hpp"
|
||||||
|
#include "io/devices/StdfsDevice.hpp"
|
||||||
|
#include "io/devices/ZipFileDevice.hpp"
|
||||||
|
#include "maths/util.hpp"
|
||||||
|
#include "typedefs.hpp"
|
||||||
|
#include "util/platform.hpp"
|
||||||
|
#include "util/random.hpp"
|
||||||
|
#include "util/stringutil.hpp"
|
||||||
|
#include "world/files/WorldFiles.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <chrono>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include "typedefs.hpp"
|
#include <stdexcept>
|
||||||
#include "util/stringutil.hpp"
|
|
||||||
#include "util/platform.hpp"
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "io/devices/StdfsDevice.hpp"
|
|
||||||
#include "io/devices/ZipFileDevice.hpp"
|
|
||||||
#include "world/files/WorldFiles.hpp"
|
|
||||||
#include "debug/Logger.hpp"
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include "maths/util.hpp"
|
|
||||||
|
|
||||||
template<int n>
|
|
||||||
static std::string generate_random_base64() {
|
|
||||||
auto now = std::chrono::high_resolution_clock::now();
|
|
||||||
auto seed = now.time_since_epoch().count();
|
|
||||||
|
|
||||||
util::PseudoRandom random(seed); // fixme: replace with safe random
|
|
||||||
ubyte bytes[n];
|
|
||||||
random.rand(bytes, n);
|
|
||||||
return util::base64_urlsafe_encode(bytes, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
static debug::Logger logger("engine-paths");
|
static std::random_device random_device;
|
||||||
|
|
||||||
static inline io::path SCREENSHOTS_FOLDER = "user:screenshots";
|
static inline io::path SCREENSHOTS_FOLDER = "user:screenshots";
|
||||||
static inline io::path CONTENT_FOLDER = "user:content";
|
static inline io::path CONTENT_FOLDER = "user:content";
|
||||||
static inline io::path WORLDS_FOLDER = "user:worlds";
|
static inline io::path WORLDS_FOLDER = "user:worlds";
|
||||||
|
|
||||||
void EnginePaths::prepare() {
|
static debug::Logger logger("engine-paths");
|
||||||
|
|
||||||
|
template<int n>
|
||||||
|
static std::string generate_random_base64() {
|
||||||
|
auto randomEngine = util::seeded_random_engine(random_device);
|
||||||
|
static std::uniform_int_distribution<integer_t> dist(0, 0xFF);
|
||||||
|
ubyte bytes[n];
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
bytes[i] = dist(randomEngine);
|
||||||
|
}
|
||||||
|
return util::base64_urlsafe_encode(bytes, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnginePaths::EnginePaths(CoreParameters& params)
|
||||||
|
: resourcesFolder(params.resFolder),
|
||||||
|
userFilesFolder(params.userFolder),
|
||||||
|
projectFolder(params.projectFolder) {
|
||||||
|
if (!params.scriptFile.empty()) {
|
||||||
|
scriptFolder = params.scriptFile.parent_path();
|
||||||
|
io::set_device("script", std::make_shared<io::StdfsDevice>(*scriptFolder));
|
||||||
|
}
|
||||||
|
|
||||||
io::set_device("res", std::make_shared<io::StdfsDevice>(resourcesFolder, false));
|
io::set_device("res", std::make_shared<io::StdfsDevice>(resourcesFolder, false));
|
||||||
io::set_device("user", std::make_shared<io::StdfsDevice>(userFilesFolder));
|
io::set_device("user", std::make_shared<io::StdfsDevice>(userFilesFolder));
|
||||||
|
io::set_device("project", std::make_shared<io::StdfsDevice>(projectFolder));
|
||||||
|
|
||||||
if (!io::is_directory("res:")) {
|
if (!io::is_directory("res:")) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
@ -59,15 +71,7 @@ void EnginePaths::prepare() {
|
|||||||
io::create_subdevice("config", "user", "config");
|
io::create_subdevice("config", "user", "config");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::filesystem::path& EnginePaths::getUserFilesFolder() const {
|
io::path EnginePaths::getNewScreenshotFile(const std::string& ext) const {
|
||||||
return userFilesFolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::filesystem::path& EnginePaths::getResourcesFolder() const {
|
|
||||||
return resourcesFolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
io::path EnginePaths::getNewScreenshotFile(const std::string& ext) {
|
|
||||||
auto folder = SCREENSHOTS_FOLDER;
|
auto folder = SCREENSHOTS_FOLDER;
|
||||||
if (!io::is_directory(folder)) {
|
if (!io::is_directory(folder)) {
|
||||||
io::create_directories(folder);
|
io::create_directories(folder);
|
||||||
@ -95,10 +99,6 @@ io::path EnginePaths::getWorldsFolder() const {
|
|||||||
return WORLDS_FOLDER;
|
return WORLDS_FOLDER;
|
||||||
}
|
}
|
||||||
|
|
||||||
io::path EnginePaths::getCurrentWorldFolder() {
|
|
||||||
return currentWorldFolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
io::path EnginePaths::getWorldFolderByName(const std::string& name) {
|
io::path EnginePaths::getWorldFolderByName(const std::string& name) {
|
||||||
return getWorldsFolder() / name;
|
return getWorldsFolder() / name;
|
||||||
}
|
}
|
||||||
@ -132,24 +132,6 @@ std::vector<io::path> EnginePaths::scanForWorlds() const {
|
|||||||
return folders;
|
return folders;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnginePaths::setUserFilesFolder(std::filesystem::path folder) {
|
|
||||||
this->userFilesFolder = std::move(folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnginePaths::setResourcesFolder(std::filesystem::path folder) {
|
|
||||||
this->resourcesFolder = std::move(folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnginePaths::setScriptFolder(std::filesystem::path folder) {
|
|
||||||
io::set_device("script", std::make_shared<io::StdfsDevice>(folder));
|
|
||||||
this->scriptFolder = std::move(folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnginePaths::setProjectFolder(std::filesystem::path folder) {
|
|
||||||
io::set_device("project", std::make_shared<io::StdfsDevice>(folder));
|
|
||||||
this->projectFolder = std::move(folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnginePaths::setCurrentWorldFolder(io::path folder) {
|
void EnginePaths::setCurrentWorldFolder(io::path folder) {
|
||||||
if (folder.empty()) {
|
if (folder.empty()) {
|
||||||
io::remove_device("world");
|
io::remove_device("world");
|
||||||
@ -1,15 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "io/io.hpp"
|
||||||
|
#include "data/dv.hpp"
|
||||||
|
#include "CoreParameters.hpp"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <stdexcept>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
#include "io.hpp"
|
|
||||||
#include "data/dv.hpp"
|
|
||||||
|
|
||||||
struct PathsRoot {
|
struct PathsRoot {
|
||||||
std::string name;
|
std::string name;
|
||||||
io::path path;
|
io::path path;
|
||||||
@ -46,24 +46,13 @@ class EnginePaths {
|
|||||||
public:
|
public:
|
||||||
ResPaths resPaths;
|
ResPaths resPaths;
|
||||||
|
|
||||||
void prepare();
|
EnginePaths(CoreParameters& params);
|
||||||
|
|
||||||
void setUserFilesFolder(std::filesystem::path folder);
|
|
||||||
const std::filesystem::path& getUserFilesFolder() const;
|
|
||||||
|
|
||||||
void setResourcesFolder(std::filesystem::path folder);
|
|
||||||
const std::filesystem::path& getResourcesFolder() const;
|
|
||||||
|
|
||||||
void setScriptFolder(std::filesystem::path folder);
|
|
||||||
|
|
||||||
void setProjectFolder(std::filesystem::path folder);
|
|
||||||
|
|
||||||
io::path getWorldFolderByName(const std::string& name);
|
io::path getWorldFolderByName(const std::string& name);
|
||||||
io::path getWorldsFolder() const;
|
io::path getWorldsFolder() const;
|
||||||
|
|
||||||
void setCurrentWorldFolder(io::path folder);
|
void setCurrentWorldFolder(io::path folder);
|
||||||
io::path getCurrentWorldFolder();
|
io::path getNewScreenshotFile(const std::string& ext) const;
|
||||||
io::path getNewScreenshotFile(const std::string& ext);
|
|
||||||
|
|
||||||
std::string mount(const io::path& file);
|
std::string mount(const io::path& file);
|
||||||
void unmount(const std::string& name);
|
void unmount(const std::string& name);
|
||||||
@ -80,9 +69,9 @@ public:
|
|||||||
static inline io::path CONTROLS_FILE = "user:controls.toml";
|
static inline io::path CONTROLS_FILE = "user:controls.toml";
|
||||||
static inline io::path SETTINGS_FILE = "user:settings.toml";
|
static inline io::path SETTINGS_FILE = "user:settings.toml";
|
||||||
private:
|
private:
|
||||||
std::filesystem::path userFilesFolder {"."};
|
std::filesystem::path resourcesFolder;
|
||||||
std::filesystem::path resourcesFolder {"res"};
|
std::filesystem::path userFilesFolder;
|
||||||
std::filesystem::path projectFolder = resourcesFolder;
|
std::filesystem::path projectFolder;
|
||||||
io::path currentWorldFolder;
|
io::path currentWorldFolder;
|
||||||
std::optional<std::filesystem::path> scriptFolder;
|
std::optional<std::filesystem::path> scriptFolder;
|
||||||
std::vector<PathsRoot> entryPoints;
|
std::vector<PathsRoot> entryPoints;
|
||||||
@ -18,6 +18,7 @@ Mainloop::Mainloop(Engine& engine) : engine(engine) {
|
|||||||
void Mainloop::run() {
|
void Mainloop::run() {
|
||||||
auto& time = engine.getTime();
|
auto& time = engine.getTime();
|
||||||
auto& window = engine.getWindow();
|
auto& window = engine.getWindow();
|
||||||
|
auto& settings = engine.getSettings();
|
||||||
|
|
||||||
engine.setLevelConsumer([this](auto level, int64_t localPlayer) {
|
engine.setLevelConsumer([this](auto level, int64_t localPlayer) {
|
||||||
if (level == nullptr) {
|
if (level == nullptr) {
|
||||||
@ -38,13 +39,17 @@ void Mainloop::run() {
|
|||||||
logger.info() << "main loop started";
|
logger.info() << "main loop started";
|
||||||
while (!window.isShouldClose()){
|
while (!window.isShouldClose()){
|
||||||
time.update(window.time());
|
time.update(window.time());
|
||||||
|
engine.applicationTick();
|
||||||
engine.updateFrontend();
|
engine.updateFrontend();
|
||||||
|
|
||||||
if (!window.isIconified()) {
|
if (!window.isIconified()) {
|
||||||
engine.renderFrame();
|
engine.renderFrame();
|
||||||
}
|
}
|
||||||
engine.postUpdate();
|
engine.postUpdate();
|
||||||
engine.nextFrame();
|
engine.nextFrame(
|
||||||
|
settings.display.adaptiveFpsInMenu.get() &&
|
||||||
|
dynamic_cast<const MenuScreen*>(engine.getScreen().get()) != nullptr
|
||||||
|
);
|
||||||
}
|
}
|
||||||
logger.info() << "main loop stopped";
|
logger.info() << "main loop stopped";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#include "ServerMainloop.hpp"
|
#include "ServerMainloop.hpp"
|
||||||
|
|
||||||
#include "Engine.hpp"
|
#include "Engine.hpp"
|
||||||
|
#include "EnginePaths.hpp"
|
||||||
#include "logic/scripting/scripting.hpp"
|
#include "logic/scripting/scripting.hpp"
|
||||||
#include "logic/LevelController.hpp"
|
#include "logic/LevelController.hpp"
|
||||||
#include "interfaces/Process.hpp"
|
#include "interfaces/Process.hpp"
|
||||||
@ -60,6 +61,7 @@ void ServerMainloop::run() {
|
|||||||
controller->getLevel()->getWorld()->updateTimers(delta);
|
controller->getLevel()->getWorld()->updateTimers(delta);
|
||||||
controller->update(glm::min(delta, 0.2), false);
|
controller->update(glm::min(delta, 0.2), false);
|
||||||
}
|
}
|
||||||
|
engine.applicationTick();
|
||||||
engine.postUpdate();
|
engine.postUpdate();
|
||||||
|
|
||||||
if (!coreParams.testMode) {
|
if (!coreParams.testMode) {
|
||||||
|
|||||||
93
src/engine/WindowControl.cpp
Normal file
93
src/engine/WindowControl.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include "WindowControl.hpp"
|
||||||
|
|
||||||
|
#include "Engine.hpp"
|
||||||
|
#include "engine/EnginePaths.hpp"
|
||||||
|
#include "devtools/Project.hpp"
|
||||||
|
#include "coders/imageio.hpp"
|
||||||
|
#include "window/Window.hpp"
|
||||||
|
#include "window/input.hpp"
|
||||||
|
#include "debug/Logger.hpp"
|
||||||
|
#include "graphics/core/ImageData.hpp"
|
||||||
|
#include "util/platform.hpp"
|
||||||
|
|
||||||
|
static debug::Logger logger("window-control");
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static std::unique_ptr<ImageData> load_icon() {
|
||||||
|
try {
|
||||||
|
auto file = "res:textures/misc/icon.png";
|
||||||
|
if (io::exists(file)) {
|
||||||
|
return imageio::read(file);
|
||||||
|
}
|
||||||
|
} catch (const std::exception& err) {
|
||||||
|
logger.error() << "could not load window icon: " << err.what();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowControl::WindowControl(Engine& engine) : engine(engine) {}
|
||||||
|
|
||||||
|
WindowControl::Result WindowControl::initialize() {
|
||||||
|
const auto& project = engine.getProject();
|
||||||
|
auto& settings = engine.getSettings();
|
||||||
|
|
||||||
|
std::string title = project.title;
|
||||||
|
if (title.empty()) {
|
||||||
|
title = "VoxelCore v" +
|
||||||
|
std::to_string(ENGINE_VERSION_MAJOR) + "." +
|
||||||
|
std::to_string(ENGINE_VERSION_MINOR);
|
||||||
|
}
|
||||||
|
if (ENGINE_DEBUG_BUILD) {
|
||||||
|
title += " [debug]";
|
||||||
|
}
|
||||||
|
if (engine.getDebuggingServer()) {
|
||||||
|
title = "[debugging] " + title;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto [window, input] = Window::initialize(&settings.display, title);
|
||||||
|
if (!window || !input){
|
||||||
|
throw initialize_error("could not initialize window");
|
||||||
|
}
|
||||||
|
window->setFramerate(settings.display.framerate.get());
|
||||||
|
if (auto icon = load_icon()) {
|
||||||
|
icon->flipY();
|
||||||
|
window->setIcon(icon.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result {std::move(window), std::move(input)};
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowControl::saveScreenshot() {
|
||||||
|
auto& window = engine.getWindow();
|
||||||
|
const auto& paths = engine.getPaths();
|
||||||
|
|
||||||
|
auto image = window.takeScreenshot();
|
||||||
|
image->flipY();
|
||||||
|
io::path filename = paths.getNewScreenshotFile("png");
|
||||||
|
imageio::write(filename.string(), image.get());
|
||||||
|
logger.info() << "saved screenshot as " << filename.string();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowControl::toggleFullscreen() {
|
||||||
|
auto& settings = engine.getSettings();
|
||||||
|
auto& windowMode = settings.display.windowMode;
|
||||||
|
if (windowMode.get() != static_cast<int>(WindowMode::FULLSCREEN)) {
|
||||||
|
windowMode.set(static_cast<int>(WindowMode::FULLSCREEN));
|
||||||
|
} else {
|
||||||
|
windowMode.set(static_cast<int>(WindowMode::WINDOWED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowControl::nextFrame(bool waitForRefresh) {
|
||||||
|
const auto& settings = engine.getSettings();
|
||||||
|
auto& window = engine.getWindow();
|
||||||
|
auto& input = engine.getInput();
|
||||||
|
window.setFramerate(
|
||||||
|
window.isIconified() && settings.display.limitFpsIconified.get()
|
||||||
|
? 20
|
||||||
|
: settings.display.framerate.get()
|
||||||
|
);
|
||||||
|
window.swapBuffers();
|
||||||
|
input.pollEvents(waitForRefresh && !window.checkShouldRefresh());
|
||||||
|
}
|
||||||
26
src/engine/WindowControl.hpp
Normal file
26
src/engine/WindowControl.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class Window;
|
||||||
|
class Input;
|
||||||
|
class Engine;
|
||||||
|
|
||||||
|
class WindowControl {
|
||||||
|
public:
|
||||||
|
struct Result {
|
||||||
|
std::unique_ptr<Window> window;
|
||||||
|
std::unique_ptr<Input> input;
|
||||||
|
};
|
||||||
|
WindowControl(Engine& engine);
|
||||||
|
|
||||||
|
Result initialize();
|
||||||
|
|
||||||
|
void nextFrame(bool waitForRefresh);
|
||||||
|
|
||||||
|
void saveScreenshot();
|
||||||
|
|
||||||
|
void toggleFullscreen();
|
||||||
|
private:
|
||||||
|
Engine& engine;
|
||||||
|
};
|
||||||
@ -756,3 +756,13 @@ void Hud::setAllowPause(bool flag) {
|
|||||||
}
|
}
|
||||||
allowPause = flag;
|
allowPause = flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Hud::isOpen(const std::string& layoutid) const {
|
||||||
|
for (const auto& element : elements) {
|
||||||
|
auto doc = element.getDocument();
|
||||||
|
if (doc && doc->getId() == layoutid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@ -213,6 +213,8 @@ public:
|
|||||||
|
|
||||||
void setAllowPause(bool flag);
|
void setAllowPause(bool flag);
|
||||||
|
|
||||||
|
bool isOpen(const std::string& layoutid) const;
|
||||||
|
|
||||||
static bool showGeneratorMinimap;
|
static bool showGeneratorMinimap;
|
||||||
|
|
||||||
/// @brief Runtime updating debug visualization texture
|
/// @brief Runtime updating debug visualization texture
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
#include "graphics/ui/elements/Menu.hpp"
|
#include "graphics/ui/elements/Menu.hpp"
|
||||||
#include "graphics/ui/gui_util.hpp"
|
#include "graphics/ui/gui_util.hpp"
|
||||||
#include "interfaces/Task.hpp"
|
#include "interfaces/Task.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "locale.hpp"
|
#include "locale.hpp"
|
||||||
#include "logic/scripting/scripting.hpp"
|
#include "logic/scripting/scripting.hpp"
|
||||||
#include "screens/MenuScreen.hpp"
|
#include "screens/MenuScreen.hpp"
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "core_defs.hpp"
|
#include "core_defs.hpp"
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "assets/Assets.hpp"
|
#include "assets/Assets.hpp"
|
||||||
#include "frontend/ContentGfxCache.hpp"
|
#include "frontend/ContentGfxCache.hpp"
|
||||||
#include "frontend/LevelFrontend.hpp"
|
#include "frontend/LevelFrontend.hpp"
|
||||||
|
|||||||
@ -12,9 +12,11 @@
|
|||||||
#include "window/Camera.hpp"
|
#include "window/Camera.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
|
|
||||||
MenuScreen::MenuScreen(Engine& engine) : Screen(engine) {
|
MenuScreen::MenuScreen(Engine& engine)
|
||||||
uicamera =
|
: Screen(engine),
|
||||||
std::make_unique<Camera>(glm::vec3(), engine.getWindow().getSize().y);
|
uicamera(
|
||||||
|
std::make_unique<Camera>(glm::vec3(), engine.getWindow().getSize().y)
|
||||||
|
) {
|
||||||
uicamera->perspective = false;
|
uicamera->perspective = false;
|
||||||
uicamera->near = -1.0f;
|
uicamera->near = -1.0f;
|
||||||
uicamera->far = 1.0f;
|
uicamera->far = 1.0f;
|
||||||
@ -24,7 +26,7 @@ MenuScreen::MenuScreen(Engine& engine) : Screen(engine) {
|
|||||||
MenuScreen::~MenuScreen() = default;
|
MenuScreen::~MenuScreen() = default;
|
||||||
|
|
||||||
void MenuScreen::onOpen() {
|
void MenuScreen::onOpen() {
|
||||||
engine.getContentControl().resetContent();
|
engine.getContentControl().resetContent({});
|
||||||
|
|
||||||
auto menu = engine.getGUI().getMenu();
|
auto menu = engine.getGUI().getMenu();
|
||||||
menu->reset();
|
menu->reset();
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
#include "logic/LevelController.hpp"
|
#include "logic/LevelController.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "audio/audio.hpp"
|
#include "audio/audio.hpp"
|
||||||
#include "maths/util.hpp"
|
#include "maths/util.hpp"
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "graphics/core/DrawContext.hpp"
|
#include "graphics/core/DrawContext.hpp"
|
||||||
#include "graphics/core/Batch2D.hpp"
|
#include "graphics/core/Batch2D.hpp"
|
||||||
|
#include "window/Window.hpp"
|
||||||
|
#include "../GUI.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -77,6 +79,10 @@ void Container::act(float delta) {
|
|||||||
node->act(delta);
|
node->act(delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!intervalEvents.empty()) {
|
||||||
|
// TODO: make it interval-based
|
||||||
|
gui.getWindow().setShouldRefresh();
|
||||||
|
}
|
||||||
for (IntervalEvent& event : intervalEvents) {
|
for (IntervalEvent& event : intervalEvents) {
|
||||||
event.timer += delta;
|
event.timer += delta;
|
||||||
if (event.timer > event.interval) {
|
if (event.timer > event.interval) {
|
||||||
@ -87,9 +93,10 @@ void Container::act(float delta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GUI& gui = this->gui;
|
||||||
intervalEvents.erase(std::remove_if(
|
intervalEvents.erase(std::remove_if(
|
||||||
intervalEvents.begin(), intervalEvents.end(),
|
intervalEvents.begin(), intervalEvents.end(),
|
||||||
[](const IntervalEvent& event) {
|
[&gui](const IntervalEvent& event) {
|
||||||
return event.repeat == 0;
|
return event.repeat == 0;
|
||||||
}
|
}
|
||||||
), intervalEvents.end());
|
), intervalEvents.end());
|
||||||
|
|||||||
@ -51,6 +51,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
|||||||
builder.add("framerate", &settings.display.framerate);
|
builder.add("framerate", &settings.display.framerate);
|
||||||
builder.add("limit-fps-iconified", &settings.display.limitFpsIconified);
|
builder.add("limit-fps-iconified", &settings.display.limitFpsIconified);
|
||||||
builder.add("window-mode", &settings.display.windowMode);
|
builder.add("window-mode", &settings.display.windowMode);
|
||||||
|
builder.add("adaptive-menu-fps", &settings.display.adaptiveFpsInMenu);
|
||||||
|
|
||||||
builder.section("camera");
|
builder.section("camera");
|
||||||
builder.add("sensitivity", &settings.camera.sensitivity);
|
builder.add("sensitivity", &settings.camera.sensitivity);
|
||||||
|
|||||||
@ -4,28 +4,29 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "engine/Engine.hpp"
|
|
||||||
#include "coders/commons.hpp"
|
#include "coders/commons.hpp"
|
||||||
#include "debug/Logger.hpp"
|
|
||||||
#include "coders/json.hpp"
|
#include "coders/json.hpp"
|
||||||
#include "content/ContentReport.hpp"
|
|
||||||
#include "content/ContentControl.hpp"
|
#include "content/ContentControl.hpp"
|
||||||
|
#include "content/ContentReport.hpp"
|
||||||
#include "content/PacksManager.hpp"
|
#include "content/PacksManager.hpp"
|
||||||
#include "world/files/WorldConverter.hpp"
|
#include "debug/Logger.hpp"
|
||||||
#include "world/files/WorldFiles.hpp"
|
#include "engine/Engine.hpp"
|
||||||
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "frontend/locale.hpp"
|
#include "frontend/locale.hpp"
|
||||||
#include "frontend/menu.hpp"
|
#include "frontend/menu.hpp"
|
||||||
#include "frontend/screens/LevelScreen.hpp"
|
#include "frontend/screens/LevelScreen.hpp"
|
||||||
#include "frontend/screens/MenuScreen.hpp"
|
#include "frontend/screens/MenuScreen.hpp"
|
||||||
#include "graphics/ui/GUI.hpp"
|
|
||||||
#include "graphics/ui/elements/Menu.hpp"
|
#include "graphics/ui/elements/Menu.hpp"
|
||||||
#include "graphics/ui/gui_util.hpp"
|
#include "graphics/ui/gui_util.hpp"
|
||||||
#include "objects/Players.hpp"
|
#include "graphics/ui/GUI.hpp"
|
||||||
#include "interfaces/Task.hpp"
|
#include "interfaces/Task.hpp"
|
||||||
|
#include "LevelController.hpp"
|
||||||
|
#include "objects/Players.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
|
#include "world/files/WorldConverter.hpp"
|
||||||
|
#include "world/files/WorldFiles.hpp"
|
||||||
#include "world/Level.hpp"
|
#include "world/Level.hpp"
|
||||||
#include "world/World.hpp"
|
#include "world/World.hpp"
|
||||||
#include "LevelController.hpp"
|
|
||||||
|
|
||||||
static debug::Logger logger("engine-control");
|
static debug::Logger logger("engine-control");
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#include "audio/audio.hpp"
|
#include "audio/audio.hpp"
|
||||||
#include "assets/Assets.hpp"
|
#include "assets/Assets.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "api_lua.hpp"
|
#include "api_lua.hpp"
|
||||||
|
|
||||||
inline const char* DEFAULT_CHANNEL = "regular";
|
inline const char* DEFAULT_CHANNEL = "regular";
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
#include "content/ContentControl.hpp"
|
#include "content/ContentControl.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "io/settings_io.hpp"
|
#include "io/settings_io.hpp"
|
||||||
#include "frontend/menu.hpp"
|
#include "frontend/menu.hpp"
|
||||||
@ -43,7 +43,16 @@ static int l_reset_content(lua::State* L) {
|
|||||||
if (level != nullptr) {
|
if (level != nullptr) {
|
||||||
throw std::runtime_error("world must be closed before");
|
throw std::runtime_error("world must be closed before");
|
||||||
}
|
}
|
||||||
content_control->resetContent();
|
std::vector<std::string> nonResetPacks;
|
||||||
|
if (lua::istable(L, 1)) {
|
||||||
|
int len = lua::objlen(L, 1);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
lua::rawgeti(L, i + 1, 1);
|
||||||
|
nonResetPacks.emplace_back(lua::require_lstring(L, -1));
|
||||||
|
lua::pop(L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content_control->resetContent(std::move(nonResetPacks));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "objects/Entities.hpp"
|
#include "objects/Entities.hpp"
|
||||||
#include "objects/EntityDef.hpp"
|
#include "objects/EntityDef.hpp"
|
||||||
#include "objects/Entity.hpp"
|
#include "objects/Entity.hpp"
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "coders/gzip.hpp"
|
#include "coders/gzip.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "io/devices/ZipFileDevice.hpp"
|
#include "io/devices/ZipFileDevice.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
#include "content/ContentControl.hpp"
|
#include "content/ContentControl.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "../usertypes/lua_type_voxelfragment.hpp"
|
#include "../usertypes/lua_type_voxelfragment.hpp"
|
||||||
|
|
||||||
using namespace scripting;
|
using namespace scripting;
|
||||||
|
|||||||
@ -189,6 +189,11 @@ static int l_reload_script(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_is_open(lua::State* L) {
|
||||||
|
auto layoutid = lua::require_string(L, 1);
|
||||||
|
return lua::pushboolean(L, hud->isOpen(layoutid));
|
||||||
|
}
|
||||||
|
|
||||||
const luaL_Reg hudlib[] = {
|
const luaL_Reg hudlib[] = {
|
||||||
{"open_inventory", wrap_hud<l_open_inventory>},
|
{"open_inventory", wrap_hud<l_open_inventory>},
|
||||||
{"close_inventory", wrap_hud<l_close_inventory>},
|
{"close_inventory", wrap_hud<l_close_inventory>},
|
||||||
@ -208,5 +213,6 @@ const luaL_Reg hudlib[] = {
|
|||||||
{"_set_debug_cheats", wrap_hud<l_set_debug_cheats>},
|
{"_set_debug_cheats", wrap_hud<l_set_debug_cheats>},
|
||||||
{"set_allow_pause", wrap_hud<l_set_allow_pause>},
|
{"set_allow_pause", wrap_hud<l_set_allow_pause>},
|
||||||
{"reload_script", wrap_hud<l_reload_script>},
|
{"reload_script", wrap_hud<l_reload_script>},
|
||||||
|
{"is_open", wrap_hud<l_is_open>},
|
||||||
{nullptr, nullptr}
|
{nullptr, nullptr}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
#include "graphics/ui/elements/Menu.hpp"
|
#include "graphics/ui/elements/Menu.hpp"
|
||||||
#include "frontend/locale.hpp"
|
#include "frontend/locale.hpp"
|
||||||
#include "world/files/WorldFiles.hpp"
|
#include "world/files/WorldFiles.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "world/Level.hpp"
|
#include "world/Level.hpp"
|
||||||
#include "world/World.hpp"
|
#include "world/World.hpp"
|
||||||
#include "api_lua.hpp"
|
#include "api_lua.hpp"
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
#include "content/ContentControl.hpp"
|
#include "content/ContentControl.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
#include "world/files/WorldFiles.hpp"
|
#include "world/files/WorldFiles.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "lighting/Lighting.hpp"
|
#include "lighting/Lighting.hpp"
|
||||||
#include "voxels/Chunk.hpp"
|
#include "voxels/Chunk.hpp"
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
#include "libs/api_lua.hpp"
|
#include "libs/api_lua.hpp"
|
||||||
|
|||||||
@ -336,6 +336,22 @@ int lua::create_environment(State* L, int parent) {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lua::restore_pack_environment(lua::State* L, const std::string& packid) {
|
||||||
|
if(!lua::getglobal(L, "__vc__pack_envs")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int id = nextEnvironment++;
|
||||||
|
|
||||||
|
if (lua::getfield(L, packid)) {
|
||||||
|
// envname = env
|
||||||
|
setglobal(L, env_name(id));
|
||||||
|
lua::pop(L);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
lua::pop(L);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void lua::remove_environment(State* L, int id) {
|
void lua::remove_environment(State* L, int id) {
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -613,6 +613,7 @@ namespace lua {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int create_environment(lua::State*, int parent);
|
int create_environment(lua::State*, int parent);
|
||||||
|
int restore_pack_environment(lua::State*, const std::string& packid);
|
||||||
void remove_environment(lua::State*, int id);
|
void remove_environment(lua::State*, int id);
|
||||||
|
|
||||||
inline void close(lua::State* L) {
|
inline void close(lua::State* L) {
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
#include "graphics/core/ImageData.hpp"
|
#include "graphics/core/ImageData.hpp"
|
||||||
#include "maths/Heightmap.hpp"
|
#include "maths/Heightmap.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "../lua_util.hpp"
|
#include "../lua_util.hpp"
|
||||||
#include "lua_type_heightmap.hpp"
|
#include "lua_type_heightmap.hpp"
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
#include "content/ContentControl.hpp"
|
#include "content/ContentControl.hpp"
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "frontend/UiDocument.hpp"
|
#include "frontend/UiDocument.hpp"
|
||||||
#include "items/Inventory.hpp"
|
#include "items/Inventory.hpp"
|
||||||
@ -172,7 +172,15 @@ std::unique_ptr<Process> scripting::start_app_script(const io::path& script) {
|
|||||||
const ContentPack& pack
|
const ContentPack& pack
|
||||||
) {
|
) {
|
||||||
auto L = lua::get_main_state();
|
auto L = lua::get_main_state();
|
||||||
int id = lua::create_environment(L, 0);
|
int id = lua::restore_pack_environment(L, pack.id);
|
||||||
|
if (id != -1) {
|
||||||
|
return std::shared_ptr<int>(new int(id), [=](int* id) { //-V508
|
||||||
|
lua::remove_environment(L, *id);
|
||||||
|
delete id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
id = lua::create_environment(L, 0);
|
||||||
|
|
||||||
lua::pushenv(L, id);
|
lua::pushenv(L, id);
|
||||||
lua::pushvalue(L, -1);
|
lua::pushvalue(L, -1);
|
||||||
lua::setfield(L, "PACK_ENV");
|
lua::setfield(L, "PACK_ENV");
|
||||||
@ -347,7 +355,7 @@ void scripting::on_world_quit() {
|
|||||||
scripting::controller = nullptr;
|
scripting::controller = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void scripting::cleanup() {
|
void scripting::cleanup(const std::vector<std::string>& nonReset) {
|
||||||
auto L = lua::get_main_state();
|
auto L = lua::get_main_state();
|
||||||
lua::requireglobal(L, "pack");
|
lua::requireglobal(L, "pack");
|
||||||
for (auto& pack : content_control->getAllContentPacks()) {
|
for (auto& pack : content_control->getAllContentPacks()) {
|
||||||
@ -358,7 +366,12 @@ void scripting::cleanup() {
|
|||||||
lua::pop(L);
|
lua::pop(L);
|
||||||
|
|
||||||
if (lua::getglobal(L, "__scripts_cleanup")) {
|
if (lua::getglobal(L, "__scripts_cleanup")) {
|
||||||
lua::call_nothrow(L, 0);
|
lua::createtable(L, nonReset.size(), 0);
|
||||||
|
for (size_t i = 0; i < nonReset.size(); i++) {
|
||||||
|
lua::pushstring(L, nonReset[i]);
|
||||||
|
lua::rawseti(L, i + 1);
|
||||||
|
}
|
||||||
|
lua::call_nothrow(L, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -82,7 +82,7 @@ namespace scripting {
|
|||||||
void on_world_tick(int tps);
|
void on_world_tick(int tps);
|
||||||
void on_world_save();
|
void on_world_save();
|
||||||
void on_world_quit();
|
void on_world_quit();
|
||||||
void cleanup();
|
void cleanup(const std::vector<std::string>& nonReset);
|
||||||
void on_blocks_tick(const Block& block, int tps);
|
void on_blocks_tick(const Block& block, int tps);
|
||||||
void update_block(const Block& block, const glm::ivec3& pos);
|
void update_block(const Block& block, const glm::ivec3& pos);
|
||||||
void random_update_block(const Block& block, const glm::ivec3& pos);
|
void random_update_block(const Block& block, const glm::ivec3& pos);
|
||||||
|
|||||||
@ -31,6 +31,8 @@ struct DisplaySettings {
|
|||||||
IntegerSetting framerate {-1, -1, 120};
|
IntegerSetting framerate {-1, -1, 120};
|
||||||
/// @brief Limit framerate when window is iconified
|
/// @brief Limit framerate when window is iconified
|
||||||
FlagSetting limitFpsIconified {false};
|
FlagSetting limitFpsIconified {false};
|
||||||
|
/// @brief Adaptive framerate in menu (experimental)
|
||||||
|
FlagSetting adaptiveFpsInMenu {false};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ChunksSettings {
|
struct ChunksSettings {
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
#include "io/engine_paths.hpp"
|
#include "engine/EnginePaths.hpp"
|
||||||
#include "util/ArgsReader.hpp"
|
#include "util/ArgsReader.hpp"
|
||||||
#include "engine/Engine.hpp"
|
#include "engine/Engine.hpp"
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,8 @@ enum class WindowMode {
|
|||||||
|
|
||||||
class Window {
|
class Window {
|
||||||
public:
|
public:
|
||||||
|
static inline constexpr int FPS_UNLIMITED = 0;
|
||||||
|
|
||||||
Window(glm::ivec2 size) : size(std::move(size)) {}
|
Window(glm::ivec2 size) : size(std::move(size)) {}
|
||||||
|
|
||||||
virtual ~Window() = default;
|
virtual ~Window() = default;
|
||||||
@ -40,6 +42,9 @@ public:
|
|||||||
virtual void popScissor() = 0;
|
virtual void popScissor() = 0;
|
||||||
virtual void resetScissor() = 0;
|
virtual void resetScissor() = 0;
|
||||||
|
|
||||||
|
virtual void setShouldRefresh() = 0;
|
||||||
|
virtual bool checkShouldRefresh() = 0;
|
||||||
|
|
||||||
virtual double time() = 0;
|
virtual double time() = 0;
|
||||||
|
|
||||||
virtual void setFramerate(int framerate) = 0;
|
virtual void setFramerate(int framerate) = 0;
|
||||||
|
|||||||
@ -180,14 +180,18 @@ public:
|
|||||||
: window(window) {
|
: window(window) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void pollEvents() override {
|
void pollEvents(bool waitForRefresh) override {
|
||||||
delta.x = 0.0f;
|
delta.x = 0.0f;
|
||||||
delta.y = 0.0f;
|
delta.y = 0.0f;
|
||||||
scroll = 0;
|
scroll = 0;
|
||||||
currentFrame++;
|
currentFrame++;
|
||||||
codepoints.clear();
|
codepoints.clear();
|
||||||
pressedKeys.clear();
|
pressedKeys.clear();
|
||||||
glfwPollEvents();
|
if (waitForRefresh) {
|
||||||
|
glfwWaitEvents();
|
||||||
|
} else {
|
||||||
|
glfwPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& [_, binding] : bindings.getAll()) {
|
for (auto& [_, binding] : bindings.getAll()) {
|
||||||
if (!binding.enabled) {
|
if (!binding.enabled) {
|
||||||
@ -377,6 +381,18 @@ public:
|
|||||||
prevSwap = time();
|
prevSwap = time();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setShouldRefresh() override {
|
||||||
|
shouldRefresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkShouldRefresh() override {
|
||||||
|
if (shouldRefresh) {
|
||||||
|
shouldRefresh = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool isMaximized() const override {
|
bool isMaximized() const override {
|
||||||
return glfwGetWindowAttrib(window, GLFW_MAXIMIZED);
|
return glfwGetWindowAttrib(window, GLFW_MAXIMIZED);
|
||||||
}
|
}
|
||||||
@ -557,12 +573,14 @@ private:
|
|||||||
double prevSwap = 0.0;
|
double prevSwap = 0.0;
|
||||||
int posX = 0;
|
int posX = 0;
|
||||||
int posY = 0;
|
int posY = 0;
|
||||||
|
bool shouldRefresh = true;
|
||||||
};
|
};
|
||||||
static_assert(!std::is_abstract<GLFWWindow>());
|
static_assert(!std::is_abstract<GLFWWindow>());
|
||||||
|
|
||||||
static void mouse_button_callback(GLFWwindow* window, int button, int action, int) {
|
static void mouse_button_callback(GLFWwindow* window, int button, int action, int) {
|
||||||
auto handler = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
auto handler = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||||
handler->input.onMouseCallback(button, action == GLFW_PRESS);
|
handler->input.onMouseCallback(button, action == GLFW_PRESS);
|
||||||
|
handler->setShouldRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void character_callback(GLFWwindow* window, unsigned int codepoint) {
|
static void character_callback(GLFWwindow* window, unsigned int codepoint) {
|
||||||
@ -574,6 +592,8 @@ static void key_callback(
|
|||||||
GLFWwindow* window, int key, int /*scancode*/, int action, int /*mode*/
|
GLFWwindow* window, int key, int /*scancode*/, int action, int /*mode*/
|
||||||
) {
|
) {
|
||||||
auto handler = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
auto handler = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||||
|
handler->setShouldRefresh();
|
||||||
|
|
||||||
auto& input = handler->input;
|
auto& input = handler->input;
|
||||||
if (key == GLFW_KEY_UNKNOWN) {
|
if (key == GLFW_KEY_UNKNOWN) {
|
||||||
return;
|
return;
|
||||||
@ -599,11 +619,13 @@ static void window_size_callback(GLFWwindow* window, int width, int height) {
|
|||||||
static void scroll_callback(GLFWwindow* window, double, double yoffset) {
|
static void scroll_callback(GLFWwindow* window, double, double yoffset) {
|
||||||
auto handler = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
auto handler = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||||
handler->input.scroll += yoffset;
|
handler->input.scroll += yoffset;
|
||||||
|
handler->setShouldRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) {
|
static void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) {
|
||||||
auto handler = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
auto handler = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||||
handler->input.setCursorPosition(xpos, ypos);
|
handler->input.setCursorPosition(xpos, ypos);
|
||||||
|
handler->setShouldRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iconify_callback(GLFWwindow* window, int iconified) {
|
static void iconify_callback(GLFWwindow* window, int iconified) {
|
||||||
@ -629,6 +651,11 @@ static void create_standard_cursors() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void refresh_callback(GLFWwindow* window) {
|
||||||
|
auto handler = static_cast<GLFWWindow*>(glfwGetWindowUserPointer(window));
|
||||||
|
handler->setShouldRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
static void setup_callbacks(GLFWwindow* window) {
|
static void setup_callbacks(GLFWwindow* window) {
|
||||||
glfwSetKeyCallback(window, key_callback);
|
glfwSetKeyCallback(window, key_callback);
|
||||||
glfwSetMouseButtonCallback(window, mouse_button_callback);
|
glfwSetMouseButtonCallback(window, mouse_button_callback);
|
||||||
@ -637,6 +664,7 @@ static void setup_callbacks(GLFWwindow* window) {
|
|||||||
glfwSetCharCallback(window, character_callback);
|
glfwSetCharCallback(window, character_callback);
|
||||||
glfwSetScrollCallback(window, scroll_callback);
|
glfwSetScrollCallback(window, scroll_callback);
|
||||||
glfwSetWindowIconifyCallback(window, iconify_callback);
|
glfwSetWindowIconifyCallback(window, iconify_callback);
|
||||||
|
glfwSetWindowRefreshCallback(window, refresh_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<
|
std::tuple<
|
||||||
|
|||||||
@ -261,7 +261,7 @@ class Input {
|
|||||||
public:
|
public:
|
||||||
virtual ~Input() = default;
|
virtual ~Input() = default;
|
||||||
|
|
||||||
virtual void pollEvents() = 0;
|
virtual void pollEvents(bool waitForRefresh) = 0;
|
||||||
|
|
||||||
virtual const char* getClipboardText() const = 0;
|
virtual const char* getClipboardText() const = 0;
|
||||||
virtual void setClipboardText(const char* str) = 0;
|
virtual void setClipboardText(const char* str) = 0;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user