Task interface
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user