This commit is contained in:
MihailRis 2024-12-09 01:12:41 +03:00
parent 5fe5c6b27a
commit 5ffc054d75
16 changed files with 212 additions and 126 deletions

View File

@ -1,3 +0,0 @@
print("Hello from the example test!")
test.sleep(1)
print("2")

30
src/Mainloop.cpp Normal file
View File

@ -0,0 +1,30 @@
#include "Mainloop.hpp"
#include "debug/Logger.hpp"
#include "engine.hpp"
#include "frontend/screens/MenuScreen.hpp"
#include "window/Window.hpp"
static debug::Logger logger("mainloop");
Mainloop::Mainloop(Engine& engine) : engine(engine) {
}
void Mainloop::run() {
auto& time = engine.getTime();
logger.info() << "starting menu screen";
engine.setScreen(std::make_shared<MenuScreen>(&engine));
logger.info() << "main loop started";
while (!Window::isShouldClose()){
time.update(Window::time());
engine.updateFrontend();
if (!Window::isIconified()) {
engine.renderFrame();
}
engine.postUpdate();
engine.nextFrame();
}
logger.info() << "main loop stopped";
}

11
src/Mainloop.hpp Normal file
View File

@ -0,0 +1,11 @@
#pragma once
class Engine;
class Mainloop {
Engine& engine;
public:
Mainloop(Engine& engine);
void run();
};

31
src/TestMainloop.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "TestMainloop.hpp"
#include "logic/scripting/scripting.hpp"
#include "interfaces/Process.hpp"
#include "debug/Logger.hpp"
#include "engine.hpp"
static debug::Logger logger("mainloop");
inline constexpr int TPS = 20;
TestMainloop::TestMainloop(Engine& engine) : engine(engine) {
}
void TestMainloop::run() {
const auto& coreParams = engine.getCoreParameters();
auto& time = engine.getTime();
if (coreParams.testFile.empty()) {
logger.info() << "nothing to do";
return;
}
logger.info() << "starting test " << coreParams.testFile;
auto process = scripting::start_coroutine(coreParams.testFile);
while (process->isActive()) {
time.step(1.0f / static_cast<float>(TPS));
process->update();
}
logger.info() << "test finished";
}

11
src/TestMainloop.hpp Normal file
View File

@ -0,0 +1,11 @@
#pragma once
class Engine;
class TestMainloop {
Engine& engine;
public:
TestMainloop(Engine& engine);
void run();
};

34
src/Time.hpp Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#include <stdint.h>
class Time {
uint64_t frame = 0;
double lastTime = 0.0;
double delta = 0.0;
public:
Time() {}
void update(double currentTime) {
frame++;
delta = currentTime - lastTime;
lastTime = currentTime;
}
void step(double delta) {
frame++;
lastTime += delta;
}
void set(double currentTime) {
lastTime = currentTime;
}
double getDelta() const {
return delta;
}
double getTime() const {
return lastTime;
}
};

View File

