diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fb980e7..15ddde33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 3.21 FATAL_ERROR) -project(geode-sdk VERSION 0.3.0 LANGUAGES CXX C) +set(GEODE_VERSION 0.3.0) + +project(geode-sdk VERSION ${GEODE_VERSION} LANGUAGES CXX C) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index 27eabade..00a13695 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.21 FATAL_ERROR) -project(geode-loader VERSION 0.2.1 LANGUAGES C CXX) +project(geode-loader VERSION ${GEODE_VERSION} LANGUAGES C CXX) set(PROJECT_VERSION_TYPE Alpha) # Package info file for internal representation @@ -28,6 +28,7 @@ file(GLOB CORE_SOURCES src/utils/zip/*.cpp src/index/*.cpp src/ui/nodes/*.cpp + src/ui/internal/*.cpp src/ui/internal/credits/*.cpp src/ui/internal/dev/*.cpp src/ui/internal/info/*.cpp diff --git a/loader/include/Geode/loader/Loader.hpp b/loader/include/Geode/loader/Loader.hpp index 183d2182..6f148a03 100644 --- a/loader/include/Geode/loader/Loader.hpp +++ b/loader/include/Geode/loader/Loader.hpp @@ -60,25 +60,6 @@ namespace geode { bool m_isSetup = false; static bool s_unloading; - /** - * Lowest supported mod version. - * Any mod targeting a geode version - * lower than this will not be loaded, - * as they will be considered out-of-date. - */ - static constexpr VersionInfo s_supportedVersionMin { 0, 1, 0 }; - /** - * Highest support mod version. - * Any mod targeting a geode version - * higher than this will not be loaded, - * as a higher version means that - * the user's geode is out-of-date, - * or that the user is a time traveller - * and has downloaded a mod from the - * future. - */ - static constexpr VersionInfo s_supportedVersionMax { 0, 2, 1 }; - Result<std::string> createTempDirectoryForMod(ModInfo const& info); Result<Mod*> loadModFromFile(std::string const& file); size_t loadModsFromDirectory( @@ -107,8 +88,8 @@ namespace geode { */ static Loader* get(); - VersionInfo getVersion() const; - std::string getVersionType() const; + static VersionInfo getVersion(); + static std::string getVersionType(); Result<> saveSettings(); Result<> loadSettings(); @@ -133,10 +114,18 @@ namespace geode { */ ghc::filesystem::path getGeodeSaveDirectory() const; + /** + * Minimum supported mod version + */ + static VersionInfo minModVersion(); + /** + * Maximum supported mod version + */ + static VersionInfo maxModVersion(); /** * Check if a mod's version is within the supported range */ - bool supportedModVersion(VersionInfo const& version); + static bool supportedModVersion(VersionInfo const& version); /** * Whether mod specified with ID is enabled diff --git a/loader/include/Geode/loader/Setting.hpp b/loader/include/Geode/loader/Setting.hpp index fec606f9..77a93546 100644 --- a/loader/include/Geode/loader/Setting.hpp +++ b/loader/include/Geode/loader/Setting.hpp @@ -332,7 +332,7 @@ namespace geode { bool m_hasArrows = true; bool m_hasBigArrows = false; size_t m_arrowStep = 1; - size_t m_bigArrowStep = 1; + size_t m_bigArrowStep = 5; public: Result<> parseArrows(JsonMaybeObject<ModJson>& obj) { diff --git a/loader/include/Geode/meta/preproc.hpp b/loader/include/Geode/meta/preproc.hpp index 80dcc9a7..6a0beabe 100644 --- a/loader/include/Geode/meta/preproc.hpp +++ b/loader/include/Geode/meta/preproc.hpp @@ -11,6 +11,7 @@ #define GEODE_PLATFORM_TARGET PlatformID::Windows #define GEODE_CALL __stdcall #define GEODE_PLATFORM_EXTENSION ".dll" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "win" #else #define GEODE_WINDOWS(...) #endif @@ -26,6 +27,7 @@ #define GEODE_PLATFORM_NAME "iOS" #define GEODE_PLATFORM_TARGET PlatformID::iOS #define GEODE_PLATFORM_EXTENSION ".ios.dylib" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "ios" #else #define GEODE_IOS(...) #define GEODE_MACOS(...) __VA_ARGS__ @@ -34,6 +36,7 @@ #define GEODE_PLATFORM_NAME "MacOS" #define GEODE_PLATFORM_TARGET PlatformID::MacOS #define GEODE_PLATFORM_EXTENSION ".dylib" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "mac" #endif #define GEODE_CALL #else @@ -50,6 +53,7 @@ #define GEODE_PLATFORM_TARGET PlatformID::Android #define GEODE_CALL #define GEODE_PLATFORM_EXTENSION ".so" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "android" #else #define GEODE_ANDROID(...) #endif diff --git a/loader/include/Geode/platform/cplatform.h b/loader/include/Geode/platform/cplatform.h index 297f8aea..5efbee26 100644 --- a/loader/include/Geode/platform/cplatform.h +++ b/loader/include/Geode/platform/cplatform.h @@ -20,6 +20,7 @@ #define GEODE_PLATFORM_NAME "Windows" #define GEODE_CALL __stdcall #define GEODE_PLATFORM_EXTENSION ".dll" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "win" #ifdef GEODE_EXPORTING #undef GEODE_C_DLL @@ -43,6 +44,7 @@ #define GEODE_IS_MOBILE #define GEODE_PLATFORM_NAME "iOS" #define GEODE_PLATFORM_EXTENSION ".ios.dylib" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "ios" #else #define GEODE_IOS(...) #define GEODE_MACOS(...) __VA_ARGS__ @@ -50,6 +52,7 @@ #define GEODE_IS_DESKTOP #define GEODE_PLATFORM_NAME "MacOS" #define GEODE_PLATFORM_EXTENSION ".dylib" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "mac" #endif #define GEODE_CALL #else @@ -65,6 +68,7 @@ #define GEODE_PLATFORM_NAME "Android" #define GEODE_CALL #define GEODE_PLATFORM_EXTENSION ".so" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "android" #else #define GEODE_ANDROID(...) #endif diff --git a/loader/include/Geode/platform/platform.hpp b/loader/include/Geode/platform/platform.hpp index 4b4ee893..bb34ca2f 100644 --- a/loader/include/Geode/platform/platform.hpp +++ b/loader/include/Geode/platform/platform.hpp @@ -77,6 +77,7 @@ namespace std { #define GEODE_VIRTUAL_CONSTEXPR #define GEODE_NOINLINE __declspec(noinline) #define GEODE_PLATFORM_EXTENSION ".dll" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "win" #ifdef GEODE_EXPORTING #define GEODE_DLL __declspec(dllexport) @@ -111,6 +112,7 @@ namespace std { #define GEODE_VIRTUAL_CONSTEXPR constexpr #define GEODE_NOINLINE __attribute__((noinline)) #define GEODE_PLATFORM_EXTENSION ".ios.dylib" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "ios" #ifdef GEODE_EXPORTING #define GEODE_DLL __attribute__((visibility("default"))) @@ -137,6 +139,7 @@ namespace std { #define GEODE_VIRTUAL_CONSTEXPR constexpr #define GEODE_NOINLINE __attribute__((noinline)) #define GEODE_PLATFORM_EXTENSION ".dylib" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "mac" #ifdef GEODE_EXPORTING #define GEODE_DLL __attribute__((visibility("default"))) @@ -169,6 +172,7 @@ namespace std { #define GEODE_VIRTUAL_CONSTEXPR constexpr #define GEODE_NOINLINE __attribute__((noinline)) #define GEODE_PLATFORM_EXTENSION ".so" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "android" #ifdef GEODE_EXPORTING #define GEODE_DLL __attribute__((visibility("default"))) diff --git a/loader/include/Geode/ui/Popup.hpp b/loader/include/Geode/ui/Popup.hpp index c24cf9fc..5077fd2b 100644 --- a/loader/include/Geode/ui/Popup.hpp +++ b/loader/include/Geode/ui/Popup.hpp @@ -9,6 +9,7 @@ namespace geode { cocos2d::CCSize m_size; cocos2d::extension::CCScale9Sprite* m_bgSprite; cocos2d::CCLabelBMFont* m_title = nullptr; + CCMenuItemSpriteExtra* m_closeBtn; bool init( float width, @@ -36,21 +37,21 @@ namespace geode { cocos2d::CCDirector::sharedDirector()->getTouchDispatcher()->incrementForcePrio(2); this->registerWithTouchDispatcher(); - if (!setup(std::forward<InitArgs>(args)...)) { - return false; - } - auto closeSpr = cocos2d::CCSprite::createWithSpriteFrameName("GJ_closeBtn_001.png"); closeSpr->setScale(.8f); - auto closeBtn = CCMenuItemSpriteExtra::create( + m_closeBtn = CCMenuItemSpriteExtra::create( closeSpr, this, (cocos2d::SEL_MenuHandler)(&Popup::onClose) ); - closeBtn->setPosition( + m_closeBtn->setPosition( -m_size.width / 2 + 3.f, m_size.height / 2 - 3.f ); - m_buttonMenu->addChild(closeBtn); + m_buttonMenu->addChild(m_closeBtn); + + if (!setup(std::forward<InitArgs>(args)...)) { + return false; + } this->setKeypadEnabled(true); this->setTouchEnabled(true); diff --git a/loader/include/Geode/utils/fetch.hpp b/loader/include/Geode/utils/fetch.hpp new file mode 100644 index 00000000..0686fefe --- /dev/null +++ b/loader/include/Geode/utils/fetch.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "../DefaultInclude.hpp" +#include <fs/filesystem.hpp> +#include "Result.hpp" +#include "json.hpp" + +namespace geode::utils::web { + using FileProgressCallback = std::function<bool(double, double)>; + + /** + * Synchronously fetch data from the internet + * @param url URL to fetch + * @returns Returned data as string, or error on error + */ + GEODE_DLL Result<std::string> fetch(std::string const& url); + + /** + * Syncronously download a file from the internet + * @param url URL to fetch + * @param into Path to download file into + * @param prog Progress function; first parameter is bytes downloaded so + * far, and second is total bytes to download. Return true to continue + * downloading, and false to interrupt. Note that interrupting does not + * automatically remove the file that was being downloaded + * @returns Returned data as JSON, or error on error + */ + GEODE_DLL Result<> fetchFile( + std::string const& url, + ghc::filesystem::path const& into, + FileProgressCallback prog = nullptr + ); + + /** + * Synchronously fetch data from the internet and parse it as JSON + * @param url URL to fetch + * @returns Returned data as JSON, or error on error + */ + template<class Json = nlohmann::json> + Result<Json> fetchJSON(std::string const& url) { + auto res = fetch(url); + if (!res) return Err(res.error()); + try { + return Ok(Json::parse(res.value())); + } catch(std::exception& e) { + return Err(e.what()); + } + } +} + diff --git a/loader/include/Geode/utils/file.hpp b/loader/include/Geode/utils/file.hpp index 999bbd85..059f466f 100644 --- a/loader/include/Geode/utils/file.hpp +++ b/loader/include/Geode/utils/file.hpp @@ -4,7 +4,7 @@ #include "Result.hpp" #include <string> #include "types.hpp" -#include "fs/filesystem.hpp" +#include <fs/filesystem.hpp> namespace geode::utils::file { GEODE_DLL Result<std::string> readString(std::string const& path); @@ -25,4 +25,15 @@ namespace geode::utils::file { GEODE_DLL Result<> createDirectoryAll(std::string const& path); GEODE_DLL Result<std::vector<std::string>> listFiles(std::string const& path); GEODE_DLL Result<std::vector<std::string>> listFilesRecursively(std::string const& path); + + /** + * Unzip file to directory + * @param from File to unzip + * @param to Directory to unzip to + * @returns Ok on success, Error on error + */ + GEODE_DLL Result<> unzipTo( + ghc::filesystem::path const& from, + ghc::filesystem::path const& to + ); } diff --git a/loader/lilac/include/geode/core/meta/preproc.hpp b/loader/lilac/include/geode/core/meta/preproc.hpp index bd584ea0..2cb8f24f 100644 --- a/loader/lilac/include/geode/core/meta/preproc.hpp +++ b/loader/lilac/include/geode/core/meta/preproc.hpp @@ -11,6 +11,7 @@ #define GEODE_PLATFORM_TARGET PlatformID::Windows #define GEODE_CALL __stdcall #define GEODE_PLATFORM_EXTENSION ".dll" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "win" #else #define GEODE_WINDOWS(...) #endif @@ -26,6 +27,7 @@ #define GEODE_PLATFORM_NAME "iOS" #define GEODE_PLATFORM_TARGET PlatformID::iOS #define GEODE_PLATFORM_EXTENSION ".ios.dylib" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "ios" #else #define GEODE_IOS(...) #define GEODE_MACOS(...) __VA_ARGS__ @@ -34,6 +36,7 @@ #define GEODE_PLATFORM_NAME "MacOS" #define GEODE_PLATFORM_TARGET PlatformID::MacOS #define GEODE_PLATFORM_EXTENSION ".dylib" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "mac" #endif #define GEODE_CALL #else @@ -50,6 +53,7 @@ #define GEODE_PLATFORM_TARGET PlatformID::Android #define GEODE_CALL #define GEODE_PLATFORM_EXTENSION ".so" + #define GEODE_PLATFORM_SHORT_IDENTIFIER "android" #else #define GEODE_ANDROID(...) #endif diff --git a/loader/resources/mod.json.in b/loader/resources/mod.json.in index 0debeb34..9646fbdc 100644 --- a/loader/resources/mod.json.in +++ b/loader/resources/mod.json.in @@ -52,7 +52,13 @@ "type": "bool", "default": false, "name": "Show Platform Console", - "description": "Show the native console (if one exists). <cr>This setting is meant for developers</c>." + "description": "Show the native console (if one exists). <cr>This setting is meant for developers</c>" + }, + "auto-check-updates": { + "type": "bool", + "default": true, + "name": "Check For Updates", + "description": "Automatically check for <cy>updates</c> to Geode on startup" } }, "issues": { diff --git a/loader/src/hooks/MenuLayer.cpp b/loader/src/hooks/MenuLayer.cpp index 1754a534..b948da56 100644 --- a/loader/src/hooks/MenuLayer.cpp +++ b/loader/src/hooks/MenuLayer.cpp @@ -7,6 +7,7 @@ #include <Geode/ui/MDPopup.hpp> #include <InternalMod.hpp> #include "../ui/internal/info/ModInfoLayer.hpp" +#include <InternalLoader.hpp> USE_GEODE_NAMESPACE(); diff --git a/loader/src/index/Index.cpp b/loader/src/index/Index.cpp index 7a18fb71..36dd368a 100644 --- a/loader/src/index/Index.cpp +++ b/loader/src/index/Index.cpp @@ -2,7 +2,7 @@ #include <thread> #include <Geode/utils/json.hpp> #include <Geode/utils/JsonValidation.hpp> -#include "fetch.hpp" +#include <Geode/utils/fetch.hpp> #define GITHUB_DONT_RATE_LIMIT_ME_PLS 0 @@ -19,61 +19,6 @@ static Result<Json> readJSON(ghc::filesystem::path const& path) { } } -static Result<> unzipTo( - ghc::filesystem::path const& from, - ghc::filesystem::path const& to -) { - // unzip downloaded - auto unzip = ZipFile(from.string()); - if (!unzip.isLoaded()) { - return Err("Unable to unzip index.zip"); - } - - for (auto file : unzip.getAllFiles()) { - // this is a very bad check for seeing - // if file is a directory. it seems to - // work on windows at least. idk why - // getAllFiles returns the directories - // aswell now - if ( - utils::string::endsWith(file, "\\") || - utils::string::endsWith(file, "/") - ) continue; - - auto zipPath = file; - - // dont include the github repo folder - file = file.substr(file.find_first_of("/") + 1); - - auto path = ghc::filesystem::path(file); - if (path.has_parent_path()) { - if ( - !ghc::filesystem::exists(to / path.parent_path()) && - !ghc::filesystem::create_directories(to / path.parent_path()) - ) { - return Err( - "Unable to create directories \"" + - path.parent_path().string() + "\"" - ); - } - } - unsigned long size; - auto data = unzip.getFileData(zipPath, &size); - if (!data || !size) { - return Err("Unable to read \"" + std::string(zipPath) + "\""); - } - auto wrt = utils::file::writeBinary( - to / file, - byte_array(data, data + size) - ); - if (!wrt) { - return Err("Unable to write \"" + file + "\": " + wrt.error()); - } - } - - return Ok(); -} - static PlatformID platformFromString(std::string const& str) { switch (hash(utils::string::trim(utils::string::toLower(str)).c_str())) { default: @@ -126,7 +71,7 @@ void Index::updateIndexThread(bool force) { ); // get all commits in index repo - auto commit = fetchJSON( + auto commit = web::fetchJSON( "https://api.github.com/repos/geode-sdk/mods/commits" ); if (!commit) { @@ -202,7 +147,7 @@ void Index::updateIndexThread(bool force) { "Downloading index", 50 ); - auto gotZip = fetchFile( + auto gotZip = web::fetchFile( "https://github.com/geode-sdk/mods/zipball/main", indexDir / "index.zip" ); @@ -218,7 +163,7 @@ void Index::updateIndexThread(bool force) { ghc::filesystem::remove_all(indexDir / "index"); } - auto unzip = unzipTo(indexDir / "index.zip", indexDir); + auto unzip = file::unzipTo(indexDir / "index.zip", indexDir); if (!unzip) { return indexUpdateProgress( UpdateStatus::Failed, unzip.error() diff --git a/loader/src/index/InstallTicket.cpp b/loader/src/index/InstallTicket.cpp index 4fc82e18..1833d022 100644 --- a/loader/src/index/InstallTicket.cpp +++ b/loader/src/index/InstallTicket.cpp @@ -2,7 +2,7 @@ #include <thread> #include <Geode/utils/json.hpp> #include <hash.hpp> -#include "fetch.hpp" +#include <Geode/utils/fetch.hpp> void InstallTicket::postProgress( UpdateStatus status, @@ -46,7 +46,7 @@ void InstallTicket::install(std::string const& id) { auto tempFile = indexDir / item.m_download.m_filename; this->postProgress(UpdateStatus::Progress, "Fetching binary", 0); - auto res = fetchFile( + auto res = web::fetchFile( item.m_download.m_url, tempFile, [this, tempFile](double now, double total) -> int { @@ -54,7 +54,7 @@ void InstallTicket::install(std::string const& id) { std::lock_guard cancelLock(m_cancelMutex); if (m_cancelling) { try { ghc::filesystem::remove(tempFile); } catch(...) {} - return 1; + return false; } // no need to scope the lock guard more as this @@ -65,7 +65,7 @@ void InstallTicket::install(std::string const& id) { "Downloading binary", static_cast<uint8_t>(now / total * 100.0) ); - return 0; + return true; } ); if (!res) { diff --git a/loader/src/index/fetch.hpp b/loader/src/index/fetch.hpp deleted file mode 100644 index b2f590cd..00000000 --- a/loader/src/index/fetch.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include <Geode/Geode.hpp> - -USE_GEODE_NAMESPACE(); - -Result<std::string> fetch(std::string const& url); -Result<> fetchFile( - std::string const& url, - ghc::filesystem::path const& into, - std::function<int(double, double)> prog = nullptr -); - -template<class Json = nlohmann::json> -Result<Json> fetchJSON(std::string const& url) { - auto res = fetch(url); - if (!res) return Err(res.error()); - try { - return Ok(Json::parse(res.value())); - } catch(std::exception& e) { - return Err(e.what()); - } -} - - diff --git a/loader/src/internal/InternalLoader.cpp b/loader/src/internal/InternalLoader.cpp index c396ac5d..dc541631 100644 --- a/loader/src/internal/InternalLoader.cpp +++ b/loader/src/internal/InternalLoader.cpp @@ -7,6 +7,7 @@ #include <Geode/loader/Log.hpp> #include <Geode/loader/Loader.hpp> #include <Geode/Geode.hpp> +#include <Geode/utils/fetch.hpp> #include <thread> InternalLoader::InternalLoader() : Loader() {} diff --git a/loader/src/internal/InternalLoader.hpp b/loader/src/internal/InternalLoader.hpp index 099707a0..0492143c 100644 --- a/loader/src/internal/InternalLoader.hpp +++ b/loader/src/internal/InternalLoader.hpp @@ -8,6 +8,8 @@ #include <Geode/loader/Log.hpp> #include <Geode/utils/Result.hpp> #include <unordered_set> +#include <Geode/utils/json.hpp> +#include <optional> USE_GEODE_NAMESPACE(); @@ -52,6 +54,6 @@ public: void openPlatformConsole(); void closePlatformConsole(); static void platformMessageBox(const char* title, std::string const& info); - + friend int geodeEntry(void* platformData); }; diff --git a/loader/src/load/Loader.cpp b/loader/src/load/Loader.cpp index b830eb68..8471fade 100644 --- a/loader/src/load/Loader.cpp +++ b/loader/src/load/Loader.cpp @@ -19,11 +19,11 @@ USE_GEODE_NAMESPACE(); bool Loader::s_unloading = false; std::mutex g_unloadMutex; -VersionInfo Loader::getVersion() const { +VersionInfo Loader::getVersion() { return LOADER_VERSION; } -std::string Loader::getVersionType() const { +std::string Loader::getVersionType() { return LOADER_VERSION_TYPE; } @@ -51,14 +51,23 @@ void Loader::createDirectories() { } void Loader::updateResourcePaths() { - // add own resources directory + // add own geode/resources directory CCFileUtils::sharedFileUtils()->addSearchPath( (this->getGeodeDirectory() / GEODE_RESOURCE_DIRECTORY).string().c_str() ); - // add mods directory - CCFileUtils::sharedFileUtils()->addSearchPath( - (this->getGeodeDirectory() / GEODE_TEMP_DIRECTORY).string().c_str() - ); + + // add geode/temp for accessing root resources in mods + auto tempDir = this->getGeodeDirectory() / GEODE_TEMP_DIRECTORY; + CCFileUtils::sharedFileUtils()->addSearchPath(tempDir.string().c_str()); + + // add geode/temp/mod.id/resources for accessing additional resources in mods + for (auto& [_, mod] : m_mods) { + if (mod->m_addResourcesToSearchPath) { + CCFileUtils::sharedFileUtils()->addSearchPath( + (tempDir / mod->getID() / "resources").string().c_str() + ); + } + } } void Loader::updateModResources(Mod* mod) { @@ -447,10 +456,18 @@ size_t Loader::getFieldIndexForClass(size_t hash) { return nextIndex[hash]++; } +VersionInfo Loader::minModVersion() { + return { 0, 1, 0 }; +} + +VersionInfo Loader::maxModVersion() { + return Loader::getVersion(); +} + bool Loader::supportedModVersion(VersionInfo const& version) { return - version >= s_supportedVersionMin && - version <= s_supportedVersionMax; + version >= Loader::minModVersion() && + version <= Loader::maxModVersion(); } void Loader::openPlatformConsole() { diff --git a/loader/src/load/ModInfo.cpp b/loader/src/load/ModInfo.cpp index af3b322e..b9b600f3 100644 --- a/loader/src/load/ModInfo.cpp +++ b/loader/src/load/ModInfo.cpp @@ -148,28 +148,28 @@ Result<ModInfo> ModInfo::create(ModJson const& json) { "specified, or it is invalidally formatted (required: \"[v]X.X.X\")!" ); } - if (schema < Loader::s_supportedVersionMin) { + if (schema < Loader::minModVersion()) { return Err( "[mod.json] is built for an older version (" + schema.toString() + ") of Geode (current: " + - Loader::s_supportedVersionMin.toString() + + Loader::minModVersion().toString() + "). Please update the mod to the latest version, " "and if the problem persists, contact the developer " "to update it." ); } - if (schema > Loader::s_supportedVersionMax) { + if (schema > Loader::maxModVersion()) { return Err( "[mod.json] is built for a newer version (" + schema.toString() + ") of Geode (current: " + - Loader::s_supportedVersionMax.toString() + + Loader::maxModVersion().toString() + "). You need to update Geode in order to use " "this mod." ); } // Handle mod.json data based on target - if (schema <= VersionInfo(0, 2, 1)) { + if (schema >= VersionInfo(0, 1, 0)) { return ModInfo::createFromSchemaV010(json); } diff --git a/loader/src/main.cpp b/loader/src/main.cpp index 62b9fb6d..6bdebdc4 100644 --- a/loader/src/main.cpp +++ b/loader/src/main.cpp @@ -121,7 +121,7 @@ int geodeEntry(void* platformData) { if (InternalMod::get()->getSettingValue<bool>("show-platform-console")) { Loader::get()->openPlatformConsole(); } - + InternalMod::get()->log() << Severity::Debug << "Entry done."; diff --git a/loader/src/index/fetch.cpp b/loader/src/utils/fetch.cpp similarity index 85% rename from loader/src/index/fetch.cpp rename to loader/src/utils/fetch.cpp index 3a88d486..299ec3ad 100644 --- a/loader/src/index/fetch.cpp +++ b/loader/src/utils/fetch.cpp @@ -1,5 +1,8 @@ -#include "fetch.hpp" +#include <Geode/utils/fetch.hpp> #include <curl/curl.h> +#include <Geode/utils/casts.hpp> + +USE_GEODE_NAMESPACE(); namespace geode::utils::fetch { static size_t writeData(char* data, size_t size, size_t nmemb, void* str) { @@ -13,14 +16,14 @@ namespace geode::utils::fetch { } static int progress(void* ptr, double total, double now, double, double) { - return (*as<std::function<int(double, double)>*>(ptr))(now, total); + return (*as<web::FileProgressCallback*>(ptr))(now, total) != true; } } -Result<> fetchFile( +Result<> web::fetchFile( std::string const& url, ghc::filesystem::path const& into, - std::function<int(double, double)> prog + FileProgressCallback prog ) { auto curl = curl_easy_init(); @@ -46,7 +49,7 @@ Result<> fetchFile( auto res = curl_easy_perform(curl); if (res != CURLE_OK) { curl_easy_cleanup(curl); - return Err("Fetch failed"); + return Err("Fetch failed: " + std::string(curl_easy_strerror(res))); } char* ct; @@ -59,7 +62,7 @@ Result<> fetchFile( return Err("Error getting info: " + std::string(curl_easy_strerror(res))); } -Result<std::string> fetch(std::string const& url) { +Result<std::string> web::fetch(std::string const& url) { auto curl = curl_easy_init(); if (!curl) return Err("Curl not initialized!"); diff --git a/loader/src/utils/file.cpp b/loader/src/utils/file.cpp index 5307d6f6..e6175b38 100644 --- a/loader/src/utils/file.cpp +++ b/loader/src/utils/file.cpp @@ -1,5 +1,7 @@ #include <Geode/utils/file.hpp> +#include <Geode/utils/string.hpp> #include <fstream> +#include <Geode/Bindings.hpp> USE_GEODE_NAMESPACE(); @@ -188,3 +190,69 @@ Result<std::vector<std::string>> utils::file::listFilesRecursively(std::string c } return Ok<>(res); } + +Result<> utils::file::unzipTo( + ghc::filesystem::path const& from, + ghc::filesystem::path const& to +) { + // unzip downloaded + auto unzip = ZipFile(from.string()); + if (!unzip.isLoaded()) { + return Err("Unable to unzip index.zip"); + } + + if ( + !ghc::filesystem::exists(to) && + !ghc::filesystem::create_directories(to) + ) { + return Err( + "Unable to create directories \"" + + to.string() + "\"" + ); + } + + for (auto file : unzip.getAllFiles()) { + // this is a very bad check for seeing + // if file is a directory. it seems to + // work on windows at least. idk why + // getAllFiles returns the directories + // aswell now + if ( + utils::string::endsWith(file, "\\") || + utils::string::endsWith(file, "/") + ) continue; + + auto zipPath = file; + + // dont include the github repo folder + file = file.substr(file.find_first_of("/") + 1); + + auto path = ghc::filesystem::path(file); + if (path.has_parent_path()) { + auto dir = to / path.parent_path(); + if ( + !ghc::filesystem::exists(dir) && + !ghc::filesystem::create_directories(dir) + ) { + return Err( + "Unable to create directories \"" + + dir.string() + "\"" + ); + } + } + unsigned long size; + auto data = unzip.getFileData(zipPath, &size); + if (!data || !size) { + return Err("Unable to read \"" + std::string(zipPath) + "\""); + } + auto wrt = utils::file::writeBinary( + to / file, + byte_array(data, data + size) + ); + if (!wrt) { + return Err("Unable to write \"" + (to / file).string() + "\": " + wrt.error()); + } + } + + return Ok(); +}