Merge branch 'main' into anchor-layout

This commit is contained in:
HJfod 2024-01-31 23:14:17 +02:00
commit 389c8b1bda
15 changed files with 153 additions and 35 deletions

View file

@ -31,7 +31,7 @@ body:
attributes: attributes:
label: Additional Information label: Additional Information
description: Any additional information you wish to provide. Please add anything which did not fit into the other sections here. description: Any additional information you wish to provide. Please add anything which did not fit into the other sections here.
placeholder: "Example: This is likely achieveable by doing X because..." placeholder: "Example: This is likely achievable by doing X because..."
validations: validations:
required: false required: false
- type: markdown - type: markdown

View file

@ -13,6 +13,7 @@
* Add utils for setting thread name, show it on log (832bcf81, ce53fb31) * Add utils for setting thread name, show it on log (832bcf81, ce53fb31)
* Add some launch arguments for geode (7ccaef90) * Add some launch arguments for geode (7ccaef90)
* Deprecate blocking file picking utils (ee97e2da) * Deprecate blocking file picking utils (ee97e2da)
* Sort mods by id in crashlog (984d1482)
## v2.0.0-beta.11 ## v2.0.0-beta.11

View file

@ -35,7 +35,9 @@ namespace geode {
EnableFailed, EnableFailed,
MissingDependency, MissingDependency,
PresentIncompatibility, PresentIncompatibility,
UnzipFailed UnzipFailed,
UnsupportedVersion,
UnsupportedGeodeVersion,
}; };
Type type; Type type;
std::variant<ghc::filesystem::path, ModMetadata, Mod*> cause; std::variant<ghc::filesystem::path, ModMetadata, Mod*> cause;

View file