@ -146,9 +146,7 @@ void ContentPack::scanFolder(
std::vector<std::string> ContentPack::worldPacksList(const fs::path& folder) { std::vector<std::string> ContentPack::worldPacksList(const fs::path& folder) {
fs::path listfile = folder / fs::path("packs.list"); fs::path listfile = folder / fs::path("packs.list");
if (!fs::is_regular_file(listfile)) { if (!fs::is_regular_file(listfile)) {
std::cerr << "warning: packs.list not found (will be created)"; throw std::runtime_error("missing file 'packs.list'");
std::cerr << std::endl;
files::write_string(listfile, "# autogenerated, do not modify\nbase\n");
} }
return files::read_list(listfile); return files::read_list(listfile);
} }

View File

@ -20,7 +20,6 @@
#include "frontend/screens/Screen.hpp" #include "frontend/screens/Screen.hpp"
#include "frontend/screens/MenuScreen.hpp" #include "frontend/screens/MenuScreen.hpp"
#include "graphics/render/ModelsGenerator.hpp" #include "graphics/render/ModelsGenerator.hpp"
#include "graphics/core/Batch2D.hpp"
#include "graphics/core/DrawContext.hpp" #include "graphics/core/DrawContext.hpp"
#include "graphics/core/ImageData.hpp" #include "graphics/core/ImageData.hpp"
#include "graphics/core/Shader.hpp" #include "graphics/core/Shader.hpp"
@ -36,7 +35,8 @@
#include "window/Events.hpp" #include "window/Events.hpp"
#include "window/input.hpp" #include "window/input.hpp"
#include "window/Window.hpp" #include "window/Window.hpp"
#include "interfaces/Process.hpp" #include "Mainloop.hpp"
#include "TestMainloop.hpp"
#include <iostream> #include <iostream>
#include <assert.h> #include <assert.h>
@ -92,6 +92,7 @@ Engine::Engine(CoreParameters coreParameters)
if (Window::initialize(&settings.display)){ if (Window::initialize(&settings.display)){
throw initialize_error("could not initialize window"); throw initialize_error("could not initialize window");
} }
time.set(Window::time());
if (auto icon = load_icon(resdir)) { if (auto icon = load_icon(resdir)) {
icon->flipY(); icon->flipY();
Window::setIcon(icon.get()); Window::setIcon(icon.get());
@ -153,13 +154,6 @@ void Engine::onAssetsLoaded() {
gui->onAssetsLoad(assets.get()); gui->onAssetsLoad(assets.get());
} }
void Engine::updateTimers() {
frame++;
double currentTime = Window::time();
delta = currentTime - lastTime;
lastTime = currentTime;
}
void Engine::updateHotkeys() { void Engine::updateHotkeys() {
if (Events::jpressed(keycode::F2)) { if (Events::jpressed(keycode::F2)) {
saveScreenshot(); saveScreenshot();
@ -179,70 +173,40 @@ void Engine::saveScreenshot() {
void Engine::run() { void Engine::run() {
if (params.headless) { if (params.headless) {
runTest(); TestMainloop(*this).run();
} else { } else {
mainloop(); Mainloop(*this).run();
} }
} }
void Engine::runTest() { void Engine::postUpdate() {
if (params.testFile.empty()) { network->update();
logger.info() << "nothing to do"; processPostRunnables();
return;
}
int tps = 20;
logger.info() << "starting test " << params.testFile;
auto process = scripting::start_coroutine(params.testFile);
while (process->isActive()) {
frame++;
delta = 1.0f / static_cast<float>(tps);
lastTime += delta;
process->update();
}
logger.info() << "test finished";
} }
void Engine::mainloop() { void Engine::updateFrontend() {
logger.info() << "starting menu screen"; double delta = time.getDelta();
setScreen(std::make_shared<MenuScreen>(this));
Batch2D batch(1024);
lastTime = Window::time();
logger.info() << "engine started";
while (!Window::isShouldClose()){
assert(screen != nullptr);
updateTimers();
updateHotkeys(); updateHotkeys();
audio::update(delta); audio::update(delta);
gui->act(delta, Viewport(Window::width, Window::height)); gui->act(delta, Viewport(Window::width, Window::height));
screen->update(delta); screen->update(delta);
if (!Window::isIconified()) {
renderFrame(batch);
} }
void Engine::nextFrame() {
Window::setFramerate( Window::setFramerate(
Window::isIconified() && settings.display.limitFpsIconified.get() Window::isIconified() && settings.display.limitFpsIconified.get()
? 20 ? 20
: settings.display.framerate.get() : settings.display.framerate.get()
); );
network->update();
processPostRunnables();
Window::swapBuffers(); Window::swapBuffers();
Events::pollEvents(); Events::pollEvents();
} }
}
void Engine::renderFrame(Batch2D& batch) { void Engine::renderFrame() {
screen->draw(delta); screen->draw(time.getDelta());
Viewport viewport(Window::width, Window::height); Viewport viewport(Window::width, Window::height);
DrawContext ctx(nullptr, viewport, &batch); DrawContext ctx(nullptr, viewport, nullptr);
gui->draw(ctx, *assets); gui->draw(ctx, *assets);
} }
@ -334,10 +298,11 @@ void Engine::loadAssets() {
} }
assets = std::move(new_assets); assets = std::move(new_assets);
if (content) { if (content == nullptr) {
return;
}
for (auto& [name, def] : content->blocks.getDefs()) { for (auto& [name, def] : content->blocks.getDefs()) {
if (def->model == BlockModel::custom) { if (def->model == BlockModel::custom && def->modelName.empty()) {
if (def->modelName.empty()) {
assets->store( assets->store(
std::make_unique<model::Model>( std::make_unique<model::Model>(
ModelsGenerator::loadCustomBlockModel( ModelsGenerator::loadCustomBlockModel(
@ -349,7 +314,6 @@ void Engine::loadAssets() {
def->modelName = def->name + ".model"; def->modelName = def->name + ".model";
} }
} }
}
for (auto& [name, def] : content->items.getDefs()) { for (auto& [name, def] : content->items.getDefs()) {
assets->store( assets->store(
std::make_unique<model::Model>( std::make_unique<model::Model>(
@ -359,7 +323,6 @@ void Engine::loadAssets() {
); );
} }
} }
}
static void load_configs(const fs::path& root) { static void load_configs(const fs::path& root) {
auto configFolder = root/fs::path("config"); auto configFolder = root/fs::path("config");
@ -468,14 +431,6 @@ void Engine::loadAllPacks() {
contentPacks = manager.getAll(manager.assembly(allnames)); contentPacks = manager.getAll(manager.assembly(allnames));
} }
double Engine::getDelta() const {
return delta;
}
double Engine::getUptime() const {
return lastTime;
}
void Engine::setScreen(std::shared_ptr<Screen> screen) { void Engine::setScreen(std::shared_ptr<Screen> screen) {
// reset audio channels (stop all sources) // reset audio channels (stop all sources)
audio::reset_channel(audio::get_channel_index("regular")); audio::reset_channel(audio::get_channel_index("regular"));
@ -545,6 +500,14 @@ network::Network& Engine::getNetwork() {
return *network; return *network;
} }
Time& Engine::getTime() {
return time;
}
const CoreParameters& Engine::getCoreParameters() const { const CoreParameters& Engine::getCoreParameters() const {
return params; return params;
} }
bool Engine::isHeadless() const {
return params.headless;
}

View File

@ -11,6 +11,7 @@
#include "files/engine_paths.hpp" #include "files/engine_paths.hpp"
#include "files/settings_io.hpp" #include "files/settings_io.hpp"
#include "util/ObjectsKeeper.hpp" #include "util/ObjectsKeeper.hpp"
#include "Time.hpp"
#include <filesystem> #include <filesystem>
#include <memory> #include <memory>
@ -23,7 +24,6 @@
class Screen; class Screen;
class EnginePaths; class EnginePaths;
class ResPaths; class ResPaths;
class Batch2D;
class EngineController; class EngineController;
class SettingsHandler; class SettingsHandler;
struct EngineSettings; struct EngineSettings;
@ -70,17 +70,12 @@ class Engine : public util::ObjectsKeeper {
std::unique_ptr<network::Network> network; std::unique_ptr<network::Network> network;
std::vector<std::string> basePacks; std::vector<std::string> basePacks;
std::unique_ptr<gui::GUI> gui; std::unique_ptr<gui::GUI> gui;
Time time;
uint64_t frame = 0;
double lastTime = 0.0;
double delta = 0.0;
void loadControls(); void loadControls();
void loadSettings(); void loadSettings();
void saveSettings(); void saveSettings();
void updateTimers();
void updateHotkeys(); void updateHotkeys();
void renderFrame(Batch2D& batch);
void processPostRunnables(); void processPostRunnables();
void loadAssets(); void loadAssets();
public: public:
@ -90,11 +85,11 @@ public:
/// @brief Start the engine /// @brief Start the engine
void run(); void run();
/// @brief Start main engine input/update/render loop. void postUpdate();
/// Automatically sets MenuScreen
void mainloop();
void runTest(); void updateFrontend();
void renderFrame();
void nextFrame();
/// @brief Called after assets loading when all engine systems are initialized /// @brief Called after assets loading when all engine systems are initialized
void onAssetsLoaded(); void onAssetsLoaded();
@ -122,11 +117,6 @@ public:
/// @brief Collect all available content-packs from res/content /// @brief Collect all available content-packs from res/content
void loadAllPacks(); void loadAllPacks();
/// @brief Get current frame delta-time
double getDelta() const;
double getUptime() const;
/// @brief Get active assets storage instance /// @brief Get active assets storage instance
Assets* getAssets(); Assets* getAssets();
@ -169,5 +159,9 @@ public:
network::Network& getNetwork(); network::Network& getNetwork();
Time& getTime();
const CoreParameters& getCoreParameters() const; const CoreParameters& getCoreParameters() const;
bool isHeadless() const;
}; };

View File

@ -56,7 +56,7 @@ std::shared_ptr<UINode> create_debug_panel(
static std::wstring fpsString = L""; static std::wstring fpsString = L"";
panel->listenInterval(0.016f, [engine]() { panel->listenInterval(0.016f, [engine]() {
fps = 1.0f / engine->getDelta(); fps = 1.0f / engine->getTime().getDelta();
fpsMin = std::min(fps, fpsMin); fpsMin = std::min(fps, fpsMin);
fpsMax = std::max(fps, fpsMax); fpsMax = std::max(fps, fpsMax);
}); });

View File

@ -92,6 +92,9 @@ DrawContext DrawContext::sub(Flushable* flushable) const {
ctx.parent = this; ctx.parent = this;
ctx.flushable = flushable; ctx.flushable = flushable;
ctx.scissorsCount = 0; ctx.scissorsCount = 0;
if (auto batch2D = dynamic_cast<Batch2D*>(flushable)) {
ctx.g2d = batch2D;
}
return ctx; return ctx;
} }

View File

@ -10,7 +10,7 @@ class Framebuffer;
class DrawContext { class DrawContext {
const DrawContext* parent; const DrawContext* parent;
Viewport viewport; Viewport viewport;
Batch2D* const g2d; Batch2D* g2d;
Flushable* flushable = nullptr; Flushable* flushable = nullptr;
Framebuffer* fbo = nullptr; Framebuffer* fbo = nullptr;
bool depthMask = true; bool depthMask = true;

View File

@ -23,7 +23,7 @@
using namespace gui; using namespace gui;
GUI::GUI() { GUI::GUI() : batch2D(std::make_unique<Batch2D>(1024)) {
container = std::make_shared<Container>(glm::vec2(1000)); container = std::make_shared<Container>(glm::vec2(1000));
uicamera = std::make_unique<Camera>(glm::vec3(), Window::height); uicamera = std::make_unique<Camera>(glm::vec3(), Window::height);
uicamera->perspective = false; uicamera->perspective = false;
@ -198,7 +198,9 @@ void GUI::act(float delta, const Viewport& vp) {
} }
void GUI::draw(const DrawContext& pctx, const Assets& assets) { void GUI::draw(const DrawContext& pctx, const Assets& assets) {
auto& viewport = pctx.getViewport(); auto ctx = pctx.sub(batch2D.get());
auto& viewport = ctx.getViewport();
glm::vec2 wsize = viewport.size(); glm::vec2 wsize = viewport.size();
menu->setPos((wsize - menu->getSize()) / 2.0f); menu->setPos((wsize - menu->getSize()) / 2.0f);
@ -208,8 +210,8 @@ void GUI::draw(const DrawContext& pctx, const Assets& assets) {
uishader->use(); uishader->use();
uishader->uniformMatrix("u_projview", uicamera->getProjView()); uishader->uniformMatrix("u_projview", uicamera->getProjView());
pctx.getBatch2D()->begin(); batch2D->begin();
container->draw(pctx, assets); container->draw(ctx, assets);
} }
std::shared_ptr<UINode> GUI::getFocused() const { std::shared_ptr<UINode> GUI::getFocused() const {

View File

@ -13,6 +13,7 @@ class Viewport;
class DrawContext; class DrawContext;
class Assets; class Assets;
class Camera; class Camera;
class Batch2D;
/* /*
Some info about padding and margin. Some info about padding and margin.
@ -52,6 +53,7 @@ namespace gui {
/// @brief The main UI controller /// @brief The main UI controller
class GUI { class GUI {
std::unique_ptr<Batch2D> batch2D;
std::shared_ptr<Container> container; std::shared_ptr<Container> container;
std::shared_ptr<UINode> hover; std::shared_ptr<UINode> hover;
std::shared_ptr<UINode> pressed; std::shared_ptr<UINode> pressed;

View File

@ -132,13 +132,18 @@ static void show_content_missing(
menus::show(engine, "reports/missing_content", {std::move(root)}); menus::show(engine, "reports/missing_content", {std::move(root)});
} }
static bool loadWorldContent(Engine* engine, const fs::path& folder) { static bool load_world_content(Engine* engine, const fs::path& folder) {
if (engine->isHeadless()) {
engine->loadWorldContent(folder);
return true;
} else {
return menus::call(engine, [engine, folder]() { return menus::call(engine, [engine, folder]() {
engine->loadWorldContent(folder); engine->loadWorldContent(folder);
}); });
} }
}
static void loadWorld(Engine* engine, const std::shared_ptr<WorldFiles>& worldFiles) { static void load_world(Engine* engine, const std::shared_ptr<WorldFiles>& worldFiles) {
try { try {
auto content = engine->getContent(); auto content = engine->getContent();
auto& packs = engine->getContentPacks(); auto& packs = engine->getContentPacks();
@ -160,7 +165,12 @@ static void loadWorld(Engine* engine, const std::shared_ptr<WorldFiles>& worldFi
void EngineController::openWorld(const std::string& name, bool confirmConvert) { void EngineController::openWorld(const std::string& name, bool confirmConvert) {
auto paths = engine->getPaths(); auto paths = engine->getPaths();
auto folder = paths->getWorldsFolder() / fs::u8path(name); auto folder = paths->getWorldsFolder() / fs::u8path(name);
if (!loadWorldContent(engine, folder)) { auto worldFile = folder / fs::u8path("world.json");
if (!fs::exists(worldFile)) {
throw std::runtime_error(worldFile.u8string() + " does not exists");
}
if (!load_world_content(engine, folder)) {
return; return;
} }
@ -192,7 +202,7 @@ void EngineController::openWorld(const std::string& name, bool confirmConvert) {
} }
return; return;
} }
loadWorld(engine, std::move(worldFiles)); load_world(engine, std::move(worldFiles));
} }
inline uint64_t str2seed(const std::string& seedstr) { inline uint64_t str2seed(const std::string& seedstr) {

View File

@ -5,11 +5,11 @@
using namespace scripting; using namespace scripting;
static int l_uptime(lua::State* L) { static int l_uptime(lua::State* L) {
return lua::pushnumber(L, engine->getUptime()); return lua::pushnumber(L, engine->getTime().getTime());
} }
static int l_delta(lua::State* L) { static int l_delta(lua::State* L) {
return lua::pushnumber(L, engine->getDelta()); return lua::pushnumber(L, engine->getTime().getDelta());
} }
const luaL_Reg timelib[] = { const luaL_Reg timelib[] = {