2021-01-13 17:28:27 +01:00
|
|
|
#include <hex/api/content_registry.hpp>
|
2021-01-11 20:31:40 +01:00
|
|
|
|
2022-03-04 11:36:37 +01:00
|
|
|
#include <hex/helpers/fs.hpp>
|
2022-01-13 14:33:30 +01:00
|
|
|
#include <hex/helpers/logger.hpp>
|
2021-01-11 20:31:40 +01:00
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
#include <hex/ui/view.hpp>
|
2023-03-12 18:27:29 +01:00
|
|
|
#include <hex/data_processor/node.hpp>
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2021-01-11 20:31:40 +01:00
|
|
|
#include <filesystem>
|
2023-05-15 11:30:24 +02:00
|
|
|
#include <thread>
|
2023-10-04 12:00:32 +02:00
|
|
|
#if defined(OS_WEB)
|
|
|
|
#include <jthread.hpp>
|
|
|
|
#include <emscripten.h>
|
|
|
|
#endif
|
2021-01-11 20:31:40 +01:00
|
|
|
|
2021-08-29 14:18:45 +02:00
|
|
|
#include <nlohmann/json.hpp>
|
|
|
|
|
2023-03-12 18:27:29 +01:00
|
|
|
#include <wolv/io/file.hpp>
|
2023-07-09 12:53:31 +02:00
|
|
|
#include <wolv/utils/string.hpp>
|
2022-08-08 21:23:52 +02:00
|
|
|
|
2021-01-11 20:31:40 +01:00
|
|
|
namespace hex {
|
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
namespace ContentRegistry::Settings {
|
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
[[maybe_unused]] constexpr auto SettingsFile = "settings.json";
|
2022-07-30 11:19:56 +02:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
std::map<Category, std::vector<Entry>> &getEntries() {
|
|
|
|
static std::map<Category, std::vector<Entry>> entries;
|
|
|
|
|
|
|
|
return entries;
|
2021-03-01 08:56:49 +01:00
|
|
|
}
|
2021-07-31 17:11:10 +02:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
std::map<std::string, std::string> &getCategoryDescriptions() {
|
|
|
|
static std::map<std::string, std::string> descriptions;
|
2021-01-11 20:31:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
return descriptions;
|
|
|
|
}
|
|
|
|
|
|
|
|
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
|
|
|
|
auto &settings = getSettingsData();
|
2021-03-01 08:56:49 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
if (!settings.contains(unlocalizedCategory)) return {};
|
|
|
|
if (!settings[unlocalizedCategory].contains(unlocalizedName)) return {};
|
|
|
|
|
|
|
|
return settings[unlocalizedCategory][unlocalizedName];
|
|
|
|
}
|
|
|
|
|
|
|
|
nlohmann::json &getSettingsData() {
|
|
|
|
static nlohmann::json settings;
|
|
|
|
|
|
|
|
return settings;
|
|
|
|
}
|
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
#if defined(OS_WEB)
|
|
|
|
void load() {
|
|
|
|
char *data = (char *) MAIN_THREAD_EM_ASM_INT({
|
|
|
|
let data = localStorage.getItem("config");
|
|
|
|
return data ? stringToNewUTF8(data) : null;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (data == nullptr) {
|
|
|
|
store();
|
|
|
|
} else {
|
|
|
|
getSettingsData() = nlohmann::json::parse(data);
|
2023-03-21 15:33:43 +01:00
|
|
|
}
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2023-03-21 15:33:43 +01:00
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
void store() {
|
|
|
|
auto data = getSettingsData().dump();
|
|
|
|
MAIN_THREAD_EM_ASM({
|
|
|
|
localStorage.setItem("config", UTF8ToString($0));
|
|
|
|
}, data.c_str());
|
|
|
|
}
|
2021-01-11 20:31:40 +01:00
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
void clear() {
|
|
|
|
MAIN_THREAD_EM_ASM({
|
|
|
|
localStorage.removeItem("config");
|
|
|
|
});
|
feat: Added hex::group attribute and various fixes (#1302)
As discussed (many times) on Discord, does the same as the new favorite
tag, but instead allows you to add multiple groups.
Initially, this would cause some insane issues with draw/reset
(apparantly) fighting eachother in the pattern drawer. After a lot of
trial and error, I decided to rewrite the flow that is responsible for
calling reset. Now evaluating patterns is the one to decide when the
reset happens, not the core "game"-loop.
To make sure that draw and reset can never happen at the same time, the
mutex originally used for the favorites has been repurposed. Due to the
restructuring, the mutex in the favorite-task is no longer needed, as
that will only ever kick-off after reset is called and if there are
actually patterns, which can never line up to be accessed on different
threads at the same time.
Last but not least, I noticed that hard crashes could result in your
config file getting overridden. I added a check to prevent that.
Last I issue I can see is that if you use an excessive amount of
favorites/groups, a crash can still happen, but it only happens when you
close the program (occasionally, but unpredictable). Before, this would
happen if you ran the evaluation a second time. I boiled the cause of
the crash down to these lines of code in evaluator.cpp >
patternDestroyed:
```cpp
if (pattern->isPatternLocal()) {
if (auto it = this->m_patternLocalStorage.find(pattern->getHeapAddress()); it != this->m_patternLocalStorage.end()) {
auto &[key, data] = *it;
data.referenceCount--;
if (data.referenceCount == 0)
this->m_patternLocalStorage.erase(it);
} else if (!this->m_evaluated) {
err::E0001.throwError(fmt::format("Double free of variable named '{}'.", pattern->getVariableName()));
}
}
```
Specifically, trying to access the `*it` is the reason for the crash
(this was also the cause of the crashes before my fixes, but then during
evaluation).
I'm suspecting the root cause is somewhere in the `.clone` methods of
the patterns. I'd say that for now a crash when closing the program is
more acceptable than during evaluation (which can even happen if you use
favorites).
2023-09-16 13:09:59 +02:00
|
|
|
}
|
2023-10-04 12:00:32 +02:00
|
|
|
#else
|
|
|
|
void load() {
|
|
|
|
bool loaded = false;
|
|
|
|
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
|
|
|
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Read);
|
|
|
|
|
|
|
|
if (file.isValid()) {
|
|
|
|
getSettingsData() = nlohmann::json::parse(file.readString());
|
|
|
|
loaded = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
feat: Added hex::group attribute and various fixes (#1302)
As discussed (many times) on Discord, does the same as the new favorite
tag, but instead allows you to add multiple groups.
Initially, this would cause some insane issues with draw/reset
(apparantly) fighting eachother in the pattern drawer. After a lot of
trial and error, I decided to rewrite the flow that is responsible for
calling reset. Now evaluating patterns is the one to decide when the
reset happens, not the core "game"-loop.
To make sure that draw and reset can never happen at the same time, the
mutex originally used for the favorites has been repurposed. Due to the
restructuring, the mutex in the favorite-task is no longer needed, as
that will only ever kick-off after reset is called and if there are
actually patterns, which can never line up to be accessed on different
threads at the same time.
Last but not least, I noticed that hard crashes could result in your
config file getting overridden. I added a check to prevent that.
Last I issue I can see is that if you use an excessive amount of
favorites/groups, a crash can still happen, but it only happens when you
close the program (occasionally, but unpredictable). Before, this would
happen if you ran the evaluation a second time. I boiled the cause of
the crash down to these lines of code in evaluator.cpp >
patternDestroyed:
```cpp
if (pattern->isPatternLocal()) {
if (auto it = this->m_patternLocalStorage.find(pattern->getHeapAddress()); it != this->m_patternLocalStorage.end()) {
auto &[key, data] = *it;
data.referenceCount--;
if (data.referenceCount == 0)
this->m_patternLocalStorage.erase(it);
} else if (!this->m_evaluated) {
err::E0001.throwError(fmt::format("Double free of variable named '{}'.", pattern->getVariableName()));
}
}
```
Specifically, trying to access the `*it` is the reason for the crash
(this was also the cause of the crashes before my fixes, but then during
evaluation).
I'm suspecting the root cause is somewhere in the `.clone` methods of
the patterns. I'd say that for now a crash when closing the program is
more acceptable than during evaluation (which can even happen if you use
favorites).
2023-09-16 13:09:59 +02:00
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
if (!loaded)
|
|
|
|
store();
|
|
|
|
}
|
2023-03-21 15:33:43 +01:00
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
void store() {
|
|
|
|
// During a crash settings can be empty, causing them to be overwritten.
|
|
|
|
if(getSettingsData().empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
|
|
|
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
|
|
|
|
|
|
|
|
if (file.isValid()) {
|
|
|
|
file.writeString(getSettingsData().dump(4));
|
|
|
|
break;
|
|
|
|
}
|
2023-03-21 15:33:43 +01:00
|
|
|
}
|
|
|
|
}
|
2022-07-30 11:19:56 +02:00
|
|
|
|
2023-10-04 12:00:32 +02:00
|
|
|
void clear() {
|
|
|
|
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
|
|
|
wolv::io::fs::remove(dir / SettingsFile);
|
|
|
|
}
|
2023-03-21 15:33:43 +01:00
|
|
|
}
|
2023-10-04 12:00:32 +02:00
|
|
|
#endif
|
2023-03-21 15:33:43 +01:00
|
|
|
|
|
|
|
static auto getCategoryEntry(const std::string &unlocalizedCategory) {
|
|
|
|
auto &entries = getEntries();
|
|
|
|
const size_t curSlot = entries.size();
|
|
|
|
auto found = entries.find(Category { unlocalizedCategory });
|
|
|
|
|
|
|
|
if (found == entries.end()) {
|
|
|
|
auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector<Entry> {});
|
|
|
|
return iter;
|
|
|
|
}
|
2022-02-18 22:34:54 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
return found;
|
2022-02-18 22:34:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const impl::Callback &callback, bool requiresRestart) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new integer setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
|
2021-01-11 20:31:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
auto &json = impl::getSettingsData();
|
2021-01-11 20:31:40 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
if (!json.contains(unlocalizedCategory))
|
|
|
|
json[unlocalizedCategory] = nlohmann::json::object();
|
|
|
|
if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_number())
|
|
|
|
json[unlocalizedCategory][unlocalizedName] = int(defaultValue);
|
|
|
|
}
|
2021-01-11 20:31:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const impl::Callback &callback, bool requiresRestart) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new string setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
|
2021-02-13 15:15:32 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
auto &json = impl::getSettingsData();
|
2021-02-13 15:15:32 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
if (!json.contains(unlocalizedCategory))
|
|
|
|
json[unlocalizedCategory] = nlohmann::json::object();
|
|
|
|
if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_string())
|
|
|
|
json[unlocalizedCategory][unlocalizedName] = std::string(defaultValue);
|
|
|
|
}
|
2021-01-11 20:31:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const impl::Callback &callback, bool requiresRestart) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new string array setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
2022-02-18 22:34:54 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
|
2022-02-18 22:34:54 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
auto &json = impl::getSettingsData();
|
2022-02-18 22:34:54 +01:00
|
|
|
|
|
|
|
if (!json.contains(unlocalizedCategory))
|
|
|
|
json[unlocalizedCategory] = nlohmann::json::object();
|
|
|
|
if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_array())
|
|
|
|
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
|
|
|
}
|
|
|
|
|
2022-02-21 21:46:25 +01:00
|
|
|
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription) {
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getCategoryDescriptions()[unlocalizedCategory] = unlocalizedCategoryDescription;
|
2022-02-18 22:34:54 +01:00
|
|
|
}
|
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value) {
|
2023-03-21 15:33:43 +01:00
|
|
|
auto &json = impl::getSettingsData();
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
if (!json.contains(unlocalizedCategory))
|
|
|
|
json[unlocalizedCategory] = nlohmann::json::object();
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
json[unlocalizedCategory][unlocalizedName] = value;
|
|
|
|
}
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value) {
|
2023-03-21 15:33:43 +01:00
|
|
|
auto &json = impl::getSettingsData();
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
if (!json.contains(unlocalizedCategory))
|
|
|
|
json[unlocalizedCategory] = nlohmann::json::object();
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
json[unlocalizedCategory][unlocalizedName] = value;
|
|
|
|
}
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &value) {
|
2023-03-21 15:33:43 +01:00
|
|
|
auto &json = impl::getSettingsData();
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
if (!json.contains(unlocalizedCategory))
|
|
|
|
json[unlocalizedCategory] = nlohmann::json::object();
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
json[unlocalizedCategory][unlocalizedName] = value;
|
|
|
|
}
|
2021-02-01 19:03:28 +01:00
|
|
|
|
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue) {
|
2023-03-21 15:33:43 +01:00
|
|
|
auto &json = impl::getSettingsData();
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
if (!json.contains(unlocalizedCategory))
|
|
|
|
return defaultValue;
|
|
|
|
if (!json[unlocalizedCategory].contains(unlocalizedName))
|
|
|
|
return defaultValue;
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
if (!json[unlocalizedCategory][unlocalizedName].is_number())
|
|
|
|
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
2021-09-12 13:59:23 +02:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
return json[unlocalizedCategory][unlocalizedName].get<i64>();
|
|
|
|
}
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue) {
|
2023-03-21 15:33:43 +01:00
|
|
|
auto &json = impl::getSettingsData();
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
if (!json.contains(unlocalizedCategory))
|
|
|
|
return defaultValue;
|
|
|
|
if (!json[unlocalizedCategory].contains(unlocalizedName))
|
|
|
|
return defaultValue;
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
if (!json[unlocalizedCategory][unlocalizedName].is_string())
|
|
|
|
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
2021-09-12 13:59:23 +02:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
return json[unlocalizedCategory][unlocalizedName].get<std::string>();
|
|
|
|
}
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue) {
|
2023-03-21 15:33:43 +01:00
|
|
|
auto &json = impl::getSettingsData();
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
if (!json.contains(unlocalizedCategory))
|
|
|
|
return defaultValue;
|
|
|
|
if (!json[unlocalizedCategory].contains(unlocalizedName))
|
|
|
|
return defaultValue;
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
if (!json[unlocalizedCategory][unlocalizedName].is_array())
|
|
|
|
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
2021-09-12 20:27:56 +02:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
if (!json[unlocalizedCategory][unlocalizedName].array().empty() && !json[unlocalizedCategory][unlocalizedName][0].is_string())
|
|
|
|
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
2021-09-12 13:59:23 +02:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
return json[unlocalizedCategory][unlocalizedName].get<std::vector<std::string>>();
|
|
|
|
}
|
2021-02-01 19:03:28 +01:00
|
|
|
|
2021-01-11 20:31:40 +01:00
|
|
|
}
|
|
|
|
|
2021-01-11 21:11:03 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
namespace ContentRegistry::CommandPaletteCommands {
|
2021-01-11 23:02:55 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
void add(Type type, const std::string &command, const std::string &unlocalizedDescription, const impl::DisplayCallback &displayCallback, const impl::ExecuteCallback &executeCallback) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new command palette command: {}", command);
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getEntries().push_back(ContentRegistry::CommandPaletteCommands::impl::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback });
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
void addHandler(Type type, const std::string &command, const impl::QueryCallback &queryCallback, const impl::DisplayCallback &displayCallback) {
|
2023-03-20 14:11:43 +01:00
|
|
|
log::debug("Registered new command palette command handler: {}", command);
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getHandlers().push_back(ContentRegistry::CommandPaletteCommands::impl::Handler { type, command, queryCallback, displayCallback });
|
2023-03-20 14:11:43 +01:00
|
|
|
}
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
2021-01-11 23:02:55 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
std::vector<Entry> &getEntries() {
|
|
|
|
static std::vector<Entry> commands;
|
|
|
|
|
|
|
|
return commands;
|
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
std::vector<Handler> &getHandlers() {
|
|
|
|
static std::vector<Handler> commands;
|
|
|
|
|
|
|
|
return commands;
|
|
|
|
}
|
2023-03-20 14:11:43 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-01-11 23:02:55 +01:00
|
|
|
}
|
|
|
|
|
2021-01-11 23:54:12 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
namespace ContentRegistry::PatternLanguage {
|
2021-01-11 23:54:12 +01:00
|
|
|
|
2022-04-17 16:57:30 +02:00
|
|
|
static std::string getFunctionName(const pl::api::Namespace &ns, const std::string &name) {
|
2022-02-02 00:36:09 +01:00
|
|
|
std::string functionName;
|
|
|
|
for (auto &scope : ns)
|
|
|
|
functionName += scope + "::";
|
2021-08-27 09:56:20 +02:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
functionName += name;
|
2021-08-27 09:56:20 +02:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
return functionName;
|
|
|
|
}
|
2021-08-27 09:56:20 +02:00
|
|
|
|
2023-04-17 16:18:48 +02:00
|
|
|
pl::PatternLanguage& getRuntime() {
|
|
|
|
static PerProvider<pl::PatternLanguage> runtime;
|
|
|
|
|
|
|
|
return *runtime;
|
|
|
|
}
|
|
|
|
|
2023-05-12 15:46:13 +02:00
|
|
|
std::mutex& getRuntimeLock() {
|
2023-04-17 16:18:48 +02:00
|
|
|
static std::mutex runtimeLock;
|
|
|
|
|
2023-05-12 15:46:13 +02:00
|
|
|
return runtimeLock;
|
2023-04-17 16:18:48 +02:00
|
|
|
}
|
|
|
|
|
2022-09-15 09:34:40 +02:00
|
|
|
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider) {
|
|
|
|
runtime.reset();
|
2021-01-11 23:54:12 +01:00
|
|
|
|
2022-08-10 09:26:48 +02:00
|
|
|
if (provider != nullptr) {
|
2022-12-16 11:20:39 +01:00
|
|
|
runtime.setDataSource(provider->getBaseAddress(), provider->getActualSize(),
|
|
|
|
[provider](u64 offset, u8 *buffer, size_t size) {
|
|
|
|
provider->read(offset, buffer, size);
|
|
|
|
},
|
|
|
|
[provider](u64 offset, const u8 *buffer, size_t size) {
|
|
|
|
if (provider->isWritable())
|
|
|
|
provider->write(offset, buffer, size);
|
|
|
|
}
|
|
|
|
);
|
2022-08-10 09:26:48 +02:00
|
|
|
}
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2022-09-15 09:34:40 +02:00
|
|
|
runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
|
2021-12-20 20:40:28 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
for (const auto &func : impl::getFunctions()) {
|
2022-04-17 16:57:30 +02:00
|
|
|
if (func.dangerous)
|
2022-09-15 09:34:40 +02:00
|
|
|
runtime.addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
|
2022-04-17 16:57:30 +02:00
|
|
|
else
|
2022-09-15 09:34:40 +02:00
|
|
|
runtime.addFunction(func.ns, func.name, func.parameterCount, func.callback);
|
2022-04-17 16:57:30 +02:00
|
|
|
}
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
for (const auto &[name, callback] : impl::getPragmas()) {
|
2022-09-15 09:34:40 +02:00
|
|
|
runtime.addPragma(name, callback);
|
2022-04-17 16:57:30 +02:00
|
|
|
}
|
2021-12-20 20:40:28 +01:00
|
|
|
|
2022-09-15 09:34:40 +02:00
|
|
|
runtime.addDefine("__IMHEX__");
|
2023-06-26 14:01:45 +02:00
|
|
|
runtime.addDefine("__IMHEX_VERSION__", ImHexApi::System::getImHexVersion());
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2022-04-17 16:57:30 +02:00
|
|
|
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new pattern language pragma: {}", name);
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getPragmas()[name] = handler;
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2022-04-17 16:57:30 +02:00
|
|
|
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new pattern language function: {}", getFunctionName(ns, name));
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getFunctions().push_back({
|
2022-04-17 16:57:30 +02:00
|
|
|
ns, name,
|
|
|
|
parameterCount, func,
|
|
|
|
false
|
|
|
|
});
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2022-04-17 16:57:30 +02:00
|
|
|
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new dangerous pattern language function: {}", getFunctionName(ns, name));
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getFunctions().push_back({
|
2022-04-17 16:57:30 +02:00
|
|
|
ns, name,
|
|
|
|
parameterCount, func,
|
|
|
|
true
|
|
|
|
});
|
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-01-20 21:16:28 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, u32 parameterCount) {
|
2023-01-20 21:16:28 +01:00
|
|
|
log::debug("Registered new pattern visualizer function: {}", name);
|
|
|
|
impl::getVisualizers()[name] = impl::Visualizer { parameterCount, function };
|
|
|
|
}
|
|
|
|
|
2023-07-04 22:18:06 +02:00
|
|
|
void addInlineVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, u32 parameterCount) {
|
|
|
|
log::debug("Registered new inline pattern visualizer function: {}", name);
|
|
|
|
impl::getInlineVisualizers()[name] = impl::Visualizer { parameterCount, function };
|
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
std::map<std::string, impl::Visualizer> &getVisualizers() {
|
|
|
|
static std::map<std::string, impl::Visualizer> visualizers;
|
|
|
|
|
|
|
|
return visualizers;
|
|
|
|
}
|
|
|
|
|
2023-07-04 22:18:06 +02:00
|
|
|
std::map<std::string, impl::Visualizer> &getInlineVisualizers() {
|
|
|
|
static std::map<std::string, impl::Visualizer> visualizers;
|
|
|
|
|
|
|
|
return visualizers;
|
|
|
|
}
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
|
|
|
|
static std::map<std::string, pl::api::PragmaHandler> pragmas;
|
|
|
|
|
|
|
|
return pragmas;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<impl::FunctionDefinition> &getFunctions() {
|
|
|
|
static std::vector<impl::FunctionDefinition> functions;
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
return functions;
|
|
|
|
}
|
2022-04-17 16:57:30 +02:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
|
2021-01-11 23:54:12 +01:00
|
|
|
}
|
|
|
|
|
2021-01-12 16:50:15 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
namespace ContentRegistry::Views {
|
2021-01-12 16:50:15 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
|
|
|
|
2023-04-08 12:08:45 +02:00
|
|
|
std::map<std::string, std::unique_ptr<View>> &getEntries() {
|
|
|
|
static std::map<std::string, std::unique_ptr<View>> views;
|
2023-03-21 15:33:43 +01:00
|
|
|
|
|
|
|
return views;
|
|
|
|
}
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2021-01-12 16:50:15 +01:00
|
|
|
|
2023-04-08 12:08:45 +02:00
|
|
|
void impl::add(std::unique_ptr<View> &&view) {
|
2023-03-21 15:33:43 +01:00
|
|
|
log::debug("Registered new view: {}", view->getUnlocalizedName());
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-04-08 12:08:45 +02:00
|
|
|
impl::getEntries().insert({ view->getUnlocalizedName(), std::move(view) });
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2021-01-12 16:50:15 +01:00
|
|
|
|
2023-04-08 12:08:45 +02:00
|
|
|
View* getViewByName(const std::string &unlocalizedName) {
|
2023-03-21 15:33:43 +01:00
|
|
|
auto &views = impl::getEntries();
|
2022-02-02 00:36:09 +01:00
|
|
|
|
|
|
|
if (views.contains(unlocalizedName))
|
2023-04-08 12:08:45 +02:00
|
|
|
return views[unlocalizedName].get();
|
2022-02-02 00:36:09 +01:00
|
|
|
else
|
|
|
|
return nullptr;
|
|
|
|
}
|
2022-01-18 00:10:10 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
namespace ContentRegistry::Tools {
|
2021-01-12 16:50:15 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void add(const std::string &unlocalizedName, const impl::Callback &function) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new tool: {}", unlocalizedName);
|
2021-01-12 16:50:15 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getEntries().emplace_back(impl::Entry { unlocalizedName, function, false });
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
std::vector<Entry> &getEntries() {
|
|
|
|
static std::vector<Entry> tools;
|
|
|
|
|
|
|
|
return tools;
|
|
|
|
}
|
2021-01-12 16:50:15 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2021-01-12 16:50:15 +01:00
|
|
|
}
|
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
namespace ContentRegistry::DataInspector {
|
2021-01-13 01:24:27 +01:00
|
|
|
|
2022-02-15 21:50:27 +01:00
|
|
|
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new data inspector format: {}", unlocalizedName);
|
2021-01-13 01:24:27 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getEntries().push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
|
2022-08-01 19:20:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
|
2022-08-02 23:07:12 +02:00
|
|
|
log::debug("Registered new data inspector format: {}", unlocalizedName);
|
2022-08-01 19:20:20 +08:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getEntries().push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
std::vector<impl::Entry> &getEntries() {
|
|
|
|
static std::vector<impl::Entry> entries;
|
|
|
|
|
|
|
|
return entries;
|
|
|
|
}
|
2021-01-13 01:24:27 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
|
2021-01-13 01:24:27 +01:00
|
|
|
}
|
2021-01-30 22:39:06 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
namespace ContentRegistry::DataProcessorNode {
|
2021-01-30 22:39:06 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void impl::add(const impl::Entry &entry) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new data processor node type: [{}]: {}", entry.category, entry.name);
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
getEntries().push_back(entry);
|
|
|
|
}
|
2021-01-30 22:39:06 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void addSeparator() {
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getEntries().push_back({ "", "", [] { return nullptr; } });
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2021-01-30 22:39:06 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
std::vector<impl::Entry> &getEntries() {
|
|
|
|
static std::vector<impl::Entry> nodes;
|
|
|
|
|
|
|
|
return nodes;
|
|
|
|
}
|
2022-02-02 00:36:09 +01:00
|
|
|
|
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2021-01-30 22:39:06 +01:00
|
|
|
}
|
2021-02-11 00:35:30 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
namespace ContentRegistry::Language {
|
2021-02-11 00:35:30 +01:00
|
|
|
|
2022-12-02 12:00:04 +01:00
|
|
|
void addLocalization(const nlohmann::json &data) {
|
2023-02-02 10:08:47 +01:00
|
|
|
if (!data.is_object())
|
|
|
|
return;
|
|
|
|
|
2022-12-02 12:00:04 +01:00
|
|
|
if (!data.contains("code") || !data.contains("country") || !data.contains("language") || !data.contains("translations")) {
|
|
|
|
log::error("Localization data is missing required fields!");
|
|
|
|
return;
|
|
|
|
}
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2022-12-02 12:00:04 +01:00
|
|
|
const auto &code = data["code"];
|
|
|
|
const auto &country = data["country"];
|
|
|
|
const auto &language = data["language"];
|
|
|
|
const auto &translations = data["translations"];
|
|
|
|
|
|
|
|
if (!code.is_string() || !country.is_string() || !language.is_string() || !translations.is_object()) {
|
|
|
|
log::error("Localization data has invalid fields!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data.contains("fallback")) {
|
|
|
|
const auto &fallback = data["fallback"];
|
2021-02-11 00:35:30 +01:00
|
|
|
|
2022-12-02 12:00:04 +01:00
|
|
|
if (fallback.is_boolean() && fallback.get<bool>())
|
|
|
|
LangEntry::setFallbackLanguage(code.get<std::string>());
|
|
|
|
}
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getLanguages().insert({ code.get<std::string>(), hex::format("{} ({})", language.get<std::string>(), country.get<std::string>()) });
|
2022-12-02 12:00:04 +01:00
|
|
|
|
|
|
|
std::map<std::string, std::string> translationDefinitions;
|
|
|
|
for (auto &[key, value] : translations.items()) {
|
|
|
|
if (!value.is_string()) {
|
|
|
|
log::error("Localization data has invalid fields!");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
translationDefinitions[key] = value.get<std::string>();
|
|
|
|
}
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getLanguageDefinitions()[code.get<std::string>()].emplace_back(std::move(translationDefinitions));
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2021-02-11 00:35:30 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
std::map<std::string, std::string> &getLanguages() {
|
|
|
|
static std::map<std::string, std::string> languages;
|
2021-02-11 00:35:30 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
return languages;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions() {
|
|
|
|
static std::map<std::string, std::vector<LanguageDefinition>> definitions;
|
|
|
|
|
|
|
|
return definitions;
|
|
|
|
}
|
2022-02-02 00:36:09 +01:00
|
|
|
|
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
|
2021-02-11 00:35:30 +01:00
|
|
|
}
|
2021-02-18 12:09:19 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
namespace ContentRegistry::Interface {
|
2021-02-18 12:09:19 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new main menu item: {}", unlocalizedName);
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getMainMenuItems().insert({ priority, { unlocalizedName } });
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-01-18 00:10:10 +01:00
|
|
|
|
2023-03-20 15:12:12 +01:00
|
|
|
void addMenuItem(const std::vector<std::string> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
|
2023-03-20 13:11:43 +01:00
|
|
|
log::debug("Added new menu item to menu {} with priority {}", wolv::util::combineStrings(unlocalizedMainMenuNames, " -> "), priority);
|
2022-01-18 00:10:10 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getMenuItems().insert({
|
2023-03-20 13:11:43 +01:00
|
|
|
priority, { unlocalizedMainMenuNames, shortcut, function, enabledCallback }
|
|
|
|
});
|
|
|
|
|
2023-03-20 15:12:12 +01:00
|
|
|
if (shortcut.isLocal() && view != nullptr)
|
|
|
|
ShortcutManager::addShortcut(view, shortcut, function);
|
|
|
|
else
|
|
|
|
ShortcutManager::addGlobalShortcut(shortcut, function);
|
2023-03-20 13:11:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void addMenuItemSubMenu(std::vector<std::string> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback) {
|
|
|
|
log::debug("Added new menu item sub menu to menu {} with priority {}", wolv::util::combineStrings(unlocalizedMainMenuNames, " -> "), priority);
|
|
|
|
|
|
|
|
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getMenuItems().insert({
|
2023-03-20 13:11:43 +01:00
|
|
|
priority, { unlocalizedMainMenuNames, {}, function, enabledCallback }
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void addMenuItemSeparator(std::vector<std::string> unlocalizedMainMenuNames, u32 priority) {
|
|
|
|
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getMenuItems().insert({
|
2023-03-20 13:11:43 +01:00
|
|
|
priority, { unlocalizedMainMenuNames, {}, []{}, []{ return true; } }
|
2022-02-02 00:36:09 +01:00
|
|
|
});
|
|
|
|
}
|
2022-01-23 02:28:38 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void addWelcomeScreenEntry(const impl::DrawCallback &function) {
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getWelcomeScreenEntries().push_back(function);
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-01-23 02:28:38 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void addFooterItem(const impl::DrawCallback &function) {
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getFooterItems().push_back(function);
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2021-02-18 12:09:19 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void addToolbarItem(const impl::DrawCallback &function) {
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getToolbarItems().push_back(function);
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2021-02-18 12:09:19 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function) {
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getSidebarItems().push_back({ icon, function });
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2021-08-21 00:52:11 +02:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function) {
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getTitleBarButtons().push_back({ icon, unlocalizedTooltip, function });
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-01-22 22:03:19 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
2022-01-18 00:10:10 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems() {
|
|
|
|
static std::multimap<u32, impl::MainMenuItem> items;
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
return items;
|
|
|
|
}
|
|
|
|
std::multimap<u32, impl::MenuItem> &getMenuItems() {
|
|
|
|
static std::multimap<u32, impl::MenuItem> items;
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
return items;
|
|
|
|
}
|
2022-01-18 00:10:10 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
std::vector<impl::DrawCallback> &getWelcomeScreenEntries() {
|
|
|
|
static std::vector<impl::DrawCallback> entries;
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
return entries;
|
|
|
|
}
|
|
|
|
std::vector<impl::DrawCallback> &getFooterItems() {
|
|
|
|
static std::vector<impl::DrawCallback> items;
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
return items;
|
|
|
|
}
|
|
|
|
std::vector<impl::DrawCallback> &getToolbarItems() {
|
|
|
|
static std::vector<impl::DrawCallback> items;
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
return items;
|
|
|
|
}
|
|
|
|
std::vector<impl::SidebarItem> &getSidebarItems() {
|
|
|
|
static std::vector<impl::SidebarItem> items;
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
return items;
|
|
|
|
}
|
|
|
|
std::vector<impl::TitleBarButton> &getTitleBarButtons() {
|
|
|
|
static std::vector<impl::TitleBarButton> buttons;
|
2021-12-07 22:47:41 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
return buttons;
|
|
|
|
}
|
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2022-01-18 00:10:10 +01:00
|
|
|
}
|
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
namespace ContentRegistry::Provider {
|
2021-12-07 22:47:41 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void impl::addProviderName(const std::string &unlocalizedName) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new provider: {}", unlocalizedName);
|
2021-12-07 22:47:41 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
getEntries().push_back(unlocalizedName);
|
|
|
|
}
|
2022-01-13 14:34:27 +01:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
std::vector<std::string> &getEntries() {
|
|
|
|
static std::vector<std::string> providerNames;
|
|
|
|
|
|
|
|
return providerNames;
|
|
|
|
}
|
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
}
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
namespace ContentRegistry::DataFormatter {
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void add(const std::string &unlocalizedName, const impl::Callback &callback) {
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new data formatter: {}", unlocalizedName);
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getEntries().push_back({ unlocalizedName, callback });
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-01-13 14:34:19 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
std::vector<impl::Entry> &getEntries() {
|
|
|
|
static std::vector<impl::Entry> entries;
|
|
|
|
|
|
|
|
return entries;
|
|
|
|
}
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2022-01-13 00:27:31 +01:00
|
|
|
}
|
2022-01-13 14:34:19 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
namespace ContentRegistry::FileHandler {
|
2022-01-13 14:34:19 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
void add(const std::vector<std::string> &extensions, const impl::Callback &callback) {
|
|
|
|
for (const auto &extension : extensions)
|
2022-07-30 11:26:51 +02:00
|
|
|
log::debug("Registered new data handler for extensions: {}", extension);
|
2022-01-13 14:34:19 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
impl::getEntries().push_back({ extensions, callback });
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-01-13 14:34:19 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
std::vector<impl::Entry> &getEntries() {
|
|
|
|
static std::vector<impl::Entry> entries;
|
|
|
|
|
|
|
|
return entries;
|
|
|
|
}
|
2022-01-13 14:34:19 +01:00
|
|
|
|
2022-02-02 00:36:09 +01:00
|
|
|
}
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2022-01-13 14:34:19 +01:00
|
|
|
}
|
2022-02-02 00:36:09 +01:00
|
|
|
|
2022-05-27 20:42:07 +02:00
|
|
|
namespace ContentRegistry::HexEditor {
|
|
|
|
|
2022-06-03 10:53:03 +02:00
|
|
|
const int DataVisualizer::TextInputFlags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll;
|
2022-05-27 20:42:07 +02:00
|
|
|
|
2023-02-18 22:20:02 +01:00
|
|
|
bool DataVisualizer::drawDefaultScalarEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const {
|
2022-05-27 20:42:07 +02:00
|
|
|
struct UserData {
|
|
|
|
u8 *data;
|
|
|
|
i32 maxChars;
|
|
|
|
|
|
|
|
bool editingDone;
|
|
|
|
};
|
|
|
|
|
|
|
|
UserData userData = {
|
|
|
|
.data = data,
|
|
|
|
.maxChars = this->getMaxCharsPerCell(),
|
|
|
|
|
|
|
|
.editingDone = false
|
|
|
|
};
|
|
|
|
|
|
|
|
ImGui::PushID(reinterpret_cast<void*>(address));
|
|
|
|
ImGui::InputScalarCallback("##editing_input", dataType, data, format, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int {
|
|
|
|
auto &userData = *reinterpret_cast<UserData*>(data->UserData);
|
|
|
|
|
|
|
|
if (data->BufTextLen >= userData.maxChars)
|
|
|
|
userData.editingDone = true;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}, &userData);
|
|
|
|
ImGui::PopID();
|
|
|
|
|
2022-10-12 10:56:03 +02:00
|
|
|
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
2023-02-18 22:20:02 +01:00
|
|
|
bool DataVisualizer::drawDefaultTextEditingTextBox(u64 address, std::string &data, ImGuiInputTextFlags flags) const {
|
|
|
|
struct UserData {
|
|
|
|
std::string *data;
|
|
|
|
i32 maxChars;
|
|
|
|
|
|
|
|
bool editingDone;
|
|
|
|
};
|
|
|
|
|
|
|
|
UserData userData = {
|
|
|
|
.data = &data,
|
|
|
|
.maxChars = this->getMaxCharsPerCell(),
|
|
|
|
|
|
|
|
.editingDone = false
|
|
|
|
};
|
|
|
|
|
|
|
|
ImGui::PushID(reinterpret_cast<void*>(address));
|
|
|
|
ImGui::InputText("##editing_input", data.data(), data.size() + 1, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int {
|
|
|
|
auto &userData = *reinterpret_cast<UserData*>(data->UserData);
|
|
|
|
|
|
|
|
userData.data->resize(data->BufSize);
|
|
|
|
|
|
|
|
if (data->BufTextLen >= userData.maxChars)
|
|
|
|
userData.editingDone = true;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}, &userData);
|
|
|
|
ImGui::PopID();
|
|
|
|
|
|
|
|
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
|
|
|
|
}
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
2022-05-27 20:42:07 +02:00
|
|
|
|
2023-06-21 17:48:51 +02:00
|
|
|
void addDataVisualizer(std::shared_ptr<DataVisualizer> &&visualizer) {
|
|
|
|
getVisualizers().emplace_back(std::move(visualizer));
|
2023-03-21 15:33:43 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-06-21 17:48:51 +02:00
|
|
|
std::vector<std::shared_ptr<DataVisualizer>> &getVisualizers() {
|
|
|
|
static std::vector<std::shared_ptr<DataVisualizer>> visualizers;
|
2022-05-27 20:42:07 +02:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
return visualizers;
|
|
|
|
}
|
2022-05-27 20:42:07 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-06-21 17:48:51 +02:00
|
|
|
std::shared_ptr<DataVisualizer> getVisualizerByName(const std::string &unlocalizedName) {
|
|
|
|
for (const auto &visualizer : impl::getVisualizers()) {
|
|
|
|
if (visualizer->getUnlocalizedName() == unlocalizedName)
|
|
|
|
return visualizer;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
|
|
|
|
2022-05-30 16:36:46 +02:00
|
|
|
namespace ContentRegistry::Hashes {
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
namespace impl {
|
2022-05-30 16:36:46 +02:00
|
|
|
|
2023-06-11 10:47:17 +02:00
|
|
|
std::vector<std::unique_ptr<Hash>> &getHashes() {
|
|
|
|
static std::vector<std::unique_ptr<Hash>> hashes;
|
2023-03-21 15:33:43 +01:00
|
|
|
|
|
|
|
return hashes;
|
|
|
|
}
|
|
|
|
|
2023-06-11 10:47:17 +02:00
|
|
|
void add(std::unique_ptr<Hash> &&hash) {
|
|
|
|
getHashes().emplace_back(std::move(hash));
|
2023-03-21 15:33:43 +01:00
|
|
|
}
|
2022-05-30 16:36:46 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-15 11:30:24 +02:00
|
|
|
namespace ContentRegistry::BackgroundServices {
|
|
|
|
|
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
std::vector<Service> &getServices() {
|
|
|
|
static std::vector<Service> services;
|
|
|
|
|
|
|
|
return services;
|
|
|
|
}
|
|
|
|
|
|
|
|
void stopServices() {
|
|
|
|
for (auto &service : getServices()) {
|
|
|
|
service.thread.request_stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &service : getServices()) {
|
2023-05-16 14:59:14 +02:00
|
|
|
service.thread.detach();
|
2023-05-15 11:30:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void registerService(const std::string &unlocalizedName, const impl::Callback &callback) {
|
|
|
|
log::debug("Registered new background service: {}", unlocalizedName);
|
|
|
|
|
|
|
|
impl::getServices().push_back(impl::Service {
|
|
|
|
unlocalizedName,
|
|
|
|
std::jthread([callback](const std::stop_token &stopToken){
|
|
|
|
while (!stopToken.stop_requested()) {
|
|
|
|
callback();
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace ContentRegistry::CommunicationInterface {
|
|
|
|
|
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
std::map<std::string, NetworkCallback> &getNetworkEndpoints() {
|
|
|
|
static std::map<std::string, NetworkCallback> endpoints;
|
|
|
|
|
|
|
|
return endpoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void registerNetworkEndpoint(const std::string &endpoint, const impl::NetworkCallback &callback) {
|
|
|
|
log::debug("Registered new network endpoint: {}", endpoint);
|
|
|
|
|
|
|
|
impl::getNetworkEndpoints().insert({ endpoint, callback });
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-02-18 22:34:54 +01:00
|
|
|
}
|