Merge branch 'headless-mode' into Fix-usage-vcpkg-for-windows-and-add-cmake-preset-for-vscode

This commit is contained in:
Stepanov Igor 2024-12-25 14:58:24 +03:00
commit 9b0d1fdd52
56 changed files with 454 additions and 107 deletions

View File

@ -1,8 +1,8 @@
test.set_setting("chunks.load-distance", 3)
test.set_setting("chunks.load-speed", 1)
app.set_setting("chunks.load-distance", 3)
app.set_setting("chunks.load-speed", 1)
test.reconfig_packs({"base"}, {})
test.new_world("demo", "2019", "core:default")
app.reconfig_packs({"base"}, {})
app.new_world("demo", "2019", "core:default")
local pid1 = player.create("Xerxes")
assert(player.get_name(pid1) == "Xerxes")
@ -21,7 +21,7 @@ for i=1,25 do
end
player.set_pos(pid1, math.random() * 100 - 50, 100, math.random() * 100 - 50)
player.set_pos(pid2, math.random() * 200 - 100, 100, math.random() * 200 - 100)
test.tick()
app.tick()
end
test.close_world(true)
app.close_world(true)

View File

@ -1,23 +1,23 @@
-- Create/close/open/close world
-- Open
test.new_world("demo", "2019", "core:default")
app.new_world("demo", "2019", "core:default")
assert(world.is_open())
assert(world.get_generator() == "core:default")
test.sleep(1)
app.sleep(1)
assert(world.get_total_time() > 0.0)
print(world.get_total_time())
-- Close
test.close_world(true)
app.close_world(true)
assert(not world.is_open())
-- Reopen
test.open_world("demo")
app.open_world("demo")
assert(world.is_open())
assert(world.get_total_time() > 0.0)
assert(world.get_seed() == 2019)
test.tick()
app.tick()
-- Close
test.close_world(true)
app.close_world(true)

View File

@ -35,6 +35,16 @@ Block model type from list:
- "X" - grass model (two crossed sprites)
- "aabb" - model based of block hitbox (complex hitbox will be combined into one). Examples: pipes, bulbs, panels.
### *model-name*
In addition to built-in model types, you can use your own, loaded from file.
The property specifies the model name without `entry_point:models/` nor extension.
> [!WARNING]
> Textures (materials) used in the model must be in the `blocks` atlas and specified in the *atlas-texture* format:
> `blocks:texture_name`
### *draw-group*
Integer specifying number of block draw group (render order). Used for semi-transparent blocks.

View File

@ -0,0 +1,130 @@
# *app* library
A library for high-level engine control, available only in script or test mode.
The script/test name without the path and extension is available as `app.script`. The file path can be obtained as:
```lua
local filename = "script:"..app.script..".lua"
```
## Functions
```lua
app.tick()
```
Performs one tick of the main engine loop.
```lua
app.sleep(time: number)
```
Waits for the specified time in seconds, performing the main engine loop.
```lua
app.sleep_until(
-- function that checks the condition for ending the wait
predicate: function() -> bool,
-- the maximum number of engine loop ticks after which
-- a "max ticks exceed" exception will be thrown
[optional] max_ticks = 1e9
)
```
Waits for the condition checked by the function to be true, performing the main engine loop.
```lua
app.quit()
```
Terminates the engine, printing the call stack to trace the function call location.
```lua
app.reconfig_packs(
-- packs to add
add_packs: table,
-- packs to remove
remove_packs: table
)
```
Updates the pack configuration, checking its correctness (dependencies and availability of packs).
To remove all packs from the configuration, you can use `pack.get_installed()`:
```lua
app.reconfig_packs({}, pack.get_installed())
```
In this case, `base` will also be removed from the configuration.
```lua
app.new_world(
-- world name
name: str,
-- generation seed
seed: str,
-- generator name
generator: str
)
```
Creates a new world and opens it.
```lua
app.open_world(name: str)
```
Opens a world by name.
```lua
app.reopen_world()
```
Reopens the world.
```lua
app.close_world(
-- save the world before closing
[optional] save_world: bool=false
)
```
Closes the world.
```lua
app.delete_world(name: str)
```
Deletes a world by name.
```lua
app.get_version() -> int, int
```
Returns the major and minor versions of the engine.
```lua
app.get_setting(name: str) -> value
```
Returns the value of a setting. Throws an exception if the setting does not exist.
```lua
app.set_setting(name: str, value: value)
```
Sets the value of a setting. Throws an exception if the setting does not exist.
```lua
app.get_setting_info(name: str) -> {
-- default value
def: value,
-- minimum value
[only for numeric settings] min: number,
-- maximum value
[only for numeric settings] max: number
}
```
Returns a table with information about a setting. Throws an exception if the setting does not exist.

