diff --git a/loader/include/Geode/loader/Loader.hpp b/loader/include/Geode/loader/Loader.hpp index fa2a6743..44de7429 100644 --- a/loader/include/Geode/loader/Loader.hpp +++ b/loader/include/Geode/loader/Loader.hpp @@ -41,6 +41,7 @@ namespace geode { NeedsNewerGeodeVersion, DisabledDependency, OutdatedDependency, + OutdatedIncompatibility, }; Type type; std::variant cause; diff --git a/loader/include/Geode/utils/VersionInfo.hpp b/loader/include/Geode/utils/VersionInfo.hpp index 9c6827c2..ee3d53a0 100644 --- a/loader/include/Geode/utils/VersionInfo.hpp +++ b/loader/include/Geode/utils/VersionInfo.hpp @@ -16,6 +16,14 @@ namespace geode { Any }; + enum class VersionCompareResult { + TooOld, + Match, + TooNew, + MajorMismatch, + GenericMismatch + }; + /** * A version label, like v1.0.0-alpha or v2.3.4-prerelease. Limited to these * options; arbitary identifiers are not supported. Additional numbering @@ -198,30 +206,35 @@ namespace geode { static Result parse(std::string const& string); constexpr bool compare(VersionInfo const& version) const { + return compareWithReason(version) == VersionCompareResult::Match; + } + + constexpr VersionCompareResult compareWithReason(VersionInfo const& version) const { if (m_compare == VersionCompare::Any) { - return true; + return VersionCompareResult::Match; } // opposing major versions never match if (m_version.getMajor() != version.getMajor()) { - return false; + return VersionCompareResult::MajorMismatch; } // the comparison works invertedly as a version like "v1.2.0" // should return true for "<=v1.3.0" switch (m_compare) { case VersionCompare::LessEq: - return version <= m_version; + return version <= m_version ? VersionCompareResult::Match : VersionCompareResult::TooNew; case VersionCompare::MoreEq: - return version >= m_version; + return version >= m_version ? VersionCompareResult::Match : VersionCompareResult::TooOld; case VersionCompare::Less: - return version < m_version; + return version < m_version ? VersionCompareResult::Match : VersionCompareResult::TooNew; case VersionCompare::More: - return version > m_version; + return version > m_version ? VersionCompareResult::Match : VersionCompareResult::TooOld; case VersionCompare::Exact: - return version == m_version; + return version == m_version ? VersionCompareResult::Match : + (version > m_version) ? VersionCompareResult::TooOld : VersionCompareResult::TooNew; default: - return false; + return VersionCompareResult::GenericMismatch; } } diff --git a/loader/src/loader/LoaderImpl.cpp b/loader/src/loader/LoaderImpl.cpp index 1601595e..85a0c308 100644 --- a/loader/src/loader/LoaderImpl.cpp +++ b/loader/src/loader/LoaderImpl.cpp @@ -558,8 +558,7 @@ void Loader::Impl::findProblems() { }); log::error("{} requires {} {}", id, dep.id, dep.version); break; - } else if(!dep.version.compare(installedDependency->getVersion())) { - // TODO: this also fires on major version mismatch + } else if(dep.version.compareWithReason(installedDependency->getVersion()) == VersionCompareResult::TooOld) { this->addProblem({ LoadProblem::Type::OutdatedDependency, mod, @@ -568,12 +567,11 @@ void Loader::Impl::findProblems() { log::error("{} requires {} {}", id, dep.id, dep.version); break; } else { - // this should never happen i think? - // (major mismatch should eventually fall through here though once that's fixed) + // fires on major mismatch or too new version of dependency this->addProblem({ LoadProblem::Type::MissingDependency, mod, - fmt::format("{}", dep.id) + fmt::format("{} {}", dep.id, dep.version) }); log::error("{} requires {} {}", id, dep.id, dep.version); break; @@ -597,9 +595,9 @@ void Loader::Impl::findProblems() { case ModMetadata::Incompatibility::Importance::Breaking: { this->addProblem({ - LoadProblem::Type::PresentIncompatibility, + dep.version.toString()[0] == '<' ? LoadProblem::Type::OutdatedIncompatibility : LoadProblem::Type::PresentIncompatibility, mod, - fmt::format("{} {}", dep.id, dep.version.toString()) + fmt::format("{}", dep.id) }); log::error("{} breaks {} {}", id, dep.id, dep.version); } break; @@ -608,7 +606,7 @@ void Loader::Impl::findProblems() { this->addProblem({ LoadProblem::Type::PresentIncompatibility, mod, - fmt::format("{} {}", dep.id, dep.version.toString()) + fmt::format("{}", dep.id) }); log::error("{} supersedes {} {}", id, dep.id, dep.version); } break; diff --git a/loader/src/ui/internal/list/ProblemsListCell.cpp b/loader/src/ui/internal/list/ProblemsListCell.cpp index b494d99a..e5d3140a 100644 --- a/loader/src/ui/internal/list/ProblemsListCell.cpp +++ b/loader/src/ui/internal/list/ProblemsListCell.cpp @@ -96,7 +96,11 @@ bool ProblemsListCell::init(LoadProblem problem, ProblemsListPopup* list, CCSize break; case LoadProblem::Type::PresentIncompatibility: icon = "info-alert.png"_spr; - message = fmt::format("{} is incompatible with {}", cause, problem.message); + message = fmt::format("Uninstall {} to use {}", problem.message, cause); + break; + case LoadProblem::Type::OutdatedIncompatibility: + icon = "info-alert.png"_spr; + message = fmt::format("Update {} to use {}", problem.message, cause); break; case LoadProblem::Type::UnzipFailed: icon = "info-alert.png"_spr;