Task interface

This commit is contained in:
MihailRis
2024-04-05 14:19:02 +03:00
parent 84c7c16860
commit c1ab97eb15
5 changed files with 102 additions and 28 deletions
+6 -1
View File
@@ -77,6 +77,7 @@ void WorldConverter::convertNext() {
} }
convert_task task = tasks.front(); convert_task task = tasks.front();
tasks.pop(); tasks.pop();
tasksDone++;
if (!fs::is_regular_file(task.file)) if (!fs::is_regular_file(task.file))
return; return;
@@ -95,6 +96,10 @@ void WorldConverter::write() {
wfile->write(nullptr, content); wfile->write(nullptr, content);
} }
uint WorldConverter::getTotalTasks() const { uint WorldConverter::getWorkRemaining() const {
return tasks.size(); return tasks.size();
} }
uint WorldConverter::getWorkDone() const {
return tasksDone;
}
+27 -4
View File
@@ -4,7 +4,10 @@
#include <queue> #include <queue>
#include <memory> #include <memory>
#include <filesystem> #include <filesystem>
#include "../typedefs.h" #include "../typedefs.h"
#include "../delegates.h"
#include "../interfaces/Task.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
@@ -21,25 +24,45 @@ struct convert_task {
fs::path file; fs::path file;
}; };
class WorldConverter { class WorldConverter : public Task {
WorldFiles* wfile; WorldFiles* wfile;
std::shared_ptr<ContentLUT> const lut; std::shared_ptr<ContentLUT> const lut;
const Content* const content; const Content* const content;
std::queue<convert_task> tasks; std::queue<convert_task> tasks;
runnable onComplete;
uint tasksDone = 0;
void convertPlayer(fs::path file); void convertPlayer(fs::path file);
void convertRegion(fs::path file); void convertRegion(fs::path file);
public: public:
WorldConverter(fs::path folder, const Content* content, WorldConverter(
std::shared_ptr<ContentLUT> lut); fs::path folder, const Content* content,
std::shared_ptr<ContentLUT> lut
);
~WorldConverter(); ~WorldConverter();
bool hasNext() const; bool hasNext() const;
void convertNext(); void convertNext();
void setOnComplete(runnable callback) {
this->onComplete = callback;
}
void update() override {
convertNext();
if (onComplete && !hasNext()) {
onComplete();
}
}
void terminate() override {
tasks = {};
}
void write(); void write();
uint getTotalTasks() const; uint getWorkRemaining() const override;
uint getWorkDone() const override;
}; };
#endif // FILES_WORLD_CONVERTER_H_ #endif // FILES_WORLD_CONVERTER_H_
+35 -20
View File
@@ -8,6 +8,7 @@
#include <filesystem> #include <filesystem>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "../../interfaces/Task.h"
#include "../../graphics/ui/GUI.h" #include "../../graphics/ui/GUI.h"
#include "../../graphics/ui/gui_util.h" #include "../../graphics/ui/gui_util.h"
#include "../../graphics/ui/elements/containers.h" #include "../../graphics/ui/elements/containers.h"
@@ -104,35 +105,27 @@ static void show_content_missing(
menu->setPage("missing-content"); menu->setPage("missing-content");
} }
void show_process_panel(Engine* engine, std::shared_ptr<WorldConverter> converter, runnable postRunnable) { void show_process_panel(Engine* engine, std::shared_ptr<Task> task, std::wstring text=L"") {
auto menu = engine->getGUI()->getMenu(); auto menu = engine->getGUI()->getMenu();
auto panel = menus::create_page(engine, "process", 400, 0.5f, 1); auto panel = menus::create_page(engine, "process", 400, 0.5f, 1);
panel->add(std::make_shared<Label>(langs::get(L"Converting world..."))); if (!text.empty()) {
panel->add(std::make_shared<Label>(langs::get(text)));
}
auto label = std::make_shared<Label>(L"0%"); auto label = std::make_shared<Label>(L"0%");
panel->add(label); panel->add(label);
uint initialTasks = converter->getTotalTasks(); uint initialWork = task->getWorkRemaining();
panel->listenInterval(0.01f, [=]() { panel->listenInterval(0.01f, [=]() {
if (!converter->hasNext()) { task->update();
converter->write();
menu->reset(); uint tasksDone = task->getWorkDone();
menu->setPage("main", false); float progress = tasksDone/static_cast<float>(initialWork);
engine->getGUI()->postRunnable([=]() {
postRunnable();
});
return;
}
converter->convertNext();
uint tasksDone = initialTasks-converter->getTotalTasks();
float progress = tasksDone/static_cast<float>(initialTasks);
label->setText( label->setText(
std::to_wstring(tasksDone)+ std::to_wstring(tasksDone)+
L"/"+std::to_wstring(initialTasks)+L" ("+ L"/"+std::to_wstring(initialWork)+L" ("+
std::to_wstring(int(progress*100))+L"%)" std::to_wstring(int(progress*100))+L"%)"
); );
}); });
@@ -141,6 +134,27 @@ void show_process_panel(Engine* engine, std::shared_ptr<WorldConverter> converte
menu->setPage("process", false); menu->setPage("process", false);
} }
std::shared_ptr<WorldConverter> create_converter(
Engine* engine,
fs::path folder,
const Content* content,
std::shared_ptr<ContentLUT> lut,
runnable postRunnable)
{
auto converter = std::make_shared<WorldConverter>(folder, content, lut);
converter->setOnComplete([=](){
converter->write();
auto menu = engine->getGUI()->getMenu();
menu->reset();
menu->setPage("main", false);
engine->getGUI()->postRunnable([=]() {
postRunnable();
});
});
return converter;
}
void show_convert_request( void show_convert_request(
Engine* engine, Engine* engine,
const Content* content, const Content* content,
@@ -149,7 +163,8 @@ void show_convert_request(
runnable postRunnable runnable postRunnable
) { ) {
guiutil::confirm(engine->getGUI(), langs::get(L"world.convert-request"), [=]() { guiutil::confirm(engine->getGUI(), langs::get(L"world.convert-request"), [=]() {
show_process_panel(engine, std::make_shared<WorldConverter>(folder, content, lut), postRunnable); auto converter = create_converter(engine, folder, content, lut, postRunnable);
show_process_panel(engine, converter, L"Converting world...");
}, L"", langs::get(L"Cancel")); }, L"", langs::get(L"Cancel"));
} }
@@ -210,9 +225,9 @@ void menus::open_world(std::string name, Engine* engine, bool confirmConvert) {
show_content_missing(engine, content, lut); show_content_missing(engine, content, lut);
} else { } else {
if (confirmConvert) { if (confirmConvert) {
show_process_panel(engine, std::make_shared<WorldConverter>(folder, content, lut), [=](){ show_process_panel(engine, create_converter(engine, folder, content, lut, [=]() {
open_world(name, engine, false); open_world(name, engine, false);
}); }), L"Converting world...");
} else { } else {
show_convert_request(engine, content, lut, folder, [=](){ show_convert_request(engine, content, lut, folder, [=](){
open_world(name, engine, false); open_world(name, engine, false);
+19
View File
@@ -0,0 +1,19 @@
#ifndef INTERFACES_TASK_H_
#define INTERFACES_TASK_H_
#include "../typedefs.h"
/// @brief Task is a finite process interface.
/// 'work' is a metric of task progress/remaining work (jobs/bytes/something other)
class Task {
public:
virtual ~Task() {}
virtual uint getWorkRemaining() const = 0;
virtual uint getWorkDone() const = 0;
virtual void update() = 0;
virtual void terminate() = 0;
};
#endif // INTERFACES_TASK_H_
+15 -3
View File
@@ -10,6 +10,7 @@
#include "../delegates.h" #include "../delegates.h"
#include "../debug/Logger.h" #include "../debug/Logger.h"
#include "../interfaces/Task.h"
namespace util { namespace util {
@@ -30,7 +31,7 @@ public:
}; };
template<class T, class R> template<class T, class R>
class ThreadPool { class ThreadPool : public Task {
debug::Logger logger; debug::Logger logger;
std::queue<T> jobs; std::queue<T> jobs;
std::queue<ThreadPoolResult<R>> results; std::queue<ThreadPoolResult<R>> results;
@@ -43,6 +44,7 @@ class ThreadPool {
consumer<T&> onJobFailed = nullptr; consumer<T&> onJobFailed = nullptr;
runnable onComplete = nullptr; runnable onComplete = nullptr;
std::atomic<int> busyWorkers = 0; std::atomic<int> busyWorkers = 0;
std::atomic<uint> jobsDone = 0;
bool working = true; bool working = true;
void threadLoop(int index, std::shared_ptr<Worker<T, R>> worker) { void threadLoop(int index, std::shared_ptr<Worker<T, R>> worker) {
@@ -79,11 +81,13 @@ class ThreadPool {
}); });
} }
} catch (std::exception& err) { } catch (std::exception& err) {
busyWorkers--;
if (onJobFailed) { if (onJobFailed) {
onJobFailed(job); onJobFailed(job);
} }
logger.error() << "uncaught exception: " << err.what(); logger.error() << "uncaught exception: " << err.what();
} }
jobsDone++;
} }
} }
public: public:
@@ -102,7 +106,7 @@ public:
terminate(); terminate();
} }
void terminate() { void terminate() override {
if (!working) { if (!working) {
return; return;
} }
@@ -126,7 +130,7 @@ public:
} }
} }
void update() { void update() override {
std::lock_guard<std::mutex> lock(resultsMutex); std::lock_guard<std::mutex> lock(resultsMutex);
while (!results.empty()) { while (!results.empty()) {
ThreadPoolResult<R> entry = results.front(); ThreadPoolResult<R> entry = results.front();
@@ -161,6 +165,14 @@ public:
void setOnComplete(runnable callback) { void setOnComplete(runnable callback) {
this->onComplete = callback; this->onComplete = callback;
} }
uint getWorkRemaining() const override {
return jobs.size();
}
uint getWorkDone() const override {
return jobsDone;
}
}; };
} // namespace util } // namespace util