@ -161,6 +161,11 @@ namespace geode {
*/ */
[[nodiscard]] std::optional<std::string> getGameVersion() const; [[nodiscard]] std::optional<std::string> getGameVersion() const;
/**
* Gets the target Geode version for the current platform.
*/
[[nodiscard]] VersionInfo getGeodeVersion() const;
/** /**
* Checks if mod can be installed on the current GD version. * Checks if mod can be installed on the current GD version.
* Returns Ok() if it can, Err otherwise. * Returns Ok() if it can, Err otherwise.

View file

@ -19,6 +19,10 @@ namespace geode {
cocos2d::CCTouchDispatcher::get()->unregisterForcePrio(this); cocos2d::CCTouchDispatcher::get()->unregisterForcePrio(this);
} }
void registerWithTouchDispatcher() override {
cocos2d::CCTouchDispatcher::get()->addTargetedDelegate(this, -500, true);
}
private: private:
bool initBase( bool initBase(
float width, float height, InitArgs... args, char const* bg, float width, float height, InitArgs... args, char const* bg,
@ -26,9 +30,11 @@ namespace geode {
) { ) {
m_dynamic = dynamic; m_dynamic = dynamic;
auto winSize = cocos2d::CCDirector::sharedDirector()->getWinSize(); auto winSize = cocos2d::CCDirector::get()->getWinSize();
m_size = cocos2d::CCSize { width, height }; m_size = cocos2d::CCSize { width, height };
cocos2d::CCTouchDispatcher::get()->registerForcePrio(this, 2);
if (!this->initWithColor({ 0, 0, 0, 105 })) return false; if (!this->initWithColor({ 0, 0, 0, 105 })) return false;
m_mainLayer = cocos2d::CCLayer::create(); m_mainLayer = cocos2d::CCLayer::create();
this->addChild(m_mainLayer); this->addChild(m_mainLayer);
@ -76,10 +82,6 @@ namespace geode {
this->setKeypadEnabled(true); this->setKeypadEnabled(true);
this->setTouchEnabled(true); this->setTouchEnabled(true);
cocos2d::CCTouchDispatcher::get()->registerForcePrio(this, 2);
cocos::handleTouchPriority(this);
return true; return true;
} }

View file

@ -228,6 +228,8 @@ namespace geode {
std::string toString() const; std::string toString() const;
friend GEODE_DLL std::string format_as(ComparableVersionInfo const& version); friend GEODE_DLL std::string format_as(ComparableVersionInfo const& version);
}; };
bool GEODE_DLL semverCompare(VersionInfo const& current, VersionInfo const& target);
} }
template <class V> template <class V>

View file

@ -31,6 +31,13 @@ void crashlog::printMods(std::stringstream& stream) {
if (mods.empty()) { if (mods.empty()) {
stream << "<None>\n"; stream << "<None>\n";
} }
std::sort(mods.begin(), mods.end(), [](Mod* a, Mod* b) {
auto const s1 = a->getID();
auto const s2 = b->getID();
return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), [](auto a, auto b) {
return std::tolower(a) < std::tolower(b);
});
});
using namespace std::string_view_literals; using namespace std::string_view_literals;
for (auto& mod : mods) { for (auto& mod : mods) {
stream << fmt::format("{} | [{}] {}\n", stream << fmt::format("{} | [{}] {}\n",
@ -51,7 +58,7 @@ std::string crashlog::writeCrashlog(geode::Mod* faultyMod, std::string const& in
std::stringstream file; std::stringstream file;
file << getDateString(false) << "\n" file << getDateString(false) << "\n"
<< std::showbase << "Whoopsies! An unhandled exception has occured.\n"; << std::showbase << "Whoopsies! An unhandled exception has occurred.\n";
if (faultyMod) { if (faultyMod) {
file << "It appears that the crash occurred while executing code from " file << "It appears that the crash occurred while executing code from "

View file

@ -148,10 +148,8 @@ VersionInfo Loader::Impl::maxModVersion() {
}; };
} }
bool Loader::Impl::isModVersionSupported(VersionInfo const& version) { bool Loader::Impl::isModVersionSupported(VersionInfo const& target) {
return return semverCompare(this->getVersion(), target);
version >= this->minModVersion() &&
version <= this->maxModVersion();
} }
// Data saving // Data saving
@ -421,6 +419,37 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
m_refreshingModCount -= 1; m_refreshingModCount -= 1;
}; };
{ // version checking
auto res = node->getMetadata().checkGameVersion();
if (!res) {
m_problems.push_back({
LoadProblem::Type::UnsupportedVersion,
node,
res.unwrapErr()
});
log::error("Unsupported game version: {}", res.unwrapErr());
m_refreshingModCount -= 1;
log::popNest();
return;
}
if (!this->isModVersionSupported(node->getMetadata().getGeodeVersion())) {
m_problems.push_back({
LoadProblem::Type::UnsupportedGeodeVersion,
node,
fmt::format(
"Geode version {} is not supported (current: {})",
node->getMetadata().getGeodeVersion().toString(),
this->getVersion().toString()
)
});
log::error("Unsupported Geode version: {}", node->getMetadata().getGeodeVersion());
m_refreshingModCount -= 1;
log::popNest();
return;
}
}
if (early) { if (early) {
auto res = unzipFunction(); auto res = unzipFunction();
if (!res) { if (!res) {

View file

@ -357,8 +357,6 @@ bool Mod::Impl::getLaunchFlag(std::string_view const name) const {
// Loading, Toggling, Installing // Loading, Toggling, Installing
Result<> Mod::Impl::loadBinary() { Result<> Mod::Impl::loadBinary() {
// i dont know where to put this so ill just plop it here
GEODE_UNWRAP(m_metadata.checkGameVersion());
log::debug("Loading binary for mod {}", m_metadata.getID()); log::debug("Loading binary for mod {}", m_metadata.getID());
if (m_enabled) if (m_enabled)

View file

@ -67,7 +67,7 @@ Result<ModMetadata> ModMetadata::Impl::createFromSchemaV010(ModJson const& rawJs
JsonChecker checker(impl->m_rawJSON); JsonChecker checker(impl->m_rawJSON);
auto root = checker.root(checkerRoot).obj(); auto root = checker.root(checkerRoot).obj();
root.addKnownKey("geode"); root.needs("geode").into(impl->m_geodeVersion);
root.addKnownKey("gd"); root.addKnownKey("gd");
// Check GD version // Check GD version
@ -194,23 +194,23 @@ Result<ModMetadata> ModMetadata::Impl::create(ModJson const& json) {
"specified, or its formatting is invalid (required: \"[v]X.X.X\")!" "specified, or its formatting is invalid (required: \"[v]X.X.X\")!"
); );
} }
if (schema < Loader::get()->minModVersion()) { // if (schema < Loader::get()->minModVersion()) {
return Err( // return Err(
"[mod.json] is built for an older version (" + schema.toString() + // "[mod.json] is built for an older version (" + schema.toString() +
") of Geode (current: " + Loader::get()->getVersion().toString() + // ") of Geode (current: " + Loader::get()->getVersion().toString() +
"). Please update the mod to the latest version, " // "). Please update the mod to the latest version, "
"and if the problem persists, contact the developer " // "and if the problem persists, contact the developer "
"to update it." // "to update it."
); // );
} // }
if (schema > Loader::get()->maxModVersion()) { // if (schema > Loader::get()->maxModVersion()) {
return Err( // return Err(
"[mod.json] is built for a newer version (" + schema.toString() + // "[mod.json] is built for a newer version (" + schema.toString() +
") of Geode (current: " + Loader::get()->getVersion().toString() + // ") of Geode (current: " + Loader::get()->getVersion().toString() +
"). You need to update Geode in order to use " // "). You need to update Geode in order to use "
"this mod." // "this mod."
); // );
} // }
// Handle mod.json data based on target // Handle mod.json data based on target
if (schema < VersionInfo(0, 1, 0)) { if (schema < VersionInfo(0, 1, 0)) {
@ -407,6 +407,10 @@ std::optional<std::string> ModMetadata::getGameVersion() const {
return m_impl->m_gdVersion; return m_impl->m_gdVersion;
} }
VersionInfo ModMetadata::getGeodeVersion() const {
return m_impl->m_geodeVersion;
}
Result<> ModMetadata::checkGameVersion() const { Result<> ModMetadata::checkGameVersion() const {
if (!m_impl->m_gdVersion.empty()) { if (!m_impl->m_gdVersion.empty()) {
auto const ver = m_impl->m_gdVersion; auto const ver = m_impl->m_gdVersion;

View file

@ -17,6 +17,7 @@ namespace geode {
std::string m_name; std::string m_name;
std::string m_developer; std::string m_developer;
std::string m_gdVersion; std::string m_gdVersion;
VersionInfo m_geodeVersion;
std::optional<std::string> m_description; std::optional<std::string> m_description;
std::optional<std::string> m_details; std::optional<std::string> m_details;
std::optional<std::string> m_changelog; std::optional<std::string> m_changelog;

View file

@ -572,8 +572,6 @@ void ModListLayer::reloadList(bool keepScroll, std::optional<ModListQuery> const
m_checkForUpdatesBtn->removeFromParent(); m_checkForUpdatesBtn->removeFromParent();
m_checkForUpdatesBtn = nullptr; m_checkForUpdatesBtn = nullptr;
} }
handleTouchPriority(this);
} }
void ModListLayer::updateAllStates() { void ModListLayer::updateAllStates() {

View file

@ -95,6 +95,16 @@ bool ProblemsListCell::init(LoadProblem problem, ProblemsListPopup* list, CCSize
message = fmt::format("{} has failed unzipping", cause); message = fmt::format("{} has failed unzipping", cause);
m_longMessage = problem.message; m_longMessage = problem.message;
break; break;
case LoadProblem::Type::UnsupportedVersion:
icon = "info-alert.png"_spr;
message = fmt::format("{} is incompatible with this version of GD", cause);
m_longMessage = problem.message;
break;
case LoadProblem::Type::UnsupportedGeodeVersion:
icon = "info-alert.png"_spr;
message = fmt::format("{} is incompatible with this version of Geode", cause);
m_longMessage = problem.message;
break;
} }
m_problem = std::move(problem); m_problem = std::move(problem);

View file

@ -182,3 +182,62 @@ std::string ComparableVersionInfo::toString() const {
std::string geode::format_as(ComparableVersionInfo const& version) { std::string geode::format_as(ComparableVersionInfo const& version) {
return version.toString(); return version.toString();
} }
bool geode::semverCompare(VersionInfo const& current, VersionInfo const& target) {
if (target.getMajor() != current.getMajor()) {
return false;
}
if (target.getMinor() > current.getMinor()) {
return false;
}
auto ct = current.getTag();
auto tt = target.getTag();
if (ct && tt) {
auto currentTag = ct.value();
auto targetTag = tt.value();
switch (targetTag.value) {
case VersionTag::Alpha:
if (currentTag.value > VersionTag::Alpha) {
return false;
}
if (currentTag.number && targetTag.number) {
return currentTag.number.value() == targetTag.number.value();
}
if (currentTag.number) {
return true;
}
if (targetTag.number) {
return false;
}
return true;
case VersionTag::Beta:
if (currentTag.number && targetTag.number) {
return currentTag.number.value() >= targetTag.number.value();
}
if (currentTag.number) {
return true;
}
if (targetTag.number) {
return false;
}
return true;
default:
return true;
}
}
else if (ct) {
auto currentTag = ct.value();
if (currentTag.value > VersionTag::Alpha) {
return true;
}
return false;
}
else if (tt) {
auto targetTag = tt.value();
if (targetTag.value > VersionTag::Alpha) {
return true;
}
return false;
}
return true;
}