diff --git a/loader/include/Geode/loader/ModInfo.hpp b/loader/include/Geode/loader/ModInfo.hpp index 9b6bbf0a..2dda4f38 100644 --- a/loader/include/Geode/loader/ModInfo.hpp +++ b/loader/include/Geode/loader/ModInfo.hpp @@ -1,10 +1,12 @@ #pragma once -#include "Types.hpp" -#include -#include "../utils/VersionInfo.hpp" #include "../utils/Result.hpp" +#include "../utils/VersionInfo.hpp" #include "Setting.hpp" +#include "Types.hpp" + +#include +#include namespace geode { namespace utils::file { @@ -28,20 +30,34 @@ namespace geode { * Represents all the data gatherable * from mod.json */ - struct GEODE_DLL ModInfo { + class GEODE_DLL ModInfo { + class Impl; + std::unique_ptr m_impl; + + public: + ModInfo(); + ModInfo(ModInfo const& other); + ModInfo(ModInfo&& other) noexcept; + ModInfo& operator=(ModInfo const& other); + ModInfo& operator=(ModInfo&& other) noexcept; + ~ModInfo(); + /** * Path to the mod file */ - ghc::filesystem::path path; + ghc::filesystem::path& path(); + ghc::filesystem::path const& path() const; /** * Name of the platform binary within * the mod zip */ - std::string binaryName; + std::string& binaryName(); + std::string const& binaryName() const; /** * Mod Version. Should follow semver. */ - VersionInfo version { 1, 0, 0 }; + VersionInfo& version(); + VersionInfo const& version() const; /** * Human-readable ID of the Mod. * Recommended to be in the format @@ -51,14 +67,16 @@ namespace geode { * be restricted to the ASCII * character set. */ - std::string id; + std::string& id(); + std::string const& id() const; /** * Name of the mod. May contain * spaces & punctuation, but should * be restricted to the ASCII * character set. */ - std::string name; + std::string& name(); + std::string const& name() const; /** * The name of the head developer. * Should be a single name, like @@ -70,61 +88,74 @@ namespace geode { * should be named in `m_credits` * instead. */ - std::string developer; + std::string& developer(); + std::string const& developer() const; /** * Short & concise description of the * mod. */ - std::optional description; + std::optional& description(); + std::optional const& description() const; /** * Detailed description of the mod, writtenin Markdown (see * ) for more info */ - std::optional details; + std::optional& details(); + std::optional const& details() const; /** * Changelog for the mod, written in Markdown (see * ) for more info */ - std::optional changelog; + std::optional& changelog(); + std::optional const& changelog() const; /** * Support info for the mod; this means anything to show ways to * support the mod's development, like donations. Written in Markdown * (see MDTextArea for more info) */ - std::optional supportInfo; + std::optional& supportInfo(); + std::optional const& supportInfo() const; /** * Git Repository of the mod */ - std::optional repository; + std::optional& repository(); + std::optional const& repository() const; /** * Info about where users should report issues and request help */ - std::optional issues; + std::optional& issues(); + std::optional const& issues() const; /** * Dependencies */ - std::vector dependencies; + std::vector& dependencies(); + std::vector const& dependencies() const; /** * Mod spritesheet names */ - std::vector spritesheets; + std::vector& spritesheets(); + std::vector const& spritesheets() const; /** * Mod settings * @note Not a map because insertion order must be preserved */ - std::vector> settings; + std::vector>& settings(); + std::vector> const& settings() const; /** * Whether the mod can be disabled or not */ - bool supportsDisabling = true; + bool& supportsDisabling(); + bool const& supportsDisabling() const; /** * Whether the mod can be unloaded or not */ - bool supportsUnloading = false; + bool& supportsUnloading(); + bool const& supportsUnloading() const; /** * Whether this mod has to be loaded before the loading screen or not */ - bool needsEarlyLoad = false; + bool& needsEarlyLoad(); + bool const& needsEarlyLoad() const; /** * Create ModInfo from an unzipped .geode package */ @@ -143,7 +174,7 @@ namespace geode { static Result create(ModJson const& json); /** - * Convert to JSON. Essentially same as getRawJSON except dynamically + * Convert to JSON. Essentially same as getRawJSON except dynamically * adds runtime fields like path */ ModJson toJSON() const; @@ -157,8 +188,8 @@ namespace geode { static bool validateID(std::string const& id); private: - std::shared_ptr m_rawJSON; - + ModJson& rawJSON(); + ModJson const& rawJSON() const; /** * Version is passed for backwards * compatibility if we update the mod.json diff --git a/loader/src/loader/Index.cpp b/loader/src/loader/Index.cpp index 074524f9..871b9d31 100644 --- a/loader/src/loader/Index.cpp +++ b/loader/src/loader/Index.cpp @@ -381,16 +381,16 @@ void Index::updateSourceFromLocal(IndexSourceImpl* src) { } auto add = addRes.unwrap(); // check if this major version of this item has already been added - if (m_items[add->info.id].count(add->info.version.getMajor())) { + if (m_items[add->info.id()].count(add->info.version().getMajor())) { log::warn( "Item {}@{} has already been added, skipping", - add->info.id, add->info.version + add->info.id(), add->info.version() ); continue; } // add new major version of this item - m_items[add->info.id].insert({ - add->info.version.getMajor(), + m_items[add->info.id()].insert({ + add->info.version().getMajor(), add }); } @@ -486,7 +486,7 @@ std::vector Index::getItemsByDeveloper( std::vector res; for (auto& items : map::values(m_items)) { if (items.size()) { - if (items.rbegin()->second->info.developer == name) { + if (items.rbegin()->second->info.developer() == name) { res.push_back(items.rbegin()->second); } } @@ -510,7 +510,7 @@ IndexItemHandle Index::getItem( if (version) { // prefer most major version for (auto& [_, item] : ranges::reverse(m_items.at(id))) { - if (version.value() == item->info.version) { + if (version.value() == item->info.version()) { return item; } } @@ -530,7 +530,7 @@ IndexItemHandle Index::getItem( if (m_items.count(id)) { // prefer most major version for (auto& [_, item] : ranges::reverse(m_items.at(id))) { - if (version.compare(item->info.version)) { + if (version.compare(item->info.version())) { return item; } } @@ -539,7 +539,7 @@ IndexItemHandle Index::getItem( } IndexItemHandle Index::getItem(ModInfo const& info) const { - return this->getItem(info.id, info.version); + return this->getItem(info.id(), info.version()); } IndexItemHandle Index::getItem(Mod* mod) const { @@ -547,17 +547,17 @@ IndexItemHandle Index::getItem(Mod* mod) const { } bool Index::isUpdateAvailable(IndexItemHandle item) const { - auto installed = Loader::get()->getInstalledMod(item->info.id); + auto installed = Loader::get()->getInstalledMod(item->info.id()); if (!installed) { return false; } - return item->info.version > installed->getVersion(); + return item->info.version() > installed->getVersion(); } bool Index::areUpdatesAvailable() const { for (auto& mod : Loader::get()->getAllMods()) { auto item = this->getItem(mod); - if (item && item->info.version > mod->getVersion()) { + if (item && item->info.version() > mod->getVersion()) { return true; } } @@ -573,7 +573,7 @@ Result Index::getInstallList(IndexItemHandle item) const { IndexInstallList list; list.target = item; - for (auto& dep : item->info.dependencies) { + for (auto& dep : item->info.dependencies()) { if (!dep.isResolved()) { // check if this dep is available in the index if (auto depItem = this->getItem(dep.id, dep.version)) { @@ -595,7 +595,7 @@ Result Index::getInstallList(IndexItemHandle item) const { "reason is that the version of the dependency this mod " "depends on is not available. Please let the the developer " "({}) of the mod know!", - dep.id, dep.version.toString(), item->info.developer + dep.id, dep.version.toString(), item->info.developer() ); } } @@ -610,7 +610,7 @@ Result Index::getInstallList(IndexItemHandle item) const { void Index::installNext(size_t index, IndexInstallList const& list) { auto postError = [this, list](std::string const& error) { m_runningInstallations.erase(list.target); - ModInstallEvent(list.target->info.id, error).post(); + ModInstallEvent(list.target->info.id(), error).post(); }; // If we're at the end of the list, move the downloaded items to mods @@ -619,12 +619,12 @@ void Index::installNext(size_t index, IndexInstallList const& list) { // Move all downloaded files for (auto& item : list.list) { // If the mod is already installed, delete the old .geode file - if (auto mod = Loader::get()->getInstalledMod(item->info.id)) { + if (auto mod = Loader::get()->getInstalledMod(item->info.id())) { auto res = mod->uninstall(); if (!res) { return postError(fmt::format( "Unable to uninstall old version of {}: {}", - item->info.id, res.unwrapErr() + item->info.id(), res.unwrapErr() )); } } @@ -632,13 +632,13 @@ void Index::installNext(size_t index, IndexInstallList const& list) { // Move the temp file try { ghc::filesystem::rename( - dirs::getTempDir() / (item->info.id + ".index"), - dirs::getModsDir() / (item->info.id + ".geode") + dirs::getTempDir() / (item->info.id() + ".index"), + dirs::getModsDir() / (item->info.id() + ".geode") ); } catch(std::exception& e) { return postError(fmt::format( "Unable to install {}: {}", - item->info.id, e.what() + item->info.id(), e.what() )); } } @@ -646,7 +646,7 @@ void Index::installNext(size_t index, IndexInstallList const& list) { // load mods Loader::get()->refreshModsList(); - ModInstallEvent(list.target->info.id, UpdateFinished()).post(); + ModInstallEvent(list.target->info.id(), UpdateFinished()).post(); return; } @@ -657,9 +657,9 @@ void Index::installNext(size_t index, IndexInstallList const& list) { }; auto item = list.list.at(index); - auto tempFile = dirs::getTempDir() / (item->info.id + ".index"); + auto tempFile = dirs::getTempDir() / (item->info.id() + ".index"); m_runningInstallations[list.target] = web::AsyncWebRequest() - .join("install_item_" + item->info.id) + .join("install_item_" + item->info.id()) .fetch(item->download.url) .into(tempFile) .then([=](auto) { @@ -669,16 +669,16 @@ void Index::installNext(size_t index, IndexInstallList const& list) { return postError(fmt::format( "Binary file download for {} returned \"404 Not found\". " "Report this to the Geode development team.", - item->info.id + item->info.id() )); } // Verify checksum ModInstallEvent( - list.target->info.id, + list.target->info.id(), UpdateProgress( scaledProgress(100), - fmt::format("Verifying {}", item->info.id) + fmt::format("Verifying {}", item->info.id()) ) ).post(); @@ -687,7 +687,7 @@ void Index::installNext(size_t index, IndexInstallList const& list) { "Checksum mismatch with {}! (Downloaded file did not match what " "was expected. Try again, and if the download fails another time, " "report this to the Geode development team.)", - item->info.id + item->info.id() )); } @@ -697,15 +697,15 @@ void Index::installNext(size_t index, IndexInstallList const& list) { .expect([postError, list, item](std::string const& err) { postError(fmt::format( "Unable to download {}: {}", - item->info.id, err + item->info.id(), err )); }) .progress([this, item, list, scaledProgress](auto&, double now, double total) { ModInstallEvent( - list.target->info.id, + list.target->info.id(), UpdateProgress( scaledProgress(now / total * 100.0), - fmt::format("Downloading {}", item->info.id) + fmt::format("Downloading {}", item->info.id()) ) ).post(); }) @@ -740,7 +740,7 @@ void Index::install(IndexItemHandle item) { this->install(list.unwrap()); } else { ModInstallEvent( - item->info.id, + item->info.id(), UpdateFailed(list.unwrapErr()) ).post(); } diff --git a/loader/src/loader/LoaderImpl.cpp b/loader/src/loader/LoaderImpl.cpp index 167e5c64..e915c4d6 100644 --- a/loader/src/loader/LoaderImpl.cpp +++ b/loader/src/loader/LoaderImpl.cpp @@ -187,8 +187,8 @@ Result<> Loader::Impl::loadData() { // Mod loading Result Loader::Impl::loadModFromInfo(ModInfo const& info) { - if (m_mods.count(info.id)) { - return Err(fmt::format("Mod with ID '{}' already loaded", info.id)); + if (m_mods.count(info.id())) { + return Err(fmt::format("Mod with ID '{}' already loaded", info.id())); } // create Mod instance @@ -197,13 +197,13 @@ Result Loader::Impl::loadModFromInfo(ModInfo const& info) { if (!setupRes) { return Err(fmt::format( "Unable to setup mod '{}': {}", - info.id, setupRes.unwrapErr() + info.id(), setupRes.unwrapErr() )); } - m_mods.insert({ info.id, mod }); + m_mods.insert({ info.id(), mod }); mod->m_impl->m_enabled = Mod::get()->getSavedValue( - "should-load-" + info.id, true + "should-load-" + info.id(), true ); // add mod resources @@ -258,7 +258,7 @@ Mod* Loader::Impl::getLoadedMod(std::string const& id) const { } void Loader::Impl::updateModResources(Mod* mod) { - if (!mod->m_impl->m_info.spritesheets.size()) { + if (!mod->m_impl->m_info.spritesheets().size()) { return; } @@ -267,7 +267,7 @@ void Loader::Impl::updateModResources(Mod* mod) { log::debug("Adding resources for {}", mod->getID()); // add spritesheets - for (auto const& sheet : mod->m_impl->m_info.spritesheets) { + for (auto const& sheet : mod->m_impl->m_info.spritesheets()) { log::debug("Adding sheet {}", sheet); auto png = sheet + ".png"; auto plist = sheet + ".plist"; @@ -277,7 +277,7 @@ void Loader::Impl::updateModResources(Mod* mod) { plist == std::string(ccfu->fullPathForFilename(plist.c_str(), false))) { log::warn( "The resource dir of \"{}\" is missing \"{}\" png and/or plist files", - mod->m_impl->m_info.id, sheet + mod->m_impl->m_info.id(), sheet ); } else { @@ -312,7 +312,7 @@ void Loader::Impl::loadModsFromDirectory( } // skip this entry if it's already loaded if (map::contains(m_mods, [entry](Mod* p) -> bool { - return p->m_impl->m_info.path == entry.path(); + return p->m_impl->m_info.path() == entry.path(); })) { continue; } @@ -359,10 +359,10 @@ void Loader::Impl::refreshModsList() { // load early-load mods first for (auto& mod : m_modsToLoad) { - if (mod.needsEarlyLoad) { + if (mod.needsEarlyLoad()) { auto load = this->loadModFromInfo(mod); if (!load) { - log::error("Unable to load {}: {}", mod.id, load.unwrapErr()); + log::error("Unable to load {}: {}", mod.id(), load.unwrapErr()); } } } @@ -373,10 +373,10 @@ void Loader::Impl::refreshModsList() { // load the rest of the mods for (auto& mod : m_modsToLoad) { - if (!mod.needsEarlyLoad) { + if (!mod.needsEarlyLoad()) { auto load = this->loadModFromInfo(mod); if (!load) { - log::error("Unable to load {}: {}", mod.id, load.unwrapErr()); + log::error("Unable to load {}: {}", mod.id(), load.unwrapErr()); } } } @@ -700,7 +700,7 @@ void Loader::Impl::checkForLoaderUpdates() { bool Loader::Impl::isNewUpdateDownloaded() const { return m_isNewUpdateDownloaded; } - + json::Value Loader::Impl::processRawIPC(void* rawHandle, std::string const& buffer) { json::Value reply; diff --git a/loader/src/loader/ModImpl.cpp b/loader/src/loader/ModImpl.cpp index 35594d4b..c0180854 100644 --- a/loader/src/loader/ModImpl.cpp +++ b/loader/src/loader/ModImpl.cpp @@ -28,13 +28,13 @@ Mod::Impl::~Impl() { } Result<> Mod::Impl::setup() { - m_saveDirPath = dirs::getModsSaveDir() / m_info.id; + m_saveDirPath = dirs::getModsSaveDir() / m_info.id(); ghc::filesystem::create_directories(m_saveDirPath); this->setupSettings(); auto loadRes = this->loadData(); if (!loadRes) { - log::warn("Unable to load data for \"{}\": {}", m_info.id, loadRes.unwrapErr()); + log::warn("Unable to load data for \"{}\": {}", m_info.id(), loadRes.unwrapErr()); } return Ok(); } @@ -46,23 +46,23 @@ ghc::filesystem::path Mod::Impl::getSaveDir() const { } std::string Mod::Impl::getID() const { - return m_info.id; + return m_info.id(); } std::string Mod::Impl::getName() const { - return m_info.name; + return m_info.name(); } std::string Mod::Impl::getDeveloper() const { - return m_info.developer; + return m_info.developer(); } std::optional Mod::Impl::getDescription() const { - return m_info.description; + return m_info.description(); } std::optional Mod::Impl::getDetails() const { - return m_info.details; + return m_info.details(); } ModInfo Mod::Impl::getModInfo() const { @@ -74,15 +74,15 @@ ghc::filesystem::path Mod::Impl::getTempDir() const { } ghc::filesystem::path Mod::Impl::getBinaryPath() const { - return m_tempDirName / m_info.binaryName; + return m_tempDirName / m_info.binaryName(); } ghc::filesystem::path Mod::Impl::getPackagePath() const { - return m_info.path; + return m_info.path(); } VersionInfo Mod::Impl::getVersion() const { - return m_info.version; + return m_info.version(); } json::Value& Mod::Impl::getSaveContainer() { @@ -98,11 +98,11 @@ bool Mod::Impl::isLoaded() const { } bool Mod::Impl::supportsDisabling() const { - return m_info.supportsDisabling; + return m_info.supportsDisabling(); } bool Mod::Impl::supportsUnloading() const { - return m_info.supportsUnloading; + return m_info.supportsUnloading(); } bool Mod::Impl::wasSuccesfullyLoaded() const { @@ -143,7 +143,7 @@ Result<> Mod::Impl::loadData() { Severity::Error, m_self, "{}: Unable to load value for setting \"{}\"", - m_info.id, + m_info.id(), key ); } @@ -229,7 +229,7 @@ Result<> Mod::Impl::saveData() { } void Mod::Impl::setupSettings() { - for (auto& [key, sett] : m_info.settings) { + for (auto& [key, sett] : m_info.settings()) { if (auto value = sett.createDefaultValue()) { m_settings.emplace(key, std::move(value)); } @@ -247,19 +247,19 @@ void Mod::Impl::registerCustomSetting(std::string const& key, std::unique_ptr Mod::Impl::getSettingKeys() const { std::vector keys; - for (auto& [key, _] : m_info.settings) { + for (auto& [key, _] : m_info.settings()) { keys.push_back(key); } return keys; } std::optional Mod::Impl::getSettingDefinition(std::string const& key) const { - for (auto& setting : m_info.settings) { + for (auto& setting : m_info.settings()) { if (setting.first == key) { return setting.second; } @@ -275,7 +275,7 @@ SettingValue* Mod::Impl::getSetting(std::string const& key) const { } bool Mod::Impl::hasSetting(std::string const& key) const { - for (auto& setting : m_info.settings) { + for (auto& setting : m_info.settings()) { if (setting.first == key) { return true; } @@ -322,7 +322,7 @@ Result<> Mod::Impl::unloadBinary() { return Ok(); } - if (!m_info.supportsUnloading) { + if (!m_info.supportsUnloading()) { return Err("Mod does not support unloading"); } @@ -375,7 +375,7 @@ Result<> Mod::Impl::disable() { if (!m_enabled) { return Ok(); } - if (!m_info.supportsDisabling) { + if (!m_info.supportsDisabling()) { return Err("Mod does not support disabling"); } @@ -396,15 +396,15 @@ Result<> Mod::Impl::disable() { } Result<> Mod::Impl::uninstall() { - if (m_info.supportsDisabling) { + if (m_info.supportsDisabling()) { GEODE_UNWRAP(this->disable()); - if (m_info.supportsUnloading) { + if (m_info.supportsUnloading()) { GEODE_UNWRAP(this->unloadBinary()); } } try { - ghc::filesystem::remove(m_info.path); + ghc::filesystem::remove(m_info.path()); } catch (std::exception& e) { return Err( @@ -418,14 +418,14 @@ Result<> Mod::Impl::uninstall() { } bool Mod::Impl::isUninstalled() const { - return m_self != Mod::get() && !ghc::filesystem::exists(m_info.path); + return m_self != Mod::get() && !ghc::filesystem::exists(m_info.path()); } // Dependencies Result<> Mod::Impl::updateDependencies() { bool hasUnresolved = false; - for (auto& dep : m_info.dependencies) { + for (auto& dep : m_info.dependencies()) { // set the dependency's loaded mod if such exists if (!dep.mod) { dep.mod = Loader::get()->getLoadedMod(dep.id); @@ -455,20 +455,20 @@ Result<> Mod::Impl::updateDependencies() { } // load if there weren't any unresolved dependencies if (!hasUnresolved) { - log::debug("All dependencies for {} found", m_info.id); + log::debug("All dependencies for {} found", m_info.id()); if (m_enabled) { - log::debug("Resolved & loading {}", m_info.id); + log::debug("Resolved & loading {}", m_info.id()); GEODE_UNWRAP(this->loadBinary()); } else { - log::debug("Resolved {}, however not loading it as it is disabled", m_info.id); + log::debug("Resolved {}, however not loading it as it is disabled", m_info.id()); } } return Ok(); } bool Mod::Impl::hasUnresolvedDependencies() const { - for (auto const& dep : m_info.dependencies) { + for (auto const& dep : m_info.dependencies()) { if (!dep.isResolved()) { return true; } @@ -478,7 +478,7 @@ bool Mod::Impl::hasUnresolvedDependencies() const { std::vector Mod::Impl::getUnresolvedDependencies() { std::vector unresolved; - for (auto const& dep : m_info.dependencies) { + for (auto const& dep : m_info.dependencies()) { if (!dep.isResolved()) { unresolved.push_back(dep); } @@ -487,7 +487,7 @@ std::vector Mod::Impl::getUnresolvedDependencies() { } bool Mod::Impl::depends(std::string const& id) const { - return utils::ranges::contains(m_info.dependencies, [id](Dependency const& t) { + return utils::ranges::contains(m_info.dependencies(), [id](Dependency const& t) { return t.id == id; }); } @@ -498,7 +498,7 @@ Result<> Mod::Impl::enableHook(Hook* hook) { auto res = hook->enable(); if (res) m_hooks.push_back(hook); else { - log::error("Can't enable hook {} for mod {}: {}", m_info.id, res.unwrapErr()); + log::error("Can't enable hook {} for mod {}: {}", m_info.id(), res.unwrapErr()); } return res; @@ -583,16 +583,16 @@ Result<> Mod::Impl::createTempDir() { } // Create geode/temp/mod.id - auto tempPath = tempDir / m_info.id; + auto tempPath = tempDir / m_info.id(); if (!file::createDirectoryAll(tempPath)) { return Err("Unable to create mod runtime directory"); } // Unzip .geode file into temp dir - GEODE_UNWRAP_INTO(auto unzip, file::Unzip::create(m_info.path)); - if (!unzip.hasEntry(m_info.binaryName)) { + GEODE_UNWRAP_INTO(auto unzip, file::Unzip::create(m_info.path())); + if (!unzip.hasEntry(m_info.binaryName())) { return Err( - fmt::format("Unable to find platform binary under the name \"{}\"", m_info.binaryName) + fmt::format("Unable to find platform binary under the name \"{}\"", m_info.binaryName()) ); } GEODE_UNWRAP(unzip.extractAllTo(tempPath)); @@ -604,7 +604,7 @@ Result<> Mod::Impl::createTempDir() { } ghc::filesystem::path Mod::Impl::getConfigDir(bool create) const { - auto dir = dirs::getModConfigDir() / m_info.id; + auto dir = dirs::getModConfigDir() / m_info.id(); if (create) { (void)file::createDirectoryAll(dir); } @@ -615,8 +615,8 @@ char const* Mod::Impl::expandSpriteName(char const* name) { static std::unordered_map expanded = {}; if (expanded.count(name)) return expanded[name]; - auto exp = new char[strlen(name) + 2 + m_info.id.size()]; - auto exps = m_info.id + "/" + name; + auto exp = new char[strlen(name) + 2 + m_info.id().size()]; + auto exps = m_info.id() + "/" + name; memcpy(exp, exps.c_str(), exps.size() + 1); expanded[name] = exp; @@ -679,9 +679,9 @@ static ModInfo getModImplInfo() { return ModInfo(); } auto info = infoRes.unwrap(); - info.details = LOADER_ABOUT_MD; - info.supportInfo = SUPPORT_INFO; - info.supportsDisabling = false; + info.details() = LOADER_ABOUT_MD; + info.supportInfo() = SUPPORT_INFO; + info.supportsDisabling() = false; return info; } diff --git a/loader/src/loader/ModInfo.cpp b/loader/src/loader/ModInfo.cpp index f2bc948a..cb4b2642 100644 --- a/loader/src/loader/ModInfo.cpp +++ b/loader/src/loader/ModInfo.cpp @@ -1,24 +1,18 @@ #include #include -#include -#include -#include #include #include - +#include +#include #include +#include USE_GEODE_NAMESPACE(); bool Dependency::isResolved() const { - return - !this->required || - ( - this->mod && - this->mod->isLoaded() && - this->mod->isEnabled() && - this->version.compare(this->mod->getVersion()) - ); + return !this->required || + (this->mod && this->mod->isLoaded() && this->mod->isEnabled() && + this->version.compare(this->mod->getVersion())); } static std::string sanitizeDetailsData(std::string const& str) { @@ -26,7 +20,50 @@ static std::string sanitizeDetailsData(std::string const& str) { return utils::string::replace(str, "\r", ""); } -bool ModInfo::validateID(std::string const& id) { +class ModInfo::Impl { +public: + ghc::filesystem::path m_path; + std::string m_binaryName; + VersionInfo m_version{1, 0, 0}; + std::string m_id; + std::string m_name; + std::string m_developer; + std::optional m_description; + std::optional m_details; + std::optional m_changelog; + std::optional m_supportInfo; + std::optional m_repository; + std::optional m_issues; + std::vector m_dependencies; + std::vector m_spritesheets; + std::vector> m_settings; + bool m_supportsDisabling = true; + bool m_supportsUnloading = false; + bool m_needsEarlyLoad = false; + + std::shared_ptr m_rawJSON; + + static Result createFromGeodeZip(utils::file::Unzip& zip); + static Result createFromGeodeFile(ghc::filesystem::path const& path); + static Result createFromFile(ghc::filesystem::path const& path); + static Result create(ModJson const& json); + + ModJson toJSON() const; + ModJson getRawJSON() const; + + bool operator==(ModInfo::Impl const& other) const; + + static bool validateID(std::string const& id); + + static Result createFromSchemaV010(ModJson const& json); + + Result<> addSpecialFiles(ghc::filesystem::path const& dir); + Result<> addSpecialFiles(utils::file::Unzip& zip); + + std::vector*>> getSpecialFiles(); +}; + +bool ModInfo::Impl::validateID(std::string const& id) { // ids may not be empty if (!id.size()) return false; for (auto const& c : id) { @@ -37,47 +74,49 @@ bool ModInfo::validateID(std::string const& id) { return true; } -Result ModInfo::createFromSchemaV010(ModJson const& rawJson) { +Result ModInfo::Impl::createFromSchemaV010(ModJson const& rawJson) { ModInfo info; - info.m_rawJSON = std::make_unique(rawJson); + auto impl = info.m_impl.get(); - JsonChecker checker(*info.m_rawJSON); + impl->m_rawJSON = std::make_unique(rawJson); + + JsonChecker checker(*impl->m_rawJSON); auto root = checker.root("[mod.json]").obj(); root.addKnownKey("geode"); root.addKnownKey("binary"); - root.needs("id").validate(&ModInfo::validateID).into(info.id); - root.needs("version").into(info.version); - root.needs("name").into(info.name); - root.needs("developer").into(info.developer); - root.has("description").into(info.description); - root.has("repository").into(info.repository); - root.has("toggleable").into(info.supportsDisabling); - root.has("unloadable").into(info.supportsUnloading); - root.has("early-load").into(info.needsEarlyLoad); + root.needs("id").validate(&ModInfo::validateID).into(impl->m_id); + root.needs("version").into(impl->m_version); + root.needs("name").into(impl->m_name); + root.needs("developer").into(impl->m_developer); + root.has("description").into(impl->m_description); + root.has("repository").into(impl->m_repository); + root.has("toggleable").into(impl->m_supportsDisabling); + root.has("unloadable").into(impl->m_supportsUnloading); + root.has("early-load").into(impl->m_needsEarlyLoad); for (auto& dep : root.has("dependencies").iterate()) { auto obj = dep.obj(); - auto depobj = Dependency {}; + auto depobj = Dependency{}; obj.needs("id").validate(&ModInfo::validateID).into(depobj.id); obj.needs("version").into(depobj.version); obj.has("required").into(depobj.required); obj.checkUnknownKeys(); - info.dependencies.push_back(depobj); + impl->m_dependencies.push_back(depobj); } for (auto& [key, value] : root.has("settings").items()) { GEODE_UNWRAP_INTO(auto sett, Setting::parse(key, value)); - info.settings.push_back({ key, sett }); + impl->m_settings.push_back({key, sett}); } if (auto resources = root.has("resources").obj()) { for (auto& [key, _] : resources.has("spritesheets").items()) { - info.spritesheets.push_back(info.id + "/" + key); + impl->m_spritesheets.push_back(impl->m_id + "/" + key); } } @@ -85,11 +124,11 @@ Result ModInfo::createFromSchemaV010(ModJson const& rawJson) { IssuesInfo issuesInfo; issues.needs("info").into(issuesInfo.info); issues.has("url").intoAs(issuesInfo.url); - info.issues = issuesInfo; + impl->m_issues = issuesInfo; } // with new cli, binary name is always mod id - info.binaryName = info.id + GEODE_PLATFORM_EXTENSION; + impl->m_binaryName = impl->m_id + GEODE_PLATFORM_EXTENSION; // removed keys if (root.has("datastore")) { @@ -110,12 +149,13 @@ Result ModInfo::createFromSchemaV010(ModJson const& rawJson) { return Ok(info); } -Result ModInfo::create(ModJson const& json) { +Result ModInfo::Impl::create(ModJson const& json) { // Check mod.json target version auto schema = LOADER_VERSION; if (json.contains("geode") && json["geode"].is_string()) { GEODE_UNWRAP_INTO( - schema, VersionInfo::parse(json["geode"].as_string()) + schema, + VersionInfo::parse(json["geode"].as_string()) .expect("[mod.json] has invalid target loader version: {error}") ); } @@ -159,13 +199,15 @@ Result ModInfo::create(ModJson const& json) { ); } -Result ModInfo::createFromFile(ghc::filesystem::path const& path) { +Result ModInfo::Impl::createFromFile(ghc::filesystem::path const& path) { GEODE_UNWRAP_INTO(auto read, utils::file::readString(path)); - + try { GEODE_UNWRAP_INTO(auto info, ModInfo::create(json::parse(read))); - info.path = path; + auto impl = info.m_impl.get(); + + impl->m_path = path; if (path.has_parent_path()) { GEODE_UNWRAP(info.addSpecialFiles(path.parent_path())); } @@ -176,12 +218,12 @@ Result ModInfo::createFromFile(ghc::filesystem::path const& path) { } } -Result ModInfo::createFromGeodeFile(ghc::filesystem::path const& path) { +Result ModInfo::Impl::createFromGeodeFile(ghc::filesystem::path const& path) { GEODE_UNWRAP_INTO(auto unzip, file::Unzip::create(path)); return ModInfo::createFromGeodeZip(unzip); } -Result ModInfo::createFromGeodeZip(file::Unzip& unzip) { +Result ModInfo::Impl::createFromGeodeZip(file::Unzip& unzip) { // Check if mod.json exists in zip if (!unzip.hasEntry("mod.json")) { return Err("\"" + unzip.getPath().string() + "\" is missing mod.json"); @@ -206,16 +248,17 @@ Result ModInfo::createFromGeodeZip(file::Unzip& unzip) { return Err("\"" + unzip.getPath().string() + "\" - " + res.unwrapErr()); } auto info = res.unwrap(); - info.path = unzip.getPath(); + auto impl = info.m_impl.get(); + impl->m_path = unzip.getPath(); GEODE_UNWRAP(info.addSpecialFiles(unzip).expect("Unable to add extra files: {error}")); return Ok(info); } -Result<> ModInfo::addSpecialFiles(file::Unzip& unzip) { +Result<> ModInfo::Impl::addSpecialFiles(file::Unzip& unzip) { // unzip known MD files - for (auto& [file, target] : getSpecialFiles()) { + for (auto& [file, target] : this->getSpecialFiles()) { if (unzip.hasEntry(file)) { GEODE_UNWRAP_INTO(auto data, unzip.extract(file).expect("Unable to extract \"{}\"", file)); *target = sanitizeDetailsData(std::string(data.begin(), data.end())); @@ -224,9 +267,9 @@ Result<> ModInfo::addSpecialFiles(file::Unzip& unzip) { return Ok(); } -Result<> ModInfo::addSpecialFiles(ghc::filesystem::path const& dir) { +Result<> ModInfo::Impl::addSpecialFiles(ghc::filesystem::path const& dir) { // unzip known MD files - for (auto& [file, target] : getSpecialFiles()) { + for (auto& [file, target] : this->getSpecialFiles()) { if (ghc::filesystem::exists(dir / file)) { auto data = file::readString(dir / file); if (!data) { @@ -238,25 +281,223 @@ Result<> ModInfo::addSpecialFiles(ghc::filesystem::path const& dir) { return Ok(); } -std::vector*>> ModInfo::getSpecialFiles() { +std::vector*>> ModInfo::Impl::getSpecialFiles() { return { - { "about.md", &this->details }, - { "changelog.md", &this->changelog }, - { "support.md", &this->supportInfo }, + {"about.md", &this->m_details}, + {"changelog.md", &this->m_changelog}, + {"support.md", &this->m_supportInfo}, }; } -ModJson ModInfo::toJSON() const { +ModJson ModInfo::Impl::toJSON() const { auto json = *m_rawJSON; - json["path"] = this->path.string(); - json["binary"] = this->binaryName; + json["path"] = this->m_path.string(); + json["binary"] = this->m_binaryName; return json; } -ModJson ModInfo::getRawJSON() const { +ModJson ModInfo::Impl::getRawJSON() const { return *m_rawJSON; } -bool ModInfo::operator==(ModInfo const& other) const { - return this->id == other.id; +bool ModInfo::Impl::operator==(ModInfo::Impl const& other) const { + return this->m_id == other.m_id; } + +ghc::filesystem::path& ModInfo::path() { + return m_impl->m_path; +} +ghc::filesystem::path const& ModInfo::path() const { + return m_impl->m_path; +} + +std::string& ModInfo::binaryName() { + return m_impl->m_binaryName; +} +std::string const& ModInfo::binaryName() const { + return m_impl->m_binaryName; +} + +VersionInfo& ModInfo::version() { + return m_impl->m_version; +} +VersionInfo const& ModInfo::version() const { + return m_impl->m_version; +} + +std::string& ModInfo::id() { + return m_impl->m_id; +} +std::string const& ModInfo::id() const { + return m_impl->m_id; +} + +std::string& ModInfo::name() { + return m_impl->m_name; +} +std::string const& ModInfo::name() const { + return m_impl->m_name; +} + +std::string& ModInfo::developer() { + return m_impl->m_developer; +} +std::string const& ModInfo::developer() const { + return m_impl->m_developer; +} + +std::optional& ModInfo::description() { + return m_impl->m_description; +} +std::optional const& ModInfo::description() const { + return m_impl->m_description; +} + +std::optional& ModInfo::details() { + return m_impl->m_details; +} +std::optional const& ModInfo::details() const { + return m_impl->m_details; +} + +std::optional& ModInfo::changelog() { + return m_impl->m_changelog; +} +std::optional const& ModInfo::changelog() const { + return m_impl->m_changelog; +} + +std::optional& ModInfo::supportInfo() { + return m_impl->m_supportInfo; +} +std::optional const& ModInfo::supportInfo() const { + return m_impl->m_supportInfo; +} + +std::optional& ModInfo::repository() { + return m_impl->m_repository; +} +std::optional const& ModInfo::repository() const { + return m_impl->m_repository; +} + +std::optional& ModInfo::issues() { + return m_impl->m_issues; +} +std::optional const& ModInfo::issues() const { + return m_impl->m_issues; +} + +std::vector& ModInfo::dependencies() { + return m_impl->m_dependencies; +} +std::vector const& ModInfo::dependencies() const { + return m_impl->m_dependencies; +} + +std::vector& ModInfo::spritesheets() { + return m_impl->m_spritesheets; +} +std::vector const& ModInfo::spritesheets() const { + return m_impl->m_spritesheets; +} + +std::vector>& ModInfo::settings() { + return m_impl->m_settings; +} +std::vector> const& ModInfo::settings() const { + return m_impl->m_settings; +} + +bool& ModInfo::supportsDisabling() { + return m_impl->m_supportsDisabling; +} +bool const& ModInfo::supportsDisabling() const { + return m_impl->m_supportsDisabling; +} + +bool& ModInfo::supportsUnloading() { + return m_impl->m_supportsUnloading; +} +bool const& ModInfo::supportsUnloading() const { + return m_impl->m_supportsUnloading; +} + +bool& ModInfo::needsEarlyLoad() { + return m_impl->m_needsEarlyLoad; +} +bool const& ModInfo::needsEarlyLoad() const { + return m_impl->m_needsEarlyLoad; +} + +Result ModInfo::createFromGeodeZip(utils::file::Unzip& zip) { + return Impl::createFromGeodeZip(zip); +} + +Result ModInfo::createFromGeodeFile(ghc::filesystem::path const& path) { + return Impl::createFromGeodeFile(path); +} + +Result ModInfo::createFromFile(ghc::filesystem::path const& path) { + return Impl::createFromFile(path); +} + +Result ModInfo::create(ModJson const& json) { + return Impl::create(json); +} + +ModJson ModInfo::toJSON() const { + return m_impl->toJSON(); +} + +ModJson ModInfo::getRawJSON() const { + return m_impl->getRawJSON(); +} + +bool ModInfo::operator==(ModInfo const& other) const { + return m_impl->operator==(*other.m_impl); +} + +bool ModInfo::validateID(std::string const& id) { + return Impl::validateID(id); +} + +ModJson& ModInfo::rawJSON() { + return *m_impl->m_rawJSON; +} +ModJson const& ModInfo::rawJSON() const { + return *m_impl->m_rawJSON; +} + +Result ModInfo::createFromSchemaV010(ModJson const& json) { + return Impl::createFromSchemaV010(json); +} + +Result<> ModInfo::addSpecialFiles(ghc::filesystem::path const& dir) { + return m_impl->addSpecialFiles(dir); +} +Result<> ModInfo::addSpecialFiles(utils::file::Unzip& zip) { + return m_impl->addSpecialFiles(zip); +} + +std::vector*>> ModInfo::getSpecialFiles() { + return m_impl->getSpecialFiles(); +} + +ModInfo::ModInfo() : m_impl() {} + +ModInfo::ModInfo(ModInfo const& other) : m_impl(std::make_unique(*other.m_impl)) {} + +ModInfo::ModInfo(ModInfo&& other) noexcept : m_impl(std::move(other.m_impl)) {} + +ModInfo& ModInfo::operator=(ModInfo const& other) { + m_impl = std::make_unique(*other.m_impl); + return *this; +} + +ModInfo& ModInfo::operator=(ModInfo&& other) noexcept { + m_impl = std::move(other.m_impl); + return *this; +} + +ModInfo::~ModInfo() {} \ No newline at end of file diff --git a/loader/src/platform/ios/ModImpl.cpp b/loader/src/platform/ios/ModImpl.cpp index 68be9e01..64c4d465 100644 --- a/loader/src/platform/ios/ModImpl.cpp +++ b/loader/src/platform/ios/ModImpl.cpp @@ -19,7 +19,7 @@ T findSymbolOrMangled(void* dylib, char const* name, char const* mangled) { Result<> Mod::Impl::loadPlatformBinary() { auto dylib = - dlopen((m_tempDirName / m_info.binaryName).string().c_str(), RTLD_LAZY); + dlopen((m_tempDirName / m_info.binaryName()).string().c_str(), RTLD_LAZY); if (dylib) { if (m_platformInfo) { delete m_platformInfo; diff --git a/loader/src/platform/mac/ModImpl.cpp b/loader/src/platform/mac/ModImpl.cpp index 87e50d00..079e5683 100644 --- a/loader/src/platform/mac/ModImpl.cpp +++ b/loader/src/platform/mac/ModImpl.cpp @@ -19,7 +19,7 @@ T findSymbolOrMangled(void* dylib, char const* name, char const* mangled) { Result<> Mod::Impl::loadPlatformBinary() { auto dylib = - dlopen((m_tempDirName / m_info.binaryName).string().c_str(), RTLD_LAZY); + dlopen((m_tempDirName / m_info.binaryName()).string().c_str(), RTLD_LAZY); if (dylib) { if (m_platformInfo) { delete m_platformInfo; diff --git a/loader/src/platform/windows/ModImpl.cpp b/loader/src/platform/windows/ModImpl.cpp index 4075ee62..fe81db7b 100644 --- a/loader/src/platform/windows/ModImpl.cpp +++ b/loader/src/platform/windows/ModImpl.cpp @@ -73,7 +73,7 @@ std::string getLastWinError() { } Result<> Mod::Impl::loadPlatformBinary() { - auto load = LoadLibraryW((m_tempDirName / m_info.binaryName).wstring().c_str()); + auto load = LoadLibraryW((m_tempDirName / m_info.binaryName()).wstring().c_str()); if (load) { if (m_platformInfo) { delete m_platformInfo; diff --git a/loader/src/ui/internal/GeodeUI.cpp b/loader/src/ui/internal/GeodeUI.cpp index 806566a3..a4a95206 100644 --- a/loader/src/ui/internal/GeodeUI.cpp +++ b/loader/src/ui/internal/GeodeUI.cpp @@ -14,19 +14,19 @@ void geode::openModsList() { } void geode::openIssueReportPopup(Mod* mod) { - if (mod->getModInfo().issues) { + if (mod->getModInfo().issues()) { MDPopup::create( "Issue Report", - mod->getModInfo().issues.value().info + + mod->getModInfo().issues().value().info + "\n\n" "If your issue relates to a game crash, please include the " "latest crash log(s) from `" + dirs::getCrashlogsDir().string() + "`", - "OK", (mod->getModInfo().issues.value().url ? "Open URL" : ""), + "OK", (mod->getModInfo().issues().value().url ? "Open URL" : ""), [mod](bool btn2) { if (btn2) { web::openLinkInBrowser( - mod->getModInfo().issues.value().url.value() + mod->getModInfo().issues().value().url.value() ); } } diff --git a/loader/src/ui/internal/info/DevProfilePopup.cpp b/loader/src/ui/internal/info/DevProfilePopup.cpp index 3f5285ef..516db347 100644 --- a/loader/src/ui/internal/info/DevProfilePopup.cpp +++ b/loader/src/ui/internal/info/DevProfilePopup.cpp @@ -25,7 +25,7 @@ bool DevProfilePopup::setup(std::string const& developer) { // index mods for (auto& item : Index::get()->getItemsByDeveloper(developer)) { - if (Loader::get()->isModInstalled(item->info.id)) { + if (Loader::get()->isModInstalled(item->info.id())) { continue; } items->addObject(IndexItemCell::create( diff --git a/loader/src/ui/internal/info/ModInfoPopup.cpp b/loader/src/ui/internal/info/ModInfoPopup.cpp index d19eab75..b395e62b 100644 --- a/loader/src/ui/internal/info/ModInfoPopup.cpp +++ b/loader/src/ui/internal/info/ModInfoPopup.cpp @@ -49,7 +49,7 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) { constexpr float logoSize = 40.f; constexpr float logoOffset = 10.f; - auto nameLabel = CCLabelBMFont::create(info.name.c_str(), "bigFont.fnt"); + auto nameLabel = CCLabelBMFont::create(info.name().c_str(), "bigFont.fnt"); nameLabel->setAnchorPoint({ .0f, .5f }); nameLabel->limitLabelWidth(200.f, .7f, .1f); m_mainLayer->addChild(nameLabel, 2); @@ -57,7 +57,7 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) { auto logoSpr = this->createLogo({logoSize, logoSize}); m_mainLayer->addChild(logoSpr); - auto developerStr = "by " + info.developer; + auto developerStr = "by " + info.developer(); auto developerLabel = CCLabelBMFont::create(developerStr.c_str(), "goldFont.fnt"); developerLabel->setScale(.5f); developerLabel->setAnchorPoint({.0f, .5f}); @@ -78,7 +78,7 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) { ); auto versionLabel = CCLabelBMFont::create( - info.version.toString().c_str(), + info.version().toString().c_str(), "bigFont.fnt" ); versionLabel->setAnchorPoint({ .0f, .5f }); @@ -94,7 +94,7 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) { this->registerWithTouchDispatcher(); m_detailsArea = MDTextArea::create( - (info.details ? info.details.value() : "### No description provided."), + (info.details() ? info.details().value() : "### No description provided."), { 350.f, 137.5f } ); m_detailsArea->setPosition( @@ -111,8 +111,8 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) { m_mainLayer->addChild(m_scrollbar); // changelog - if (info.changelog) { - m_changelogArea = MDTextArea::create(info.changelog.value(), { 350.f, 137.5f }); + if (info.changelog()) { + m_changelogArea = MDTextArea::create(info.changelog().value(), { 350.f, 137.5f }); m_changelogArea->setPosition( -5000.f, winSize.height / 2 - m_changelogArea->getScaledContentSize().height / 2 - 20.f ); @@ -155,7 +155,7 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) { m_buttonMenu->addChild(m_infoBtn); // repo button - if (info.repository) { + if (info.repository()) { auto repoBtn = CCMenuItemSpriteExtra::create( CCSprite::createWithSpriteFrameName("github.png"_spr), this, @@ -166,7 +166,7 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) { } // support button - if (info.supportInfo) { + if (info.supportInfo()) { auto supportBtn = CCMenuItemSpriteExtra::create( CCSprite::createWithSpriteFrameName("gift.png"_spr), this, @@ -192,30 +192,30 @@ bool ModInfoPopup::init(ModInfo const& info, ModListLayer* list) { void ModInfoPopup::onSupport(CCObject*) { MDPopup::create( - "Support " + this->getModInfo().name, - this->getModInfo().supportInfo.value(), + "Support " + this->getModInfo().name(), + this->getModInfo().supportInfo().value(), "OK" )->show(); } void ModInfoPopup::onRepository(CCObject*) { - web::openLinkInBrowser(this->getModInfo().repository.value()); + web::openLinkInBrowser(this->getModInfo().repository().value()); } void ModInfoPopup::onInfo(CCObject*) { auto info = this->getModInfo(); FLAlertLayer::create( nullptr, - ("About " + info.name).c_str(), + ("About " + info.name()).c_str(), fmt::format( "ID: {}\n" "Version: {}\n" "Developer: {}\n" "Path: {}\n", - info.id, - info.version.toString(), - info.developer, - info.path.string() + info.id(), + info.version().toString(), + info.developer(), + info.path().string() ), "OK", nullptr, @@ -357,7 +357,7 @@ bool LocalModInfoPopup::init(Mod* mod, ModListLayer* list) { m_mainLayer->addChild(m_installStatus); m_updateVersionLabel = CCLabelBMFont::create( - ("Available: " + indexItem->info.version.toString()).c_str(), + ("Available: " + indexItem->info.version().toString()).c_str(), "bigFont.fnt" ); m_updateVersionLabel->setScale(.35f); @@ -369,7 +369,7 @@ bool LocalModInfoPopup::init(Mod* mod, ModListLayer* list) { } // issue report button - if (mod->getModInfo().issues) { + if (mod->getModInfo().issues()) { auto issuesBtnSpr = ButtonSprite::create( "Report an Issue", "goldFont.fnt", "GJ_button_04.png", .8f ); @@ -526,7 +526,7 @@ IndexItemInfoPopup::IndexItemInfoPopup() bool IndexItemInfoPopup::init(IndexItemHandle item, ModListLayer* list) { m_item = item; - m_installListener.setFilter(m_item->info.id); + m_installListener.setFilter(m_item->info.id()); auto winSize = CCDirector::sharedDirector()->getWinSize(); @@ -613,7 +613,7 @@ void IndexItemInfoPopup::onInstall(CCObject*) { [](IndexItemHandle handle) { return fmt::format( " - {} ({})", - handle->info.name, handle->info.id + handle->info.name(), handle->info.id() ); } ), diff --git a/loader/src/ui/internal/list/ModListCell.cpp b/loader/src/ui/internal/list/ModListCell.cpp index bd4106f6..a2b89bf1 100644 --- a/loader/src/ui/internal/list/ModListCell.cpp +++ b/loader/src/ui/internal/list/ModListCell.cpp @@ -45,9 +45,9 @@ void ModListCell::setupInfo( bool hasDesc = display == ModListDisplay::Expanded && - info.description.has_value(); + info.description().has_value(); - auto titleLabel = CCLabelBMFont::create(info.name.c_str(), "bigFont.fnt"); + auto titleLabel = CCLabelBMFont::create(info.name().c_str(), "bigFont.fnt"); titleLabel->setAnchorPoint({ .0f, .5f }); titleLabel->setPositionX(m_height / 2 + logoSize / 2 + 13.f); if (hasDesc && spaceForTags) { @@ -66,7 +66,7 @@ void ModListCell::setupInfo( this->addChild(titleLabel); auto versionLabel = CCLabelBMFont::create( - info.version.toString(false).c_str(), + info.version().toString(false).c_str(), "bigFont.fnt" ); versionLabel->setAnchorPoint({ .0f, .5f }); @@ -78,7 +78,7 @@ void ModListCell::setupInfo( versionLabel->setColor({ 0, 255, 0 }); this->addChild(versionLabel); - if (auto tag = info.version.getTag()) { + if (auto tag = info.version().getTag()) { auto tagLabel = TagNode::create( versionTagToString(tag.value()).c_str() ); @@ -92,7 +92,7 @@ void ModListCell::setupInfo( this->addChild(tagLabel); } - auto creatorStr = "by " + info.developer; + auto creatorStr = "by " + info.developer(); auto creatorLabel = CCLabelBMFont::create(creatorStr.c_str(), "goldFont.fnt"); creatorLabel->setScale(.43f); @@ -131,7 +131,7 @@ void ModListCell::setupInfo( descBG->setScale(.25f); this->addChild(descBG); - m_description = CCLabelBMFont::create(info.description.value().c_str(), "chatFont.fnt"); + m_description = CCLabelBMFont::create(info.description().value().c_str(), "chatFont.fnt"); m_description->setAnchorPoint({ .0f, .5f }); m_description->setPosition(m_height / 2 + logoSize / 2 + 18.f, descBG->getPositionY()); m_description->limitLabelWidth(m_width / 2 - 10.f, .5f, .1f); @@ -354,7 +354,7 @@ bool IndexItemCell::init( void IndexItemCell::updateState() {} std::string IndexItemCell::getDeveloper() const { - return m_item->info.developer; + return m_item->info.developer(); } CCNode* IndexItemCell::createLogo(CCSize const& size) { diff --git a/loader/src/ui/internal/list/ModListLayer.cpp b/loader/src/ui/internal/list/ModListLayer.cpp index e9e15aec..1ba096f7 100644 --- a/loader/src/ui/internal/list/ModListLayer.cpp +++ b/loader/src/ui/internal/list/ModListLayer.cpp @@ -52,11 +52,11 @@ static std::optional queryMatchKeywords( // fuzzy match keywords if (query.keywords) { bool someMatched = false; - WEIGHTED_MATCH(info.name, 2); - WEIGHTED_MATCH(info.id, 1.5); - WEIGHTED_MATCH(info.developer, 1); - WEIGHTED_MATCH(info.details.value_or(""), 2); - WEIGHTED_MATCH(info.description.value_or(""), 1); + WEIGHTED_MATCH(info.name(), 2); + WEIGHTED_MATCH(info.id(), 1.5); + WEIGHTED_MATCH(info.developer(), 1); + WEIGHTED_MATCH(info.details().value_or(""), 2); + WEIGHTED_MATCH(info.description().value_or(""), 1); if (!someMatched) { return std::nullopt; } @@ -66,7 +66,7 @@ static std::optional queryMatchKeywords( // sorted, at least enough so that if you're scrolling it based on // alphabetical order you will find the part you're looking for easily // so it's fine - weighted = -tolower(info.name[0]); + weighted = -tolower(info.name()[0]); } // empty keywords always match @@ -83,7 +83,7 @@ static std::optional queryMatch(ModListQuery const& query, Mod* mod) { static std::optional queryMatch(ModListQuery const& query, IndexItemHandle item) { // if no force visibility was provided and item is already installed, don't // show it - if (!query.forceVisibility && Loader::get()->isModInstalled(item->info.id)) { + if (!query.forceVisibility && Loader::get()->isModInstalled(item->info.id())) { return std::nullopt; } // make sure all tags match