mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-22 15:37:53 -05:00
Merge branch 'main' into settings
This commit is contained in:
commit
ad537375fa
8 changed files with 179 additions and 41 deletions
27
CHANGELOG.md
27
CHANGELOG.md
|
@ -1,15 +1,38 @@
|
||||||
# Geode Changelog
|
# Geode Changelog
|
||||||
|
|
||||||
## v3.5.0
|
## v3.6.0
|
||||||
* Major rework of the entire settings system with lots of new features; see the [docs page](todo) for more
|
* Major rework of the entire settings system with lots of new features; see the [docs page](https://docs.geode-sdk.org/mods/settings) for more
|
||||||
* Rework JSON validation; now uses the `JsonExpectedValue` class with the `checkJson` helper (89d1a51)
|
* Rework JSON validation; now uses the `JsonExpectedValue` class with the `checkJson` helper (89d1a51)
|
||||||
* Add `Task::cancelled` for creating immediately cancelled Tasks (1a82d12)
|
* Add `Task::cancelled` for creating immediately cancelled Tasks (1a82d12)
|
||||||
* Add function type utilities in `utils/function.hpp` (659c168)
|
* Add function type utilities in `utils/function.hpp` (659c168)
|
||||||
* Add `typeinfo_pointer_cast` for casting `std::shared_ptr`s (28cc6fd)
|
* Add `typeinfo_pointer_cast` for casting `std::shared_ptr`s (28cc6fd)
|
||||||
* Add `GEODE_PLATFORM_SHORT_IDENTIFIER_NOARCH` (1032d9a)
|
* Add `GEODE_PLATFORM_SHORT_IDENTIFIER_NOARCH` (1032d9a)
|
||||||
|
* Add `PlatformID::getCovered` (d5718be)
|
||||||
* Rename `toByteArray` to `toBytes` (6eb0797)
|
* Rename `toByteArray` to `toBytes` (6eb0797)
|
||||||
* Improve `AxisLayout::getSizeHint` (85e7b5e)
|
* Improve `AxisLayout::getSizeHint` (85e7b5e)
|
||||||
* Fix issues with file dialogs on Windows (62b6241, 971e3fb)
|
* Fix issues with file dialogs on Windows (62b6241, 971e3fb)
|
||||||
|
* Mod incompatibilities may now be platform-specific (9f1c70a)
|
||||||
|
|
||||||
|
## v3.5.0
|
||||||
|
* Move CCLighting to cocos headers (#1036)
|
||||||
|
* Add new `gd::string` constructor (bae22b4)
|
||||||
|
* Use `getChildren` instead of member in `getChildByID` (fe730ed)
|
||||||
|
* Fix sprite order in `CCMenuItemExt::createToggler` (d729a12, 59a0ade)
|
||||||
|
* Add restart button to windows's crashlog window (#1025)
|
||||||
|
* Update FMOD headers (63b82f9)
|
||||||
|
* Change SwelvyBG sprites to be 2048x512 (#1029)
|
||||||
|
* Fix missing `GEODE_DLL` (e4054d4)
|
||||||
|
* Add code of conduct (80693c1, ab8ace0, ca3a2a3)
|
||||||
|
* Add ID system to Geode's web requests (#1040, 1f2aa2c, 1b5ae86)
|
||||||
|
* Add `Notification::cancel` (cd5a66c)
|
||||||
|
* Update matjson (e5dd2c9)
|
||||||
|
* Update TulipHook (a31c68f)
|
||||||
|
* Fix a bug where only 1 word wrap variant can exist (#1058)
|
||||||
|
* Fix ScrollLayer when anchor point is not ignored (d95a43b)
|
||||||
|
* Move macOS builds to using apple clang, fixing issues on older macOS versions (#1030)
|
||||||
|
* Allow dashes when searching for developers (#1023)
|
||||||
|
* Split update checks into multiple batches (#1066)
|
||||||
|
* Show invalid mods on mod search (#1065)
|
||||||
|
|
||||||
## v3.4.0
|
## v3.4.0
|
||||||
* Add an API for modifying the Geode UI via events; see [the corresponding docs page](https://docs.geode-sdk.org/tutorials/modify-geode) (2a3c35f)
|
* Add an API for modifying the Geode UI via events; see [the corresponding docs page](https://docs.geode-sdk.org/tutorials/modify-geode) (2a3c35f)
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
3.5.0
|
3.6.0
|
||||||
|
|
|
@ -243,6 +243,8 @@ namespace geode {
|
||||||
void setTags(std::unordered_set<std::string> const& value);
|
void setTags(std::unordered_set<std::string> const& value);
|
||||||
void setNeedsEarlyLoad(bool const& value);
|
void setNeedsEarlyLoad(bool const& value);
|
||||||
void setIsAPI(bool const& value);
|
void setIsAPI(bool const& value);
|
||||||
|
void setGameVersion(std::string const& value);
|
||||||
|
void setGeodeVersion(VersionInfo const& value);
|
||||||
ModMetadataLinks& getLinksMut();
|
ModMetadataLinks& getLinksMut();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -651,6 +651,12 @@ void ModMetadata::setNeedsEarlyLoad(bool const& value) {
|
||||||
void ModMetadata::setIsAPI(bool const& value) {
|
void ModMetadata::setIsAPI(bool const& value) {
|
||||||
m_impl->m_isAPI = value;
|
m_impl->m_isAPI = value;
|
||||||
}
|
}
|
||||||
|
void ModMetadata::setGameVersion(std::string const& value) {
|
||||||
|
m_impl->m_gdVersion = value;
|
||||||
|
}
|
||||||
|
void ModMetadata::setGeodeVersion(VersionInfo const& value) {
|
||||||
|
m_impl->m_geodeVersion = value;
|
||||||
|
}
|
||||||
ModMetadataLinks& ModMetadata::getLinksMut() {
|
ModMetadataLinks& ModMetadata::getLinksMut() {
|
||||||
return m_impl->m_links;
|
return m_impl->m_links;
|
||||||
}
|
}
|
||||||
|
|
|
@ -264,22 +264,17 @@ Result<ServerModVersion> ServerModVersion::parse(matjson::Value const& raw) {
|
||||||
|
|
||||||
auto res = ServerModVersion();
|
auto res = ServerModVersion();
|
||||||
|
|
||||||
// Verify target Geode version
|
res.metadata.setGeodeVersion(root.needs("geode").template get<VersionInfo>());
|
||||||
auto version = root.needs("geode").template get<VersionInfo>();
|
|
||||||
if (!semverCompare(Loader::get()->getVersion(), version)) {
|
|
||||||
return Err(
|
|
||||||
"Mod targets version {} but Geode is version {}",
|
|
||||||
version, Loader::get()->getVersion()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify target GD version
|
// Verify target GD version
|
||||||
auto gd = root.needs("gd").obj().needs(GEODE_PLATFORM_SHORT_IDENTIFIER).template get<std::string>();
|
auto gd_obj = root.needs("gd").obj();
|
||||||
if (gd != GEODE_GD_VERSION_STR && gd != "*") {
|
std::string gd = "0.000";
|
||||||
return Err(
|
if (gd_obj.has(GEODE_PLATFORM_SHORT_IDENTIFIER)) {
|
||||||
"Mod targets GD version {} but current is version {}",
|
gd = gd_obj.has(GEODE_PLATFORM_SHORT_IDENTIFIER).template get<std::string>();
|
||||||
gd, GEODE_GD_VERSION_STR
|
}
|
||||||
);
|
|
||||||
|
if (gd != "*") {
|
||||||
|
res.metadata.setGameVersion(gd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get server info
|
// Get server info
|
||||||
|
@ -571,14 +566,15 @@ ServerRequest<ServerModsList> server::getMods(ModsQuery const& query, bool useCa
|
||||||
auto req = web::WebRequest();
|
auto req = web::WebRequest();
|
||||||
req.userAgent(getServerUserAgent());
|
req.userAgent(getServerUserAgent());
|
||||||
|
|
||||||
// Always target current GD version and Loader version
|
|
||||||
req.param("gd", GEODE_GD_VERSION_STR);
|
|
||||||
req.param("geode", Loader::get()->getVersion().toNonVString());
|
|
||||||
|
|
||||||
// Add search params
|
// Add search params
|
||||||
if (query.query) {
|
if (query.query) {
|
||||||
req.param("query", *query.query);
|
req.param("query", *query.query);
|
||||||
|
} else {
|
||||||
|
// Target current GD version and Loader version when query is not set
|
||||||
|
req.param("gd", GEODE_GD_VERSION_STR);
|
||||||
|
req.param("geode", Loader::get()->getVersion().toNonVString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query.platforms.size()) {
|
if (query.platforms.size()) {
|
||||||
std::string plats = "";
|
std::string plats = "";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
@ -789,24 +785,14 @@ ServerRequest<std::optional<ServerModUpdate>> server::checkUpdates(Mod const* mo
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerRequest<std::vector<ServerModUpdate>> server::checkAllUpdates(bool useCache) {
|
ServerRequest<std::vector<ServerModUpdate>> server::batchedCheckUpdates(std::vector<std::string> const& batch) {
|
||||||
if (useCache) {
|
|
||||||
return getCache<checkAllUpdates>().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto modIDs = ranges::map<std::vector<std::string>>(
|
|
||||||
Loader::get()->getAllMods(),
|
|
||||||
[](auto mod) { return mod->getID(); }
|
|
||||||
);
|
|
||||||
|
|
||||||
auto req = web::WebRequest();
|
auto req = web::WebRequest();
|
||||||
req.userAgent(getServerUserAgent());
|
req.userAgent(getServerUserAgent());
|
||||||
req.param("platform", GEODE_PLATFORM_SHORT_IDENTIFIER);
|
req.param("platform", GEODE_PLATFORM_SHORT_IDENTIFIER);
|
||||||
req.param("gd", GEODE_GD_VERSION_STR);
|
req.param("gd", GEODE_GD_VERSION_STR);
|
||||||
req.param("geode", Loader::get()->getVersion().toNonVString());
|
req.param("geode", Loader::get()->getVersion().toNonVString());
|
||||||
if (modIDs.size()) {
|
|
||||||
req.param("ids", ranges::join(modIDs, ";"));
|
req.param("ids", ranges::join(batch, ";"));
|
||||||
}
|
|
||||||
return req.get(formatServerURL("/mods/updates")).map(
|
return req.get(formatServerURL("/mods/updates")).map(
|
||||||
[](web::WebResponse* response) -> Result<std::vector<ServerModUpdate>, ServerError> {
|
[](web::WebResponse* response) -> Result<std::vector<ServerModUpdate>, ServerError> {
|
||||||
if (response->ok()) {
|
if (response->ok()) {
|
||||||
|
@ -830,6 +816,79 @@ ServerRequest<std::vector<ServerModUpdate>> server::checkAllUpdates(bool useCach
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void server::queueBatches(
|
||||||
|
ServerRequest<std::vector<ServerModUpdate>>::PostResult const resolve,
|
||||||
|
std::shared_ptr<std::vector<std::vector<std::string>>> const batches,
|
||||||
|
std::shared_ptr<std::vector<ServerModUpdate>> accum
|
||||||
|
) {
|
||||||
|
// we have to do the copy here, or else our values die
|
||||||
|
batchedCheckUpdates(batches->back()).listen([resolve, batches, accum](auto result) {
|
||||||
|
if (result->ok()) {
|
||||||
|
auto serverValues = result->unwrap();
|
||||||
|
|
||||||
|
accum->reserve(accum->size() + serverValues.size());
|
||||||
|
accum->insert(accum->end(), serverValues.begin(), serverValues.end());
|
||||||
|
|
||||||
|
if (batches->size() > 1) {
|
||||||
|
batches->pop_back();
|
||||||
|
queueBatches(resolve, batches, accum);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(Ok(*accum));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(*result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerRequest<std::vector<ServerModUpdate>> server::checkAllUpdates(bool useCache) {
|
||||||
|
if (useCache) {
|
||||||
|
return getCache<checkAllUpdates>().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto modIDs = ranges::map<std::vector<std::string>>(
|
||||||
|
Loader::get()->getAllMods(),
|
||||||
|
[](auto mod) { return mod->getID(); }
|
||||||
|
);
|
||||||
|
|
||||||
|
// if there's no mods, the request would just be empty anyways
|
||||||
|
if (modIDs.empty()) {
|
||||||
|
// you would think it could infer like literally anything
|
||||||
|
return ServerRequest<std::vector<ServerModUpdate>>::immediate(
|
||||||
|
Ok<std::vector<ServerModUpdate>>({})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto modBatches = std::make_shared<std::vector<std::vector<std::string>>>();
|
||||||
|
auto modCount = modIDs.size();
|
||||||
|
std::size_t maxMods = 200u; // this affects 0.03% of users
|
||||||
|
|
||||||
|
if (modCount <= maxMods) {
|
||||||
|
// no tricks needed
|
||||||
|
return batchedCheckUpdates(modIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// even out the mod count, so a request with 230 mods sends two 115 mod requests
|
||||||
|
auto batchCount = modCount / maxMods + 1;
|
||||||
|
auto maxBatchSize = modCount / batchCount + 1;
|
||||||
|
|
||||||
|
for (std::size_t i = 0u; i < modCount; i += maxBatchSize) {
|
||||||
|
auto end = std::min(modCount, i + maxBatchSize);
|
||||||
|
modBatches->emplace_back(modIDs.begin() + i, modIDs.begin() + end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// chain requests to avoid doing too many large requests at once
|
||||||
|
return ServerRequest<std::vector<ServerModUpdate>>::runWithCallback(
|
||||||
|
[modBatches](auto finish, auto progress, auto hasBeenCancelled) {
|
||||||
|
auto accum = std::make_shared<std::vector<ServerModUpdate>>();
|
||||||
|
queueBatches(finish, modBatches, accum);
|
||||||
|
},
|
||||||
|
"Mod Update Check"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void server::clearServerCaches(bool clearGlobalCaches) {
|
void server::clearServerCaches(bool clearGlobalCaches) {
|
||||||
getCache<&getMods>().clear();
|
getCache<&getMods>().clear();
|
||||||
getCache<&getMod>().clear();
|
getCache<&getMod>().clear();
|
||||||
|
|
|
@ -151,6 +151,14 @@ namespace server {
|
||||||
ServerRequest<std::unordered_set<std::string>> getTags(bool useCache = true);
|
ServerRequest<std::unordered_set<std::string>> getTags(bool useCache = true);
|
||||||
|
|
||||||
ServerRequest<std::optional<ServerModUpdate>> checkUpdates(Mod const* mod);
|
ServerRequest<std::optional<ServerModUpdate>> checkUpdates(Mod const* mod);
|
||||||
|
|
||||||
|
ServerRequest<std::vector<ServerModUpdate>> batchedCheckUpdates(std::vector<std::string> const& batch);
|
||||||
|
void queueBatches(
|
||||||
|
ServerRequest<std::vector<ServerModUpdate>>::PostResult const finish,
|
||||||
|
std::shared_ptr<std::vector<std::vector<std::string>>> const batches,
|
||||||
|
std::shared_ptr<std::vector<ServerModUpdate>> const accum
|
||||||
|
);
|
||||||
|
|
||||||
ServerRequest<std::vector<ServerModUpdate>> checkAllUpdates(bool useCache = true);
|
ServerRequest<std::vector<ServerModUpdate>> checkAllUpdates(bool useCache = true);
|
||||||
|
|
||||||
void clearServerCaches(bool clearGlobalCaches = false);
|
void clearServerCaches(bool clearGlobalCaches = false);
|
||||||
|
|
|
@ -134,12 +134,27 @@ bool ModItem::init(ModSource&& source) {
|
||||||
m_viewMenu->setAnchorPoint({ 1.f, .5f });
|
m_viewMenu->setAnchorPoint({ 1.f, .5f });
|
||||||
m_viewMenu->setScale(.55f);
|
m_viewMenu->setScale(.55f);
|
||||||
|
|
||||||
ButtonSprite* spr;
|
ButtonSprite* spr = nullptr;
|
||||||
if (Loader::get()->isModInstalled(m_source.getID())) {
|
if (auto serverMod = m_source.asServer(); serverMod != nullptr) {
|
||||||
spr = createGeodeButton("View", 50, false, true);
|
auto version = serverMod->latestVersion();
|
||||||
} else {
|
|
||||||
spr = createGeodeButton("Get", 50, false, true, GeodeButtonSprite::Install);
|
auto geodeValid = Loader::get()->isModVersionSupported(version.getGeodeVersion());
|
||||||
|
auto gameVersion = version.getGameVersion();
|
||||||
|
auto gdValid = gameVersion == "*" || gameVersion == GEODE_STR(GEODE_GD_VERSION);
|
||||||
|
|
||||||
|
if (!geodeValid || !gdValid) {
|
||||||
|
spr = createGeodeButton("NA", 50, false, true, GeodeButtonSprite::Default);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!spr) {
|
||||||
|
if (Loader::get()->isModInstalled(m_source.getID())) {
|
||||||
|
spr = createGeodeButton("View", 50, false, true);
|
||||||
|
} else {
|
||||||
|
spr = createGeodeButton("Get", 50, false, true, GeodeButtonSprite::Install);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto viewBtn = CCMenuItemSpriteExtra::create(
|
auto viewBtn = CCMenuItemSpriteExtra::create(
|
||||||
spr,
|
spr,
|
||||||
this, menu_selector(ModItem::onView)
|
this, menu_selector(ModItem::onView)
|
||||||
|
@ -478,6 +493,25 @@ void ModItem::onView(CCObject*) {
|
||||||
)->show();
|
)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto serverMod = m_source.asServer(); serverMod != nullptr) {
|
||||||
|
auto version = serverMod->latestVersion();
|
||||||
|
auto geodeVersion = version.getGeodeVersion();
|
||||||
|
auto geodeValid = Loader::get()->isModVersionSupported(geodeVersion);
|
||||||
|
|
||||||
|
if (auto res = version.checkGameVersion(); !res) {
|
||||||
|
FLAlertLayer::create(nullptr, "Unavailable", res.unwrapErr(), "Close", nullptr)->show();
|
||||||
|
return;
|
||||||
|
} else if (!geodeValid) {
|
||||||
|
auto msg = fmt::format(
|
||||||
|
"Geode {} is required to view this mod. You currently have {}.",
|
||||||
|
geodeVersion.toVString(),
|
||||||
|
Loader::get()->getVersion().toVString()
|
||||||
|
);
|
||||||
|
FLAlertLayer::create(nullptr, "Unavailable", msg, "Close", nullptr)->show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Always open up the popup for the installed mod page if that is possible
|
// Always open up the popup for the installed mod page if that is possible
|
||||||
ModPopup::create(m_source.convertForPopup())->show();
|
ModPopup::create(m_source.convertForPopup())->show();
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,13 @@ ServerModListSource* ServerModListSource::get(ServerModListType type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerModListSource::setSearchQuery(std::string const& query) {
|
void ServerModListSource::setSearchQuery(std::string const& query) {
|
||||||
m_query.query = query.size() ? std::optional(query) : std::nullopt;
|
if (query.empty()) {
|
||||||
|
m_query.query = std::nullopt;
|
||||||
|
m_query.platforms = { GEODE_PLATFORM_TARGET };
|
||||||
|
} else {
|
||||||
|
m_query.query = std::optional(query);
|
||||||
|
m_query.platforms = {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<std::string> ServerModListSource::getModTags() const {
|
std::unordered_set<std::string> ServerModListSource::getModTags() const {
|
||||||
|
|
Loading…
Reference in a new issue