From e1eecaa8e7c24659748a3ae8da1e9fb207121d9e Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Tue, 31 Jan 2023 16:43:17 +0300 Subject: [PATCH 01/20] make ModImpl pimp --- loader/include/Geode/loader/ModInfo.hpp | 81 ++-- loader/src/loader/Index.cpp | 60 +-- loader/src/loader/LoaderImpl.cpp | 28 +- loader/src/loader/ModImpl.cpp | 84 ++--- loader/src/loader/ModInfo.cpp | 347 +++++++++++++++--- loader/src/platform/ios/ModImpl.cpp | 2 +- loader/src/platform/mac/ModImpl.cpp | 2 +- loader/src/platform/windows/ModImpl.cpp | 2 +- loader/src/ui/internal/GeodeUI.cpp | 8 +- .../src/ui/internal/info/DevProfilePopup.cpp | 2 +- loader/src/ui/internal/info/ModInfoPopup.cpp | 40 +- loader/src/ui/internal/list/ModListCell.cpp | 14 +- loader/src/ui/internal/list/ModListLayer.cpp | 14 +- 13 files changed, 478 insertions(+), 206 deletions(-) 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 From 51990ad89b25cecbabaf748a5bcb279227fce090 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Tue, 31 Jan 2023 16:43:17 +0300 Subject: [PATCH 02/20] make ModInfo pimpl --- loader/include/Geode/loader/ModInfo.hpp | 81 ++-- loader/src/loader/Index.cpp | 60 +-- loader/src/loader/LoaderImpl.cpp | 28 +- loader/src/loader/ModImpl.cpp | 84 ++--- loader/src/loader/ModInfo.cpp | 347 +++++++++++++++--- loader/src/platform/ios/ModImpl.cpp | 2 +- loader/src/platform/mac/ModImpl.cpp | 2 +- loader/src/platform/windows/ModImpl.cpp | 2 +- loader/src/ui/internal/GeodeUI.cpp | 8 +- .../src/ui/internal/info/DevProfilePopup.cpp | 2 +- loader/src/ui/internal/info/ModInfoPopup.cpp | 40 +- loader/src/ui/internal/list/ModListCell.cpp | 14 +- loader/src/ui/internal/list/ModListLayer.cpp | 14 +- 13 files changed, 478 insertions(+), 206 deletions(-) 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 From df00ad7b88eb6270bcd62d7091bcf0083a99a555 Mon Sep 17 00:00:00 2001 From: mat <26722564+matcool@users.noreply.github.com> Date: Sat, 4 Feb 2023 17:31:37 -0300 Subject: [PATCH 03/20] disable zstd support for minizip this should fix some macos issues --- loader/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index fb8bead5..7b1b519a 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -135,6 +135,7 @@ if (NOT GEODE_BUILDING_DOCS) # Zip support (needed for in-memory streams, which zlib's minizip doesn't support) set(MZ_LZMA Off CACHE INTERNAL "Enables LZMA & XZ compression") + set(MZ_ZSTD Off CACHE INTERNAL "") CPMAddPackage("gh:zlib-ng/minizip-ng#cee6d8c") # Regex support From 1f7d50a9b9140d02f6a9afb97734eb9761b6a0d4 Mon Sep 17 00:00:00 2001 From: camila314 <47485054+camila314@users.noreply.github.com> Date: Tue, 7 Feb 2023 13:58:21 -0600 Subject: [PATCH 04/20] fix potentially modifying event listeners set while iterating --- loader/src/loader/Event.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/loader/src/loader/Event.cpp b/loader/src/loader/Event.cpp index 87c97e3b..133263b2 100644 --- a/loader/src/loader/Event.cpp +++ b/loader/src/loader/Event.cpp @@ -19,7 +19,9 @@ Event::~Event() {} void Event::postFrom(Mod* m) { if (m) this->sender = m; - for (auto h : Event::listeners()) { + std::unordered_set listeners_copy = Event::listeners(); + + for (auto h : listeners_copy) { if (h->passThrough(this) == ListenerResult::Stop) { break; } From 4f259c6e3aa63eba80165e12ff8ce3f8930adf45 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Wed, 8 Feb 2023 16:42:34 +0300 Subject: [PATCH 05/20] forward filesystem --- codegen/src/ModifyGen.cpp | 4 +- codegen/src/Shared.hpp | 2 +- loader/hash/hash.hpp | 2 +- loader/include/Geode/Geode.hpp | 4 +- loader/include/Geode/Modify.hpp | 4 +- loader/include/Geode/c++stl/gnustl.hpp | 229 +--------------- .../cocos/support/zip_support/ZipUtils.h | 2 +- loader/include/Geode/loader/Dirs.hpp | 2 +- loader/include/Geode/loader/Loader.hpp | 2 +- loader/include/Geode/loader/Log.hpp | 2 +- .../include/Geode/modify/InternalMacros.hpp | 57 ---- loader/include/Geode/modify/Modify.hpp | 57 ++++ loader/include/Geode/utils/file.hpp | 2 +- loader/include/Geode/utils/general.hpp | 2 +- loader/include/Geode/utils/web.hpp | 2 +- loader/launcher/mac/Bootstrapper.cpp | 2 +- loader/launcher/windows/Bootstrapper.cpp | 2 +- loader/src/hooks/DynamicCastFix.cpp | 7 +- loader/src/hooks/MessageBoxFix.cpp | 16 +- loader/src/internal/FileWatcher.hpp | 2 +- loader/src/internal/crashlog.hpp | 2 +- loader/src/main.cpp | 1 + loader/src/platform/mac/crashlog.mm | 6 +- loader/src/platform/mac/gdstdlib.cpp | 251 +++++++++++++++++- loader/src/platform/windows/util.cpp | 2 +- 25 files changed, 349 insertions(+), 315 deletions(-) delete mode 100644 loader/include/Geode/modify/InternalMacros.hpp diff --git a/codegen/src/ModifyGen.cpp b/codegen/src/ModifyGen.cpp index 22fbb690..f976b7a9 100644 --- a/codegen/src/ModifyGen.cpp +++ b/codegen/src/ModifyGen.cpp @@ -10,7 +10,6 @@ namespace { char const* modify_start = R"GEN(#pragma once #include #include -#include #include {class_include} using namespace geode::modifier; @@ -92,8 +91,7 @@ std::string generateModifyHeader(Root& root, ghc::filesystem::path const& single if (fn->type == FunctionType::Normal && !used.count(fn->name)) { used.insert(fn->name); statics += fmt::format( - format_strings::statics_declare_identifier, - fmt::arg("function_name", fn->name) + format_strings::statics_declare_identifier, fmt::arg("function_name", fn->name) ); } } diff --git a/codegen/src/Shared.hpp b/codegen/src/Shared.hpp index d37dc3dd..1ae45ceb 100644 --- a/codegen/src/Shared.hpp +++ b/codegen/src/Shared.hpp @@ -4,7 +4,7 @@ #include #include #include -#include // bruh +#include #include using std::istreambuf_iterator; diff --git a/loader/hash/hash.hpp b/loader/hash/hash.hpp index 05f01593..67b2e9bc 100644 --- a/loader/hash/hash.hpp +++ b/loader/hash/hash.hpp @@ -6,7 +6,7 @@ #include "picosha3.h" #include "picosha2.h" #include -#include +#include static std::string calculateSHA3_256(ghc::filesystem::path const& path) { std::vector s(picosha3::bits_to_bytes(256)); diff --git a/loader/include/Geode/Geode.hpp b/loader/include/Geode/Geode.hpp index 521b9174..2f46ec70 100644 --- a/loader/include/Geode/Geode.hpp +++ b/loader/include/Geode/Geode.hpp @@ -2,6 +2,6 @@ #include "Bindings.hpp" #include "Loader.hpp" -#include "Utils.hpp" -// #include "Modify.hpp" #include "UI.hpp" +#include "Utils.hpp" +#include "modify/Modify.hpp" // doesn't include generated modify diff --git a/loader/include/Geode/Modify.hpp b/loader/include/Geode/Modify.hpp index a1972cb8..d9815e99 100644 --- a/loader/include/Geode/Modify.hpp +++ b/loader/include/Geode/Modify.hpp @@ -1,9 +1,7 @@ #pragma once -#include "modify/Field.hpp" -#include "modify/InternalMacros.hpp" +#include "modify/Modify.hpp" -#include #include using namespace geode::modifier; \ No newline at end of file diff --git a/loader/include/Geode/c++stl/gnustl.hpp b/loader/include/Geode/c++stl/gnustl.hpp index 8f1c7bd6..3f793382 100644 --- a/loader/include/Geode/c++stl/gnustl.hpp +++ b/loader/include/Geode/c++stl/gnustl.hpp @@ -28,6 +28,8 @@ namespace gd { return std::string((char*)m_data, m_data[-1].m_len); } + bool operator<(string const& other) const; + bool operator==(string const& other) const; string(string const& ok); string& operator=(char const* ok); @@ -58,142 +60,6 @@ namespace gd { T m_value; }; - static void _rb_tree_rotate_left(_rb_tree_base* const x, _rb_tree_base*& root) { - _rb_tree_base* const y = x->m_right; - - x->m_right = y->m_left; - if (y->m_left != 0) y->m_left->m_parent = x; - y->m_parent = x->m_parent; - - if (x == root) root = y; - else if (x == x->m_parent->m_left) x->m_parent->m_left = y; - else x->m_parent->m_right = y; - y->m_left = x; - x->m_parent = y; - } - - static void _rb_tree_rotate_right(_rb_tree_base* const x, _rb_tree_base*& root) { - _rb_tree_base* const y = x->m_left; - - x->m_left = y->m_right; - if (y->m_right != 0) y->m_right->m_parent = x; - y->m_parent = x->m_parent; - - if (x == root) root = y; - else if (x == x->m_parent->m_right) x->m_parent->m_right = y; - else x->m_parent->m_left = y; - y->m_right = x; - x->m_parent = y; - } - - static void _rb_insert_rebalance( - bool const insert_left, _rb_tree_base* x, _rb_tree_base* p, _rb_tree_base& header - ) { - _rb_tree_base*& root = header.m_parent; - - x->m_parent = p; - x->m_left = 0; - x->m_right = 0; - x->m_isblack = false; - - if (insert_left) { - p->m_left = x; - - if (p == &header) { - header.m_parent = x; - header.m_right = x; - } - else if (p == header.m_left) { - header.m_left = x; - } - } - else { - p->m_right = x; - - if (p == header.m_right) { - header.m_right = x; - } - } - - while (x != root && x->m_parent->m_isblack == false) { - _rb_tree_base* const xpp = x->m_parent->m_parent; - - if (x->m_parent == xpp->m_left) { - _rb_tree_base* const y = xpp->m_right; - if (y && y->m_isblack == false) { - x->m_parent->m_isblack = true; - y->m_isblack = true; - xpp->m_isblack = false; - x = xpp; - } - else { - if (x == x->m_parent->m_right) { - x = x->m_parent; - _rb_tree_rotate_left(x, root); - } - x->m_parent->m_isblack = true; - xpp->m_isblack = false; - _rb_tree_rotate_right(xpp, root); - } - } - else { - _rb_tree_base* const y = xpp->m_left; - if (y && y->m_isblack == false) { - x->m_parent->m_isblack = true; - y->m_isblack = true; - xpp->m_isblack = false; - x = xpp; - } - else { - if (x == x->m_parent->m_left) { - x = x->m_parent; - _rb_tree_rotate_right(x, root); - } - x->m_parent->m_isblack = true; - xpp->m_isblack = false; - _rb_tree_rotate_left(xpp, root); - } - } - } - root->m_isblack = true; - } - - static _rb_tree_base* _rb_increment(_rb_tree_base* __x) throw() { - if (__x->m_right != 0) { - __x = __x->m_right; - while (__x->m_left != 0) - __x = __x->m_left; - } - else { - _rb_tree_base* __y = __x->m_parent; - while (__x == __y->m_right) { - __x = __y; - __y = __y->m_parent; - } - if (__x->m_right != __y) __x = __y; - } - return __x; - } - - static _rb_tree_base* _rb_decrement(_rb_tree_base* __x) throw() { - if (!__x->m_isblack && __x->m_parent->m_parent == __x) __x = __x->m_right; - else if (__x->m_left != 0) { - _rb_tree_base* __y = __x->m_left; - while (__y->m_right != 0) - __y = __y->m_right; - __x = __y; - } - else { - _rb_tree_base* __y = __x->m_parent; - while (__x == __y->m_left) { - __x = __y; - __y = __y->m_parent; - } - __x = __y; - } - return __x; - } - template class GEODE_DLL map { protected: @@ -204,96 +70,25 @@ namespace gd { public: typedef _rb_tree_node>* _tree_node; - std::map std() { - return (std::map)(*this); - } + std::map std(); - operator std::map() { - auto iter_node = static_cast<_tree_node>(m_header.m_left); - auto end_node = static_cast<_tree_node>(&m_header); - std::map out; - for (; iter_node != end_node; - iter_node = static_cast<_tree_node>(_rb_increment(iter_node))) { - out[iter_node->m_value.first] = iter_node->m_value.second; - } + operator std::map(); - return out; - } + operator std::map() const; - operator std::map() const { - auto iter_node = static_cast<_tree_node>(m_header.m_left); - auto end_node = (_tree_node)(&m_header); - std::map out; - for (; iter_node != end_node; - iter_node = static_cast<_tree_node>(_rb_increment(iter_node))) { - out[iter_node->m_value.first] = iter_node->m_value.second; - } + void insert(_tree_node x, _tree_node p, std::pair const& val); - return out; - } + void insert_pair(std::pair const& val); - void insert(_tree_node x, _tree_node p, std::pair const& val) { - bool insert_left = - (x != 0 || p == static_cast<_tree_node>(&m_header) || val.first < p->m_value.first); + map(std::map input); - _tree_node z = new _rb_tree_node>(); - z->m_value = val; + void erase(_tree_node x); - _rb_insert_rebalance(insert_left, z, p, m_header); - ++m_nodecount; - } + map(map const& lol); - void insert_pair(std::pair const& val) { - _tree_node x = static_cast<_tree_node>(m_header.m_parent); - _tree_node y = static_cast<_tree_node>(&m_header); - bool comp = true; - while (x != 0) { - y = x; - comp = val.first < x->m_value.first; - x = comp ? static_cast<_tree_node>(x->m_left) : static_cast<_tree_node>(x->m_right); - } - auto iter = y; + map(); - if (comp) { - if (iter == static_cast<_tree_node>(m_header.m_left)) { - insert(x, y, val); - } - else { - iter = static_cast<_tree_node>(_rb_decrement(iter)); - } - } - if (iter->m_value.first < val.first) { - insert(x, y, val); - } - } - - map(std::map input) { - m_header.m_isblack = false; - m_header.m_parent = 0; - m_header.m_left = &m_header; - m_header.m_right = &m_header; - - for (auto i : input) { - insert_pair(i); - } - } - - void erase(_tree_node x) { - while (x != 0) { - erase(static_cast<_tree_node>(x->m_right)); - auto y = static_cast<_tree_node>(x->m_left); - delete y; - x = y; - } - } - - map(map const& lol) : map(std::map(lol)) {} - - map() : map(std::map()) {} - - ~map() { - erase(static_cast<_tree_node>(m_header.m_parent)); - } + ~map(); }; // template diff --git a/loader/include/Geode/cocos/support/zip_support/ZipUtils.h b/loader/include/Geode/cocos/support/zip_support/ZipUtils.h index 066ca23a..bf702fb9 100644 --- a/loader/include/Geode/cocos/support/zip_support/ZipUtils.h +++ b/loader/include/Geode/cocos/support/zip_support/ZipUtils.h @@ -25,7 +25,7 @@ THE SOFTWARE. #define __SUPPORT_ZIPUTILS_H__ #include -#include +#include #include "../../platform/CCPlatformDefine.h" #include "../../platform/CCPlatformConfig.h" #include "../../include/ccMacros.h" diff --git a/loader/include/Geode/loader/Dirs.hpp b/loader/include/Geode/loader/Dirs.hpp index 60ba8fea..bf33e16a 100644 --- a/loader/include/Geode/loader/Dirs.hpp +++ b/loader/include/Geode/loader/Dirs.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "../DefaultInclude.hpp" namespace geode::dirs { diff --git a/loader/include/Geode/loader/Loader.hpp b/loader/include/Geode/loader/Loader.hpp index 755accb6..d6856f19 100644 --- a/loader/include/Geode/loader/Loader.hpp +++ b/loader/include/Geode/loader/Loader.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "../utils/Result.hpp" #include "Log.hpp" #include "ModInfo.hpp" diff --git a/loader/include/Geode/loader/Log.hpp b/loader/include/Geode/loader/Log.hpp index 938ae7a3..bea6cd1b 100644 --- a/loader/include/Geode/loader/Log.hpp +++ b/loader/include/Geode/loader/Log.hpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/loader/include/Geode/modify/InternalMacros.hpp b/loader/include/Geode/modify/InternalMacros.hpp deleted file mode 100644 index 8ddde752..00000000 --- a/loader/include/Geode/modify/InternalMacros.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#include - -/** - * Main class implementation, it has the structure - * - * class hook0Dummy; - * template - * struct hook0 {}; - * namespace { - * struct hook0Parent {}; - * } - * template<> - * struct GEODE_HIDDEN hook0 : Modify, MenuLayer> { - * // code stuff idk - * }; - * - * I tried to make the macro as verbose as it can be but - * I am bad at this stuff - */ - -#define GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived) \ - derived##Dummy; \ - template \ - struct derived {}; \ - namespace { \ - struct derived##Parent {}; \ - } \ - template <> \ - struct GEODE_HIDDEN derived : geode::Modify, base> - -#define GEODE_MODIFY_DECLARE(base, derived) \ - derived##Dummy; \ - struct GEODE_HIDDEN derived : geode::Modify - -#define GEODE_MODIFY_REDIRECT4(base, derived) GEODE_MODIFY_DECLARE(base, derived) -#define GEODE_MODIFY_REDIRECT3(base, derived) GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived) -#define GEODE_MODIFY_REDIRECT2(base) GEODE_MODIFY_REDIRECT3(base, GEODE_CONCAT(hook, __LINE__)) -#define GEODE_MODIFY_REDIRECT1(base) GEODE_MODIFY_REDIRECT2(base) - -/** - * Interfaces for the class implementation - * - * class $modify(MenuLayer) {}; - * class $modify(MyMenuLayerInterface, MenuLayer) {}; - */ - -#define GEODE_CRTP1(base) GEODE_MODIFY_REDIRECT1(base) -#define GEODE_CRTP2(derived, base) GEODE_MODIFY_REDIRECT4(base, derived) -#define $modify(...) \ - GEODE_INVOKE(GEODE_CONCAT(GEODE_CRTP, GEODE_NUMBER_OF_ARGS(__VA_ARGS__)), __VA_ARGS__) -#define $(...) $modify(__VA_ARGS__) - -/** - * Get current hook class without needing to name it. - * Useful for callbacks - */ -#define $cls std::remove_pointer::type diff --git a/loader/include/Geode/modify/Modify.hpp b/loader/include/Geode/modify/Modify.hpp index ca00ef48..3b046c96 100644 --- a/loader/include/Geode/modify/Modify.hpp +++ b/loader/include/Geode/modify/Modify.hpp @@ -141,3 +141,60 @@ namespace geode { static void onModify(auto& self) {} }; } + +/** + * Main class implementation, it has the structure + * + * class hook0Dummy; + * template + * struct hook0 {}; + * namespace { + * struct hook0Parent {}; + * } + * template<> + * struct GEODE_HIDDEN hook0 : Modify, MenuLayer> { + * // code stuff idk + * }; + * + * I tried to make the macro as verbose as it can be but + * I am bad at this stuff + */ + +#define GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived) \ + derived##Dummy; \ + template \ + struct derived {}; \ + namespace { \ + struct derived##Parent {}; \ + } \ + template <> \ + struct GEODE_HIDDEN derived : geode::Modify, base> + +#define GEODE_MODIFY_DECLARE(base, derived) \ + derived##Dummy; \ + struct GEODE_HIDDEN derived : geode::Modify + +#define GEODE_MODIFY_REDIRECT4(base, derived) GEODE_MODIFY_DECLARE(base, derived) +#define GEODE_MODIFY_REDIRECT3(base, derived) GEODE_MODIFY_DECLARE_ANONYMOUS(base, derived) +#define GEODE_MODIFY_REDIRECT2(base) GEODE_MODIFY_REDIRECT3(base, GEODE_CONCAT(hook, __LINE__)) +#define GEODE_MODIFY_REDIRECT1(base) GEODE_MODIFY_REDIRECT2(base) + +/** + * Interfaces for the class implementation + * + * class $modify(MenuLayer) {}; + * class $modify(MyMenuLayerInterface, MenuLayer) {}; + */ + +#define GEODE_CRTP1(base) GEODE_MODIFY_REDIRECT1(base) +#define GEODE_CRTP2(derived, base) GEODE_MODIFY_REDIRECT4(base, derived) +#define $modify(...) \ + GEODE_INVOKE(GEODE_CONCAT(GEODE_CRTP, GEODE_NUMBER_OF_ARGS(__VA_ARGS__)), __VA_ARGS__) +#define $(...) $modify(__VA_ARGS__) + +/** + * Get current hook class without needing to name it. + * Useful for callbacks + * this is a camila moment if you ask me + */ +#define $cls std::remove_pointer::type diff --git a/loader/include/Geode/utils/file.hpp b/loader/include/Geode/utils/file.hpp index 998eebe4..acc250ef 100644 --- a/loader/include/Geode/utils/file.hpp +++ b/loader/include/Geode/utils/file.hpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/loader/include/Geode/utils/general.hpp b/loader/include/Geode/utils/general.hpp index 2013d493..ec736efb 100644 --- a/loader/include/Geode/utils/general.hpp +++ b/loader/include/Geode/utils/general.hpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include // for some reason std::filesystem::path doesn't have std::hash defined in C++17 // and ghc seems to have inherited this limitation diff --git a/loader/include/Geode/utils/web.hpp b/loader/include/Geode/utils/web.hpp index 8a592159..05c18bea 100644 --- a/loader/include/Geode/utils/web.hpp +++ b/loader/include/Geode/utils/web.hpp @@ -5,7 +5,7 @@ #include "Result.hpp" #include "general.hpp" -#include +#include #include namespace geode::utils::web { diff --git a/loader/launcher/mac/Bootstrapper.cpp b/loader/launcher/mac/Bootstrapper.cpp index 0fbf8642..9c97eafd 100644 --- a/loader/launcher/mac/Bootstrapper.cpp +++ b/loader/launcher/mac/Bootstrapper.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/loader/launcher/windows/Bootstrapper.cpp b/loader/launcher/windows/Bootstrapper.cpp index 84b75896..02ccdd88 100644 --- a/loader/launcher/windows/Bootstrapper.cpp +++ b/loader/launcher/windows/Bootstrapper.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include void showError(std::string const& error) { MessageBoxA(nullptr, error.c_str(), "Error Loading Geode", MB_ICONERROR); diff --git a/loader/src/hooks/DynamicCastFix.cpp b/loader/src/hooks/DynamicCastFix.cpp index f0717118..2eec794a 100644 --- a/loader/src/hooks/DynamicCastFix.cpp +++ b/loader/src/hooks/DynamicCastFix.cpp @@ -4,16 +4,15 @@ USE_GEODE_NAMESPACE(); -#include -#include + #include + #include $execute { // this replaces the call to __dynamic_cast with a call to our own // this is needed because the transitions in cocos uses dynamic cast to check // layers, which fail on user layers due to typeinfo not matching (void)Mod::get()->patch( - reinterpret_cast(base::get() + 0x603948), - toByteArray(&cast::typeinfoCastInternal) + reinterpret_cast(base::get() + 0x603948), toByteArray(&cast::typeinfoCastInternal) ); } diff --git a/loader/src/hooks/MessageBoxFix.cpp b/loader/src/hooks/MessageBoxFix.cpp index fbe366af..7d659109 100644 --- a/loader/src/hooks/MessageBoxFix.cpp +++ b/loader/src/hooks/MessageBoxFix.cpp @@ -3,8 +3,8 @@ #ifdef GEODE_IS_WINDOWS -#include -#include + #include + #include USE_GEODE_NAMESPACE(); @@ -19,16 +19,18 @@ static void __cdecl fixedErrorHandler(int code, char const* description) { fmt::format( "GLFWError #{}: {}\nPlease contact the " "Geode Development Team for more information.", - code, description - ).c_str(), - "OpenGL Error", MB_ICONERROR + code, + description + ) + .c_str(), + "OpenGL Error", + MB_ICONERROR ); } $execute { (void)Mod::get()->patch( - reinterpret_cast(geode::base::getCocos() + 0x19feec), - toByteArray(&fixedErrorHandler) + reinterpret_cast(geode::base::getCocos() + 0x19feec), toByteArray(&fixedErrorHandler) ); } diff --git a/loader/src/internal/FileWatcher.hpp b/loader/src/internal/FileWatcher.hpp index 93ac1ca5..469f96ed 100644 --- a/loader/src/internal/FileWatcher.hpp +++ b/loader/src/internal/FileWatcher.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/loader/src/internal/crashlog.hpp b/loader/src/internal/crashlog.hpp index 7569c6c2..ec9e9100 100644 --- a/loader/src/internal/crashlog.hpp +++ b/loader/src/internal/crashlog.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include /** diff --git a/loader/src/main.cpp b/loader/src/main.cpp index 81a02ab0..8b45c933 100644 --- a/loader/src/main.cpp +++ b/loader/src/main.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include USE_GEODE_NAMESPACE(); diff --git a/loader/src/platform/mac/crashlog.mm b/loader/src/platform/mac/crashlog.mm index d64c2293..a73609f5 100644 --- a/loader/src/platform/mac/crashlog.mm +++ b/loader/src/platform/mac/crashlog.mm @@ -2,10 +2,10 @@ #ifdef GEODE_IS_MACOS - #include - #include +#include +#include - #include +#include bool crashlog::setupPlatformHandler() { return true; diff --git a/loader/src/platform/mac/gdstdlib.cpp b/loader/src/platform/mac/gdstdlib.cpp index fe3a8515..69e62a49 100644 --- a/loader/src/platform/mac/gdstdlib.cpp +++ b/loader/src/platform/mac/gdstdlib.cpp @@ -6,8 +6,7 @@ namespace gd { namespace { static inline auto emptyInternalString() { return reinterpret_cast<_internal_string*>( - *reinterpret_cast(geode::base::get() + 0x6030d0) + - sizeof(_internal_string) + *reinterpret_cast(geode::base::get() + 0x6030d0) + sizeof(_internal_string) ); } } @@ -50,11 +49,253 @@ namespace gd { } } - bool string::operator==(string const& other) const { - if (size() != other.size()) return false; - return strcmp(c_str(), other.c_str()) == 0; + bool string::operator<(string const& other) const { + return std::string(*this) < std::string(other); } + bool string::operator==(string const& other) const { + return std::string(*this) == std::string(other); + } + + static void _rb_tree_rotate_left(_rb_tree_base* const x, _rb_tree_base*& root) { + _rb_tree_base* const y = x->m_right; + + x->m_right = y->m_left; + if (y->m_left != 0) y->m_left->m_parent = x; + y->m_parent = x->m_parent; + + if (x == root) root = y; + else if (x == x->m_parent->m_left) x->m_parent->m_left = y; + else x->m_parent->m_right = y; + y->m_left = x; + x->m_parent = y; + } + + static void _rb_tree_rotate_right(_rb_tree_base* const x, _rb_tree_base*& root) { + _rb_tree_base* const y = x->m_left; + + x->m_left = y->m_right; + if (y->m_right != 0) y->m_right->m_parent = x; + y->m_parent = x->m_parent; + + if (x == root) root = y; + else if (x == x->m_parent->m_right) x->m_parent->m_right = y; + else x->m_parent->m_left = y; + y->m_right = x; + x->m_parent = y; + } + + static void _rb_insert_rebalance( + bool const insert_left, _rb_tree_base* x, _rb_tree_base* p, _rb_tree_base& header + ) { + _rb_tree_base*& root = header.m_parent; + + x->m_parent = p; + x->m_left = 0; + x->m_right = 0; + x->m_isblack = false; + + if (insert_left) { + p->m_left = x; + + if (p == &header) { + header.m_parent = x; + header.m_right = x; + } + else if (p == header.m_left) { + header.m_left = x; + } + } + else { + p->m_right = x; + + if (p == header.m_right) { + header.m_right = x; + } + } + + while (x != root && x->m_parent->m_isblack == false) { + _rb_tree_base* const xpp = x->m_parent->m_parent; + + if (x->m_parent == xpp->m_left) { + _rb_tree_base* const y = xpp->m_right; + if (y && y->m_isblack == false) { + x->m_parent->m_isblack = true; + y->m_isblack = true; + xpp->m_isblack = false; + x = xpp; + } + else { + if (x == x->m_parent->m_right) { + x = x->m_parent; + _rb_tree_rotate_left(x, root); + } + x->m_parent->m_isblack = true; + xpp->m_isblack = false; + _rb_tree_rotate_right(xpp, root); + } + } + else { + _rb_tree_base* const y = xpp->m_left; + if (y && y->m_isblack == false) { + x->m_parent->m_isblack = true; + y->m_isblack = true; + xpp->m_isblack = false; + x = xpp; + } + else { + if (x == x->m_parent->m_left) { + x = x->m_parent; + _rb_tree_rotate_right(x, root); + } + x->m_parent->m_isblack = true; + xpp->m_isblack = false; + _rb_tree_rotate_left(xpp, root); + } + } + } + root->m_isblack = true; + } + + static _rb_tree_base* _rb_increment(_rb_tree_base* __x) throw() { + if (__x->m_right != 0) { + __x = __x->m_right; + while (__x->m_left != 0) + __x = __x->m_left; + } + else { + _rb_tree_base* __y = __x->m_parent; + while (__x == __y->m_right) { + __x = __y; + __y = __y->m_parent; + } + if (__x->m_right != __y) __x = __y; + } + return __x; + } + + static _rb_tree_base* _rb_decrement(_rb_tree_base* __x) throw() { + if (!__x->m_isblack && __x->m_parent->m_parent == __x) __x = __x->m_right; + else if (__x->m_left != 0) { + _rb_tree_base* __y = __x->m_left; + while (__y->m_right != 0) + __y = __y->m_right; + __x = __y; + } + else { + _rb_tree_base* __y = __x->m_parent; + while (__x == __y->m_left) { + __x = __y; + __y = __y->m_parent; + } + __x = __y; + } + return __x; + } + + template + std::map map::std() { + return (std::map)(*this); + } + + template + map::operator std::map() { + auto iter_node = static_cast<_tree_node>(m_header.m_left); + auto end_node = static_cast<_tree_node>(&m_header); + std::map out; + for (; iter_node != end_node; iter_node = static_cast<_tree_node>(_rb_increment(iter_node))) { + out[iter_node->m_value.first] = iter_node->m_value.second; + } + + return out; + } + + template + map::operator std::map() const { + auto iter_node = static_cast<_tree_node>(m_header.m_left); + auto end_node = (_tree_node)(&m_header); + std::map out; + for (; iter_node != end_node; iter_node = static_cast<_tree_node>(_rb_increment(iter_node))) { + out[iter_node->m_value.first] = iter_node->m_value.second; + } + + return out; + } + + template + void map::insert(_tree_node x, _tree_node p, std::pair const& val) { + bool insert_left = + (x != 0 || p == static_cast<_tree_node>(&m_header) || val.first < p->m_value.first); + + _tree_node z = new _rb_tree_node>(); + z->m_value = val; + + _rb_insert_rebalance(insert_left, z, p, m_header); + ++m_nodecount; + } + + template + void map::insert_pair(std::pair const& val) { + _tree_node x = static_cast<_tree_node>(m_header.m_parent); + _tree_node y = static_cast<_tree_node>(&m_header); + bool comp = true; + while (x != 0) { + y = x; + comp = val.first < x->m_value.first; + x = comp ? static_cast<_tree_node>(x->m_left) : static_cast<_tree_node>(x->m_right); + } + auto iter = y; + + if (comp) { + if (iter == static_cast<_tree_node>(m_header.m_left)) { + insert(x, y, val); + } + else { + iter = static_cast<_tree_node>(_rb_decrement(iter)); + } + } + if (iter->m_value.first < val.first) { + insert(x, y, val); + } + } + + template + map::map(std::map input) { + m_header.m_isblack = false; + m_header.m_parent = 0; + m_header.m_left = &m_header; + m_header.m_right = &m_header; + + for (auto i : input) { + insert_pair(i); + } + } + + template + void map::erase(_tree_node x) { + while (x != 0) { + erase(static_cast<_tree_node>(x->m_right)); + auto y = static_cast<_tree_node>(x->m_left); + delete y; + x = y; + } + } + + template + map::map(map const& lol) : map(std::map(lol)) {} + + template + map::map() : map(std::map()) {} + + template + map::~map() { + erase(static_cast<_tree_node>(m_header.m_parent)); + } + + template class map; + template class map; + template class map; + template class map; } #endif \ No newline at end of file diff --git a/loader/src/platform/windows/util.cpp b/loader/src/platform/windows/util.cpp index cfb7c4bf..78e35ac5 100644 --- a/loader/src/platform/windows/util.cpp +++ b/loader/src/platform/windows/util.cpp @@ -6,7 +6,7 @@ USE_GEODE_NAMESPACE(); #include "nfdwin.hpp" -#include +#include #include #include #include From 478f70e900649460f77d75b8a5ef117fdfe41622 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Wed, 8 Feb 2023 17:37:37 +0300 Subject: [PATCH 06/20] fix filesystem pch breaking the impl --- CMakeLists.txt | 29 ++++++++++++++---------- FilesystemImpl.cpp | 4 ++++ loader/CMakeLists.txt | 1 + loader/hash/hash.hpp | 2 +- loader/include/Geode/loader/ModInfo.hpp | 3 ++- loader/launcher/mac/Bootstrapper.cpp | 2 +- loader/launcher/windows/Bootstrapper.cpp | 2 +- loader/src/loader/ModInfo.cpp | 11 ++++++++- loader/src/main.cpp | 2 +- 9 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 FilesystemImpl.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 65075a92..74774539 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,8 +54,23 @@ include(cmake/GeodeFile.cmake) include(cmake/Platform.cmake) include(cmake/CPM.cmake) +CPMAddPackage("gh:geode-sdk/json#2b76460") +CPMAddPackage("gh:fmtlib/fmt#9.1.0") +CPMAddPackage("gh:gulrak/filesystem#3e5b930") + +# Tulip hook (hooking) +if (PROJECT_IS_TOP_LEVEL AND NOT GEODE_BUILDING_DOCS) + set(TULIP_LINK_SOURCE ON) +endif() +CPMAddPackage("gh:geode-sdk/TulipHook#76984a4") + + target_sources(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/entry.cpp) +# Filesystem implementation in a separate target because i couldnt disable pch +add_library(GeodeFilesystemImpl ${CMAKE_CURRENT_SOURCE_DIR}/FilesystemImpl.cpp) +target_link_libraries(GeodeFilesystemImpl PUBLIC ghc_filesystem) + include(ExternalProject) set(GEODE_CODEGEN_BINARY_OUT ${CMAKE_CURRENT_BINARY_DIR}/codegen) ExternalProject_Add(CodegenProject @@ -103,7 +118,7 @@ endif() add_library(GeodeCodegenSources ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp ${GEODE_CODEGEN_PATH}/Geode/GeneratedAddress.cpp) target_link_directories(GeodeCodegenSources PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/loader/include/link) -target_link_libraries(GeodeCodegenSources PRIVATE ghc_filesystem fmt TulipHookInclude) +target_link_libraries(GeodeCodegenSources PRIVATE ghc_filesystem GeodeFilesystemImpl fmt TulipHookInclude) target_include_directories(GeodeCodegenSources PRIVATE ${GEODE_CODEGEN_PATH} ${GEODE_LOADER_PATH}/include @@ -127,17 +142,7 @@ target_include_directories(${PROJECT_NAME} INTERFACE ) target_link_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/loader/include/link) -CPMAddPackage("gh:geode-sdk/json#2b76460") -CPMAddPackage("gh:fmtlib/fmt#9.1.0") -CPMAddPackage("gh:gulrak/filesystem#3e5b930") - -# Tulip hook (hooking) -if (PROJECT_IS_TOP_LEVEL AND NOT GEODE_BUILDING_DOCS) - set(TULIP_LINK_SOURCE ON) -endif() -CPMAddPackage("gh:geode-sdk/TulipHook#76984a4") - -target_link_libraries(${PROJECT_NAME} INTERFACE ghc_filesystem fmt TulipHookInclude GeodeCodegenSources mat-json) +target_link_libraries(${PROJECT_NAME} INTERFACE ghc_filesystem fmt TulipHookInclude GeodeCodegenSources mat-json GeodeFilesystemImpl) if (NOT EXISTS ${GEODE_BIN_PATH}) diff --git a/FilesystemImpl.cpp b/FilesystemImpl.cpp new file mode 100644 index 00000000..58cdc9b4 --- /dev/null +++ b/FilesystemImpl.cpp @@ -0,0 +1,4 @@ +// filesystem implementation +#undef GHC_FILESYSTEM_H +#include + diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index 7b1b519a..a6d93936 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -40,6 +40,7 @@ file(GLOB OBJC_SOURCES ) set_source_files_properties(${OBJC_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON) + # Add platform sources if (WIN32) diff --git a/loader/hash/hash.hpp b/loader/hash/hash.hpp index 67b2e9bc..05f01593 100644 --- a/loader/hash/hash.hpp +++ b/loader/hash/hash.hpp @@ -6,7 +6,7 @@ #include "picosha3.h" #include "picosha2.h" #include -#include +#include static std::string calculateSHA3_256(ghc::filesystem::path const& path) { std::vector s(picosha3::bits_to_bytes(256)); diff --git a/loader/include/Geode/loader/ModInfo.hpp b/loader/include/Geode/loader/ModInfo.hpp index d2278c7a..7d6f0d23 100644 --- a/loader/include/Geode/loader/ModInfo.hpp +++ b/loader/include/Geode/loader/ModInfo.hpp @@ -159,7 +159,8 @@ namespace geode { /** * Whether this mod is an API or not */ - bool isAPI = false; + bool& isAPI(); + bool const& isAPI() const; /** * Create ModInfo from an unzipped .geode package */ diff --git a/loader/launcher/mac/Bootstrapper.cpp b/loader/launcher/mac/Bootstrapper.cpp index 9c97eafd..0fbf8642 100644 --- a/loader/launcher/mac/Bootstrapper.cpp +++ b/loader/launcher/mac/Bootstrapper.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/loader/launcher/windows/Bootstrapper.cpp b/loader/launcher/windows/Bootstrapper.cpp index 02ccdd88..84b75896 100644 --- a/loader/launcher/windows/Bootstrapper.cpp +++ b/loader/launcher/windows/Bootstrapper.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include void showError(std::string const& error) { MessageBoxA(nullptr, error.c_str(), "Error Loading Geode", MB_ICONERROR); diff --git a/loader/src/loader/ModInfo.cpp b/loader/src/loader/ModInfo.cpp index 99b8138e..0529b8f8 100644 --- a/loader/src/loader/ModInfo.cpp +++ b/loader/src/loader/ModInfo.cpp @@ -40,6 +40,7 @@ public: bool m_supportsDisabling = true; bool m_supportsUnloading = false; bool m_needsEarlyLoad = false; + bool m_isAPI = false; std::shared_ptr m_rawJSON; @@ -96,7 +97,8 @@ Result ModInfo::Impl::createFromSchemaV010(ModJson const& rawJson) { root.has("unloadable").into(impl->m_supportsUnloading); root.has("early-load").into(impl->m_needsEarlyLoad); if (root.has("api")) { - impl->isAPI = true; + // TODO: figure out what got wiped with merge + // impl->isAPI = true; } for (auto& dep : root.has("dependencies").iterate()) { @@ -432,6 +434,13 @@ bool const& ModInfo::needsEarlyLoad() const { return m_impl->m_needsEarlyLoad; } +bool& ModInfo::isAPI() { + return m_impl->m_isAPI; +} +bool const& ModInfo::isAPI() const { + return m_impl->m_isAPI; +} + Result ModInfo::createFromGeodeZip(utils::file::Unzip& zip) { return Impl::createFromGeodeZip(zip); } diff --git a/loader/src/main.cpp b/loader/src/main.cpp index 8b45c933..71fd07aa 100644 --- a/loader/src/main.cpp +++ b/loader/src/main.cpp @@ -8,7 +8,7 @@ #include #include #include -#include + #include USE_GEODE_NAMESPACE(); From d31d95d6bfb5a94f9a3ca66cf72f7a2a7d817c05 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Wed, 8 Feb 2023 17:43:31 +0300 Subject: [PATCH 07/20] somewhat improve objc compile times --- loader/src/internal/FileWatcher.hpp | 2 +- loader/src/platform/mac/crashlog.mm | 2 +- loader/src/platform/mac/util.mm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/loader/src/internal/FileWatcher.hpp b/loader/src/internal/FileWatcher.hpp index 469f96ed..427f8949 100644 --- a/loader/src/internal/FileWatcher.hpp +++ b/loader/src/internal/FileWatcher.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +//#include #include #include #include diff --git a/loader/src/platform/mac/crashlog.mm b/loader/src/platform/mac/crashlog.mm index a73609f5..684cc981 100644 --- a/loader/src/platform/mac/crashlog.mm +++ b/loader/src/platform/mac/crashlog.mm @@ -5,7 +5,7 @@ #include #include -#include +#import bool crashlog::setupPlatformHandler() { return true; diff --git a/loader/src/platform/mac/util.mm b/loader/src/platform/mac/util.mm index 30cff32d..f9c40ee3 100644 --- a/loader/src/platform/mac/util.mm +++ b/loader/src/platform/mac/util.mm @@ -5,7 +5,7 @@ USE_GEODE_NAMESPACE(); -#include +#import #include #include From 04dd151f0ef0be590b7eb6f111ce266f29292e42 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Wed, 8 Feb 2023 18:25:07 +0300 Subject: [PATCH 08/20] minifunction replacing compiles --- loader/CMakeLists.txt | 10 +- loader/include/Geode/Utils.hpp | 1 + loader/include/Geode/loader/Dispatch.hpp | 6 +- loader/include/Geode/loader/Event.hpp | 8 +- loader/include/Geode/loader/IPC.hpp | 2 +- loader/include/Geode/loader/Index.hpp | 4 +- loader/include/Geode/loader/Loader.hpp | 3 +- loader/include/Geode/loader/ModEvent.hpp | 2 +- loader/include/Geode/loader/Setting.hpp | 18 +- loader/include/Geode/loader/SettingEvent.hpp | 4 +- loader/include/Geode/modify/Field.hpp | 5 +- loader/include/Geode/ui/EnterLayerEvent.hpp | 4 +- loader/include/Geode/ui/MDPopup.hpp | 8 +- loader/include/Geode/ui/SelectList.hpp | 6 +- loader/include/Geode/ui/TextRenderer.hpp | 2 +- loader/include/Geode/utils/JsonValidation.hpp | 80 ++++---- loader/include/Geode/utils/MiniFunction.hpp | 47 ++++- loader/include/Geode/utils/cocos.hpp | 9 +- loader/include/Geode/utils/map.hpp | 8 +- loader/include/Geode/utils/web.hpp | 21 ++- loader/src/internal/FileWatcher.hpp | 5 +- loader/src/loader/IPC.cpp | 2 +- loader/src/loader/Index.cpp | 6 +- loader/src/loader/LoaderImpl.cpp | 8 +- loader/src/loader/LoaderImpl.hpp | 11 +- loader/src/loader/ModEvent.cpp | 2 +- loader/src/loader/ModInfo.cpp | 4 +- loader/src/loader/Setting.cpp | 20 +- loader/src/ui/nodes/EnterLayerEvent.cpp | 2 +- loader/src/ui/nodes/MDPopup.cpp | 4 +- loader/src/utils/JsonValidation.cpp | 173 ++++++++---------- 31 files changed, 251 insertions(+), 234 deletions(-) diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index a6d93936..3bda82b5 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -153,13 +153,13 @@ target_link_libraries(${PROJECT_NAME} z TulipHook geode-sdk mat-json) # Use precompiled headers for faster builds if (NOT GEODE_DISABLE_PRECOMPILED_HEADERS) target_precompile_headers(${PROJECT_NAME} PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/DefaultInclude.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Geode.hpp" # "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Utils.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Loader.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/UI.hpp" + # "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Loader.hpp" + # "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/UI.hpp" # "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/Bindings.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/include/cocos2d.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/extensions/cocos-ext.h" + # "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/include/cocos2d.h" + # "${CMAKE_CURRENT_SOURCE_DIR}/include/Geode/cocos/extensions/cocos-ext.h" ) endif() diff --git a/loader/include/Geode/Utils.hpp b/loader/include/Geode/Utils.hpp index 9aadbbee..5aa821cf 100644 --- a/loader/include/Geode/Utils.hpp +++ b/loader/include/Geode/Utils.hpp @@ -10,3 +10,4 @@ #include "utils/file.hpp" #include "utils/general.hpp" #include "utils/timer.hpp" +#include "utils/MiniFunction.hpp" diff --git a/loader/include/Geode/loader/Dispatch.hpp b/loader/include/Geode/loader/Dispatch.hpp index c020c49f..dec81ba5 100644 --- a/loader/include/Geode/loader/Dispatch.hpp +++ b/loader/include/Geode/loader/Dispatch.hpp @@ -28,9 +28,9 @@ namespace geode { // template // class DispatchHandler : public EventHandler> { // std::string m_selector; - // std::function m_callback; + // utils::MiniFunction m_callback; - // DispatchHandler(std::string const& name, std::function callback) : + // DispatchHandler(std::string const& name, utils::MiniFunction callback) : // m_selector(name), m_callback(callback) {} // public: @@ -42,7 +42,7 @@ namespace geode { // } // static DispatchHandler* create( - // std::string const& name, std::function callback + // std::string const& name, utils::MiniFunction callback // ) { // return new DispatchHandler(name, callback); // } diff --git a/loader/include/Geode/loader/Event.hpp b/loader/include/Geode/loader/Event.hpp index a95ecf57..7fb0d901 100644 --- a/loader/include/Geode/loader/Event.hpp +++ b/loader/include/Geode/loader/Event.hpp @@ -41,7 +41,7 @@ namespace geode { using Callback = ListenerResult(T*); using Event = T; - ListenerResult handle(std::function fn, T* e) { + ListenerResult handle(utils::MiniFunction fn, T* e) { return fn(e); } }; @@ -74,7 +74,7 @@ namespace geode { this->enable(); } - EventListener(std::function fn, T filter = T()) + EventListener(utils::MiniFunction fn, T filter = T()) : m_callback(fn), m_filter(filter) { this->enable(); @@ -106,7 +106,7 @@ namespace geode { this->enable(); } - void bind(std::function fn) { + void bind(utils::MiniFunction fn) { m_callback = fn; } @@ -120,7 +120,7 @@ namespace geode { } protected: - std::function m_callback = nullptr; + utils::MiniFunction m_callback = nullptr; T m_filter; }; diff --git a/loader/include/Geode/loader/IPC.hpp b/loader/include/Geode/loader/IPC.hpp index ff949f75..5802d1b2 100644 --- a/loader/include/Geode/loader/IPC.hpp +++ b/loader/include/Geode/loader/IPC.hpp @@ -56,7 +56,7 @@ namespace geode { std::string m_messageID; public: - ListenerResult handle(std::function fn, IPCEvent* event); + ListenerResult handle(utils::MiniFunction fn, IPCEvent* event); IPCFilter( std::string const& modID, std::string const& messageID diff --git a/loader/include/Geode/loader/Index.hpp b/loader/include/Geode/loader/Index.hpp index 7ab3a995..7d23f462 100644 --- a/loader/include/Geode/loader/Index.hpp +++ b/loader/include/Geode/loader/Index.hpp @@ -26,7 +26,7 @@ namespace geode { public: using Callback = void(ModInstallEvent*); - ListenerResult handle(std::function fn, ModInstallEvent* event); + ListenerResult handle(utils::MiniFunction fn, ModInstallEvent* event); ModInstallFilter(std::string const& id); }; @@ -39,7 +39,7 @@ namespace geode { public: using Callback = void(IndexUpdateEvent*); - ListenerResult handle(std::function fn, IndexUpdateEvent* event); + ListenerResult handle(utils::MiniFunction fn, IndexUpdateEvent* event); IndexUpdateFilter(); }; diff --git a/loader/include/Geode/loader/Loader.hpp b/loader/include/Geode/loader/Loader.hpp index d6856f19..aa178009 100644 --- a/loader/include/Geode/loader/Loader.hpp +++ b/loader/include/Geode/loader/Loader.hpp @@ -2,6 +2,7 @@ #include #include "../utils/Result.hpp" +#include "../utils/MiniFunction.hpp" #include "Log.hpp" #include "ModInfo.hpp" #include "Types.hpp" @@ -10,7 +11,7 @@ #include namespace geode { - using ScheduledFunction = std::function; + using ScheduledFunction = utils::MiniFunction; struct InvalidGeodeFile { ghc::filesystem::path path; diff --git a/loader/include/Geode/loader/ModEvent.hpp b/loader/include/Geode/loader/ModEvent.hpp index 15c63d7c..e77f11e2 100644 --- a/loader/include/Geode/loader/ModEvent.hpp +++ b/loader/include/Geode/loader/ModEvent.hpp @@ -37,7 +37,7 @@ namespace geode { Mod* m_mod; public: - ListenerResult handle(std::function fn, ModStateEvent* event); + ListenerResult handle(utils::MiniFunction fn, ModStateEvent* event); ModStateFilter(Mod* mod, ModEventType type); }; } diff --git a/loader/include/Geode/loader/Setting.hpp b/loader/include/Geode/loader/Setting.hpp index 8d540a9a..0c77f265 100644 --- a/loader/include/Geode/loader/Setting.hpp +++ b/loader/include/Geode/loader/Setting.hpp @@ -15,9 +15,7 @@ namespace geode { class SettingNode; class SettingValue; - template struct JsonMaybeObject; - template struct JsonMaybeValue; struct GEODE_DLL BoolSetting final { @@ -27,7 +25,7 @@ namespace geode { std::optional description; bool defaultValue; - static Result parse(JsonMaybeObject& obj); + static Result parse(JsonMaybeObject& obj); }; struct GEODE_DLL IntSetting final { @@ -48,7 +46,7 @@ namespace geode { bool input = true; } controls; - static Result parse(JsonMaybeObject& obj); + static Result parse(JsonMaybeObject& obj); }; struct GEODE_DLL FloatSetting final { @@ -69,7 +67,7 @@ namespace geode { bool input = true; } controls; - static Result parse(JsonMaybeObject& obj); + static Result parse(JsonMaybeObject& obj); }; struct GEODE_DLL StringSetting final { @@ -80,7 +78,7 @@ namespace geode { ValueType defaultValue; std::optional match; - static Result parse(JsonMaybeObject& obj); + static Result parse(JsonMaybeObject& obj); }; struct GEODE_DLL FileSetting final { @@ -94,7 +92,7 @@ namespace geode { std::vector filters; } controls; - static Result parse(JsonMaybeObject& obj); + static Result parse(JsonMaybeObject& obj); }; struct GEODE_DLL ColorSetting final { @@ -104,7 +102,7 @@ namespace geode { std::optional description; ValueType defaultValue; - static Result parse(JsonMaybeObject& obj); + static Result parse(JsonMaybeObject& obj); }; struct GEODE_DLL ColorAlphaSetting final { @@ -114,7 +112,7 @@ namespace geode { std::optional description; ValueType defaultValue; - static Result parse(JsonMaybeObject& obj); + static Result parse(JsonMaybeObject& obj); }; struct GEODE_DLL CustomSetting final { @@ -142,7 +140,7 @@ namespace geode { public: static Result parse( std::string const& key, - JsonMaybeValue& obj + JsonMaybeValue& obj ); Setting(std::string const& key, SettingKind const& kind); diff --git a/loader/include/Geode/loader/SettingEvent.hpp b/loader/include/Geode/loader/SettingEvent.hpp index 5bb37033..33a396c6 100644 --- a/loader/include/Geode/loader/SettingEvent.hpp +++ b/loader/include/Geode/loader/SettingEvent.hpp @@ -22,7 +22,7 @@ namespace geode { public: using Callback = void(SettingValue*); - ListenerResult handle(std::function fn, SettingChangedEvent* event); + ListenerResult handle(utils::MiniFunction fn, SettingChangedEvent* event); /** * Listen to changes on a setting, or all settings * @param modID Mod whose settings to listen to @@ -42,7 +42,7 @@ namespace geode { public: using Callback = void(T); - ListenerResult handle(std::function fn, SettingChangedEvent* event) { + ListenerResult handle(utils::MiniFunction fn, SettingChangedEvent* event) { if ( m_modID == event->mod->getID() && (!m_targetKey || m_targetKey.value() == event->value->getKey()) diff --git a/loader/include/Geode/modify/Field.hpp b/loader/include/Geode/modify/Field.hpp index 215ae308..c87b59d4 100644 --- a/loader/include/Geode/modify/Field.hpp +++ b/loader/include/Geode/modify/Field.hpp @@ -3,6 +3,7 @@ #include "Traits.hpp" #include +#include "../utils/MiniFunction.hpp" #include #include @@ -19,7 +20,7 @@ namespace geode::modifier { class FieldContainer { private: std::vector m_containedFields; - std::vector> m_destructorFunctions; + std::vector> m_destructorFunctions; public: ~FieldContainer() { @@ -37,7 +38,7 @@ namespace geode::modifier { return m_containedFields.at(index); } - void* setField(size_t index, size_t size, std::function destructor) { + void* setField(size_t index, size_t size, utils::MiniFunction destructor) { m_containedFields.at(index) = operator new(size); m_destructorFunctions.at(index) = destructor; return m_containedFields.at(index); diff --git a/loader/include/Geode/ui/EnterLayerEvent.hpp b/loader/include/Geode/ui/EnterLayerEvent.hpp index 9199f369..08d595f2 100644 --- a/loader/include/Geode/ui/EnterLayerEvent.hpp +++ b/loader/include/Geode/ui/EnterLayerEvent.hpp @@ -29,7 +29,7 @@ namespace geode { std::optional m_targetID; public: - ListenerResult handle(std::function fn, AEnterLayerEvent* event); + ListenerResult handle(utils::MiniFunction fn, AEnterLayerEvent* event); AEnterLayerFilter( std::optional const& id @@ -61,7 +61,7 @@ namespace geode { std::optional m_targetID; public: - ListenerResult handle(std::function fn, EnterLayerEvent* event) { + ListenerResult handle(utils::MiniFunction fn, EnterLayerEvent* event) { if (m_targetID == event->getID()) { fn(static_cast(event)); } diff --git a/loader/include/Geode/ui/MDPopup.hpp b/loader/include/Geode/ui/MDPopup.hpp index 9ee55160..0fb46300 100644 --- a/loader/include/Geode/ui/MDPopup.hpp +++ b/loader/include/Geode/ui/MDPopup.hpp @@ -11,13 +11,13 @@ namespace geode { class MDPopup : public Popup< std::string const&, std::string const&, char const*, char const*, - std::function> { + utils::MiniFunction> { protected: - std::function m_onClick = nullptr; + utils::MiniFunction m_onClick = nullptr; bool setup( std::string const& title, std::string const& info, char const* btn1, char const* btn2, - std::function onClick + utils::MiniFunction onClick ) override; void onBtn(CCObject*); @@ -27,7 +27,7 @@ namespace geode { public: static MDPopup* create( std::string const& title, std::string const& content, char const* btn1, - char const* btn2 = nullptr, std::function onClick = nullptr + char const* btn2 = nullptr, utils::MiniFunction onClick = nullptr ); }; } diff --git a/loader/include/Geode/ui/SelectList.hpp b/loader/include/Geode/ui/SelectList.hpp index 595889fc..ffb56dc0 100644 --- a/loader/include/Geode/ui/SelectList.hpp +++ b/loader/include/Geode/ui/SelectList.hpp @@ -14,13 +14,13 @@ namespace geode { protected: std::vector m_list; size_t m_index = 0; - std::function m_onChange; + utils::MiniFunction m_onChange; cocos2d::CCLabelBMFont* m_label; CCMenuItemSpriteExtra* m_prevBtn; CCMenuItemSpriteExtra* m_nextBtn; bool init( - float width, std::vector const& list, std::function onChange + float width, std::vector const& list, utils::MiniFunction onChange ) { if (!cocos2d::CCMenu::init()) return false; @@ -95,7 +95,7 @@ namespace geode { public: static SelectList* create( - float width, std::vector const& list, std::function onChange + float width, std::vector const& list, utils::MiniFunction onChange ) { auto ret = new SelectList(); if (ret && ret->init(width, list, onChange)) { diff --git a/loader/include/Geode/ui/TextRenderer.hpp b/loader/include/Geode/ui/TextRenderer.hpp index b0719769..d749d1b5 100644 --- a/loader/include/Geode/ui/TextRenderer.hpp +++ b/loader/include/Geode/ui/TextRenderer.hpp @@ -122,7 +122,7 @@ namespace geode { * to distinguish between bold, italic and * regular text. */ - using Font = std::function; + using Font = utils::MiniFunction; protected: cocos2d::CCPoint m_origin = cocos2d::CCPointZero; diff --git a/loader/include/Geode/utils/JsonValidation.hpp b/loader/include/Geode/utils/JsonValidation.hpp index ea5a7b68..eafc44df 100644 --- a/loader/include/Geode/utils/JsonValidation.hpp +++ b/loader/include/Geode/utils/JsonValidation.hpp @@ -7,7 +7,6 @@ #include namespace geode { - template struct JsonChecker; template @@ -73,31 +72,28 @@ namespace geode { } template - using JsonValueValidator = std::function; + using JsonValueValidator = utils::MiniFunction; - template struct JsonMaybeObject; - template struct JsonMaybeValue; - template struct JsonMaybeSomething { protected: - JsonChecker& m_checker; - Json& m_json; + JsonChecker& m_checker; + json::Value& m_json; std::string m_hierarchy; bool m_hasValue; - friend struct JsonMaybeObject; - friend struct JsonMaybeValue; + friend struct JsonMaybeObject; + friend struct JsonMaybeValue; GEODE_DLL void setError(std::string const& error); public: - GEODE_DLL Json& json(); + GEODE_DLL json::Value& json(); GEODE_DLL JsonMaybeSomething( - JsonChecker& checker, Json& json, std::string const& hierarchy, bool hasValue + JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue ); GEODE_DLL bool isError() const; @@ -106,18 +102,17 @@ namespace geode { GEODE_DLL operator bool() const; }; - template - struct JsonMaybeValue : public JsonMaybeSomething { + struct JsonMaybeValue : public JsonMaybeSomething { bool m_inferType = true; GEODE_DLL JsonMaybeValue( - JsonChecker& checker, Json& json, std::string const& hierarchy, bool hasValue + JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue ); - GEODE_DLL JsonMaybeSomething& self(); + GEODE_DLL JsonMaybeSomething& self(); template - JsonMaybeValue& as() { + JsonMaybeValue& as() { if (this->isError()) return *this; if (!jsonConvertibleTo(self().m_json.type(), T)) { this->setError( @@ -129,10 +124,10 @@ namespace geode { return *this; } - GEODE_DLL JsonMaybeValue& array(); + GEODE_DLL JsonMaybeValue& array(); template - JsonMaybeValue& asOneOf() { + JsonMaybeValue& asOneOf() { if (this->isError()) return *this; bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T)); if (!isOneOf) { @@ -146,7 +141,7 @@ namespace geode { } template - JsonMaybeValue& is() { + JsonMaybeValue& is() { if (this->isError()) return *this; self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T); m_inferType = false; @@ -154,7 +149,7 @@ namespace geode { } template - JsonMaybeValue& validate(JsonValueValidator validator) { + JsonMaybeValue& validate(JsonValueValidator validator) { if (this->isError()) return *this; try { if (!validator(self().m_json.template as())) { @@ -171,35 +166,30 @@ namespace geode { } template - JsonMaybeValue& validate(bool (*validator)(T const&)) { - return this->validate(std::function(validator)); - } - - template - JsonMaybeValue& inferType() { + JsonMaybeValue& inferType() { if (this->isError() || !m_inferType) return *this; return this->as()>(); } template - JsonMaybeValue& intoRaw(T& target) { + JsonMaybeValue& intoRaw(T& target) { if (this->isError()) return *this; target = self().m_json; return *this; } template - JsonMaybeValue& into(T& target) { + JsonMaybeValue& into(T& target) { return this->intoAs(target); } template - JsonMaybeValue& into(std::optional& target) { + JsonMaybeValue& into(std::optional& target) { return this->intoAs>(target); } template - JsonMaybeValue& intoAs(T& target) { + JsonMaybeValue& intoAs(T& target) { this->inferType(); if (this->isError()) return *this; @@ -241,7 +231,7 @@ namespace geode { return T(); } - GEODE_DLL JsonMaybeObject obj(); + GEODE_DLL JsonMaybeObject obj(); template struct Iterator { @@ -267,48 +257,46 @@ namespace geode { } }; - GEODE_DLL JsonMaybeValue at(size_t i); + GEODE_DLL JsonMaybeValue at(size_t i); - GEODE_DLL Iterator> iterate(); + GEODE_DLL Iterator iterate(); - GEODE_DLL Iterator>> items(); + GEODE_DLL Iterator> items(); }; - template - struct JsonMaybeObject : JsonMaybeSomething { + struct JsonMaybeObject : JsonMaybeSomething { std::set m_knownKeys; GEODE_DLL JsonMaybeObject( - JsonChecker& checker, Json& json, std::string const& hierarchy, bool hasValue + JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue ); - GEODE_DLL JsonMaybeSomething& self(); + GEODE_DLL JsonMaybeSomething& self(); GEODE_DLL void addKnownKey(std::string const& key); - GEODE_DLL Json& json(); + GEODE_DLL json::Value& json(); - GEODE_DLL JsonMaybeValue emptyValue(); + GEODE_DLL JsonMaybeValue emptyValue(); - GEODE_DLL JsonMaybeValue has(std::string const& key); + GEODE_DLL JsonMaybeValue has(std::string const& key); - GEODE_DLL JsonMaybeValue needs(std::string const& key); + GEODE_DLL JsonMaybeValue needs(std::string const& key); GEODE_DLL void checkUnknownKeys(); }; - template struct JsonChecker { std::variant m_result; - Json& m_json; + json::Value& m_json; - GEODE_DLL JsonChecker(Json& json); + GEODE_DLL JsonChecker(json::Value& json); GEODE_DLL bool isError() const; GEODE_DLL std::string getError() const; - GEODE_DLL JsonMaybeValue root(std::string const& hierarchy); + GEODE_DLL JsonMaybeValue root(std::string const& hierarchy); }; } diff --git a/loader/include/Geode/utils/MiniFunction.hpp b/loader/include/Geode/utils/MiniFunction.hpp index 0dd12e46..b6e335dd 100644 --- a/loader/include/Geode/utils/MiniFunction.hpp +++ b/loader/include/Geode/utils/MiniFunction.hpp @@ -21,7 +21,7 @@ namespace geode::utils { public: Type m_func; - explicit MiniFunctionState(Type func) : m_func(std::move(func)) {} + explicit MiniFunctionState(Type func) : m_func(func) {} Ret call(Args... args) const override { return const_cast(m_func)(args...); @@ -31,6 +31,38 @@ namespace geode::utils { return new MiniFunctionState(*this); } }; + + template + class MiniFunctionStatePointer final : public MiniFunctionStateBase { + public: + Type m_func; + + explicit MiniFunctionStatePointer(Type func) : m_func(func) {} + + Ret call(Args... args) const override { + return const_cast(*m_func)(args...); + } + + MiniFunctionStateBase* clone() const override { + return new MiniFunctionStatePointer(*this); + } + }; + + template + class MiniFunctionStateMemberPointer final : public MiniFunctionStateBase { + public: + Type m_func; + + explicit MiniFunctionStateMemberPointer(Type func) : m_func(func) {} + + Ret call(Class self, Args... args) const override { + return const_cast(self->*m_func)(args...); + } + + MiniFunctionStateBase* clone() const override { + return new MiniFunctionStateMemberPointer(*this); + } + }; template concept MiniFunctionCallable = requires(Callable&& func, Args... args) { @@ -49,6 +81,8 @@ namespace geode::utils { public: MiniFunction() : m_state(nullptr) {} + MiniFunction(std::nullptr_t) : MiniFunction() {} + MiniFunction(MiniFunction const& other) : m_state(other.m_state ? other.m_state->clone() : nullptr) {} @@ -65,6 +99,16 @@ namespace geode::utils { MiniFunction(Callable&& func) : m_state(new MiniFunctionState, Ret, Args...>(std::forward(func))) {} + template + requires(!MiniFunctionCallable && std::is_pointer_v && std::is_function_v>) + MiniFunction(FunctionPointer func) : + m_state(new MiniFunctionStatePointer(func)) {} + + template + requires(std::is_member_function_pointer_v) + MiniFunction(MemberFunctionPointer func) : + m_state(new MiniFunctionStateMemberPointer(func)) {} + MiniFunction& operator=(MiniFunction const& other) { delete m_state; m_state = other.m_state ? other.m_state->clone() : nullptr; @@ -79,6 +123,7 @@ namespace geode::utils { } Ret operator()(Args... args) const { + if (!m_state) return Ret(); return m_state->call(args...); } diff --git a/loader/include/Geode/utils/cocos.hpp b/loader/include/Geode/utils/cocos.hpp index 52b09c78..401400fb 100644 --- a/loader/include/Geode/utils/cocos.hpp +++ b/loader/include/Geode/utils/cocos.hpp @@ -8,6 +8,7 @@ #include #include #include "../loader/Event.hpp" +#include "MiniFunction.hpp" // support converting ccColor3B / ccColor4B to / from json @@ -468,7 +469,7 @@ namespace geode::cocos { */ GEODE_DLL cocos2d::CCScene* switchToScene(cocos2d::CCLayer* layer); - using CreateLayerFunc = std::function; + using CreateLayerFunc = utils::MiniFunction; /** * Reload textures, overwriting the scene to return to after the loading @@ -518,7 +519,7 @@ namespace geode::cocos { * there is none */ template - Type* findFirstChildRecursive(cocos2d::CCNode* node, std::function predicate) { + Type* findFirstChildRecursive(cocos2d::CCNode* node, utils::MiniFunction predicate) { if (cast::safe_cast(node) && predicate(static_cast(node))) return static_cast(node); @@ -707,7 +708,7 @@ namespace geode::cocos { } template >> - static cocos2d::CCArray* vectorToCCArray(std::vector const& vec, std::function convFunc) { + static cocos2d::CCArray* vectorToCCArray(std::vector const& vec, utils::MiniFunction convFunc) { auto res = cocos2d::CCArray::createWithCapacity(vec.size()); for (auto const& item : vec) res->addObject(convFunc(item)); @@ -734,7 +735,7 @@ namespace geode::cocos { template < typename K, typename V, typename C, typename = std::enable_if_t || std::is_same_v>> - static cocos2d::CCDictionary* mapToCCDict(std::map const& map, std::function convFunc) { + static cocos2d::CCDictionary* mapToCCDict(std::map const& map, utils::MiniFunction convFunc) { auto res = cocos2d::CCDictionary::create(); for (auto const& [key, value] : map) res->setObject(value, convFunc(key)); diff --git a/loader/include/Geode/utils/map.hpp b/loader/include/Geode/utils/map.hpp index e5110a27..f426fe7d 100644 --- a/loader/include/Geode/utils/map.hpp +++ b/loader/include/Geode/utils/map.hpp @@ -20,7 +20,7 @@ namespace geode::utils::map { * false if not. */ template - bool contains(std::unordered_map const& map, std::function containFunc) { + bool contains(std::unordered_map const& map, utils::MiniFunction containFunc) { for (auto const& [_, r] : map) { if (containFunc(r)) return true; } @@ -39,7 +39,7 @@ namespace geode::utils::map { * a pointer. */ template - R select(std::unordered_map const& map, std::function selectFunc) { + R select(std::unordered_map const& map, utils::MiniFunction selectFunc) { for (auto const& [_, r] : map) { if (selectFunc(r)) return r; } @@ -59,7 +59,7 @@ namespace geode::utils::map { */ template std::vector selectAll( - std::unordered_map const& map, std::function selectFunc + std::unordered_map const& map, utils::MiniFunction selectFunc ) { std::vector res; for (auto const& [_, r] : map) { @@ -111,7 +111,7 @@ namespace geode::utils::map { template std::unordered_map remap( std::unordered_map const& map, - std::function(std::pair)> remapFunc + utils::MiniFunction(std::pair)> remapFunc ) { std::unordered_map res; for (auto const& [t, v] : map) { diff --git a/loader/include/Geode/utils/web.hpp b/loader/include/Geode/utils/web.hpp index 05c18bea..286142ae 100644 --- a/loader/include/Geode/utils/web.hpp +++ b/loader/include/Geode/utils/web.hpp @@ -1,6 +1,7 @@ #pragma once #include "../DefaultInclude.hpp" +#include "MiniFunction.hpp" #include #include "Result.hpp" #include "general.hpp" @@ -11,7 +12,7 @@ namespace geode::utils::web { GEODE_DLL void openLinkInBrowser(std::string const& url); - using FileProgressCallback = std::function; + using FileProgressCallback = utils::MiniFunction; /** * Synchronously fetch data from the internet @@ -54,11 +55,11 @@ namespace geode::utils::web { class AsyncWebResponse; class AsyncWebRequest; - using AsyncProgress = std::function; - using AsyncExpect = std::function; - using AsyncExpectCode = std::function; - using AsyncThen = std::function; - using AsyncCancelled = std::function; + using AsyncProgress = utils::MiniFunction; + using AsyncExpect = utils::MiniFunction; + using AsyncExpectCode = utils::MiniFunction; + using AsyncThen = utils::MiniFunction; + using AsyncCancelled = utils::MiniFunction; /** * A handle to an in-progress sent asynchronous web request. Use this to @@ -217,7 +218,7 @@ namespace geode::utils::web { * @returns The original AsyncWebRequest, where you can specify more * aspects about the request like failure and progress callbacks */ - AsyncWebRequest& then(std::function handle); + AsyncWebRequest& then(utils::MiniFunction handle); /** * Specify a callback to run after a download is finished. Runs in the * GD thread, so interacting with UI is safe @@ -225,7 +226,7 @@ namespace geode::utils::web { * @returns The original AsyncWebRequest, where you can specify more * aspects about the request like failure and progress callbacks */ - AsyncWebRequest& then(std::function handle); + AsyncWebRequest& then(utils::MiniFunction handle); }; class GEODE_DLL AsyncWebResponse { @@ -294,7 +295,7 @@ namespace geode::utils::web { }; template - AsyncWebRequest& AsyncWebResult::then(std::function handle) { + AsyncWebRequest& AsyncWebResult::then(utils::MiniFunction handle) { m_request.m_then = [converter = m_converter, handle](SentAsyncWebRequest& req, ByteVector const& arr) { auto conv = converter(arr); @@ -309,7 +310,7 @@ namespace geode::utils::web { } template - AsyncWebRequest& AsyncWebResult::then(std::function handle) { + AsyncWebRequest& AsyncWebResult::then(utils::MiniFunction handle) { m_request.m_then = [converter = m_converter, handle](SentAsyncWebRequest& req, ByteVector const& arr) { auto conv = converter(arr); diff --git a/loader/src/internal/FileWatcher.hpp b/loader/src/internal/FileWatcher.hpp index 427f8949..c42b62bf 100644 --- a/loader/src/internal/FileWatcher.hpp +++ b/loader/src/internal/FileWatcher.hpp @@ -2,14 +2,15 @@ #include //#include +#include #include #include #include class FileWatcher { public: - using FileWatchCallback = std::function; - using ErrorCallback = std::function; + using FileWatchCallback = geode::utils::MiniFunction; + using ErrorCallback = geode::utils::MiniFunction; protected: ghc::filesystem::path m_file; diff --git a/loader/src/loader/IPC.cpp b/loader/src/loader/IPC.cpp index 1dd71e23..ea26d467 100644 --- a/loader/src/loader/IPC.cpp +++ b/loader/src/loader/IPC.cpp @@ -24,7 +24,7 @@ IPCEvent::IPCEvent( IPCEvent::~IPCEvent() {} -ListenerResult IPCFilter::handle(std::function fn, IPCEvent* event) { +ListenerResult IPCFilter::handle(utils::MiniFunction fn, IPCEvent* event) { if (event->targetModID == m_modID && event->messageID == m_messageID) { event->replyData = fn(event); return ListenerResult::Stop; diff --git a/loader/src/loader/Index.cpp b/loader/src/loader/Index.cpp index 871b9d31..e9488aca 100644 --- a/loader/src/loader/Index.cpp +++ b/loader/src/loader/Index.cpp @@ -17,7 +17,7 @@ ModInstallEvent::ModInstallEvent( std::string const& id, const UpdateStatus status ) : modID(id), status(status) {} -ListenerResult ModInstallFilter::handle(std::function fn, ModInstallEvent* event) { +ListenerResult ModInstallFilter::handle(utils::MiniFunction fn, ModInstallEvent* event) { if (m_id == event->modID) { fn(event); } @@ -67,7 +67,7 @@ class SourceUpdateFilter : public EventFilter { public: using Callback = void(SourceUpdateEvent*); - ListenerResult handle(std::function fn, SourceUpdateEvent* event) { + ListenerResult handle(utils::MiniFunction fn, SourceUpdateEvent* event) { fn(event); return ListenerResult::Propagate; } @@ -79,7 +79,7 @@ public: IndexUpdateEvent::IndexUpdateEvent(const UpdateStatus status) : status(status) {} ListenerResult IndexUpdateFilter::handle( - std::function fn, + utils::MiniFunction fn, IndexUpdateEvent* event ) { fn(event); diff --git a/loader/src/loader/LoaderImpl.cpp b/loader/src/loader/LoaderImpl.cpp index e915c4d6..b75d138a 100644 --- a/loader/src/loader/LoaderImpl.cpp +++ b/loader/src/loader/LoaderImpl.cpp @@ -467,8 +467,8 @@ bool Loader::Impl::platformConsoleOpen() const { } void Loader::Impl::fetchLatestGithubRelease( - std::function then, - std::function expect + utils::MiniFunction then, + utils::MiniFunction expect ) { if (m_latestGithubRelease) { return then(m_latestGithubRelease.value()); @@ -735,7 +735,7 @@ ResourceDownloadEvent::ResourceDownloadEvent( ) : status(status) {} ListenerResult ResourceDownloadFilter::handle( - std::function fn, + utils::MiniFunction fn, ResourceDownloadEvent* event ) { fn(event); @@ -749,7 +749,7 @@ LoaderUpdateEvent::LoaderUpdateEvent( ) : status(status) {} ListenerResult LoaderUpdateFilter::handle( - std::function fn, + utils::MiniFunction fn, LoaderUpdateEvent* event ) { fn(event); diff --git a/loader/src/loader/LoaderImpl.hpp b/loader/src/loader/LoaderImpl.hpp index 548f9c40..fde4ae6f 100644 --- a/loader/src/loader/LoaderImpl.hpp +++ b/loader/src/loader/LoaderImpl.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "ModImpl.hpp" #include #include @@ -31,7 +32,7 @@ namespace geode { public: using Callback = void(ResourceDownloadEvent*); - ListenerResult handle(std::function fn, ResourceDownloadEvent* event); + ListenerResult handle(utils::MiniFunction fn, ResourceDownloadEvent* event); ResourceDownloadFilter(); }; @@ -44,7 +45,7 @@ namespace geode { public: using Callback = void(LoaderUpdateEvent*); - ListenerResult handle(std::function fn, LoaderUpdateEvent* event); + ListenerResult handle(utils::MiniFunction fn, LoaderUpdateEvent* event); LoaderUpdateFilter(); }; @@ -67,7 +68,7 @@ namespace geode { std::condition_variable m_earlyLoadFinishedCV; std::mutex m_earlyLoadFinishedMutex; std::atomic_bool m_earlyLoadFinished = false; - std::vector> m_gdThreadQueue; + std::vector> m_gdThreadQueue; mutable std::mutex m_gdThreadMutex; bool m_platformConsoleOpen = false; std::vector> m_internalHooks; @@ -94,8 +95,8 @@ namespace geode { void downloadLoaderResources(bool useLatestRelease = false); void downloadLoaderUpdate(std::string const& url); void fetchLatestGithubRelease( - std::function then, - std::function expect + utils::MiniFunction then, + utils::MiniFunction expect ); bool loadHooks(); diff --git a/loader/src/loader/ModEvent.cpp b/loader/src/loader/ModEvent.cpp index 753d8e5d..d83e02a5 100644 --- a/loader/src/loader/ModEvent.cpp +++ b/loader/src/loader/ModEvent.cpp @@ -12,7 +12,7 @@ Mod* ModStateEvent::getMod() const { return m_mod; } -ListenerResult ModStateFilter::handle(std::function fn, ModStateEvent* event) { +ListenerResult ModStateFilter::handle(utils::MiniFunction fn, ModStateEvent* event) { if (event->getMod() == m_mod && event->getType() == m_type) { fn(event); } diff --git a/loader/src/loader/ModInfo.cpp b/loader/src/loader/ModInfo.cpp index 0529b8f8..9bd7e477 100644 --- a/loader/src/loader/ModInfo.cpp +++ b/loader/src/loader/ModInfo.cpp @@ -87,7 +87,7 @@ Result ModInfo::Impl::createFromSchemaV010(ModJson const& rawJson) { root.addKnownKey("geode"); - root.needs("id").validate(&ModInfo::validateID).into(impl->m_id); + root.needs("id").validate(MiniFunction(&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); @@ -105,7 +105,7 @@ Result ModInfo::Impl::createFromSchemaV010(ModJson const& rawJson) { auto obj = dep.obj(); auto depobj = Dependency{}; - obj.needs("id").validate(&ModInfo::validateID).into(depobj.id); + obj.needs("id").validate(MiniFunction(&ModInfo::validateID)).into(depobj.id); obj.needs("version").into(depobj.version); obj.has("required").into(depobj.required); obj.checkUnknownKeys(); diff --git a/loader/src/loader/Setting.cpp b/loader/src/loader/Setting.cpp index 63709414..4b5d0b3e 100644 --- a/loader/src/loader/Setting.cpp +++ b/loader/src/loader/Setting.cpp @@ -11,19 +11,19 @@ USE_GEODE_NAMESPACE(); template -static void parseCommon(T& sett, JsonMaybeObject& obj) { +static void parseCommon(T& sett, JsonMaybeObject& obj) { obj.has("name").into(sett.name); obj.has("description").into(sett.description); obj.has("default").into(sett.defaultValue); } -Result BoolSetting::parse(JsonMaybeObject& obj) { +Result BoolSetting::parse(JsonMaybeObject& obj) { BoolSetting sett; parseCommon(sett, obj); return Ok(sett); } -Result IntSetting::parse(JsonMaybeObject& obj) { +Result IntSetting::parse(JsonMaybeObject& obj) { IntSetting sett; parseCommon(sett, obj); obj.has("min").into(sett.min); @@ -40,7 +40,7 @@ Result IntSetting::parse(JsonMaybeObject& obj) { return Ok(sett); } -Result FloatSetting::parse(JsonMaybeObject& obj) { +Result FloatSetting::parse(JsonMaybeObject& obj) { FloatSetting sett; parseCommon(sett, obj); obj.has("min").into(sett.min); @@ -57,14 +57,14 @@ Result FloatSetting::parse(JsonMaybeObject& obj) { return Ok(sett); } -Result StringSetting::parse(JsonMaybeObject& obj) { +Result StringSetting::parse(JsonMaybeObject& obj) { StringSetting sett; parseCommon(sett, obj); obj.has("match").into(sett.match); return Ok(sett); } -Result FileSetting::parse(JsonMaybeObject& obj) { +Result FileSetting::parse(JsonMaybeObject& obj) { FileSetting sett; parseCommon(sett, obj); if (auto controls = obj.has("control").obj()) { @@ -87,13 +87,13 @@ Result FileSetting::parse(JsonMaybeObject& obj) { return Ok(sett); } -Result ColorSetting::parse(JsonMaybeObject& obj) { +Result ColorSetting::parse(JsonMaybeObject& obj) { ColorSetting sett; parseCommon(sett, obj); return Ok(sett); } -Result ColorAlphaSetting::parse(JsonMaybeObject& obj) { +Result ColorAlphaSetting::parse(JsonMaybeObject& obj) { ColorAlphaSetting sett; parseCommon(sett, obj); return Ok(sett); @@ -101,7 +101,7 @@ Result ColorAlphaSetting::parse(JsonMaybeObject& obj Result Setting::parse( std::string const& key, - JsonMaybeValue& value + JsonMaybeValue& value ) { auto sett = Setting(); sett.m_key = key; @@ -378,7 +378,7 @@ SettingChangedEvent::SettingChangedEvent(Mod* mod, SettingValue* value) // SettingChangedFilter ListenerResult SettingChangedFilter::handle( - std::function fn, SettingChangedEvent* event + utils::MiniFunction fn, SettingChangedEvent* event ) { if (m_modID == event->mod->getID() && (!m_targetKey || m_targetKey.value() == event->value->getKey()) diff --git a/loader/src/ui/nodes/EnterLayerEvent.cpp b/loader/src/ui/nodes/EnterLayerEvent.cpp index 8583b626..3805cae2 100644 --- a/loader/src/ui/nodes/EnterLayerEvent.cpp +++ b/loader/src/ui/nodes/EnterLayerEvent.cpp @@ -8,7 +8,7 @@ AEnterLayerEvent::AEnterLayerEvent( ) : layerID(layerID), layer(layer) {} -ListenerResult AEnterLayerFilter::handle(std::function fn, AEnterLayerEvent* event) { +ListenerResult AEnterLayerFilter::handle(utils::MiniFunction fn, AEnterLayerEvent* event) { if (m_targetID == event->layerID) { fn(event); } diff --git a/loader/src/ui/nodes/MDPopup.cpp b/loader/src/ui/nodes/MDPopup.cpp index 96426985..64b23545 100644 --- a/loader/src/ui/nodes/MDPopup.cpp +++ b/loader/src/ui/nodes/MDPopup.cpp @@ -6,7 +6,7 @@ USE_GEODE_NAMESPACE(); bool MDPopup::setup( std::string const& title, std::string const& info, char const* btn1Text, char const* btn2Text, - std::function onClick + utils::MiniFunction onClick ) { this->setTitle(title.c_str(), "goldFont.fnt", .9f, 33.f); @@ -65,7 +65,7 @@ float MDPopup::estimateHeight(std::string const& content) { MDPopup* MDPopup::create( std::string const& title, std::string const& content, char const* btn1, char const* btn2, - std::function onClick + utils::MiniFunction onClick ) { auto ret = new MDPopup(); if (ret && diff --git a/loader/src/utils/JsonValidation.cpp b/loader/src/utils/JsonValidation.cpp index b0ef31bb..0a592fc3 100644 --- a/loader/src/utils/JsonValidation.cpp +++ b/loader/src/utils/JsonValidation.cpp @@ -2,52 +2,52 @@ USE_GEODE_NAMESPACE(); -template -Json& JsonMaybeSomething::json() { + +json::Value& JsonMaybeSomething::json() { return m_json; } -template -JsonMaybeSomething::JsonMaybeSomething( - JsonChecker& checker, Json& json, std::string const& hierarchy, bool hasValue + +JsonMaybeSomething::JsonMaybeSomething( + JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue ) : m_checker(checker), m_json(json), m_hierarchy(hierarchy), m_hasValue(hasValue) {} -template -bool JsonMaybeSomething::isError() const { + +bool JsonMaybeSomething::isError() const { return m_checker.isError() || !m_hasValue; } -template -std::string JsonMaybeSomething::getError() const { + +std::string JsonMaybeSomething::getError() const { return m_checker.getError(); } -template -JsonMaybeSomething::operator bool() const { + +JsonMaybeSomething::operator bool() const { return !isError(); } -template -void JsonMaybeSomething::setError(std::string const& error) { + +void JsonMaybeSomething::setError(std::string const& error) { m_checker.m_result = error; } -template -JsonMaybeValue::JsonMaybeValue( - JsonChecker& checker, Json& json, std::string const& hierarchy, bool hasValue -) : - JsonMaybeSomething(checker, json, hierarchy, hasValue) {} -template -JsonMaybeSomething& JsonMaybeValue::self() { - return *static_cast*>(this); +JsonMaybeValue::JsonMaybeValue( + JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue +) : + JsonMaybeSomething(checker, json, hierarchy, hasValue) {} + + +JsonMaybeSomething& JsonMaybeValue::self() { + return *static_cast(this); } // template // template -// JsonMaybeValue& JsonMaybeValue::as() { +// JsonMaybeValue& JsonMaybeValue::as() { // if (this->isError()) return *this; // if (!jsonConvertibleTo(self().m_json.type(), T)) { // this->setError( @@ -60,15 +60,15 @@ JsonMaybeSomething& JsonMaybeValue::self() { // return *this; // } -template -JsonMaybeValue& JsonMaybeValue::array() { + +JsonMaybeValue& JsonMaybeValue::array() { this->as(); return *this; } // template // template -// JsonMaybeValue JsonMaybeValue::asOneOf() { +// JsonMaybeValue JsonMaybeValue::asOneOf() { // if (this->isError()) return *this; // bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T)); // if (!isOneOf) { @@ -84,7 +84,7 @@ JsonMaybeValue& JsonMaybeValue::array() { // template // template -// JsonMaybeValue JsonMaybeValue::is() { +// JsonMaybeValue JsonMaybeValue::is() { // if (this->isError()) return *this; // self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T); // m_inferType = false; @@ -93,7 +93,7 @@ JsonMaybeValue& JsonMaybeValue::array() { // template // template -// JsonMaybeValue JsonMaybeValue::validate(JsonValueValidator validator) { +// JsonMaybeValue JsonMaybeValue::validate(JsonValueValidator validator) { // if (this->isError()) return *this; // try { // if (!validator(self().m_json.template get())) { @@ -110,14 +110,14 @@ JsonMaybeValue& JsonMaybeValue::array() { // template // template -// JsonMaybeValue JsonMaybeValue::inferType() { +// JsonMaybeValue JsonMaybeValue::inferType() { // if (this->isError() || !m_inferType) return *this; // return this->as()>(); // } // template // template -// JsonMaybeValue JsonMaybeValue::intoRaw(T& target) { +// JsonMaybeValue JsonMaybeValue::intoRaw(T& target) { // if (this->isError()) return *this; // target = self().m_json; // return *this; @@ -125,19 +125,19 @@ JsonMaybeValue& JsonMaybeValue::array() { // template // template -// JsonMaybeValue JsonMaybeValue::into(T& target) { +// JsonMaybeValue JsonMaybeValue::into(T& target) { // return this->intoAs(target); // } // template // template -// JsonMaybeValue JsonMaybeValue::into(std::optional& target) { +// JsonMaybeValue JsonMaybeValue::into(std::optional& target) { // return this->intoAs>(target); // } // template // template -// JsonMaybeValue JsonMaybeValue::intoAs(T& target) { +// JsonMaybeValue JsonMaybeValue::intoAs(T& target) { // this->inferType(); // if (this->isError()) return *this; // try { @@ -153,7 +153,7 @@ JsonMaybeValue& JsonMaybeValue::array() { // template // template -// T JsonMaybeValue::get() { +// T JsonMaybeValue::get() { // this->inferType(); // if (this->isError()) return T(); // try { @@ -167,15 +167,15 @@ JsonMaybeValue& JsonMaybeValue::array() { // return T(); // } -template -JsonMaybeObject JsonMaybeValue::obj() { + +JsonMaybeObject JsonMaybeValue::obj() { this->as(); return JsonMaybeObject(self().m_checker, self().m_json, self().m_hierarchy, self().m_hasValue); } // template // template -// struct JsonMaybeValue::Iterator { +// struct JsonMaybeValue::Iterator { // std::vector m_values; // using iterator = typename std::vector::iterator; @@ -196,8 +196,8 @@ JsonMaybeObject JsonMaybeValue::obj() { // } // }; -template -JsonMaybeValue JsonMaybeValue::at(size_t i) { + +JsonMaybeValue JsonMaybeValue::at(size_t i) { this->as(); if (this->isError()) return *this; @@ -211,15 +211,15 @@ JsonMaybeValue JsonMaybeValue::at(size_t i) { ); return *this; } - return JsonMaybeValue( + return JsonMaybeValue( self().m_checker, json.at(i), self().m_hierarchy + "." + std::to_string(i), self().m_hasValue ); } -template -typename JsonMaybeValue::template Iterator> JsonMaybeValue::iterate() { + +typename JsonMaybeValue::template Iterator JsonMaybeValue::iterate() { this->as(); - Iterator> iter; + Iterator iter; if (this->isError()) return iter; auto& json = self().m_json.as_array(); @@ -232,72 +232,71 @@ typename JsonMaybeValue::template Iterator> JsonMaybe return iter; } -template -typename JsonMaybeValue::template Iterator>> JsonMaybeValue< - Json>::items() { + +typename JsonMaybeValue::template Iterator> JsonMaybeValue::items() { this->as(); - Iterator>> iter; + Iterator> iter; if (this->isError()) return iter; for (auto& [k, v] : self().m_json.as_object()) { iter.m_values.emplace_back( k, - JsonMaybeValue(self().m_checker, v, self().m_hierarchy + "." + k, self().m_hasValue) + JsonMaybeValue(self().m_checker, v, self().m_hierarchy + "." + k, self().m_hasValue) ); } return iter; } -template -JsonMaybeObject::JsonMaybeObject( - JsonChecker& checker, Json& json, std::string const& hierarchy, bool hasValue -) : - JsonMaybeSomething(checker, json, hierarchy, hasValue) {} -template -JsonMaybeSomething& JsonMaybeObject::self() { - return *static_cast*>(this); +JsonMaybeObject::JsonMaybeObject( + JsonChecker& checker, json::Value& json, std::string const& hierarchy, bool hasValue +) : + JsonMaybeSomething(checker, json, hierarchy, hasValue) {} + + +JsonMaybeSomething& JsonMaybeObject::self() { + return *static_cast(this); } -template -void JsonMaybeObject::addKnownKey(std::string const& key) { + +void JsonMaybeObject::addKnownKey(std::string const& key) { m_knownKeys.insert(key); } -template -Json& JsonMaybeObject::json() { + +json::Value& JsonMaybeObject::json() { return self().m_json; } -template -JsonMaybeValue JsonMaybeObject::emptyValue() { + +JsonMaybeValue JsonMaybeObject::emptyValue() { return JsonMaybeValue(self().m_checker, self().m_json, "", false); } -template -JsonMaybeValue JsonMaybeObject::has(std::string const& key) { + +JsonMaybeValue JsonMaybeObject::has(std::string const& key) { this->addKnownKey(key); if (this->isError()) return emptyValue(); if (!self().m_json.contains(key) || self().m_json[key].is_null()) { return emptyValue(); } - return JsonMaybeValue(self().m_checker, self().m_json[key], key, true); + return JsonMaybeValue(self().m_checker, self().m_json[key], key, true); } -template -JsonMaybeValue JsonMaybeObject::needs(std::string const& key) { + +JsonMaybeValue JsonMaybeObject::needs(std::string const& key) { this->addKnownKey(key); if (this->isError()) return emptyValue(); if (!self().m_json.contains(key)) { this->setError(self().m_hierarchy + " is missing required key \"" + key + "\""); return emptyValue(); } - return JsonMaybeValue(self().m_checker, self().m_json[key], key, true); + return JsonMaybeValue(self().m_checker, self().m_json[key], key, true); } -template -void JsonMaybeObject::checkUnknownKeys() { + +void JsonMaybeObject::checkUnknownKeys() { for (auto& [key, _] : self().m_json.as_object()) { if (!m_knownKeys.count(key)) { log::warn("{} contains unknown key \"{}\"", self().m_hierarchy, key); @@ -305,40 +304,20 @@ void JsonMaybeObject::checkUnknownKeys() { } } -template -JsonChecker::JsonChecker(Json& json) : m_json(json), m_result(std::monostate()) {} -template -bool JsonChecker::isError() const { +JsonChecker::JsonChecker(json::Value& json) : m_json(json), m_result(std::monostate()) {} + + +bool JsonChecker::isError() const { return std::holds_alternative(m_result); } -template -std::string JsonChecker::getError() const { + +std::string JsonChecker::getError() const { return std::get(m_result); } -template -JsonMaybeValue JsonChecker::root(std::string const& hierarchy) { + +JsonMaybeValue JsonChecker::root(std::string const& hierarchy) { return JsonMaybeValue(*this, m_json, hierarchy, true); } - -namespace geode { - - template struct JsonMaybeSomething; - template struct JsonMaybeSomething; - //template struct JsonMaybeSomething; - - template struct JsonMaybeValue; - template struct JsonMaybeValue; - //template struct JsonMaybeValue; - - template struct JsonMaybeObject; - template struct JsonMaybeObject; - //template struct JsonMaybeObject; - - template struct JsonChecker; - template struct JsonChecker; - //template struct JsonChecker; - -} \ No newline at end of file From a567e93431143d042290998ee15e74b227e3ad57 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Wed, 8 Feb 2023 18:30:12 +0300 Subject: [PATCH 09/20] fix filesystemimpl c++ version --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 74774539..e63c49d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,7 @@ target_sources(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/entry.cpp) # Filesystem implementation in a separate target because i couldnt disable pch add_library(GeodeFilesystemImpl ${CMAKE_CURRENT_SOURCE_DIR}/FilesystemImpl.cpp) +target_compile_features(GeodeFilesystemImpl PUBLIC cxx_std_20) target_link_libraries(GeodeFilesystemImpl PUBLIC ghc_filesystem) include(ExternalProject) From 4a9f6ba52a3d756d9bc28c1809afc92479783673 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Wed, 8 Feb 2023 13:30:25 -0300 Subject: [PATCH 10/20] bindings: MenuLayer methods and StatsLayer --- bindings/GeometryDash.bro | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 8298e0b9..d1df60ab 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -859,7 +859,16 @@ class CreatorLayer : cocos2d::CCLayer { void onChallenge(cocos2d::CCObject*) = win 0x4f1b0; void onLeaderboards(cocos2d::CCObject*) = win 0x4ed20; void onMyLevels(cocos2d::CCObject*) = mac 0x142b70, win 0x4eaa0; - void onSavedLevels(cocos2d::CCObject*) = mac 0x142860; + void onSavedLevels(cocos2d::CCObject*) = mac 0x142860, win 0x4ebe0; + void onDailyLevel(cocos2d::CCObject*) = win 0x4f170; + void onWeeklyLevel(cocos2d::CCObject*) = win 0x4f190; + void onFeaturedLevels(cocos2d::CCObject*) = win 0x4edf0; + void onFameLevels(cocos2d::CCObject*) = win 0x4ee70; + void onMapPacks(cocos2d::CCObject*) = win 0x4efb0; + void onOnlineLevels(cocos2d::CCObject*) = win 0x4ef60; + void onGauntlets(cocos2d::CCObject*) = win 0x4f0a0; + void onSecretVault(cocos2d::CCObject*) = win 0x4f1d0; + void onTreasureRoom(cocos2d::CCObject*) = win 0x4f540; virtual void sceneWillResume() = win 0x4fb50; virtual bool init() = mac 0x141c10, win 0x4de40; static CreatorLayer* create() = win 0x4dda0; @@ -5158,6 +5167,10 @@ class StatsCell : TableViewCell { virtual void draw() = mac 0x11bf80, win 0x59d40; } +class StatsLayer : GJDropDownLayer { + static StatsLayer* create() = win 0x25BCF0; +} + class TableView : CCScrollLayerExt, CCScrollLayerExtDelegate { inline TableView() {} inline TableView(cocos2d::CCRect rect) : CCScrollLayerExt(rect) {} From 4ecc4ac23a3a4e7ff897a1f7aa42eb80dbb687ad Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Wed, 8 Feb 2023 20:52:54 +0300 Subject: [PATCH 11/20] fix modinfo impl ctor being broken --- bindings/GeometryDash.bro | 2 +- loader/src/loader/ModInfo.cpp | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bindings/GeometryDash.bro b/bindings/GeometryDash.bro index 8298e0b9..d8e14efa 100644 --- a/bindings/GeometryDash.bro +++ b/bindings/GeometryDash.bro @@ -3692,7 +3692,7 @@ class LevelEditorLayer : GJBaseGameLayer, LevelSettingsDelegate { bool m_previewMode; GJGroundLayer* m_groundLayer; std::string m_rawLevelString; - void* m_triggerHitbox; + void* m_triggerHitbox; // why are these std vector bruh std::vector m_objectVector; std::vector m_groupVector; std::vector m_nestedObjects; diff --git a/loader/src/loader/ModInfo.cpp b/loader/src/loader/ModInfo.cpp index 9bd7e477..dbfc4802 100644 --- a/loader/src/loader/ModInfo.cpp +++ b/loader/src/loader/ModInfo.cpp @@ -42,7 +42,7 @@ public: bool m_needsEarlyLoad = false; bool m_isAPI = false; - std::shared_ptr m_rawJSON; + ModJson m_rawJSON; static Result createFromGeodeZip(utils::file::Unzip& zip); static Result createFromGeodeFile(ghc::filesystem::path const& path); @@ -80,9 +80,9 @@ Result ModInfo::Impl::createFromSchemaV010(ModJson const& rawJson) { auto impl = info.m_impl.get(); - impl->m_rawJSON = std::make_unique(rawJson); + impl->m_rawJSON = rawJson; - JsonChecker checker(*impl->m_rawJSON); + JsonChecker checker(impl->m_rawJSON); auto root = checker.root("[mod.json]").obj(); root.addKnownKey("geode"); @@ -189,7 +189,7 @@ Result ModInfo::Impl::create(ModJson const& json) { // Handle mod.json data based on target if (schema >= VersionInfo(0, 1, 0)) { - return ModInfo::createFromSchemaV010(json); + return Impl::createFromSchemaV010(json); } return Err( @@ -294,14 +294,14 @@ std::vector*>> ModInfo::Impl:: } ModJson ModInfo::Impl::toJSON() const { - auto json = *m_rawJSON; + auto json = m_rawJSON; json["path"] = this->m_path.string(); json["binary"] = this->m_binaryName; return json; } ModJson ModInfo::Impl::getRawJSON() const { - return *m_rawJSON; + return m_rawJSON; } bool ModInfo::Impl::operator==(ModInfo::Impl const& other) const { @@ -474,10 +474,10 @@ bool ModInfo::validateID(std::string const& id) { } ModJson& ModInfo::rawJSON() { - return *m_impl->m_rawJSON; + return m_impl->m_rawJSON; } ModJson const& ModInfo::rawJSON() const { - return *m_impl->m_rawJSON; + return m_impl->m_rawJSON; } Result ModInfo::createFromSchemaV010(ModJson const& json) { @@ -495,7 +495,7 @@ std::vector*>> ModInfo::getSpe return m_impl->getSpecialFiles(); } -ModInfo::ModInfo() : m_impl() {} +ModInfo::ModInfo() : m_impl(std::make_unique()) {} ModInfo::ModInfo(ModInfo const& other) : m_impl(std::make_unique(*other.m_impl)) {} From 0eb5f01ca81435cb90f2bc9d8d97a86405dadd1c Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Wed, 8 Feb 2023 21:18:47 +0300 Subject: [PATCH 12/20] make mod binaries not load not silently fail --- loader/src/loader/LoaderImpl.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/loader/src/loader/LoaderImpl.cpp b/loader/src/loader/LoaderImpl.cpp index b75d138a..c91632ae 100644 --- a/loader/src/loader/LoaderImpl.cpp +++ b/loader/src/loader/LoaderImpl.cpp @@ -195,6 +195,8 @@ Result Loader::Impl::loadModFromInfo(ModInfo const& info) { auto mod = new Mod(info); auto setupRes = mod->m_impl->setup(); if (!setupRes) { + // old code artifcat, idk why we are not using unique_ptr TBH + delete mod; return Err(fmt::format( "Unable to setup mod '{}': {}", info.id(), setupRes.unwrapErr() @@ -202,10 +204,19 @@ Result Loader::Impl::loadModFromInfo(ModInfo const& info) { } m_mods.insert({ info.id(), mod }); + mod->m_impl->m_enabled = Mod::get()->getSavedValue( "should-load-" + info.id(), true ); + // this loads the mod if its dependencies are resolved + auto dependenciesRes = mod->updateDependencies(); + if (!dependenciesRes) { + delete mod; + m_mods.erase(info.id()); + return Err("Unable to update dependencies and load: " + dependenciesRes.unwrapErr()); + } + // add mod resources this->queueInGDThread([this, mod]() { auto searchPath = dirs::getModRuntimeDir() / mod->getID() / "resources"; @@ -214,9 +225,6 @@ Result Loader::Impl::loadModFromInfo(ModInfo const& info) { this->updateModResources(mod); }); - // this loads the mod if its dependencies are resolved - GEODE_UNWRAP(mod->updateDependencies()); - return Ok(mod); } @@ -363,6 +371,11 @@ void Loader::Impl::refreshModsList() { auto load = this->loadModFromInfo(mod); if (!load) { log::error("Unable to load {}: {}", mod.id(), load.unwrapErr()); + + m_invalidMods.push_back(InvalidGeodeFile { + .path = mod.path(), + .reason = load.unwrapErr(), + }); } } } @@ -377,6 +390,11 @@ void Loader::Impl::refreshModsList() { auto load = this->loadModFromInfo(mod); if (!load) { log::error("Unable to load {}: {}", mod.id(), load.unwrapErr()); + + m_invalidMods.push_back(InvalidGeodeFile { + .path = mod.path(), + .reason = load.unwrapErr(), + }); } } } From 345625e164a89977318a57900cbbfe7fa3686861 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Wed, 8 Feb 2023 21:23:34 +0300 Subject: [PATCH 13/20] rename loading error --- loader/src/loader/LoaderImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/src/loader/LoaderImpl.cpp b/loader/src/loader/LoaderImpl.cpp index c91632ae..1179bb4d 100644 --- a/loader/src/loader/LoaderImpl.cpp +++ b/loader/src/loader/LoaderImpl.cpp @@ -214,7 +214,7 @@ Result Loader::Impl::loadModFromInfo(ModInfo const& info) { if (!dependenciesRes) { delete mod; m_mods.erase(info.id()); - return Err("Unable to update dependencies and load: " + dependenciesRes.unwrapErr()); + return Err(dependenciesRes.unwrapErr()); } // add mod resources From 28b26220c8ae2aac9e70d958432579739168fa52 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Wed, 8 Feb 2023 15:29:48 -0300 Subject: [PATCH 14/20] force ModImpl::m_saved to an object when loading saved.json --- loader/src/loader/ModImpl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/loader/src/loader/ModImpl.cpp b/loader/src/loader/ModImpl.cpp index c0180854..14f6dcd4 100644 --- a/loader/src/loader/ModImpl.cpp +++ b/loader/src/loader/ModImpl.cpp @@ -124,8 +124,6 @@ Result<> Mod::Impl::loadData() { if (ghc::filesystem::exists(settingPath)) { GEODE_UNWRAP_INTO(auto settingData, utils::file::readString(settingPath)); try { - std::string err; - // parse settings.json auto json = json::parse(settingData); @@ -169,13 +167,15 @@ Result<> Mod::Impl::loadData() { if (ghc::filesystem::exists(savedPath)) { GEODE_UNWRAP_INTO(auto data, utils::file::readString(savedPath)); - std::string err; try { m_saved = json::parse(data); } catch (std::exception& err) { return Err(std::string("Unable to parse saved values: ") + err.what()); } - + if (!m_saved.is_object()) { + log::warn("saved.json was somehow not an object, forcing it to one"); + m_saved = json::Object(); + } } return Ok(); From ebe1dd71024a9e1da4189008d67553e96dc82e90 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Wed, 8 Feb 2023 15:43:09 -0300 Subject: [PATCH 15/20] fix ScheduledFunction --- loader/include/Geode/loader/Loader.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/include/Geode/loader/Loader.hpp b/loader/include/Geode/loader/Loader.hpp index aa178009..4b00ebe2 100644 --- a/loader/include/Geode/loader/Loader.hpp +++ b/loader/include/Geode/loader/Loader.hpp @@ -11,7 +11,7 @@ #include namespace geode { - using ScheduledFunction = utils::MiniFunction; + using ScheduledFunction = utils::MiniFunction; struct InvalidGeodeFile { ghc::filesystem::path path; From 4b73d8f451f556fcee678d93ffeeedbd6e5086f5 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Thu, 9 Feb 2023 12:50:51 +0300 Subject: [PATCH 16/20] update Tuliphook to improve configure times --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e63c49d6..92540ae4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ CPMAddPackage("gh:gulrak/filesystem#3e5b930") if (PROJECT_IS_TOP_LEVEL AND NOT GEODE_BUILDING_DOCS) set(TULIP_LINK_SOURCE ON) endif() -CPMAddPackage("gh:geode-sdk/TulipHook#76984a4") +CPMAddPackage("gh:geode-sdk/TulipHook#a2c16d0") target_sources(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/entry.cpp) From 688b8c4ac94c5a625855d4ed76b482bf78c3a203 Mon Sep 17 00:00:00 2001 From: altalk23 <45172705+altalk23@users.noreply.github.com> Date: Thu, 9 Feb 2023 13:25:23 +0300 Subject: [PATCH 17/20] compile only a singe objcpp file --- loader/CMakeLists.txt | 3 +-- loader/src/platform/Objcpp.mm | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 loader/src/platform/Objcpp.mm diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index 3bda82b5..cced6f1a 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -35,8 +35,7 @@ file(GLOB SOURCES CONFIGURE_DEPENDS # Obj-c sources file(GLOB OBJC_SOURCES - src/platform/ios/*.mm - src/platform/mac/*.mm + src/platform/Objcpp.mm ) set_source_files_properties(${OBJC_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON) diff --git a/loader/src/platform/Objcpp.mm b/loader/src/platform/Objcpp.mm new file mode 100644 index 00000000..6d3ef6e1 --- /dev/null +++ b/loader/src/platform/Objcpp.mm @@ -0,0 +1,17 @@ +// Only a single objc++ file is used because since pch doesnt work, each file adds a lot to the compile times +#include + +USE_GEODE_NAMESPACE(); + +#if defined(GEODE_IS_MACOS) + +#include "mac/crashlog.mm" +#include "mac/FileWatcher.mm" +#include "mac/util.mm" + +#elif defined(GEODE_IS_IOS) + +#include "ios/FileWatcher.mm" +#include "ios/util.mm" + +#endif \ No newline at end of file From 41aef57758d7b858d5fa7cb22ab1ffe603ff365f Mon Sep 17 00:00:00 2001 From: camila314 <47485054+camila314@users.noreply.github.com> Date: Thu, 9 Feb 2023 09:45:06 -0600 Subject: [PATCH 18/20] make >= default prevent issues --- loader/include/Geode/utils/VersionInfo.hpp | 11 +++++++---- loader/src/utils/VersionInfo.cpp | 9 +++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/loader/include/Geode/utils/VersionInfo.hpp b/loader/include/Geode/utils/VersionInfo.hpp index 2744300b..f94472ca 100644 --- a/loader/include/Geode/utils/VersionInfo.hpp +++ b/loader/include/Geode/utils/VersionInfo.hpp @@ -121,12 +121,15 @@ namespace geode { if (m_version.getMajor() != version.getMajor()) { return false; } + switch (m_compare) { - case VersionCompare::Exact: return m_version == version; break; - case VersionCompare::LessEq: return m_version <= version; break; - case VersionCompare::MoreEq: return m_version >= version; break; + case VersionCompare::LessEq: + return m_version <= version; + case VersionCompare::MoreEq: + return m_version >= version; + default: + return m_version == version; } - return false; } std::string toString() const; diff --git a/loader/src/utils/VersionInfo.cpp b/loader/src/utils/VersionInfo.cpp index f0abafc3..13f8aad7 100644 --- a/loader/src/utils/VersionInfo.cpp +++ b/loader/src/utils/VersionInfo.cpp @@ -115,15 +115,16 @@ Result ComparableVersionInfo::parse(std::string const& ra if (string.starts_with("<=")) { compare = VersionCompare::LessEq; string.erase(0, 2); - } - else if (string.starts_with(">=")) { + } else if (string.starts_with(">=")) { compare = VersionCompare::MoreEq; string.erase(0, 2); - } - else if (string.starts_with("=")) { + } else if (string.starts_with("=")) { compare = VersionCompare::Exact; string.erase(0, 1); + } else { + compare = VersionCompare::MoreEq; } + GEODE_UNWRAP_INTO(auto version, VersionInfo::parse(string)); return Ok(ComparableVersionInfo(version, compare)); } From 65f2cbb286cc1e5af57e43451862a2233d66453e Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Thu, 9 Feb 2023 13:54:30 -0300 Subject: [PATCH 19/20] follow thunk functions for non virtuals --- loader/include/Geode/utils/addresser.hpp | 27 ++++++++++++++---------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/loader/include/Geode/utils/addresser.hpp b/loader/include/Geode/utils/addresser.hpp index d37e65a6..eb458ffa 100644 --- a/loader/include/Geode/utils/addresser.hpp +++ b/loader/include/Geode/utils/addresser.hpp @@ -131,15 +131,7 @@ namespace geode::addresser { // [[this + thunk] + offset] is the f we want auto address = *(intptr_t*)(*(intptr_t*)(reference_cast(ins) + thunk) + index); -#ifdef GEODE_IS_WINDOWS - // check if first instruction is a jmp, i.e. if the func is a thunk - if (*reinterpret_cast(address) == 0x25ff) { - // read where the jmp points to and jump there - address = *reinterpret_cast(address + 2); - // that then contains the actual address of the func - address = *reinterpret_cast(address); - } -#endif + address = followThunkFunction(address); return address; } @@ -171,14 +163,27 @@ namespace geode::addresser { return addressOfNonVirtual(reinterpret_cast(func)); } + static inline intptr_t followThunkFunction(intptr_t address) { +#ifdef GEODE_IS_WINDOWS + // check if first instruction is a jmp dword ptr [....], i.e. if the func is a thunk + if (*reinterpret_cast(address) == 0xFF && *reinterpret_cast(address + 1) == 0x25) { + // read where the jmp reads from + address = *reinterpret_cast(address + 2); + // that then contains the actual address of the func + address = *reinterpret_cast(address); + } +#endif + return address; + } + template static intptr_t addressOfNonVirtual(R (T::*func)(Ps...)) { - return geode::cast::reference_cast(func); + return followThunkFunction(geode::cast::reference_cast(func)); } template static intptr_t addressOfNonVirtual(R (*func)(Ps...)) { - return geode::cast::reference_cast(func); + return followThunkFunction(geode::cast::reference_cast(func)); } template From ee73b25247ea6cd4004376a92bf76dc77ab35650 Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Thu, 9 Feb 2023 14:01:52 -0300 Subject: [PATCH 20/20] potentially fix codegen cache mismatch --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 92540ae4..133fa304 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,8 +77,10 @@ set(GEODE_CODEGEN_BINARY_OUT ${CMAKE_CURRENT_BINARY_DIR}/codegen) ExternalProject_Add(CodegenProject BUILD_ALWAYS ON SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/codegen - CMAKE_CACHE_ARGS "-DCMAKE_INSTALL_PREFIX:STRING=${GEODE_CODEGEN_BINARY_OUT}" - CMAKE_ARGS ${GEODE_CODEGEN_CMAKE_ARGS} + # manually set configure command as to not inherit generator used by geode, + # this should hopefully fix generator cache mismatch between different projects, however + # it causes a warning to be shown every time. if you know a better solution please tell us ok thx + CONFIGURE_COMMAND ${CMAKE_COMMAND} ${GEODE_CODEGEN_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:STRING=${GEODE_CODEGEN_BINARY_OUT} -S -B )