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) {
fs::path listfile = folder / fs::path("packs.list");
if (!fs::is_regular_file(listfile)) {
std::cerr << "warning: packs.list not found (will be created)";
std::cerr << std::endl;
files::write_string(listfile, "# autogenerated, do not modify\nbase\n");
throw std::runtime_error("missing file 'packs.list'");
}
return files::read_list(listfile);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -13,6 +13,7 @@ class Viewport;
class DrawContext;
class Assets;
class Camera;
class Batch2D;
/*
Some info about padding and margin.
@ -52,6 +53,7 @@ namespace gui {
/// @brief The main UI controller
class GUI {
std::unique_ptr<Batch2D> batch2D;
std::shared_ptr<Container> container;
std::shared_ptr<UINode> hover;
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)});
}
static bool loadWorldContent(Engine* engine, const fs::path& folder) {
return menus::call(engine, [engine, 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]() {
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 {
auto content = engine->getContent();
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) {
auto paths = engine->getPaths();
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;
}
@ -192,7 +202,7 @@ void EngineController::openWorld(const std::string& name, bool confirmConvert) {
}
return;
}
loadWorld(engine, std::move(worldFiles));
load_world(engine, std::move(worldFiles));
}
inline uint64_t str2seed(const std::string& seedstr) {

View File

@ -5,11 +5,11 @@
using namespace scripting;
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) {
return lua::pushnumber(L, engine->getDelta());
return lua::pushnumber(L, engine->getTime().getDelta());
}
const luaL_Reg timelib[] = {