View File

@ -35,6 +35,16 @@
- "X" - модель травы (крест из двух спрайтов)
- "aabb" - модель, соответствующая хитбоксу блока (составной хитбокс будет объединен в один). Примеры: трубы, лампочки, панели.
### Имя модели - *model-name*
Кроме встроенных типов моделей, можно использовать собственные, загружаемые из файлов.
В свойстве указывается имя модели без очкахода:models/` и расширения.
> [!WARNING]
> Текстуры (материалы), использующиеся в модели, должны находиться в атласе `blocks` и указываться в соответствующем формате:
> `blocks:имя_текстуры`
### Группа отрисовки - *draw-group*
Целое число определяющее номер группы отрисовки данного блока.

View File

@ -0,0 +1,131 @@
# Библиотека *app*
Библиотека для высокоуровневого управления работой движка, доступная только в режиме сценария или теста.
Имя сценария/теста без пути и расширения доступен как `app.script`. Путь к файлу можно получить как:
```lua
local filename = "script:"..app.script..".lua"
```
## Функции
```lua
app.tick()
```
Выполняет один такт основного цикла движка.
```lua
app.sleep(time: number)
```
Ожидает указанное время в секундах, выполняя основной цикл движка.
```lua
app.sleep_until(
-- функция, проверяющее условия завершения ожидания
predicate: function() -> bool,
-- максимальное количество тактов цикла движка, после истечения которых
-- будет брошено исключение "max ticks exceed"
[опционально] max_ticks = 1e9
)
```
Ожидает истинности утверждения (условия), проверяемого функцией, выполнячя основной цикл движка.
```lua
app.quit()
```
Завершает выполнение движка, выводя стек вызовов для ослеживания места вызова функции.
```lua
app.reconfig_packs(
-- добавляемые паки
add_packs: table,
-- удаляемые паки
remove_packs: table
)
```
Обновляет конфигурацию паков, проверяя её корректность (зависимости и доступность паков).
Для удаления всех паков из конфигурации можно использовать `pack.get_installed()`:
```lua
app.reconfig_packs({}, pack.get_installed())
```
В этом случае из конфигурации будет удалён и `base`.
```lua
app.new_world(
-- название мира
name: str,
-- зерно генерации
seed: str,
-- название генератора
generator: str
)
```
Создаёт новый мир и открывает его.
```lua
app.open_world(name: str)
```
Открывает мир по названию.
```lua
app.reopen_world()
```
Переоткрывает мир.
```lua
app.close_world(
-- сохранить мир перед закрытием
[опционально] save_world: bool=false
)
```
Закрывает мир.
```lua
app.delete_world(name: str)
```
Удаляет мир по названию.
```lua
app.get_version() -> int, int
```
Возвращает мажорную и минорную версии движка.
```lua
app.get_setting(name: str) -> value
```
Возвращает значение настройки. Бросает исключение, если настройки не существует.
```lua
app.set_setting(name: str, value: value)
```
Устанавливает значение настройки. Бросает исключение, если настройки не существует.
```lua
app.get_setting_info(name: str) -> {
-- значение по-умолчанию
def: value
-- минимальное значение
[только числовые настройки] min: number,
-- максимальное значение
[только числовые настройки] max: number
}
```
Возвращает таблицу с информацией о настройке. Бросает исключение, если настройки не существует.

View File

@ -22,21 +22,24 @@ function tb_frame_tostring(frame)
return s
end
if test then
test.sleep = sleep
test.name = __VC_TEST_NAME
test.new_world = core.new_world
test.open_world = core.open_world
test.close_world = core.close_world
test.reopen_world = core.reopen_world
test.delete_world = core.delete_world
test.reconfig_packs = core.reconfig_packs
test.set_setting = core.set_setting
test.tick = coroutine.yield
if app then
app.sleep = sleep
app.script = __VC_SCRIPT_NAME
app.new_world = core.new_world
app.open_world = core.open_world
app.close_world = core.close_world
app.reopen_world = core.reopen_world
app.delete_world = core.delete_world
app.reconfig_packs = core.reconfig_packs
app.get_setting = core.get_setting
app.set_setting = core.set_setting
app.tick = coroutine.yield
app.get_version = core.get_version
app.get_setting_info = core.get_setting_info
function test.quit()
function app.quit()
local tb = debug.get_traceback(1)
local s = "test.quit() traceback:"
local s = "app.quit() traceback:"
for i, frame in ipairs(tb) do
s = s .. "\n\t"..tb_frame_tostring(frame)
end
@ -45,11 +48,12 @@ if test then
coroutine.yield()
end
function test.sleep_until(predicate, max_ticks)
function app.sleep_until(predicate, max_ticks)
max_ticks = max_ticks or 1e9
local ticks = 0
while ticks < max_ticks and not predicate() do
test.tick()
app.tick()
ticks = ticks + 1
end
if ticks == max_ticks then
error("max ticks exceed")

View File

@ -1,4 +1,4 @@
#include "engine.hpp"
#include "Engine.hpp"
#ifndef GLEW_STATIC
#define GLEW_STATIC
@ -186,7 +186,7 @@ void Engine::run() {
void Engine::postUpdate() {
network->update();
processPostRunnables();
postRunnables.run();
}
void Engine::updateFrontend() {
@ -215,15 +215,6 @@ void Engine::renderFrame() {
gui->draw(ctx, *assets);
}
void Engine::processPostRunnables() {
std::lock_guard<std::recursive_mutex> lock(postRunnablesMutex);
while (!postRunnables.empty()) {
postRunnables.front()();
postRunnables.pop();
}
scripting::process_post_runnables();
}
void Engine::saveSettings() {
logger.info() << "saving settings";
files::write_string(paths.getSettingsFile(), toml::stringify(settingsHandler));
@ -296,13 +287,8 @@ void Engine::loadAssets() {
auto task = loader.startTask([=](){});
task->waitForEnd();
} else {
try {
while (loader.hasNext()) {
loader.loadNext();
}
} catch (const assetload::error& err) {
new_assets.reset();
throw;
while (loader.hasNext()) {
loader.loadNext();
}
}
assets = std::move(new_assets);
@ -519,11 +505,6 @@ std::shared_ptr<Screen> Engine::getScreen() {
return screen;
}
void Engine::postRunnable(const runnable& callback) {
std::lock_guard<std::recursive_mutex> lock(postRunnablesMutex);
postRunnables.push(callback);
}
SettingsHandler& Engine::getSettingsHandler() {
return settingsHandler;
}

View File

@ -11,15 +11,14 @@
#include "files/engine_paths.hpp"
#include "files/settings_io.hpp"
#include "util/ObjectsKeeper.hpp"
#include "PostRunnables.hpp"
#include "Time.hpp"
#include <filesystem>
#include <memory>
#include <queue>
#include <stdexcept>
#include <string>
#include <vector>
#include <mutex>
class Level;
class Screen;
@ -65,13 +64,12 @@ class Engine : public util::ObjectsKeeper {
std::vector<ContentPack> contentPacks;
std::unique_ptr<Content> content;
std::unique_ptr<ResPaths> resPaths;
std::queue<runnable> postRunnables;
std::recursive_mutex postRunnablesMutex;
std::unique_ptr<EngineController> controller;
std::unique_ptr<cmd::CommandsInterpreter> interpreter;
std::unique_ptr<network::Network> network;
std::vector<std::string> basePacks;
std::unique_ptr<gui::GUI> gui;
PostRunnables postRunnables;
Time time;
consumer<std::unique_ptr<Level>> levelConsumer;
bool quitSignal = false;
@ -80,7 +78,6 @@ class Engine : public util::ObjectsKeeper {
void loadSettings();
void saveSettings();
void updateHotkeys();
void processPostRunnables();
void loadAssets();
public:
Engine(CoreParameters coreParameters);
@ -157,7 +154,9 @@ public:
std::shared_ptr<Screen> getScreen();
/// @brief Enqueue function call to the end of current frame in draw thread
void postRunnable(const runnable& callback);
void postRunnable(const runnable& callback) {
postRunnables.postRunnable(callback);
}
void saveScreenshot();

View File

@ -1,7 +1,7 @@
#include "Mainloop.hpp"
#include "Engine.hpp"
#include "debug/Logger.hpp"
#include "engine.hpp"
#include "frontend/screens/MenuScreen.hpp"
#include "frontend/screens/LevelScreen.hpp"
#include "window/Window.hpp"

View File

@ -0,0 +1,29 @@
#pragma once
#include <queue>
#include <mutex>
#include "delegates.hpp"
class PostRunnables {
std::queue<runnable> runnables;
std::recursive_mutex mutex;
public:
void postRunnable(runnable task) {
std::lock_guard<std::recursive_mutex> lock(mutex);
runnables.push(std::move(task));
}
void run() {
std::queue<runnable> tasksToRun;
{
std::lock_guard<std::recursive_mutex> lock(mutex);
std::swap(tasksToRun, runnables);
}
while (!tasksToRun.empty()) {
auto& task = tasksToRun.front();
task();
tasksToRun.pop();
}
}
};

View File

@ -1,5 +1,6 @@
#include "ServerMainloop.hpp"
#include "Engine.hpp"
#include "logic/scripting/scripting.hpp"
#include "logic/LevelController.hpp"
#include "interfaces/Process.hpp"
@ -7,7 +8,6 @@
#include "world/Level.hpp"
#include "world/World.hpp"
#include "util/platform.hpp"
#include "engine.hpp"
#include <chrono>

View File

@ -1,6 +1,6 @@
#include "audio/audio.hpp"
#include "delegates.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "settings.hpp"
#include "hud.hpp"
#include "content/Content.hpp"

View File

@ -8,7 +8,7 @@
#include "content/Content.hpp"
#include "core_defs.hpp"
#include "delegates.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "graphics/core/Atlas.hpp"
#include "graphics/core/Batch2D.hpp"
#include "graphics/core/Batch3D.hpp"

View File

@ -5,7 +5,7 @@
#include "screens/MenuScreen.hpp"
#include "delegates.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "data/dv.hpp"
#include "interfaces/Task.hpp"
#include "files/engine_paths.hpp"

View File

@ -5,7 +5,7 @@
#include "content/Content.hpp"
#include "core_defs.hpp"
#include "debug/Logger.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "files/files.hpp"
#include "frontend/LevelFrontend.hpp"
#include "frontend/hud.hpp"

View File

@ -8,7 +8,7 @@
#include "maths/UVRegion.hpp"
#include "window/Window.hpp"
#include "window/Camera.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
MenuScreen::MenuScreen(Engine& engine) : Screen(engine) {
engine.resetContent();

View File

@ -1,7 +1,7 @@
#include "Screen.hpp"
#include "graphics/core/Batch2D.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
Screen::Screen(Engine& engine)
: engine(engine),

View File

@ -14,7 +14,7 @@
#include "objects/Players.hpp"
#include "logic/LevelController.hpp"
#include "util/stringutil.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "files/files.hpp"
namespace fs = std::filesystem;

View File

@ -11,7 +11,7 @@
#include "assets/Assets.hpp"
#include "assets/assets_util.hpp"
#include "content/Content.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "frontend/LevelFrontend.hpp"
#include "frontend/ContentGfxCache.hpp"
#include "items/Inventory.hpp"

View File

@ -4,7 +4,7 @@
#include <filesystem>
#include <memory>
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "coders/commons.hpp"
#include "debug/Logger.hpp"
#include "content/ContentReport.hpp"

View File

@ -3,7 +3,7 @@
#include <algorithm>
#include "debug/Logger.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "files/WorldFiles.hpp"
#include "maths/voxmaths.hpp"
#include "objects/Entities.hpp"

View File

@ -37,7 +37,7 @@ extern const luaL_Reg packlib[];
extern const luaL_Reg particleslib[]; // gfx.particles
extern const luaL_Reg playerlib[];
extern const luaL_Reg quatlib[];
extern const luaL_Reg testlib[];
extern const luaL_Reg applib[];
extern const luaL_Reg text3dlib[]; // gfx.text3d
extern const luaL_Reg timelib[];
extern const luaL_Reg tomllib[];

View File

@ -1,5 +1,5 @@
#include "api_lua.hpp"
const luaL_Reg testlib[] = {
const luaL_Reg applib[] = {
{NULL, NULL}
};

View File

@ -1,5 +1,5 @@
#include "audio/audio.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "api_lua.hpp"
inline const char* DEFAULT_CHANNEL = "regular";

View File

@ -1,5 +1,5 @@
#include "coders/commons.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "logic/CommandsInterpreter.hpp"
#include "api_lua.hpp"

View File

@ -6,7 +6,7 @@
#include "constants.hpp"
#include "content/Content.hpp"
#include "debug/Logger.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "files/engine_paths.hpp"
#include "files/files.hpp"
#include "files/settings_io.hpp"

View File

@ -1,7 +1,7 @@
#include "libentity.hpp"
#include "content/Content.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "objects/Entities.hpp"
#include "objects/EntityDef.hpp"
#include "objects/Player.hpp"

View File

@ -3,7 +3,7 @@
#include <set>
#include "coders/gzip.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "files/engine_paths.hpp"
#include "files/files.hpp"
#include "util/stringutil.hpp"

View File

@ -6,7 +6,7 @@
#include "world/Level.hpp"
#include "world/generator/VoxelFragment.hpp"
#include "content/ContentLoader.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "../lua_custom_types.hpp"
using namespace scripting;

View File

@ -1,5 +1,5 @@
#include "assets/Assets.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "frontend/UiDocument.hpp"
#include "frontend/locale.hpp"
#include "graphics/ui/elements/Button.hpp"

View File

@ -3,7 +3,7 @@
#include "assets/Assets.hpp"
#include "content/Content.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "frontend/UiDocument.hpp"
#include "frontend/hud.hpp"
#include "graphics/ui/elements/InventoryView.hpp"

View File

@ -1,6 +1,6 @@
#include <filesystem>
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "files/files.hpp"
#include "frontend/hud.hpp"
#include "frontend/screens/Screen.hpp"
@ -30,7 +30,21 @@ static int l_mousecode(lua::State* L) {
}
static int l_add_callback(lua::State* L) {
auto bindname = lua::require_string(L, 1);
std::string bindname = lua::require_string(L, 1);
size_t pos = bindname.find(':');
if (pos != std::string::npos) {
std::string prefix = bindname.substr(0, pos);
if (prefix == "key") {
if (hud == nullptr) {
throw std::runtime_error("on_hud_open is not called yet");
}
auto key = input_util::keycode_from(bindname.substr(pos + 1));
auto callback = lua::create_runnable(L);
hud->keepAlive(Events::keyCallbacks[key].add(callback));
return 0;
}
}
const auto& bind = Events::bindings.find(bindname);
if (bind == Events::bindings.end()) {
throw std::runtime_error("unknown binding " + util::quote(bindname));

View File

@ -1,6 +1,6 @@
#include "api_lua.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "network/Network.hpp"
using namespace scripting;

View File

@ -5,7 +5,7 @@
#include "assets/AssetsLoader.hpp"
#include "content/Content.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "files/WorldFiles.hpp"
#include "files/engine_paths.hpp"
#include "world/Level.hpp"

View File

@ -5,7 +5,7 @@
#include "graphics/render/ParticlesRenderer.hpp"
#include "graphics/render/Emitter.hpp"
#include "assets/assets_util.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
using namespace scripting;

View File

@ -4,7 +4,7 @@
#include "graphics/render/WorldRenderer.hpp"
#include "graphics/render/TextsRenderer.hpp"
#include "graphics/render/TextNote.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
using namespace scripting;

View File

@ -1,4 +1,4 @@
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "api_lua.hpp"
using namespace scripting;

View File

@ -7,7 +7,7 @@
#include "coders/compression.hpp"
#include "coders/gzip.hpp"
#include "coders/json.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "files/engine_paths.hpp"
#include "files/files.hpp"
#include "lighting/Lighting.hpp"

View File

@ -9,7 +9,7 @@
#include "util/stringutil.hpp"
#include "libs/api_lua.hpp"
#include "lua_custom_types.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
static debug::Logger logger("lua-state");
static lua::State* main_thread = nullptr;
@ -58,10 +58,10 @@ static void create_libs(State* L, StateType stateType) {
openlib(L, "vec3", vec3lib);
openlib(L, "vec4", vec4lib);
if (stateType == StateType::TEST) {
openlib(L, "test", testlib);
if (stateType == StateType::SCRIPT) {
openlib(L, "app", applib);
}
if (stateType == StateType::BASE || stateType == StateType::TEST) {
if (stateType == StateType::BASE || stateType == StateType::SCRIPT) {
openlib(L, "gui", guilib);
openlib(L, "input", inputlib);
openlib(L, "inventory", inventorylib);
@ -119,10 +119,10 @@ void lua::initialize(const EnginePaths& paths, const CoreParameters& params) {
logger.info() << LUAJIT_VERSION;
main_thread = create_state(
paths, params.headless ? StateType::TEST : StateType::BASE
paths, params.headless ? StateType::SCRIPT : StateType::BASE
);
lua::pushstring(main_thread, params.scriptFile.stem().u8string());
lua::setglobal(main_thread, "__VC_TEST_NAME");
lua::setglobal(main_thread, "__VC_SCRIPT_NAME");
}
void lua::finalize() {

View File

@ -13,7 +13,7 @@ struct CoreParameters;
namespace lua {
enum class StateType {
BASE,
TEST,
SCRIPT,
GENERATOR,
};

View File

@ -12,7 +12,7 @@
#include "files/util.hpp"
#include "graphics/core/ImageData.hpp"
#include "maths/Heightmap.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "../lua_util.hpp"
using namespace lua;

View File

@ -7,7 +7,7 @@
#include "content/Content.hpp"
#include "content/ContentPack.hpp"
#include "debug/Logger.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "files/engine_paths.hpp"
#include "files/files.hpp"
#include "frontend/UiDocument.hpp"

View File

@ -1,7 +1,7 @@
#include "scripting_hud.hpp"
#include "debug/Logger.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "files/files.hpp"
#include "frontend/hud.hpp"
#include "graphics/render/WorldRenderer.hpp"

View File

@ -14,7 +14,7 @@
#include "world/generator/GeneratorDef.hpp"
#include "util/timeutil.hpp"
#include "files/files.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "debug/Logger.hpp"
using namespace lua;

View File

@ -1,4 +1,4 @@
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "util/platform.hpp"
#include "util/command_line.hpp"
#include "debug/Logger.hpp"

View File

@ -16,7 +16,7 @@ struct UVFace {
}
template<int n>
inline void rotate(int times) {
inline void rotate() {
int times = n % 4;
if (times < 0) {
times += 4;

View File

@ -9,6 +9,12 @@
#include <glm/gtx/norm.hpp>
namespace util {
inline uint64_t shuffle_bits_step(uint64_t x, uint64_t m, unsigned shift) {
uint64_t t = ((x >> shift) ^ x) & m;
x = (x ^ t) ^ (t << shift);
return x;
}
constexpr inline float EPSILON = 1e-6f;
class PseudoRandom {
@ -57,17 +63,20 @@ namespace util {
return randU64() / static_cast<double>(UINT64_MAX);
}
void setSeed(int number) {
seed = (static_cast<unsigned short>(number * 23729) ^
static_cast<unsigned short>(number + 16786));
rand();
}
void setSeed(int number1, int number2) {
seed = ((static_cast<unsigned short>(number1 * 23729) |
static_cast<unsigned short>(number2 % 16786)) ^
static_cast<unsigned short>(number2 * number1));
rand();
}
void setSeed(long number) {
number = shuffle_bits_step(number, 0x2222222222222222ull, 1);
number = shuffle_bits_step(number, 0x0c0c0c0c0c0c0c0cull, 2);
number = shuffle_bits_step(number, 0x00f000f000f000f0ull, 4);
seed = number;
rand();
}
};
template<typename T>

View File

@ -7,7 +7,7 @@
#include "content/Content.hpp"
#include "data/dv_util.hpp"
#include "debug/Logger.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
#include "graphics/core/DrawContext.hpp"
#include "graphics/core/LineBatch.hpp"
#include "graphics/commons/Model.hpp"

View File

@ -1,5 +1,6 @@
#pragma once
#include <mutex>
#include <memory>
#include <unordered_map>
#include <utility>
@ -11,17 +12,33 @@ namespace util {
class RunnablesList {
int nextid = 1;
std::unordered_map<int, runnable> runnables;
std::mutex mutex;
public:
RunnablesList() = default;
RunnablesList(RunnablesList&& o) {
runnables = std::move(o.runnables);
nextid = o.nextid;
}
void operator=(RunnablesList&& o) {
runnables = std::move(o.runnables);
nextid = o.nextid;
}
observer_handler add(runnable callback) {
std::lock_guard lock(mutex);
int id = nextid++;
runnables[id] = std::move(callback);
return observer_handler(new int(id), [this](int* id) { //-V508
std::lock_guard lock(mutex);
runnables.erase(*id);
delete id;
});
}
void notify() {
std::lock_guard lock(mutex);
for (auto& entry : runnables) {
entry.second();
}

View File

@ -5,7 +5,7 @@
#include "files/engine_paths.hpp"
#include "util/ArgsReader.hpp"
#include "engine.hpp"
#include "engine/Engine.hpp"
namespace fs = std::filesystem;

View File

@ -23,6 +23,7 @@ bool Events::_cursor_locked = false;
std::vector<uint> Events::codepoints;
std::vector<keycode> Events::pressedKeys;
std::unordered_map<std::string, Binding> Events::bindings;
std::unordered_map<keycode, util::RunnablesList> Events::keyCallbacks;
bool Events::pressed(keycode keycode) {
return pressed(static_cast<int>(keycode));
@ -156,6 +157,12 @@ bool Events::jactive(const std::string& name) {
void Events::setKey(int key, bool b) {
Events::keys[key] = b;
Events::frames[key] = currentFrame;
if (b) {
const auto& callbacks = keyCallbacks.find(static_cast<keycode>(key));
if (callbacks != keyCallbacks.end()) {
callbacks->second.notify();
}
}
}
void Events::setButton(int button, bool b) {
@ -173,6 +180,10 @@ void Events::setPosition(float xpos, float ypos) {
Events::cursor.y = ypos;
}
observer_handler Events::addKeyCallback(keycode key, runnable callback) {
return keyCallbacks[key].add(std::move(callback));
}
#include "coders/json.hpp"
#include "coders/toml.hpp"
@ -228,7 +239,6 @@ void Events::loadBindings(
} else if (bindType == BindType::REBIND) {
Events::rebind(key, type, code);
}
}
}
}

View File

@ -27,6 +27,7 @@ public:
static std::vector<uint> codepoints;
static std::vector<keycode> pressedKeys;
static std::unordered_map<std::string, Binding> bindings;
static std::unordered_map<keycode, util::RunnablesList> keyCallbacks;
static void pollEvents();
@ -50,6 +51,8 @@ public:
static bool active(const std::string& name);
static bool jactive(const std::string& name);
static observer_handler addKeyCallback(keycode key, runnable callback);
static void setKey(int key, bool b);
static void setButton(int button, bool b);