Merge branch 'main' of https://github.com/geode-sdk/geode into main

This commit is contained in:
HJfod 2024-02-16 01:29:45 +02:00
commit 3802af1e70
5 changed files with 109 additions and 26 deletions

View file

@ -28,6 +28,7 @@ namespace geode {
Suggestion, Suggestion,
Recommendation, Recommendation,
Conflict, Conflict,
OutdatedConflict,
InvalidFile, InvalidFile,
Duplicate, Duplicate,
SetupFailed, SetupFailed,
@ -38,6 +39,10 @@ namespace geode {
UnzipFailed, UnzipFailed,
UnsupportedVersion, UnsupportedVersion,
UnsupportedGeodeVersion, UnsupportedGeodeVersion,
NeedsNewerGeodeVersion,
DisabledDependency,
OutdatedDependency,
OutdatedIncompatibility,
}; };
Type type; Type type;
std::variant<ghc::filesystem::path, ModMetadata, Mod*> cause; std::variant<ghc::filesystem::path, ModMetadata, Mod*> cause;

View file

@ -16,6 +16,14 @@ namespace geode {
Any 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 * A version label, like v1.0.0-alpha or v2.3.4-prerelease. Limited to these
* options; arbitary identifiers are not supported. Additional numbering * options; arbitary identifiers are not supported. Additional numbering
@ -198,30 +206,35 @@ namespace geode {
static Result<ComparableVersionInfo> parse(std::string const& string); static Result<ComparableVersionInfo> parse(std::string const& string);
constexpr bool compare(VersionInfo const& version) const { constexpr bool compare(VersionInfo const& version) const {
return compareWithReason(version) == VersionCompareResult::Match;
}
constexpr VersionCompareResult compareWithReason(VersionInfo const& version) const {
if (m_compare == VersionCompare::Any) { if (m_compare == VersionCompare::Any) {
return true; return VersionCompareResult::Match;
} }
// opposing major versions never match // opposing major versions never match
if (m_version.getMajor() != version.getMajor()) { if (m_version.getMajor() != version.getMajor()) {
return false; return VersionCompareResult::MajorMismatch;
} }
// the comparison works invertedly as a version like "v1.2.0" // the comparison works invertedly as a version like "v1.2.0"
// should return true for "<=v1.3.0" // should return true for "<=v1.3.0"
switch (m_compare) { switch (m_compare) {
case VersionCompare::LessEq: case VersionCompare::LessEq:
return version <= m_version; return version <= m_version ? VersionCompareResult::Match : VersionCompareResult::TooNew;
case VersionCompare::MoreEq: case VersionCompare::MoreEq:
return version >= m_version; return version >= m_version ? VersionCompareResult::Match : VersionCompareResult::TooOld;
case VersionCompare::Less: case VersionCompare::Less:
return version < m_version; return version < m_version ? VersionCompareResult::Match : VersionCompareResult::TooNew;
case VersionCompare::More: case VersionCompare::More:
return version > m_version; return version > m_version ? VersionCompareResult::Match : VersionCompareResult::TooOld;
case VersionCompare::Exact: case VersionCompare::Exact:
return version == m_version; return version == m_version ? VersionCompareResult::Match :
(version > m_version) ? VersionCompareResult::TooOld : VersionCompareResult::TooNew;
default: default:
return false; return VersionCompareResult::GenericMismatch;
} }
} }

View file

@ -443,7 +443,7 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
node, node,
res.unwrapErr() res.unwrapErr()
}); });
log::error("Unsupported game version: {}", res.unwrapErr()); log::error("Geometry Dash version {} is required to run this mod", res.unwrapErr());
m_refreshingModCount -= 1; m_refreshingModCount -= 1;
log::popNest(); log::popNest();
return; return;
@ -451,10 +451,10 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
if (!this->isModVersionSupported(node->getMetadata().getGeodeVersion())) { if (!this->isModVersionSupported(node->getMetadata().getGeodeVersion())) {
this->addProblem({ this->addProblem({
LoadProblem::Type::UnsupportedGeodeVersion, node->getMetadata().getGeodeVersion() > this->getVersion() ? LoadProblem::Type::NeedsNewerGeodeVersion : LoadProblem::Type::UnsupportedGeodeVersion,
node, node,
fmt::format( fmt::format(
"Geode version {} is not supported (current: {})", "Geode version {}\nis required to run this mod\n(installed: {})",
node->getMetadata().getGeodeVersion().toString(), node->getMetadata().getGeodeVersion().toString(),
this->getVersion().toString() this->getVersion().toString()
) )
@ -539,13 +539,44 @@ void Loader::Impl::findProblems() {
log::warn("{} recommends {} {}", id, dep.id, dep.version); log::warn("{} recommends {} {}", id, dep.id, dep.version);
break; break;
case ModMetadata::Dependency::Importance::Required: case ModMetadata::Dependency::Importance::Required:
this->addProblem({ if(m_mods.find(dep.id) == m_mods.end()) {
LoadProblem::Type::MissingDependency, this->addProblem({
mod, LoadProblem::Type::MissingDependency,
fmt::format("{} {}", dep.id, dep.version.toString()) mod,
}); fmt::format("{}", dep.id)
log::error("{} requires {} {}", id, dep.id, dep.version); });
break; log::error("{} requires {} {}", id, dep.id, dep.version);
break;
} else {
auto installedDependency = m_mods.at(dep.id);
if(!installedDependency->isEnabled()) {
this->addProblem({
LoadProblem::Type::DisabledDependency,
mod,
fmt::format("{}", dep.id)
});
log::error("{} requires {} {}", id, dep.id, dep.version);
break;
} else if(dep.version.compareWithReason(installedDependency->getVersion()) == VersionCompareResult::TooOld) {
this->addProblem({
LoadProblem::Type::OutdatedDependency,
mod,
fmt::format("{}", dep.id)
});
log::error("{} requires {} {}", id, dep.id, dep.version);
break;
} else {
// fires on major mismatch or too new version of dependency
this->addProblem({
LoadProblem::Type::MissingDependency,
mod,
fmt::format("{} {}", dep.id, dep.version)
});
log::error("{} requires {} {}", id, dep.id, dep.version);
break;
}
}
} }
} }
@ -555,18 +586,18 @@ void Loader::Impl::findProblems() {
switch(dep.importance) { switch(dep.importance) {
case ModMetadata::Incompatibility::Importance::Conflicting: { case ModMetadata::Incompatibility::Importance::Conflicting: {
this->addProblem({ this->addProblem({
LoadProblem::Type::Conflict, dep.version.toString()[0] == '<' ? LoadProblem::Type::OutdatedConflict : LoadProblem::Type::Conflict,
mod, mod,
fmt::format("{} {}", dep.id, dep.version.toString()) fmt::format("{}", dep.id)
}); });
log::warn("{} conflicts with {} {}", id, dep.id, dep.version); log::warn("{} conflicts with {} {}", id, dep.id, dep.version);
} break; } break;
case ModMetadata::Incompatibility::Importance::Breaking: { case ModMetadata::Incompatibility::Importance::Breaking: {
this->addProblem({ this->addProblem({
LoadProblem::Type::PresentIncompatibility, dep.version.toString()[0] == '<' ? LoadProblem::Type::OutdatedIncompatibility : LoadProblem::Type::PresentIncompatibility,
mod, mod,
fmt::format("{} {}", dep.id, dep.version.toString()) fmt::format("{}", dep.id)
}); });
log::error("{} breaks {} {}", id, dep.id, dep.version); log::error("{} breaks {} {}", id, dep.id, dep.version);
} break; } break;
@ -575,7 +606,7 @@ void Loader::Impl::findProblems() {
this->addProblem({ this->addProblem({
LoadProblem::Type::PresentIncompatibility, LoadProblem::Type::PresentIncompatibility,
mod, mod,
fmt::format("{} {}", dep.id, dep.version.toString()) fmt::format("{}", dep.id)
}); });
log::error("{} supersedes {} {}", id, dep.id, dep.version); log::error("{} supersedes {} {}", id, dep.id, dep.version);
} break; } break;

View file

@ -54,8 +54,16 @@ bool ProblemsListCell::init(LoadProblem problem, ProblemsListPopup* list, CCSize
message = fmt::format("{} recommends {}", cause, problem.message); message = fmt::format("{} recommends {}", cause, problem.message);
break; break;
case LoadProblem::Type::Conflict: case LoadProblem::Type::Conflict:
// i copy pasted the message from incompatibility
// because as far as i can tell there's no behavorial
// difference, so it makes no sense to show the difference
// to the user
icon = "info-warning.png"_spr; icon = "info-warning.png"_spr;
message = fmt::format("{} conflicts with {}", cause, problem.message); message = fmt::format("Uninstall {} to use {}", problem.message, cause);
break;
case LoadProblem::Type::OutdatedConflict:
icon = "info-alert.png"_spr;
message = fmt::format("Update {} to use {}", problem.message, cause);
break; break;
case LoadProblem::Type::InvalidFile: case LoadProblem::Type::InvalidFile:
icon = "info-alert.png"_spr; icon = "info-alert.png"_spr;
@ -84,11 +92,23 @@ bool ProblemsListCell::init(LoadProblem problem, ProblemsListPopup* list, CCSize
break; break;
case LoadProblem::Type::MissingDependency: case LoadProblem::Type::MissingDependency:
icon = "info-alert.png"_spr; icon = "info-alert.png"_spr;
message = fmt::format("{} depends on {}", cause, problem.message); message = fmt::format("Install {} to use {}", problem.message, cause);
break;
case LoadProblem::Type::DisabledDependency:
icon = "info-alert.png"_spr;
message = fmt::format("Enable {} to use {}", problem.message, cause);
break;
case LoadProblem::Type::OutdatedDependency:
icon = "info-alert.png"_spr;
message = fmt::format("Update {} to use {}", problem.message, cause);
break; break;
case LoadProblem::Type::PresentIncompatibility: case LoadProblem::Type::PresentIncompatibility:
icon = "info-alert.png"_spr; 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; break;
case LoadProblem::Type::UnzipFailed: case LoadProblem::Type::UnzipFailed:
icon = "info-alert.png"_spr; icon = "info-alert.png"_spr;
@ -105,6 +125,11 @@ bool ProblemsListCell::init(LoadProblem problem, ProblemsListPopup* list, CCSize
message = fmt::format("{} is incompatible with this version of Geode", cause); message = fmt::format("{} is incompatible with this version of Geode", cause);
m_longMessage = problem.message; m_longMessage = problem.message;
break; break;
case LoadProblem::Type::NeedsNewerGeodeVersion:
icon = "info-alert.png"_spr;
message = fmt::format("Update Geode to use {}", cause);
m_longMessage = problem.message;
break;
} }
m_problem = std::move(problem); m_problem = std::move(problem);

View file

@ -38,6 +38,7 @@ void ProblemsListPopup::createList(Mod* scrollTo) {
} }
CCArray* ProblemsListPopup::createCells(Mod* scrollTo, float& scrollValue) { CCArray* ProblemsListPopup::createCells(Mod* scrollTo, float& scrollValue) {
std::vector<ProblemsListCell*> veryTop;
std::vector<ProblemsListCell*> top; std::vector<ProblemsListCell*> top;
std::vector<ProblemsListCell*> middle; std::vector<ProblemsListCell*> middle;
std::vector<ProblemsListCell*> bottom; std::vector<ProblemsListCell*> bottom;
@ -50,6 +51,10 @@ CCArray* ProblemsListPopup::createCells(Mod* scrollTo, float& scrollValue) {
case geode::LoadProblem::Type::Recommendation: case geode::LoadProblem::Type::Recommendation:
middle.push_back(ProblemsListCell::create(problem, this, this->getCellSize())); middle.push_back(ProblemsListCell::create(problem, this, this->getCellSize()));
break; break;
case geode::LoadProblem::Type::OutdatedIncompatibility:
case geode::LoadProblem::Type::PresentIncompatibility:
veryTop.push_back(ProblemsListCell::create(problem, this, this->getCellSize()));
break;
default: default:
top.push_back(ProblemsListCell::create(problem, this, this->getCellSize())); top.push_back(ProblemsListCell::create(problem, this, this->getCellSize()));
break; break;
@ -69,6 +74,10 @@ CCArray* ProblemsListPopup::createCells(Mod* scrollTo, float& scrollValue) {
scrollFound = true; scrollFound = true;
}; };
for (auto const& item : veryTop) {
tryFindScroll(item);
final->addObject(item);
}
for (auto const& item : top) { for (auto const& item : top) {
tryFindScroll(item); tryFindScroll(item);
final->addObject(item); final->addObject(item);