diff --git a/loader/include/Geode/loader/Loader.hpp b/loader/include/Geode/loader/Loader.hpp index f9dd1815..030dc0ca 100644 --- a/loader/include/Geode/loader/Loader.hpp +++ b/loader/include/Geode/loader/Loader.hpp @@ -32,7 +32,8 @@ namespace geode { LoadFailed, EnableFailed, MissingDependency, - PresentIncompatibility + PresentIncompatibility, + UnzipFailed }; Type type; std::variant cause; diff --git a/loader/include/Geode/platform/android.hpp b/loader/include/Geode/platform/android.hpp index 149d6bb2..e19402bc 100644 --- a/loader/include/Geode/platform/android.hpp +++ b/loader/include/Geode/platform/android.hpp @@ -2,8 +2,6 @@ #include -#include "ItaniumCast.hpp" - namespace geode { struct PlatformInfo { void* m_so; @@ -13,3 +11,11 @@ namespace geode { namespace geode::base { /*GEODE_NOINLINE inline*/ uintptr_t get(); } + +namespace geode::cast { + template + After typeinfo_cast(Before ptr) { + // yall have symbols smh + return dynamic_cast(ptr); + } +} diff --git a/loader/src/hooks/LoadingLayer.cpp b/loader/src/hooks/LoadingLayer.cpp index 5bc171bb..c765def5 100644 --- a/loader/src/hooks/LoadingLayer.cpp +++ b/loader/src/hooks/LoadingLayer.cpp @@ -9,30 +9,38 @@ using namespace geode::prelude; struct CustomLoadingLayer : Modify { CCLabelBMFont* m_smallLabel = nullptr; + CCLabelBMFont* m_smallLabel2 = nullptr; int m_geodeLoadStep = 0; + int m_totalMods = 0; void updateLoadedModsLabel() { auto allMods = Loader::get()->getAllMods(); auto count = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) { return item->isEnabled(); }); - auto totalCount = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) { - return item->shouldLoad(); - }); - auto str = fmt::format("Geode: Loaded {}/{} mods", count, totalCount); + auto str = fmt::format("Geode: Loaded {}/{} mods", count, m_totalMods); this->setSmallText(str); + auto currentMod = LoaderImpl::get()->m_currentlyLoadingMod; + auto modName = currentMod ? currentMod->getName() : "Unknown"; + this->setSmallText2(modName); } void setSmallText(std::string const& text) { m_fields->m_smallLabel->setString(text.c_str()); } + void setSmallText2(std::string const& text) { + m_fields->m_smallLabel2->setString(text.c_str()); + } + // hook bool init(bool fromReload) { CCFileUtils::get()->updatePaths(); if (!LoadingLayer::init(fromReload)) return false; + m_totalMods = Loader::get()->getAllMods().size(); + auto winSize = CCDirector::sharedDirector()->getWinSize(); m_fields->m_smallLabel = CCLabelBMFont::create("", "goldFont.fnt"); @@ -41,6 +49,12 @@ struct CustomLoadingLayer : Modify { m_fields->m_smallLabel->setID("geode-small-label"); this->addChild(m_fields->m_smallLabel); + m_fields->m_smallLabel2 = CCLabelBMFont::create("", "goldFont.fnt"); + m_fields->m_smallLabel2->setPosition(winSize.width / 2, 15.f); + m_fields->m_smallLabel2->setScale(.45f); + m_fields->m_smallLabel2->setID("geode-small-label"); + this->addChild(m_fields->m_smallLabel2); + return true; } @@ -51,6 +65,7 @@ struct CustomLoadingLayer : Modify { } else { this->continueLoadAssets(); + this->setSmallText2(""); } } @@ -108,11 +123,11 @@ struct CustomLoadingLayer : Modify { } int getCurrentStep() { - return m_fields->m_geodeLoadStep + m_loadStep + 1; + return m_fields->m_geodeLoadStep + m_loadStep + 1 + LoaderImpl::get()->m_refreshedModCount; } int getTotalStep() { - return 18; + return 18 + m_totalMods; } void updateLoadingBar() { diff --git a/loader/src/loader/LoaderImpl.cpp b/loader/src/loader/LoaderImpl.cpp index 8c2e056d..529e327c 100644 --- a/loader/src/loader/LoaderImpl.cpp +++ b/loader/src/loader/LoaderImpl.cpp @@ -388,7 +388,7 @@ void Loader::Impl::buildModGraph() { void Loader::Impl::loadModGraph(Mod* node, bool early) { if (early && !node->needsEarlyLoad()) { - m_modsToLoad.push(node); + m_modsToLoad.push_back(node); return; } @@ -402,32 +402,82 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) { if (node->isEnabled()) { for (auto const& dep : node->m_impl->m_dependants) { - this->loadModGraph(dep, early); + m_modsToLoad.push_front(dep); } log::popNest(); return; } - if (node->shouldLoad()) { - log::debug("Load"); - auto res = node->m_impl->loadBinary(); + m_currentlyLoadingMod = node; + m_refreshingModCount += 1; + m_refreshedModCount += 1; + + auto unzipFunction = [this, node]() { + log::debug("Unzip"); + auto res = node->m_impl->unzipGeodeFile(node->getMetadata()); + return res; + }; + + auto loadFunction = [this, node, early]() { + if (node->shouldLoad()) { + log::debug("Load"); + auto res = node->m_impl->loadBinary(); + if (!res) { + m_problems.push_back({ + LoadProblem::Type::LoadFailed, + node, + res.unwrapErr() + }); + log::error("Failed to load binary: {}", res.unwrapErr()); + log::popNest(); + m_refreshingModCount -= 1; + return; + } + + for (auto const& dep : node->m_impl->m_dependants) { + m_modsToLoad.push_front(dep); + } + } + + m_refreshingModCount -= 1; + + log::popNest(); + }; + + if (early) { + auto res = unzipFunction(); if (!res) { m_problems.push_back({ - LoadProblem::Type::LoadFailed, + LoadProblem::Type::UnzipFailed, node, res.unwrapErr() }); - log::error("Failed to load binary: {}", res.unwrapErr()); + log::error("Failed to unzip: {}", res.unwrapErr()); log::popNest(); + m_refreshingModCount -= 1; return; } - - for (auto const& dep : node->m_impl->m_dependants) { - this->loadModGraph(dep, early); - } + loadFunction(); + } + else { + std::thread([=]() { + auto res = unzipFunction(); + queueInMainThread([=]() { + if (!res) { + m_problems.push_back({ + LoadProblem::Type::UnzipFailed, + node, + res.unwrapErr() + }); + log::error("Failed to unzip: {}", res.unwrapErr()); + log::popNest(); + m_refreshingModCount -= 1; + return; + } + loadFunction(); + }); + }).detach(); } - - log::popNest(); } void Loader::Impl::findProblems() { @@ -568,12 +618,19 @@ void Loader::Impl::refreshModGraph() { else m_loadingState = LoadingState::Mods; - queueInMainThread([]() { - Loader::get()->m_impl->continueRefreshModGraph(); + queueInMainThread([&]() { + this->continueRefreshModGraph(); }); } void Loader::Impl::continueRefreshModGraph() { + if (m_refreshingModCount != 0) { + queueInMainThread([&]() { + this->continueRefreshModGraph(); + }); + return; + } + log::info("Continuing mod graph refresh..."); log::pushNest(); @@ -585,7 +642,7 @@ void Loader::Impl::continueRefreshModGraph() { log::pushNest(); this->loadModGraph(m_modsToLoad.front(), false); log::popNest(); - m_modsToLoad.pop(); + m_modsToLoad.pop_front(); if (m_modsToLoad.empty()) m_loadingState = LoadingState::Problems; break; @@ -608,8 +665,8 @@ void Loader::Impl::continueRefreshModGraph() { log::info("Took {}s", static_cast(time) / 1000.f); if (m_loadingState != LoadingState::Done) { - queueInMainThread([]() { - Loader::get()->m_impl->continueRefreshModGraph(); + queueInMainThread([&]() { + this->continueRefreshModGraph(); }); } diff --git a/loader/src/loader/LoaderImpl.hpp b/loader/src/loader/LoaderImpl.hpp index ab6f4b1a..af790a5e 100644 --- a/loader/src/loader/LoaderImpl.hpp +++ b/loader/src/loader/LoaderImpl.hpp @@ -58,7 +58,7 @@ namespace geode { std::vector m_modSearchDirectories; std::vector m_problems; std::unordered_map m_mods; - std::queue m_modsToLoad; + std::deque m_modsToLoad; std::vector m_texturePaths; bool m_isSetup = false; @@ -83,6 +83,11 @@ namespace geode { std::mutex m_nextModAccessMutex; Mod* m_nextMod = nullptr; + Mod* m_currentlyLoadingMod = nullptr; + + int m_refreshingModCount = 0; + int m_refreshedModCount = 0; + void provideNextMod(Mod* mod); Mod* takeNextMod(); void releaseNextMod(); diff --git a/loader/src/loader/ModImpl.cpp b/loader/src/loader/ModImpl.cpp index 393916cf..d97c5b0f 100644 --- a/loader/src/loader/ModImpl.cpp +++ b/loader/src/loader/ModImpl.cpp @@ -568,21 +568,25 @@ Result<> Mod::Impl::createTempDir() { return Err("Unable to create mod runtime directory"); } - // Unzip .geode file into temp dir - GEODE_UNWRAP_INTO(auto unzip, file::Unzip::create(m_metadata.getPath())); - if (!unzip.hasEntry(m_metadata.getBinaryName())) { - return Err( - fmt::format("Unable to find platform binary under the name \"{}\"", m_metadata.getBinaryName()) - ); - } - GEODE_UNWRAP(unzip.extractAllTo(tempPath)); - // Mark temp dir creation as succesful m_tempDirName = tempPath; return Ok(); } +Result<> Mod::Impl::unzipGeodeFile(ModMetadata metadata) { + // Unzip .geode file into temp dir + GEODE_UNWRAP_INTO(auto unzip, file::Unzip::create(metadata.getPath())); + if (!unzip.hasEntry(metadata.getBinaryName())) { + return Err( + fmt::format("Unable to find platform binary under the name \"{}\"", metadata.getBinaryName()) + ); + } + GEODE_UNWRAP(unzip.extractAllTo(dirs::getModRuntimeDir() / metadata.getID())); + + return Ok(); +} + ghc::filesystem::path Mod::Impl::getConfigDir(bool create) const { auto dir = dirs::getModConfigDir() / m_metadata.getID(); if (create) { diff --git a/loader/src/loader/ModImpl.hpp b/loader/src/loader/ModImpl.hpp index 55e5c88d..598d3388 100644 --- a/loader/src/loader/ModImpl.hpp +++ b/loader/src/loader/ModImpl.hpp @@ -75,6 +75,9 @@ namespace geode { Result<> unloadPlatformBinary(); Result<> createTempDir(); + // called on a separate thread + Result<> unzipGeodeFile(ModMetadata metadata); + void setupSettings(); std::string getID() const; diff --git a/loader/src/ui/internal/list/ProblemsListCell.cpp b/loader/src/ui/internal/list/ProblemsListCell.cpp index faa2086b..fbca7944 100644 --- a/loader/src/ui/internal/list/ProblemsListCell.cpp +++ b/loader/src/ui/internal/list/ProblemsListCell.cpp @@ -87,6 +87,11 @@ bool ProblemsListCell::init(LoadProblem problem, ProblemsListPopup* list, CCSize icon = "info-alert.png"_spr; message = fmt::format("{} is incompatible with {}", cause, problem.message); break; + case LoadProblem::Type::UnzipFailed: + icon = "info-alert.png"_spr; + message = fmt::format("{} has failed unzipping", cause); + m_longMessage = problem.message; + break; } m_problem = std::move(problem);