EngineController draft
This commit is contained in:
parent
79cba1afcb
commit
c47e869bdd
@ -5,19 +5,20 @@
|
||||
#include "assets/AssetsLoader.h"
|
||||
#include "audio/audio.h"
|
||||
#include "coders/GLSLExtension.h"
|
||||
#include "coders/json.h"
|
||||
#include "coders/imageio.h"
|
||||
#include "coders/json.h"
|
||||
#include "content/ContentLoader.h"
|
||||
#include "core_defs.h"
|
||||
#include "files/files.h"
|
||||
#include "frontend/locale/langs.h"
|
||||
#include "frontend/menu/menu.h"
|
||||
#include "frontend/menu/menu.hpp"
|
||||
#include "frontend/screens.h"
|
||||
#include "graphics/core/Batch2D.h"
|
||||
#include "graphics/core/GfxContext.h"
|
||||
#include "graphics/core/ImageData.h"
|
||||
#include "graphics/core/Shader.h"
|
||||
#include "graphics/ui/GUI.h"
|
||||
#include "logic/EngineController.hpp"
|
||||
#include "logic/scripting/scripting.h"
|
||||
#include "util/listutil.h"
|
||||
#include "util/platform.h"
|
||||
@ -57,7 +58,8 @@ inline void create_channel(std::string name, NumberSetting& setting) {
|
||||
|
||||
Engine::Engine(EngineSettings& settings, EnginePaths* paths)
|
||||
: settings(settings), settingsHandler(settings), paths(paths)
|
||||
{
|
||||
{
|
||||
controller = std::make_unique<EngineController>(this);
|
||||
if (Window::initialize(settings.display)){
|
||||
throw initialize_error("could not initialize window");
|
||||
}
|
||||
@ -189,6 +191,10 @@ Engine::~Engine() {
|
||||
logger.info() << "engine finished";
|
||||
}
|
||||
|
||||
EngineController* Engine::getController() {
|
||||
return controller.get();
|
||||
}
|
||||
|
||||
PacksManager Engine::createPacksManager(const fs::path& worldFolder) {
|
||||
PacksManager manager;
|
||||
manager.setSources({
|
||||
|
||||
@ -25,6 +25,7 @@ class Screen;
|
||||
class EnginePaths;
|
||||
class ResPaths;
|
||||
class Batch2D;
|
||||
class EngineController;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
@ -49,6 +50,7 @@ class Engine {
|
||||
std::unique_ptr<ResPaths> resPaths = nullptr;
|
||||
std::queue<runnable> postRunnables;
|
||||
std::recursive_mutex postRunnablesMutex;
|
||||
std::unique_ptr<EngineController> controller;
|
||||
|
||||
uint64_t frame = 0;
|
||||
double lastTime = 0.0;
|
||||
@ -125,6 +127,8 @@ public:
|
||||
|
||||
void saveScreenshot();
|
||||
|
||||
EngineController* getController();
|
||||
|
||||
PacksManager createPacksManager(const fs::path& worldFolder);
|
||||
|
||||
SettingsHandler& getSettingsHandler();
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
#include "ContentGfxCache.h"
|
||||
#include "InventoryView.h"
|
||||
#include "LevelFrontend.h"
|
||||
#include "menu/menu.h"
|
||||
#include "menu/menu.hpp"
|
||||
#include "screens.h"
|
||||
#include "UiDocument.h"
|
||||
|
||||
|
||||
@ -1,60 +1,26 @@
|
||||
#include "menu.h"
|
||||
#include "menu.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "../../interfaces/Task.h"
|
||||
#include "../../graphics/ui/GUI.h"
|
||||
#include "../../graphics/ui/gui_util.h"
|
||||
#include "../../graphics/ui/elements/layout/Menu.hpp"
|
||||
#include "../../graphics/ui/elements/display/Label.hpp"
|
||||
#include "../../graphics/ui/elements/control/Button.hpp"
|
||||
#include "../screens.h"
|
||||
#include "../UiDocument.h"
|
||||
#include "../../logic/scripting/scripting.h"
|
||||
|
||||
#include "../../coders/png.h"
|
||||
#include "../../util/stringutil.h"
|
||||
#include "../../files/engine_paths.h"
|
||||
#include "../../files/WorldConverter.h"
|
||||
#include "../../files/WorldFiles.h"
|
||||
#include "../../world/World.h"
|
||||
#include "../../world/WorldGenerators.h"
|
||||
#include "../../world/Level.h"
|
||||
#include "../../window/Events.h"
|
||||
#include "../../window/Window.h"
|
||||
#include "../../engine.h"
|
||||
#include "../../settings.h"
|
||||
#include "../../delegates.h"
|
||||
#include "../../content/Content.h"
|
||||
#include "../../content/ContentLUT.h"
|
||||
#include "../../content/ContentPack.h"
|
||||
#include "../locale/langs.h"
|
||||
#include "../../engine.h"
|
||||
#include "../../files/engine_paths.h"
|
||||
#include "../../graphics/ui/elements/display/Label.hpp"
|
||||
#include "../../graphics/ui/elements/layout/Menu.hpp"
|
||||
#include "../../graphics/ui/gui_util.h"
|
||||
#include "../../graphics/ui/GUI.h"
|
||||
#include "../../logic/scripting/scripting.h"
|
||||
#include "../../settings.h"
|
||||
#include "../../util/stringutil.h"
|
||||
#include "../../window/Window.h"
|
||||
#include "../UiDocument.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using namespace gui;
|
||||
|
||||
std::shared_ptr<Panel> create_page(
|
||||
Engine* engine,
|
||||
std::string name,
|
||||
int width,
|
||||
float opacity,
|
||||
int interval
|
||||
) {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
auto panel = std::make_shared<Panel>(
|
||||
glm::vec2(width, 200), glm::vec4(8.0f), interval
|
||||
);
|
||||
panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, opacity));
|
||||
menu->addPage(name, panel);
|
||||
return panel;
|
||||
}
|
||||
|
||||
void menus::create_version_label(Engine* engine) {
|
||||
auto gui = engine->getGUI();
|
||||
auto vlabel = std::make_shared<gui::Label>(
|
||||
@ -68,170 +34,7 @@ void menus::create_version_label(Engine* engine) {
|
||||
gui->add(vlabel);
|
||||
}
|
||||
|
||||
static void show_content_missing(
|
||||
Engine* engine,
|
||||
const Content* content,
|
||||
std::shared_ptr<ContentLUT> lut
|
||||
) {
|
||||
auto* gui = engine->getGUI();
|
||||
auto menu = gui->getMenu();
|
||||
auto panel = create_page(engine, "missing-content", 500, 0.5f, 8);
|
||||
|
||||
panel->add(std::make_shared<Label>(langs::get(L"menu.missing-content")));
|
||||
|
||||
auto subpanel = std::dynamic_pointer_cast<Panel>(guiutil::create(
|
||||
"<panel size='480,100' color='#00000080' scrollable='true' max-length='400'>"
|
||||
"</panel>"
|
||||
));
|
||||
panel->add(subpanel);
|
||||
|
||||
for (auto& entry : lut->getMissingContent()) {
|
||||
std::string contentname = contenttype_name(entry.type);
|
||||
auto hpanel = std::dynamic_pointer_cast<Panel>(guiutil::create(
|
||||
"<panel size='500,20' color='0' orientation='horizontal' padding='2'>"
|
||||
"<label color='#80808080'>["+contentname+"]</label>"
|
||||
"<label color='#FF333380'>"+entry.name+"</label>"
|
||||
"</panel>"
|
||||
));
|
||||
subpanel->add(hpanel);
|
||||
}
|
||||
|
||||
panel->add(std::make_shared<Button>(
|
||||
langs::get(L"Back to Main Menu", L"menu"), glm::vec4(8.0f), [=](GUI*){
|
||||
menu->back();
|
||||
}
|
||||
));
|
||||
menu->setPage("missing-content");
|
||||
}
|
||||
|
||||
void show_process_panel(Engine* engine, std::shared_ptr<Task> task, std::wstring text=L"") {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
auto panel = create_page(engine, "process", 400, 0.5f, 1);
|
||||
|
||||
if (!text.empty()) {
|
||||
panel->add(std::make_shared<Label>(langs::get(text)));
|
||||
}
|
||||
|
||||
auto label = std::make_shared<Label>(L"0%");
|
||||
panel->add(label);
|
||||
|
||||
uint initialWork = task->getWorkTotal();
|
||||
|
||||
panel->listenInterval(0.01f, [=]() {
|
||||
task->update();
|
||||
|
||||
uint tasksDone = task->getWorkDone();
|
||||
float progress = tasksDone/static_cast<float>(initialWork);
|
||||
label->setText(
|
||||
std::to_wstring(tasksDone)+
|
||||
L"/"+std::to_wstring(initialWork)+L" ("+
|
||||
std::to_wstring(int(progress*100))+L"%)"
|
||||
);
|
||||
});
|
||||
|
||||
menu->reset();
|
||||
menu->setPage("process", false);
|
||||
}
|
||||
|
||||
std::shared_ptr<Task> create_converter(
|
||||
Engine* engine,
|
||||
fs::path folder,
|
||||
const Content* content,
|
||||
std::shared_ptr<ContentLUT> lut,
|
||||
runnable postRunnable)
|
||||
{
|
||||
return WorldConverter::startTask(folder, content, lut, [=](){
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
menu->reset();
|
||||
menu->setPage("main", false);
|
||||
engine->getGUI()->postRunnable([=]() {
|
||||
postRunnable();
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
void show_convert_request(
|
||||
Engine* engine,
|
||||
const Content* content,
|
||||
std::shared_ptr<ContentLUT> lut,
|
||||
fs::path folder,
|
||||
runnable postRunnable
|
||||
) {
|
||||
guiutil::confirm(engine->getGUI(), langs::get(L"world.convert-request"), [=]() {
|
||||
auto converter = create_converter(engine, folder, content, lut, postRunnable);
|
||||
show_process_panel(engine, converter, L"Converting world...");
|
||||
}, L"", langs::get(L"Cancel"));
|
||||
}
|
||||
|
||||
void menus::open_world(std::string name, Engine* engine, bool confirmConvert) {
|
||||
auto paths = engine->getPaths();
|
||||
auto folder = paths->getWorldsFolder()/fs::u8path(name);
|
||||
try {
|
||||
engine->loadWorldContent(folder);
|
||||
} catch (const contentpack_error& error) {
|
||||
engine->setScreen(std::make_shared<MenuScreen>(engine));
|
||||
// could not to find or read pack
|
||||
guiutil::alert(
|
||||
engine->getGUI(), langs::get(L"error.pack-not-found")+L": "+
|
||||
util::str2wstr_utf8(error.getPackId())
|
||||
);
|
||||
return;
|
||||
} catch (const std::runtime_error& error) {
|
||||
engine->setScreen(std::make_shared<MenuScreen>(engine));
|
||||
guiutil::alert(
|
||||
engine->getGUI(), langs::get(L"Content Error", L"menu")+L": "+
|
||||
util::str2wstr_utf8(error.what())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& packs = engine->getContentPacks();
|
||||
auto* content = engine->getContent();
|
||||
auto& settings = engine->getSettings();
|
||||
|
||||
std::shared_ptr<ContentLUT> lut (World::checkIndices(folder, content));
|
||||
if (lut) {
|
||||
if (lut->hasMissingContent()) {
|
||||
engine->setScreen(std::make_shared<MenuScreen>(engine));
|
||||
show_content_missing(engine, content, lut);
|
||||
} else {
|
||||
if (confirmConvert) {
|
||||
show_process_panel(engine, create_converter(engine, folder, content, lut, [=]() {
|
||||
open_world(name, engine, false);
|
||||
}), L"Converting world...");
|
||||
} else {
|
||||
show_convert_request(engine, content, lut, folder, [=](){
|
||||
open_world(name, engine, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Level* level = World::load(folder, settings, content, packs);
|
||||
level->getWorld()->wfile->createDirectories();
|
||||
engine->setScreen(std::make_shared<LevelScreen>(engine, level));
|
||||
} catch (const world_load_error& error) {
|
||||
guiutil::alert(
|
||||
engine->getGUI(), langs::get(L"Error")+L": "+
|
||||
util::str2wstr_utf8(error.what())
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void menus::delete_world(std::string name, Engine* engine) {
|
||||
fs::path folder = engine->getPaths()->getWorldFolder(name);
|
||||
guiutil::confirm(engine->getGUI(), langs::get(L"delete-confirm", L"world")+
|
||||
L" ("+util::str2wstr_utf8(folder.u8string())+L")", [=]() {
|
||||
std::cout << "deleting " << folder.u8string() << std::endl;
|
||||
fs::remove_all(folder);
|
||||
});
|
||||
}
|
||||
|
||||
void menus::create_menus(Engine* engine) {
|
||||
// create_settings_panel(engine);
|
||||
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
menu->setPageLoader([=](auto name) {
|
||||
auto file = engine->getResPaths()->find("layouts/pages/"+name+".xml");
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
#ifndef FRONTEND_MENU_MENU_H_
|
||||
#define FRONTEND_MENU_MENU_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include "../../content/ContentPack.h"
|
||||
|
||||
namespace gui {
|
||||
class Panel;
|
||||
}
|
||||
|
||||
class Engine;
|
||||
class LevelController;
|
||||
|
||||
using packconsumer = std::function<void(const ContentPack& pack)>;
|
||||
|
||||
namespace menus {
|
||||
/// @brief Load world, convert if required and set to LevelScreen.
|
||||
/// @param name world name
|
||||
/// @param engine engine instance
|
||||
/// @param confirmConvert automatically confirm convert if requested
|
||||
void open_world(std::string name, Engine* engine, bool confirmConvert);
|
||||
|
||||
/// @brief Show world removal confirmation dialog
|
||||
/// @param name world name
|
||||
/// @param engine engine instance
|
||||
void delete_world(std::string name, Engine* engine);
|
||||
|
||||
void remove_packs(
|
||||
Engine* engine,
|
||||
LevelController* controller,
|
||||
std::vector<std::string> packs
|
||||
);
|
||||
|
||||
void add_packs(
|
||||
Engine* engine,
|
||||
LevelController* controller,
|
||||
std::vector<std::string> packs
|
||||
);
|
||||
|
||||
void create_world(
|
||||
Engine* engine,
|
||||
const std::string& name,
|
||||
const std::string& seedstr,
|
||||
const std::string& generatorID
|
||||
);
|
||||
|
||||
/// @brief Create development version label at the top-right screen corner
|
||||
void create_version_label(Engine* engine);
|
||||
void create_menus(Engine* engine);
|
||||
}
|
||||
|
||||
#endif // FRONTEND_MENU_MENU_H_
|
||||
12
src/frontend/menu/menu.hpp
Normal file
12
src/frontend/menu/menu.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef FRONTEND_MENU_MENU_HPP_
|
||||
#define FRONTEND_MENU_MENU_HPP_
|
||||
|
||||
class Engine;
|
||||
|
||||
namespace menus {
|
||||
/// @brief Create development version label at the top-right screen corner
|
||||
void create_version_label(Engine* engine);
|
||||
void create_menus(Engine* engine);
|
||||
}
|
||||
|
||||
#endif // FRONTEND_MENU_MENU_HPP_
|
||||
@ -1,160 +0,0 @@
|
||||
#include "menu.h"
|
||||
|
||||
// TODO: move functions to EngineController
|
||||
|
||||
#include "../../content/PacksManager.h"
|
||||
#include "../../content/ContentLUT.h"
|
||||
#include "../../engine.h"
|
||||
#include "../../files/WorldFiles.h"
|
||||
#include "../../graphics/ui/gui_util.h"
|
||||
#include "../../logic/LevelController.h"
|
||||
#include "../../util/stringutil.h"
|
||||
#include "../../world/Level.h"
|
||||
#include "../../world/World.h"
|
||||
#include "../locale/langs.h"
|
||||
#include "../screens.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
using namespace gui;
|
||||
|
||||
inline uint64_t str2seed(const std::string& seedstr) {
|
||||
if (util::is_integer(seedstr)) {
|
||||
try {
|
||||
return std::stoull(seedstr);
|
||||
} catch (const std::out_of_range& err) {
|
||||
std::hash<std::string> hash;
|
||||
return hash(seedstr);
|
||||
}
|
||||
} else {
|
||||
std::hash<std::string> hash;
|
||||
return hash(seedstr);
|
||||
}
|
||||
}
|
||||
|
||||
void menus::create_world(
|
||||
Engine* engine,
|
||||
const std::string& name,
|
||||
const std::string& seedstr,
|
||||
const std::string& generatorID
|
||||
) {
|
||||
uint64_t seed = str2seed(seedstr);
|
||||
|
||||
EnginePaths* paths = engine->getPaths();
|
||||
auto folder = paths->getWorldsFolder()/fs::u8path(name);
|
||||
try {
|
||||
engine->loadAllPacks();
|
||||
engine->loadContent();
|
||||
paths->setWorldFolder(folder);
|
||||
} catch (const contentpack_error& error) {
|
||||
guiutil::alert(
|
||||
engine->getGUI(),
|
||||
langs::get(L"Content Error", L"menu")+L":\n"+
|
||||
util::str2wstr_utf8(
|
||||
std::string(error.what())+
|
||||
"\npack '"+error.getPackId()+"' from "+
|
||||
error.getFolder().u8string()
|
||||
)
|
||||
);
|
||||
return;
|
||||
} catch (const std::runtime_error& error) {
|
||||
guiutil::alert(
|
||||
engine->getGUI(),
|
||||
langs::get(L"Content Error", L"menu")+
|
||||
L": "+util::str2wstr_utf8(error.what())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Level* level = World::create(
|
||||
name, generatorID, folder, seed,
|
||||
engine->getSettings(),
|
||||
engine->getContent(),
|
||||
engine->getContentPacks()
|
||||
);
|
||||
level->getWorld()->wfile->createDirectories();
|
||||
engine->setScreen(std::make_shared<LevelScreen>(engine, level));
|
||||
}
|
||||
|
||||
static void reopen_world(Engine* engine, World* world) {
|
||||
std::string wname = world->wfile->getFolder().filename().u8string();
|
||||
engine->setScreen(nullptr);
|
||||
engine->setScreen(std::make_shared<MenuScreen>(engine));
|
||||
menus::open_world(wname, engine, true);
|
||||
}
|
||||
|
||||
void menus::remove_packs(
|
||||
Engine* engine,
|
||||
LevelController* controller,
|
||||
std::vector<std::string> packsToRemove
|
||||
) {
|
||||
auto content = engine->getContent();
|
||||
auto world = controller->getLevel()->getWorld();
|
||||
bool hasIndices = false;
|
||||
|
||||
std::stringstream ss;
|
||||
for (const auto& id : packsToRemove) {
|
||||
if (content->getPackRuntime(id)->getStats().hasSavingContent()) {
|
||||
if (hasIndices) {
|
||||
ss << ", ";
|
||||
}
|
||||
hasIndices = true;
|
||||
ss << id;
|
||||
}
|
||||
}
|
||||
|
||||
runnable removeFunc = [=]() {
|
||||
controller->saveWorld();
|
||||
auto manager = engine->createPacksManager(world->wfile->getFolder());
|
||||
manager.scan();
|
||||
|
||||
auto names = PacksManager::getNames(world->getPacks());
|
||||
for (const auto& id : packsToRemove) {
|
||||
manager.exclude(id);
|
||||
names.erase(std::find(names.begin(), names.end(), id));
|
||||
}
|
||||
world->wfile->removeIndices(packsToRemove);
|
||||
world->wfile->writePacks(manager.getAll(names));
|
||||
reopen_world(engine, world);
|
||||
};
|
||||
|
||||
if (hasIndices) {
|
||||
guiutil::confirm(
|
||||
engine->getGUI(),
|
||||
langs::get(L"remove-confirm", L"pack")+
|
||||
L" ("+util::str2wstr_utf8(ss.str())+L")",
|
||||
[=]() {removeFunc();}
|
||||
);
|
||||
} else {
|
||||
removeFunc();
|
||||
}
|
||||
}
|
||||
|
||||
void menus::add_packs(
|
||||
Engine* engine,
|
||||
LevelController* controller,
|
||||
std::vector<std::string> packs
|
||||
) {
|
||||
auto level = controller->getLevel();
|
||||
auto gui = engine->getGUI();
|
||||
auto world = level->getWorld();
|
||||
auto new_packs = PacksManager::getNames(world->getPacks());
|
||||
for (auto& id : packs) {
|
||||
new_packs.push_back(id);
|
||||
}
|
||||
|
||||
auto manager = engine->createPacksManager(world->wfile->getFolder());
|
||||
manager.scan();
|
||||
try {
|
||||
new_packs = manager.assembly(new_packs);
|
||||
} catch (const contentpack_error& err) {
|
||||
guiutil::alert(
|
||||
gui, langs::get(L"error.dependency-not-found")+
|
||||
L": "+util::str2wstr_utf8(err.getPackId())
|
||||
);
|
||||
return;
|
||||
}
|
||||
world->wfile->writePacks(manager.getAll(new_packs));
|
||||
controller->saveWorld();
|
||||
reopen_world(engine, world);
|
||||
}
|
||||
@ -32,7 +32,7 @@
|
||||
#include "ContentGfxCache.h"
|
||||
#include "hud.h"
|
||||
#include "LevelFrontend.h"
|
||||
#include "menu/menu.h"
|
||||
#include "menu/menu.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
342
src/logic/EngineController.cpp
Normal file
342
src/logic/EngineController.cpp
Normal file
@ -0,0 +1,342 @@
|
||||
#include "EngineController.hpp"
|
||||
|
||||
#include "../content/ContentLUT.h"
|
||||
#include "../debug/Logger.h"
|
||||
#include "../engine.h"
|
||||
#include "../files/WorldFiles.h"
|
||||
#include "../files/WorldConverter.h"
|
||||
#include "../frontend/locale/langs.h"
|
||||
#include "../frontend/screens.h"
|
||||
#include "../graphics/ui/elements/display/Label.hpp"
|
||||
#include "../graphics/ui/elements/control/Button.hpp"
|
||||
#include "../graphics/ui/elements/layout/Panel.hpp"
|
||||
#include "../graphics/ui/elements/layout/Menu.hpp"
|
||||
#include "../graphics/ui/gui_util.h"
|
||||
#include "../interfaces/Task.h"
|
||||
#include "../util/stringutil.h"
|
||||
#include "../world/World.h"
|
||||
#include "../world/Level.h"
|
||||
#include "LevelController.h"
|
||||
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static debug::Logger logger("engine-control");
|
||||
|
||||
EngineController::EngineController(Engine* engine) : engine(engine) {
|
||||
}
|
||||
|
||||
void EngineController::deleteWorld(std::string name) {
|
||||
fs::path folder = engine->getPaths()->getWorldFolder(name);
|
||||
guiutil::confirm(engine->getGUI(), langs::get(L"delete-confirm", L"world")+
|
||||
L" ("+util::str2wstr_utf8(folder.u8string())+L")", [=]() {
|
||||
logger.info() << "deleting " << folder.u8string();
|
||||
fs::remove_all(folder);
|
||||
});
|
||||
}
|
||||
|
||||
static std::shared_ptr<gui::Panel> create_page(
|
||||
Engine* engine,
|
||||
std::string name,
|
||||
int width,
|
||||
float opacity,
|
||||
int interval
|
||||
) {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
auto panel = std::make_shared<gui::Panel>(
|
||||
glm::vec2(width, 200), glm::vec4(8.0f), interval
|
||||
);
|
||||
panel->setColor(glm::vec4(0.0f, 0.0f, 0.0f, opacity));
|
||||
menu->addPage(name, panel);
|
||||
return panel;
|
||||
}
|
||||
|
||||
void show_process_panel(Engine* engine, std::shared_ptr<Task> task, std::wstring text=L"") {
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
auto panel = create_page(engine, "process", 400, 0.5f, 1);
|
||||
|
||||
if (!text.empty()) {
|
||||
panel->add(std::make_shared<gui::Label>(langs::get(text)));
|
||||
}
|
||||
|
||||
auto label = std::make_shared<gui::Label>(L"0%");
|
||||
panel->add(label);
|
||||
|
||||
uint initialWork = task->getWorkTotal();
|
||||
|
||||
panel->listenInterval(0.01f, [=]() {
|
||||
task->update();
|
||||
|
||||
uint tasksDone = task->getWorkDone();
|
||||
float progress = tasksDone/static_cast<float>(initialWork);
|
||||
label->setText(
|
||||
std::to_wstring(tasksDone)+
|
||||
L"/"+std::to_wstring(initialWork)+L" ("+
|
||||
std::to_wstring(int(progress*100))+L"%)"
|
||||
);
|
||||
});
|
||||
|
||||
menu->reset();
|
||||
menu->setPage("process", false);
|
||||
}
|
||||
|
||||
std::shared_ptr<Task> create_converter(
|
||||
Engine* engine,
|
||||
fs::path folder,
|
||||
const Content* content,
|
||||
std::shared_ptr<ContentLUT> lut,
|
||||
runnable postRunnable)
|
||||
{
|
||||
return WorldConverter::startTask(folder, content, lut, [=](){
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
menu->reset();
|
||||
menu->setPage("main", false);
|
||||
engine->getGUI()->postRunnable([=]() {
|
||||
postRunnable();
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
void show_convert_request(
|
||||
Engine* engine,
|
||||
const Content* content,
|
||||
std::shared_ptr<ContentLUT> lut,
|
||||
fs::path folder,
|
||||
runnable postRunnable
|
||||
) {
|
||||
guiutil::confirm(engine->getGUI(), langs::get(L"world.convert-request"), [=]() {
|
||||
auto converter = create_converter(engine, folder, content, lut, postRunnable);
|
||||
show_process_panel(engine, converter, L"Converting world...");
|
||||
}, L"", langs::get(L"Cancel"));
|
||||
}
|
||||
|
||||
static void show_content_missing(
|
||||
Engine* engine,
|
||||
const Content* content,
|
||||
std::shared_ptr<ContentLUT> lut
|
||||
) {
|
||||
auto* gui = engine->getGUI();
|
||||
auto menu = gui->getMenu();
|
||||
auto panel = create_page(engine, "missing-content", 500, 0.5f, 8);
|
||||
|
||||
panel->add(std::make_shared<gui::Label>(langs::get(L"menu.missing-content")));
|
||||
|
||||
auto subpanel = std::dynamic_pointer_cast<gui::Panel>(guiutil::create(
|
||||
"<panel size='480,100' color='#00000080' scrollable='true' max-length='400'>"
|
||||
"</panel>"
|
||||
));
|
||||
panel->add(subpanel);
|
||||
|
||||
for (auto& entry : lut->getMissingContent()) {
|
||||
std::string contentname = contenttype_name(entry.type);
|
||||
auto hpanel = std::dynamic_pointer_cast<gui::Panel>(guiutil::create(
|
||||
"<panel size='500,20' color='0' orientation='horizontal' padding='2'>"
|
||||
"<label color='#80808080'>["+contentname+"]</label>"
|
||||
"<label color='#FF333380'>"+entry.name+"</label>"
|
||||
"</panel>"
|
||||
));
|
||||
subpanel->add(hpanel);
|
||||
}
|
||||
|
||||
panel->add(std::make_shared<gui::Button>(
|
||||
langs::get(L"Back to Main Menu", L"menu"), glm::vec4(8.0f), [=](auto){
|
||||
menu->back();
|
||||
}
|
||||
));
|
||||
menu->setPage("missing-content");
|
||||
}
|
||||
|
||||
void EngineController::openWorld(std::string name, bool confirmConvert) {
|
||||
auto paths = engine->getPaths();
|
||||
auto folder = paths->getWorldsFolder()/fs::u8path(name);
|
||||
try {
|
||||
engine->loadWorldContent(folder);
|
||||
} catch (const contentpack_error& error) {
|
||||
engine->setScreen(std::make_shared<MenuScreen>(engine));
|
||||
// could not to find or read pack
|
||||
guiutil::alert(
|
||||
engine->getGUI(), langs::get(L"error.pack-not-found")+L": "+
|
||||
util::str2wstr_utf8(error.getPackId())
|
||||
);
|
||||
return;
|
||||
} catch (const std::runtime_error& error) {
|
||||
engine->setScreen(std::make_shared<MenuScreen>(engine));
|
||||
guiutil::alert(
|
||||
engine->getGUI(), langs::get(L"Content Error", L"menu")+L": "+
|
||||
util::str2wstr_utf8(error.what())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& packs = engine->getContentPacks();
|
||||
auto* content = engine->getContent();
|
||||
auto& settings = engine->getSettings();
|
||||
|
||||
std::shared_ptr<ContentLUT> lut (World::checkIndices(folder, content));
|
||||
if (lut) {
|
||||
if (lut->hasMissingContent()) {
|
||||
engine->setScreen(std::make_shared<MenuScreen>(engine));
|
||||
show_content_missing(engine, content, lut);
|
||||
} else {
|
||||
if (confirmConvert) {
|
||||
show_process_panel(engine, create_converter(engine, folder, content, lut, [=]() {
|
||||
openWorld(name, false);
|
||||
}), L"Converting world...");
|
||||
} else {
|
||||
show_convert_request(engine, content, lut, folder, [=](){
|
||||
openWorld(name, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Level* level = World::load(folder, settings, content, packs);
|
||||
engine->setScreen(std::make_shared<LevelScreen>(engine, level));
|
||||
} catch (const world_load_error& error) {
|
||||
guiutil::alert(
|
||||
engine->getGUI(), langs::get(L"Error")+L": "+
|
||||
util::str2wstr_utf8(error.what())
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline uint64_t str2seed(const std::string& seedstr) {
|
||||
if (util::is_integer(seedstr)) {
|
||||
try {
|
||||
return std::stoull(seedstr);
|
||||
} catch (const std::out_of_range& err) {
|
||||
std::hash<std::string> hash;
|
||||
return hash(seedstr);
|
||||
}
|
||||
} else {
|
||||
std::hash<std::string> hash;
|
||||
return hash(seedstr);
|
||||
}
|
||||
}
|
||||
|
||||
void EngineController::createWorld(
|
||||
const std::string& name,
|
||||
const std::string& seedstr,
|
||||
const std::string& generatorID
|
||||
) {
|
||||
uint64_t seed = str2seed(seedstr);
|
||||
|
||||
EnginePaths* paths = engine->getPaths();
|
||||
auto folder = paths->getWorldsFolder()/fs::u8path(name);
|
||||
try {
|
||||
engine->loadAllPacks();
|
||||
engine->loadContent();
|
||||
paths->setWorldFolder(folder);
|
||||
} catch (const contentpack_error& error) {
|
||||
guiutil::alert(
|
||||
engine->getGUI(),
|
||||
langs::get(L"Content Error", L"menu")+L":\n"+
|
||||
util::str2wstr_utf8(
|
||||
std::string(error.what())+
|
||||
"\npack '"+error.getPackId()+"' from "+
|
||||
error.getFolder().u8string()
|
||||
)
|
||||
);
|
||||
return;
|
||||
} catch (const std::runtime_error& error) {
|
||||
guiutil::alert(
|
||||
engine->getGUI(),
|
||||
langs::get(L"Content Error", L"menu")+
|
||||
L": "+util::str2wstr_utf8(error.what())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Level* level = World::create(
|
||||
name, generatorID, folder, seed,
|
||||
engine->getSettings(),
|
||||
engine->getContent(),
|
||||
engine->getContentPacks()
|
||||
);
|
||||
engine->setScreen(std::make_shared<LevelScreen>(engine, level));
|
||||
}
|
||||
|
||||
void EngineController::reopenWorld(World* world) {
|
||||
std::string wname = world->wfile->getFolder().filename().u8string();
|
||||
engine->setScreen(nullptr);
|
||||
engine->setScreen(std::make_shared<MenuScreen>(engine));
|
||||
openWorld(wname, true);
|
||||
}
|
||||
|
||||
void EngineController::removePacks(
|
||||
LevelController* controller,
|
||||
std::vector<std::string> packsToRemove
|
||||
) {
|
||||
auto content = engine->getContent();
|
||||
auto world = controller->getLevel()->getWorld();
|
||||
bool hasIndices = false;
|
||||
|
||||
std::stringstream ss;
|
||||
for (const auto& id : packsToRemove) {
|
||||
if (content->getPackRuntime(id)->getStats().hasSavingContent()) {
|
||||
if (hasIndices) {
|
||||
ss << ", ";
|
||||
}
|
||||
hasIndices = true;
|
||||
ss << id;
|
||||
}
|
||||
}
|
||||
|
||||
runnable removeFunc = [=]() {
|
||||
controller->saveWorld();
|
||||
auto manager = engine->createPacksManager(world->wfile->getFolder());
|
||||
manager.scan();
|
||||
|
||||
auto names = PacksManager::getNames(world->getPacks());
|
||||
for (const auto& id : packsToRemove) {
|
||||
manager.exclude(id);
|
||||
names.erase(std::find(names.begin(), names.end(), id));
|
||||
}
|
||||
world->wfile->removeIndices(packsToRemove);
|
||||
world->wfile->writePacks(manager.getAll(names));
|
||||
reopenWorld(world);
|
||||
};
|
||||
|
||||
if (hasIndices) {
|
||||
guiutil::confirm(
|
||||
engine->getGUI(),
|
||||
langs::get(L"remove-confirm", L"pack")+
|
||||
L" ("+util::str2wstr_utf8(ss.str())+L")",
|
||||
[=]() {removeFunc();}
|
||||
);
|
||||
} else {
|
||||
removeFunc();
|
||||
}
|
||||
}
|
||||
|
||||
void EngineController::addPacks(
|
||||
LevelController* controller,
|
||||
std::vector<std::string> packs
|
||||
) {
|
||||
auto level = controller->getLevel();
|
||||
auto gui = engine->getGUI();
|
||||
auto world = level->getWorld();
|
||||
auto new_packs = PacksManager::getNames(world->getPacks());
|
||||
for (auto& id : packs) {
|
||||
new_packs.push_back(id);
|
||||
}
|
||||
|
||||
auto manager = engine->createPacksManager(world->wfile->getFolder());
|
||||
manager.scan();
|
||||
try {
|
||||
new_packs = manager.assembly(new_packs);
|
||||
} catch (const contentpack_error& err) {
|
||||
guiutil::alert(
|
||||
gui, langs::get(L"error.dependency-not-found")+
|
||||
L": "+util::str2wstr_utf8(err.getPackId())
|
||||
);
|
||||
return;
|
||||
}
|
||||
world->wfile->writePacks(manager.getAll(new_packs));
|
||||
controller->saveWorld();
|
||||
reopenWorld(world);
|
||||
}
|
||||
44
src/logic/EngineController.hpp
Normal file
44
src/logic/EngineController.hpp
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef LOGIC_ENGINE_CONTROLLER_HPP_
|
||||
#define LOGIC_ENGINE_CONTROLLER_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Engine;
|
||||
class World;
|
||||
class LevelController;
|
||||
|
||||
class EngineController {
|
||||
Engine* engine;
|
||||
public:
|
||||
EngineController(Engine* engine);
|
||||
|
||||
/// @brief Load world, convert if required and set to LevelScreen.
|
||||
/// @param name world name
|
||||
/// @param confirmConvert automatically confirm convert if requested
|
||||
void openWorld(std::string name, bool confirmConvert);
|
||||
|
||||
/// @brief Show world removal confirmation dialog
|
||||
/// @param name world name
|
||||
void deleteWorld(std::string name);
|
||||
|
||||
void removePacks(
|
||||
LevelController* controller,
|
||||
std::vector<std::string> packs
|
||||
);
|
||||
|
||||
void addPacks(
|
||||
LevelController* controller,
|
||||
std::vector<std::string> packs
|
||||
);
|
||||
|
||||
void createWorld(
|
||||
const std::string& name,
|
||||
const std::string& seedstr,
|
||||
const std::string& generatorID
|
||||
);
|
||||
|
||||
void reopenWorld(World* world);
|
||||
};
|
||||
|
||||
#endif // LOGIC_ENGINE_CONTROLLER_HPP_
|
||||
@ -3,9 +3,10 @@
|
||||
|
||||
#include "../../../engine.h"
|
||||
#include "../../../files/engine_paths.h"
|
||||
#include "../../../frontend/menu/menu.h"
|
||||
#include "../../../frontend/menu/menu.hpp"
|
||||
#include "../../../frontend/screens.h"
|
||||
#include "../../../logic/LevelController.h"
|
||||
#include "../../../logic/EngineController.hpp"
|
||||
#include "../../../window/Events.h"
|
||||
#include "../../../window/Window.h"
|
||||
#include "../../../world/WorldGenerators.h"
|
||||
@ -34,14 +35,16 @@ static int l_new_world(lua_State* L) {
|
||||
auto name = lua_tostring(L, 1);
|
||||
auto seed = lua_tostring(L, 2);
|
||||
auto generator = lua_tostring(L, 3);
|
||||
menus::create_world(scripting::engine, name, seed, generator);
|
||||
auto controller = scripting::engine->getController();
|
||||
controller->createWorld(name, seed, generator);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_open_world(lua_State* L) {
|
||||
auto name = lua_tostring(L, 1);
|
||||
scripting::engine->setScreen(nullptr);
|
||||
menus::open_world(name, scripting::engine, false);
|
||||
|
||||
auto controller = scripting::engine->getController();
|
||||
controller->openWorld(name, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -62,7 +65,8 @@ static int l_close_world(lua_State* L) {
|
||||
|
||||
static int l_delete_world(lua_State* L) {
|
||||
auto name = lua_tostring(L, 1);
|
||||
menus::delete_world(name, scripting::engine);
|
||||
auto controller = scripting::engine->getController();
|
||||
controller->deleteWorld(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -77,7 +81,8 @@ static int l_remove_packs(lua_State* L) {
|
||||
packs.push_back(lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
menus::remove_packs(scripting::engine, scripting::controller, packs);
|
||||
auto controller = scripting::engine->getController();
|
||||
controller->removePacks(scripting::controller, packs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -92,7 +97,8 @@ static int l_add_packs(lua_State* L) {
|
||||
packs.push_back(lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
menus::add_packs(scripting::engine, scripting::controller, packs);
|
||||
auto controller = scripting::engine->getController();
|
||||
controller->addPacks(scripting::controller, packs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user