refactor EngineController

This commit is contained in:
MihailRis
2025-04-02 15:01:24 +03:00
parent 4d1a2b3764
commit 45ccf893ae
7 changed files with 179 additions and 175 deletions
-4
View File
@@ -69,10 +69,6 @@ void ContentGfxCache::refresh() {
ContentGfxCache::~ContentGfxCache() = default; ContentGfxCache::~ContentGfxCache() = default;
const Content* ContentGfxCache::getContent() const {
return &content;
}
const model::Model& ContentGfxCache::getModel(blockid_t id) const { const model::Model& ContentGfxCache::getModel(blockid_t id) const {
const auto& found = models.find(id); const auto& found = models.find(id);
if (found == models.end()) { if (found == models.end()) {
-2
View File
@@ -38,8 +38,6 @@ public:
const model::Model& getModel(blockid_t id) const; const model::Model& getModel(blockid_t id) const;
const Content* getContent() const;
void refresh(const Block& block, const Atlas& atlas); void refresh(const Block& block, const Atlas& atlas);
void refresh(); void refresh();
-8
View File
@@ -101,14 +101,6 @@ Level& LevelFrontend::getLevel() {
return level; return level;
} }
const Level& LevelFrontend::getLevel() const {
return level;
}
const Assets& LevelFrontend::getAssets() const {
return assets;
}
ContentGfxCache& LevelFrontend::getContentGfxCache() { ContentGfxCache& LevelFrontend::getContentGfxCache() {
return *contentCache; return *contentCache;
} }
-2
View File
@@ -25,8 +25,6 @@ public:
~LevelFrontend(); ~LevelFrontend();
Level& getLevel(); Level& getLevel();
const Level& getLevel() const;
const Assets& getAssets() const;
const ContentGfxCache& getContentGfxCache() const; const ContentGfxCache& getContentGfxCache() const;
ContentGfxCache& getContentGfxCache(); ContentGfxCache& getContentGfxCache();
LevelController* getController() const; LevelController* getController() const;
+5 -6
View File
@@ -32,13 +32,12 @@ void menus::create_version_label(gui::GUI& gui) {
)); ));
} }
bool menus::call(Engine& engine, runnable func) { void menus::call(Engine& engine, runnable func) {
if (engine.isHeadless()) { if (engine.isHeadless()) {
throw std::runtime_error("menus::call(...) in headless mode"); throw std::runtime_error("menus::call(...) in headless mode");
} }
try { try {
func(); func();
return true;
} catch (const contentpack_error& error) { } catch (const contentpack_error& error) {
engine.setScreen(std::make_shared<MenuScreen>(engine)); engine.setScreen(std::make_shared<MenuScreen>(engine));
// could not to find or read pack // could not to find or read pack
@@ -47,7 +46,7 @@ bool menus::call(Engine& engine, runnable func) {
langs::get(L"error.pack-not-found") + L": " + langs::get(L"error.pack-not-found") + L": " +
util::str2wstr_utf8(error.getPackId()) util::str2wstr_utf8(error.getPackId())
); );
return false; throw std::runtime_error(error);
} catch (const assetload::error& error) { } catch (const assetload::error& error) {
engine.setScreen(std::make_shared<MenuScreen>(engine)); engine.setScreen(std::make_shared<MenuScreen>(engine));
guiutil::alert( guiutil::alert(
@@ -55,11 +54,11 @@ bool menus::call(Engine& engine, runnable func) {
langs::get(L"Assets Load Error", L"menu") + L":\n" + langs::get(L"Assets Load Error", L"menu") + L":\n" +
util::str2wstr_utf8(error.what()) util::str2wstr_utf8(error.what())
); );
return false; throw std::runtime_error(error);
} catch (const parsing_error& error) { } catch (const parsing_error& error) {
engine.setScreen(std::make_shared<MenuScreen>(engine)); engine.setScreen(std::make_shared<MenuScreen>(engine));
guiutil::alert(engine, util::str2wstr_utf8(error.errorLog())); guiutil::alert(engine, util::str2wstr_utf8(error.errorLog()));
return false; throw std::runtime_error(error);
} catch (const std::runtime_error& error) { } catch (const std::runtime_error& error) {
engine.setScreen(std::make_shared<MenuScreen>(engine)); engine.setScreen(std::make_shared<MenuScreen>(engine));
guiutil::alert( guiutil::alert(
@@ -67,7 +66,7 @@ bool menus::call(Engine& engine, runnable func) {
langs::get(L"Content Error", L"menu") + L":\n" + langs::get(L"Content Error", L"menu") + L":\n" +
util::str2wstr_utf8(error.what()) util::str2wstr_utf8(error.what())
); );
return false; throw std::runtime_error(error);
} }
} }
+1 -1
View File
@@ -32,5 +32,5 @@ namespace menus {
const std::wstring& text = L"" const std::wstring& text = L""
); );
bool call(Engine& engine, runnable func); void call(Engine& engine, runnable func);
} }
+173 -152
View File
@@ -1,7 +1,6 @@
#include "EngineController.hpp" #include "EngineController.hpp"
#include <algorithm> #include <algorithm>
#include <filesystem>
#include <memory> #include <memory>
#include "engine/Engine.hpp" #include "engine/Engine.hpp"
@@ -26,12 +25,9 @@
#include "world/World.hpp" #include "world/World.hpp"
#include "LevelController.hpp" #include "LevelController.hpp"
namespace fs = std::filesystem;
static debug::Logger logger("engine-control"); static debug::Logger logger("engine-control");
EngineController::EngineController(Engine& engine) : engine(engine) { EngineController::EngineController(Engine& engine) : engine(engine) {}
}
void EngineController::deleteWorld(const std::string& name) { void EngineController::deleteWorld(const std::string& name) {
io::path folder = engine.getPaths().getWorldFolderByName(name); io::path folder = engine.getPaths().getWorldFolderByName(name);
@@ -83,65 +79,66 @@ std::shared_ptr<Task> create_converter(
); );
} }
static void show_convert_request( struct ConfirmRequest {
Engine& engine, bool memo;
const Content* content, std::wstring message;
const std::shared_ptr<ContentReport>& report, std::wstring text;
const std::shared_ptr<WorldFiles>& worldFiles, };
const runnable& postRunnable
) {
auto on_confirm = [&engine, worldFiles, content, report, postRunnable]() {
auto converter =
create_converter(engine, worldFiles, content, report, postRunnable);
menus::show_process_panel(
engine, converter, L"Converting world..."
);
};
std::wstring message = L"world.convert-block-layouts"; static ConfirmRequest create_convert_request(
const std::shared_ptr<ContentReport>& report
) {
ConfirmRequest request {false, L"", L""};
request.message = L"world.convert-block-layouts";
if (report->hasContentReorder()) { if (report->hasContentReorder()) {
message = L"world.convert-request"; request.message = L"world.convert-request";
} }
if (report->isUpgradeRequired()) { if (report->isUpgradeRequired()) {
message = L"world.upgrade-request"; request.message = L"world.upgrade-request";
} else if (report->hasDataLoss()) { } else if (report->hasDataLoss()) {
message = L"world.convert-with-loss"; request.message = L"world.convert-with-loss";
std::wstring text; request.memo = true;
for (const auto& line : report->getDataLoss()) { for (const auto& line : report->getDataLoss()) {
text += util::str2wstr_utf8(line) + L"\n"; request.text += util::str2wstr_utf8(line) + L"\n";
} }
guiutil::confirm_with_memo(
engine,
langs::get(message),
text,
on_confirm,
L"",
langs::get(L"Cancel")
);
return;
} }
guiutil::confirm( return request;
engine,
langs::get(message),
on_confirm,
nullptr,
L"",
langs::get(L"Cancel")
);
} }
static bool load_world_content(Engine& engine, const io::path& folder) { static void call(Engine& engine, runnable func) {
if (engine.isHeadless()) {
func();
} else {
menus::call(engine, std::move(func));
}
}
static void start(Engine& engine, std::shared_ptr<Task> task, const std::wstring& message) {
if (engine.isHeadless()) {
task->waitForEnd();
} else {
menus::show_process_panel(engine, task, message);
}
}
static void check_world(const EnginePaths& paths, const io::path& folder) {
auto worldFile = folder / "world.json";
if (!io::exists(worldFile)) {
throw std::runtime_error(worldFile.string() + " does not exists");
}
}
static const Content* load_world_content(Engine& engine, const io::path& folder) {
auto& paths = engine.getPaths(); auto& paths = engine.getPaths();
auto& contentControl = engine.getContentControl(); auto& contentControl = engine.getContentControl();
paths.setCurrentWorldFolder(folder); paths.setCurrentWorldFolder(folder);
if (engine.isHeadless()) {
check_world(paths, folder);
call(engine, [&contentControl]() {
contentControl.loadContent(ContentPack::worldPacksList("world:")); contentControl.loadContent(ContentPack::worldPacksList("world:"));
return true; });
} else { return contentControl.get();
return menus::call(engine, [&contentControl]() {
contentControl.loadContent(ContentPack::worldPacksList("world:"));
});
}
} }
static void load_world( static void load_world(
@@ -149,21 +146,15 @@ static void load_world(
const std::shared_ptr<WorldFiles>& worldFiles, const std::shared_ptr<WorldFiles>& worldFiles,
int64_t localPlayer int64_t localPlayer
) { ) {
try { call(engine, [&engine, worldFiles, localPlayer] () {
auto& contentControl = engine.getContentControl(); auto& contentControl = engine.getContentControl();
auto content = contentControl.get(); auto content = contentControl.get();
auto& packs = contentControl.getContentPacks(); const auto& packs = contentControl.getContentPacks();
auto& settings = engine.getSettings(); auto& settings = engine.getSettings();
auto level = World::load(worldFiles, settings, *content, packs); auto level = World::load(worldFiles, settings, *content, packs);
engine.onWorldOpen(std::move(level), localPlayer); engine.onWorldOpen(std::move(level), localPlayer);
} catch (const world_load_error& error) { });
guiutil::alert(
engine,
langs::get(L"Error") + L": " + util::str2wstr_utf8(error.what())
);
return;
}
} }
static dv::value create_missing_content_report( static dv::value create_missing_content_report(
@@ -180,7 +171,9 @@ static dv::value create_missing_content_report(
return root; return root;
} }
void EngineController::onMissingContent(const std::shared_ptr<ContentReport>& report) { void EngineController::onMissingContent(
const std::shared_ptr<ContentReport>& report
) {
if (engine.isHeadless()) { if (engine.isHeadless()) {
throw std::runtime_error( throw std::runtime_error(
"missing content: " + "missing content: " +
@@ -196,50 +189,63 @@ void EngineController::onMissingContent(const std::shared_ptr<ContentReport>& re
} }
} }
static void confirm(
Engine& engine, ConfirmRequest request, bool confirmed, runnable callback
) {
if (confirmed || engine.isHeadless()) {
callback();
return;
}
if (request.memo) {
guiutil::confirm_with_memo(
engine,
langs::get(request.message),
request.text,
callback,
L"",
langs::get(L"Cancel")
);
} else {
guiutil::confirm(
engine,
langs::get(request.message),
callback,
nullptr,
L"",
langs::get(L"Cancel")
);
}
}
void EngineController::openWorld(const std::string& name, bool confirmConvert) { void EngineController::openWorld(const std::string& name, bool confirmConvert) {
const auto& paths = engine.getPaths(); const auto& paths = engine.getPaths();
auto& debugSettings = engine.getSettings().debug;
auto folder = paths.getWorldsFolder() / name; auto folder = paths.getWorldsFolder() / name;
auto worldFile = folder / "world.json";
if (!io::exists(worldFile)) {
throw std::runtime_error(worldFile.string() + " does not exists");
}
if (!load_world_content(engine, folder)) { auto content = load_world_content(engine, folder);
auto worldFiles = std::make_shared<WorldFiles>(folder, debugSettings);
auto report = World::checkIndices(worldFiles, content);
if (report == nullptr) {
load_world(engine, std::move(worldFiles), localPlayer);
return;
}
if (report->hasMissingContent()) {
onMissingContent(report);
return; return;
} }
const auto& contentControl = engine.getContentControl(); auto request = create_convert_request(report);
const Content* content = contentControl.get(); confirm(engine, std::move(request), confirmConvert, [=]() {
auto worldFiles = std::make_shared<WorldFiles>( auto task = create_converter(
folder, engine.getSettings().debug); engine,
if (auto report = World::checkIndices(worldFiles, content)) { worldFiles,
if (report->hasMissingContent()) { content,
onMissingContent(report); report,
} else { [=]() { openWorld(name, false); }
if (confirmConvert) { );
auto task = create_converter( start(engine, std::move(task), L"Converting world...");
engine, });
worldFiles,
content,
report,
[=]() { openWorld(name, false); }
);
if (engine.isHeadless()) {
task->waitForEnd();
} else {
menus::show_process_panel(
engine, task, L"Converting world..."
);
}
} else {
show_convert_request(engine, content, report, std::move(worldFiles), [=]() {
openWorld(name, false);
});
}
}
return;
}
load_world(engine, std::move(worldFiles), localPlayer);
} }
inline uint64_t str2seed(const std::string& seedstr) { inline uint64_t str2seed(const std::string& seedstr) {
@@ -266,15 +272,11 @@ void EngineController::createWorld(
EnginePaths& paths = engine.getPaths(); EnginePaths& paths = engine.getPaths();
auto folder = paths.getWorldsFolder() / name; auto folder = paths.getWorldsFolder() / name;
if (engine.isHeadless()) { call(engine, [this, &paths, folder]() {
engine.getContentControl().loadContent(); engine.getContentControl().loadContent();
paths.setCurrentWorldFolder(folder); paths.setCurrentWorldFolder(folder);
} else if (!menus::call(engine, [this, &paths, folder]() { });
engine.getContentControl().loadContent();
paths.setCurrentWorldFolder(folder);
})) {
return;
}
auto& contentControl = engine.getContentControl(); auto& contentControl = engine.getContentControl();
auto level = World::create( auto level = World::create(
name, name,
@@ -301,6 +303,48 @@ void EngineController::reopenWorld(World* world) {
openWorld(name, true); openWorld(name, true);
} }
static void reconfig_packs_outside(
ContentControl& contentControl,
const std::vector<std::string>& packsToAdd,
const std::vector<std::string>& packsToRemove
) {
auto& manager = contentControl.scan();
auto names = PacksManager::getNames(
contentControl.getContentPacks()
);
for (const auto& id : packsToAdd) {
names.push_back(id);
}
for (const auto& id : packsToRemove) {
manager.exclude(id);
names.erase(std::find(names.begin(), names.end(), id));
}
names = manager.assemble(names);
contentControl.getContentPacks() = manager.getAll(names);
}
static void reconfig_packs_inside(
PacksManager& manager,
std::vector<std::string>& names,
const std::vector<std::string>& packsToAdd,
const std::vector<std::string>& packsToRemove
) {
for (const auto& id : packsToAdd) {
names.push_back(id);
}
for (const auto& id : packsToRemove) {
manager.exclude(id);
const auto& found = std::find(names.begin(), names.end(), id);
if (found != names.end()) {
names.erase(found);
} else {
logger.warning()
<< "attempt to remove non-installed pack: " << id;
}
}
}
void EngineController::reconfigPacks( void EngineController::reconfigPacks(
LevelController* controller, LevelController* controller,
const std::vector<std::string>& packsToAdd, const std::vector<std::string>& packsToAdd,
@@ -308,8 +352,32 @@ void EngineController::reconfigPacks(
) { ) {
auto& contentControl = engine.getContentControl(); auto& contentControl = engine.getContentControl();
auto content = contentControl.get(); auto content = contentControl.get();
bool hasIndices = false;
runnable removeFunc = [this, controller, packsToAdd, packsToRemove, &contentControl]() {
if (controller == nullptr) {
try {
reconfig_packs_outside(contentControl, packsToAdd, packsToRemove);
} catch (const contentpack_error& err) {
throw std::runtime_error(
std::string(err.what()) + " [" + err.getPackId() + "]"
);
}
} else {
auto world = controller->getLevel()->getWorld();
controller->saveWorld();
auto names = PacksManager::getNames(world->getPacks());
auto& manager = contentControl.scan();
reconfig_packs_inside(manager, names, packsToAdd, packsToRemove);
auto& wfile = *world->wfile;
wfile.removeIndices(packsToRemove);
wfile.writePacks(manager.getAll(names));
reopenWorld(world);
}
};
bool hasIndices = false;
std::stringstream ss; std::stringstream ss;
if (content) { if (content) {
for (const auto& id : packsToRemove) { for (const auto& id : packsToRemove) {
@@ -323,53 +391,6 @@ void EngineController::reconfigPacks(
} }
} }
} }
runnable removeFunc = [this, controller, packsToAdd, packsToRemove, &contentControl]() {
auto& manager = contentControl.scan();
if (controller == nullptr) {
try {
auto names = PacksManager::getNames(
engine.getContentControl().getContentPacks()
);
for (const auto& id : packsToAdd) {
names.push_back(id);
}
for (const auto& id : packsToRemove) {
manager.exclude(id);
names.erase(std::find(names.begin(), names.end(), id));
}
names = manager.assemble(names);
engine.getContentControl().getContentPacks() = manager.getAll(names);
} catch (const contentpack_error& err) {
throw std::runtime_error(
std::string(err.what()) + " [" + err.getPackId() + "]"
);
}
} else {
auto world = controller->getLevel()->getWorld();
auto& wfile = *world->wfile;
controller->saveWorld();
auto names = PacksManager::getNames(world->getPacks());
for (const auto& id : packsToAdd) {
names.push_back(id);
}
for (const auto& id : packsToRemove) {
manager.exclude(id);
const auto& found = std::find(names.begin(), names.end(), id);
if (found != names.end()) {
names.erase(found);
} else {
logger.warning()
<< "attempt to remove non-installed pack: " << id;
}
}
wfile.removeIndices(packsToRemove);
wfile.writePacks(manager.getAll(names));
reopenWorld(world);
}
};
if (hasIndices && !engine.isHeadless()) { if (hasIndices && !engine.isHeadless()) {
guiutil::confirm( guiutil::confirm(
engine, engine,