diff --git a/loader/include/Geode/loader/Mod.hpp b/loader/include/Geode/loader/Mod.hpp index bede828d..a51af6b9 100644 --- a/loader/include/Geode/loader/Mod.hpp +++ b/loader/include/Geode/loader/Mod.hpp @@ -406,6 +406,8 @@ namespace geode { bool isLoggingEnabled() const; void setLoggingEnabled(bool enabled); + bool shouldLoad() const; + friend class ModImpl; }; } diff --git a/loader/src/hooks/LoadingLayer.cpp b/loader/src/hooks/LoadingLayer.cpp index b3a24bd0..93e82f07 100644 --- a/loader/src/hooks/LoadingLayer.cpp +++ b/loader/src/hooks/LoadingLayer.cpp @@ -8,68 +8,77 @@ using namespace geode::prelude; struct CustomLoadingLayer : Modify { - CCLabelBMFont* m_loadedModsLabel; - bool m_updatingResources; - - CustomLoadingLayer() : m_loadedModsLabel(nullptr), m_updatingResources(false) {} + CCLabelBMFont* m_smallLabel = nullptr; + int m_geodeLoadStep = 0; void updateLoadedModsLabel() { auto allMods = Loader::get()->getAllMods(); auto count = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) { return item->isEnabled(); }); - auto str = fmt::format("Geode: Loaded {}/{} mods", count, allMods.size()); - m_fields->m_loadedModsLabel->setCString(str.c_str()); + auto totalCount = std::count_if(allMods.begin(), allMods.end(), [&](auto& item) { + return item->shouldLoad(); + }); + auto str = fmt::format("Geode: Loaded {}/{} mods", count, totalCount); + this->setSmallText(str); } + void setSmallText(std::string const& text) { + m_fields->m_smallLabel->setString(text.c_str()); + } + + // hook bool init(bool fromReload) { CCFileUtils::get()->updatePaths(); if (!LoadingLayer::init(fromReload)) return false; - if (fromReload) return true; - auto winSize = CCDirector::sharedDirector()->getWinSize(); - m_fields->m_loadedModsLabel = CCLabelBMFont::create("Geode: Loaded 0/0 mods", "goldFont.fnt"); - m_fields->m_loadedModsLabel->setPosition(winSize.width / 2, 30.f); - m_fields->m_loadedModsLabel->setScale(.45f); - m_fields->m_loadedModsLabel->setID("geode-loaded-info"); - this->addChild(m_fields->m_loadedModsLabel); - this->updateLoadedModsLabel(); - - // fields have unpredictable destructors - this->addChild(EventListenerNode::create( - this, &CustomLoadingLayer::updateResourcesProgress - )); - - // verify loader resources - if (!LoaderImpl::get()->verifyLoaderResources()) { - m_fields->m_updatingResources = true; - this->setUpdateText("Downloading Resources"); - } - else { - LoaderImpl::get()->updateSpecialFiles(); - } + m_fields->m_smallLabel = CCLabelBMFont::create("", "goldFont.fnt"); + m_fields->m_smallLabel->setPosition(winSize.width / 2, 30.f); + m_fields->m_smallLabel->setScale(.45f); + m_fields->m_smallLabel->setID("geode-small-label"); + this->addChild(m_fields->m_smallLabel); return true; } - void setUpdateText(std::string const& text) { - m_textArea->setString(text.c_str()); + void setupLoadingMods() { + if (Loader::get()->getLoadingState() != Loader::LoadingState::Done) { + this->updateLoadedModsLabel(); + this->waitLoadAssets(); + } + else { + this->continueLoadAssets(); + } + } + + void setupLoaderResources() { + // verify loader resources + if (!LoaderImpl::get()->verifyLoaderResources()) { + this->setSmallText("Downloading Loader Resources"); + this->addChild(EventListenerNode::create( + this, &CustomLoadingLayer::updateResourcesProgress + )); + } + else { + this->setSmallText("Loading Loader Resources"); + LoaderImpl::get()->updateSpecialFiles(); + this->continueLoadAssets(); + } } void updateResourcesProgress(ResourceDownloadEvent* event) { std::visit(makeVisitor { [&](UpdateProgress const& progress) { - this->setUpdateText(fmt::format( - "Downloading Resources: {}%", progress.first + this->setSmallText(fmt::format( + "Downloading Loader Resources: {}%", progress.first )); }, [&](UpdateFinished) { - this->setUpdateText("Resources Downloaded"); - m_fields->m_updatingResources = false; - this->loadAssets(); + this->setSmallText("Downloaded Loader Resources"); + this->continueLoadAssets(); }, [&](UpdateFailed const& error) { LoaderImpl::get()->platformMessageBox( @@ -81,24 +90,70 @@ struct CustomLoadingLayer : Modify { "The game will be loaded as normal, but please be aware " "that it is very likely to crash. " ); - this->setUpdateText("Resource Download Failed"); - m_fields->m_updatingResources = false; - this->loadAssets(); + this->setSmallText("Failed Loader Resources"); + this->continueLoadAssets(); } }, event->status); } - void loadAssets() { - if (Loader::get()->getLoadingState() != Loader::LoadingState::Done) { - this->updateLoadedModsLabel(); - Loader::get()->queueInMainThread([this]() { - this->loadAssets(); - }); - return; + void setupModResources() { + log::debug("Loading mod resources"); + this->setSmallText("Loading mod resources"); + Loader::get()->updateResources(true); + this->continueLoadAssets(); + } + + int getCurrentStep() { + return m_fields->m_geodeLoadStep + m_loadStep + 1; + } + + int getTotalStep() { + return 18; + } + + void updateLoadingBar() { + auto length = m_sliderGrooveXPos * this->getCurrentStep() / this->getTotalStep(); + m_sliderBar->setTextureRect({0, 0, length, m_sliderGrooveHeight}); + } + + void waitLoadAssets() { + Loader::get()->queueInMainThread([this]() { + this->loadAssets(); + }); + } + + void continueLoadAssets() { + ++m_fields->m_geodeLoadStep; + Loader::get()->queueInMainThread([this]() { + this->loadAssets(); + }); + } + + bool skipOnRefresh() { + if (m_fromRefresh) { + this->continueLoadAssets(); } - if (m_fields->m_updatingResources) { - return; + return !m_fromRefresh; + } + + // hook + void loadAssets() { + switch (m_fields->m_geodeLoadStep) { + case 0: + if (this->skipOnRefresh()) this->setupLoadingMods(); + break; + case 1: + if (this->skipOnRefresh()) this->setupLoaderResources(); + break; + case 2: + this->setupModResources(); + break; + case 3: + default: + this->setSmallText("Loading game resources"); + LoadingLayer::loadAssets(); + break; } - LoadingLayer::loadAssets(); + this->updateLoadingBar(); } }; diff --git a/loader/src/hooks/updateResources.cpp b/loader/src/hooks/updateResources.cpp deleted file mode 100644 index 85817635..00000000 --- a/loader/src/hooks/updateResources.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#include - -using namespace geode::prelude; - -struct ResourcesUpdate : Modify { - void loadAssets() { - LoadingLayer::loadAssets(); - // this is in case the user refreshes texture quality at runtime - if (m_loadStep == 10) { - Loader::get()->updateResources(true); - } - } -}; diff --git a/loader/src/loader/LoaderImpl.cpp b/loader/src/loader/LoaderImpl.cpp index 197676f5..8b955b53 100644 --- a/loader/src/loader/LoaderImpl.cpp +++ b/loader/src/loader/LoaderImpl.cpp @@ -408,7 +408,7 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) { return; } - if (Mod::get()->getSavedValue("should-load-" + node->getID(), true)) { + if (node->shouldLoad()) { log::debug("Load"); auto res = node->m_impl->loadBinary(); if (!res) { @@ -432,6 +432,10 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) { void Loader::Impl::findProblems() { for (auto const& [id, mod] : m_mods) { + if (!mod->shouldLoad()) { + log::debug("{} is not enabled", id); + continue; + } log::debug(id); log::pushNest(); @@ -492,7 +496,7 @@ void Loader::Impl::findProblems() { Mod* myEpicMod = mod; // clang fix // if the mod is not loaded but there are no problems related to it if (!mod->isEnabled() && - Mod::get()->getSavedValue("should-load-" + mod->getID(), true) && + mod->shouldLoad() && !std::any_of(m_problems.begin(), m_problems.end(), [myEpicMod](auto& item) { return std::holds_alternative(item.cause) && std::get(item.cause).getID() == myEpicMod->getID() || diff --git a/loader/src/loader/Mod.cpp b/loader/src/loader/Mod.cpp index 77b551a4..0408ef10 100644 --- a/loader/src/loader/Mod.cpp +++ b/loader/src/loader/Mod.cpp @@ -245,3 +245,7 @@ void Mod::setLoggingEnabled(bool enabled) { bool Mod::hasSavedValue(std::string const& key) { return this->getSaveContainer().contains(key); } + +bool Mod::shouldLoad() const { + return m_impl->shouldLoad(); +} \ No newline at end of file diff --git a/loader/src/loader/ModImpl.cpp b/loader/src/loader/ModImpl.cpp index 510693d1..43a94026 100644 --- a/loader/src/loader/ModImpl.cpp +++ b/loader/src/loader/ModImpl.cpp @@ -43,7 +43,9 @@ Result<> Mod::Impl::setup() { log::warn("Unable to load data for \"{}\": {}", m_metadata.getID(), loadRes.unwrapErr()); } if (!m_resourcesLoaded) { - LoaderImpl::get()->updateModResources(m_self); + auto searchPathRoot = dirs::getModRuntimeDir() / m_metadata.getID() / "resources"; + CCFileUtils::get()->addSearchPath(searchPathRoot.string().c_str()); + m_resourcesLoaded = true; } @@ -633,6 +635,10 @@ void Mod::Impl::setLoggingEnabled(bool enabled) { m_loggingEnabled = enabled; } +bool Mod::Impl::shouldLoad() const { + return Mod::get()->getSavedValue("should-load-" + m_metadata.getID(), true); +} + static Result getModImplInfo() { std::string err; json::Value json; diff --git a/loader/src/loader/ModImpl.hpp b/loader/src/loader/ModImpl.hpp index c7a82dfe..ff5084d6 100644 --- a/loader/src/loader/ModImpl.hpp +++ b/loader/src/loader/ModImpl.hpp @@ -137,6 +137,8 @@ namespace geode { bool isLoggingEnabled() const; void setLoggingEnabled(bool enabled); + + bool shouldLoad() const; }; class ModImpl : public Mod::Impl { diff --git a/loader/src/ui/internal/list/ModListCell.cpp b/loader/src/ui/internal/list/ModListCell.cpp index 5b883959..b4f1923b 100644 --- a/loader/src/ui/internal/list/ModListCell.cpp +++ b/loader/src/ui/internal/list/ModListCell.cpp @@ -250,9 +250,10 @@ void ModCell::onRestart(CCObject*) { void ModCell::updateState() { bool unresolved = m_mod->hasUnresolvedDependencies(); + bool shouldLoad = m_mod->shouldLoad(); if (m_enableToggle) { m_enableToggle->toggle(m_mod->isEnabled()); - m_enableToggle->setEnabled(!unresolved); + m_enableToggle->setEnabled(!unresolved || shouldLoad); m_enableToggle->m_offButton->setOpacity(unresolved ? 100 : 255); m_enableToggle->m_offButton->setColor(unresolved ? cc3x(155) : cc3x(255)); m_enableToggle->m_onButton->setOpacity(unresolved ? 100 : 255);