diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fc7cb95..b70cdac3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,36 @@ # Geode Changelog +## v0.4.5 + + - Rework bindings and codegen to improve compile times, now individual bindings can be included with `` + - Modify has also been separated, you can now include individual modifiers with `` + - Various other fixes to improve compile times + - Fix mod resources not being loaded when installed from Index + - Fix crashes related to downloading mods + - Fix `Loader::queueInGDThread` sometimes leaving out functions + - Fix crashes related to logging + - Add new overloads to `file` utils and deprecate ones that don't use `ghc::filesystem::path` + - Index mods now show their `about.md` files + - More addresses + - Various other fixes & improvements + - Index reworked + - Fix issues with `VERSION` file + - Add `GEODE_DEBUG` macro for enabling `log::debug` to actually print stuff + - Show crashlog on crash when `GEODE_DEBUG` is enabled + - Add `JsonChecker::at` and `JsonChecker::array` for dealing with arrays + - Add `geode::utils::web::fetchBytes` for fetching a byte array synchronously + - Add `geode::utils::web::AsyncWebRequest` for creating thread-safe asynchronous web requests + - Add `Loader::updateModResourcePaths` for adding a mods' resources to search paths. Not recommended to be called manually + - Add an overload to `geode::createQuickPopup` for specifying popup width + - `ModInfo::createFromFile` now checks for `about.md` and other special files in the same directory + - Remove automatic mod updating for now, however automatic update checking for mods is still there + +## v0.4.4 + + - New `listenForSettingChanges` API for more ergonomically listening for setting changes + - Fixed bug where GD was unopenable through Steam + - Various other internal fixes + ## v0.4.3 - Simplified the minimum and maximum loader versions, loader will now load any mod whose target version major and minor match. In practice, this means that for example mods whose target version is v0.4.8 can be loaded by loader of version v0.4.6. diff --git a/loader/include/Geode/utils/fetch.hpp b/loader/include/Geode/utils/fetch.hpp index a1ce61e1..fb24f056 100644 --- a/loader/include/Geode/utils/fetch.hpp +++ b/loader/include/Geode/utils/fetch.hpp @@ -66,6 +66,10 @@ namespace geode::utils::web { using AsyncThen = std::function; using AsyncCancelled = std::function; + /** + * A handle to an in-progress sent asynchronous web request. Use this to + * cancel the request / query information about it + */ class SentAsyncWebRequest { private: std::string m_id; @@ -95,9 +99,20 @@ namespace geode::utils::web { void doCancel(); public: + /** + * Do not call this manually. + */ SentAsyncWebRequest(AsyncWebRequest const&, std::string const& id); + /** + * Cancel the request. Cleans up any downloaded files, but if you run + * extra code in `then`, you will have to clean it up manually in + * `cancelled` + */ void cancel(); + /** + * Check if the request is finished + */ bool finished() const; }; @@ -106,6 +121,11 @@ namespace geode::utils::web { template using DataConverter = Result(*)(byte_array const&); + /** + * An asynchronous, thread-safe web request. Downloads data from the + * internet without slowing the main thread. All callbacks are run in the + * GD thread, so interacting with the Cocos2d UI is perfectly safe + */ class GEODE_DLL AsyncWebRequest { private: std::optional m_joinID; @@ -127,14 +147,54 @@ namespace geode::utils::web { friend class AsyncWebResponse; public: + /** + * If you only want one instance of this web request to run (for example, + * you're downloading some global data for a manager), then use this + * to specify a Join ID. If another request with the same ID is + * already running, this request's callbacks will be appended to the + * existing one instead of creating a new request + * @param requestID The Join ID of the request. Can be anything, + * recommended to be something unique + * @returns Same AsyncWebRequest + */ AsyncWebRequest& join(std::string const& requestID); + /** + * URL to fetch from the internet asynchronously + * @param url URL of the data to download. Redirects will be + * automatically followed + * @returns Same AsyncWebRequest + */ AsyncWebResponse fetch(std::string const& url); + /** + * Specify a callback to run if the download fails. Runs in the GD + * thread, so interacting with UI is safe + * @param handler Callback to run if the download fails + * @returns Same AsyncWebRequest + */ AsyncWebRequest& expect(AsyncExpect handler); - AsyncWebRequest& progress(AsyncProgress progressFunc); - // Web requests may be cancelled after they are finished (for example, - // if downloading files in bulk and one fails). In that case, handle - // freeing up the results of `then` here - AsyncWebRequest& cancelled(AsyncCancelled cancelledFunc); + /** + * Specify a callback to run when the download progresses. Runs in the + * GD thread, so interacting with UI is safe + * @param handler Callback to run when the download progresses + * @returns Same AsyncWebRequest + */ + AsyncWebRequest& progress(AsyncProgress handler); + /** + * Specify a callback to run if the download is cancelled. Runs in the + * GD thread, so interacting with UI is safe. Web requests may be + * cancelled after they are finished (for example, if downloading files + * in bulk and one fails). In that case, handle freeing up the results + * of `then` in this handler + * @param handler Callback to run if the download is cancelled + * @returns Same AsyncWebRequest + */ + AsyncWebRequest& cancelled(AsyncCancelled handler); + /** + * Begin the web request. It's not always necessary to call this as the + * destructor calls it automatically, but if you need access to the + * handle of the sent request, use this + * @returns Handle to the sent web request + */ SentAsyncWebRequestHandle send(); ~AsyncWebRequest(); }; @@ -151,7 +211,21 @@ namespace geode::utils::web { friend class AsyncWebResponse; public: + /** + * Specify a callback to run after a download is finished. Runs in the + * GD thread, so interacting with UI is safe + * @param handle Callback to run + * @returns The original AsyncWebRequest, where you can specify more + * aspects about the request like failure and progress callbacks + */ AsyncWebRequest& then(std::function handle); + /** + * Specify a callback to run after a download is finished. Runs in the + * GD thread, so interacting with UI is safe + * @param handle Callback to run + * @returns The original AsyncWebRequest, where you can specify more + * aspects about the request like failure and progress callbacks + */ AsyncWebRequest& then(std::function handle); }; @@ -164,13 +238,56 @@ namespace geode::utils::web { friend class AsyncWebRequest; public: - // Make sure the stream lives for the entire duration of the request. + /** + * Download into a stream. Make sure the stream lives for the entire + * duration of the request. If you want to download a file, use the + * `ghc::filesystem::path` overload of `into` instead + * @param stream Stream to download into. Make sure it lives long + * enough, otherwise the web request will crash + * @returns AsyncWebResult, where you can specify the `then` action for + * after the download is finished. The result has a `std::monostate` + * template parameter, as it can be assumed you know what you passed + * into `into` + */ AsyncWebResult into(std::ostream& stream); + /** + * Download into a file + * @param path File to download into. If it already exists, it will + * be overwritten. + * @returns AsyncWebResult, where you can specify the `then` action for + * after the download is finished. The result has a `std::monostate` + * template parameter, as it can be assumed you know what you passed + * into `into` + */ AsyncWebResult into(ghc::filesystem::path const& path); + /** + * Download into memory as a string + * @returns AsyncWebResult, where you can specify the `then` action for + * after the download is finished + */ AsyncWebResult text(); + /** + * Download into memory as a byte array + * @returns AsyncWebResult, where you can specify the `then` action for + * after the download is finished + */ AsyncWebResult bytes(); + /** + * Download into memory as JSON + * @returns AsyncWebResult, where you can specify the `then` action for + * after the download is finished + */ AsyncWebResult json(); + /** + * Download into memory as a custom type. The data will first be + * downloaded into memory as a byte array, and then converted using + * the specified converter function + * @param converter Function that converts the data from a byte array + * to the desired type + * @returns AsyncWebResult, where you can specify the `then` action for + * after the download is finished + */ template AsyncWebResult as(DataConverter converter) { return AsyncWebResult(m_request, converter); diff --git a/loader/src/load/load.cpp b/loader/src/load/load.cpp index c7108d04..8c2587d1 100644 --- a/loader/src/load/load.cpp +++ b/loader/src/load/load.cpp @@ -49,12 +49,8 @@ Result Loader::loadModFromFile(std::string const& path) { m_mods.insert({ res.value().m_id, mod }); mod->updateDependencyStates(); - log::debug("loaded mod, adding resources"); - // add mod resources this->queueInGDThread([this, mod]() { - log::debug("steve :pleading_face:"); - this->updateModResourcePaths(mod); this->updateModResources(mod); });