add featured items to Index

- also fix index checksum not being saved if you close the game with the console X button like i do when developing
This commit is contained in:
HJfod 2022-12-12 00:19:54 +02:00
parent 596c806fa4
commit afe57c4bc1
3 changed files with 48 additions and 28 deletions

View file

@ -115,16 +115,19 @@ namespace geode {
void removeSource(std::string const& repository); void removeSource(std::string const& repository);
std::vector<std::string> getSources() const; std::vector<std::string> getSources() const;
/**
* Get all tags
*/
std::unordered_set<std::string> getTags() const; std::unordered_set<std::string> getTags() const;
/** /**
* Get all index items available on this platform * Get all index items
*/ */
std::vector<IndexItemHandle> getItems() const; std::vector<IndexItemHandle> getItems() const;
/** /**
* Get all index items regardless of platform * Get all featured index items
*/ */
std::vector<IndexItemHandle> getAllItems() const; std::vector<IndexItemHandle> getFeaturedItems() const;
/** /**
* Check if an item with this ID is found on the index, and optionally * Check if an item with this ID is found on the index, and optionally
* provide the version sought after * provide the version sought after

View file

@ -9,18 +9,6 @@
USE_GEODE_NAMESPACE(); USE_GEODE_NAMESPACE();
// Save data
struct IndexSourceSaveData {
std::string downloadedCommitSHA;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(IndexSourceSaveData, downloadedCommitSHA);
struct IndexSaveData {
std::unordered_map<std::string, IndexSourceSaveData> sources;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(IndexSaveData, sources);
// ModInstallEvent // ModInstallEvent
ModInstallEvent::ModInstallEvent( ModInstallEvent::ModInstallEvent(
@ -54,6 +42,12 @@ struct geode::IndexSourceImpl final {
ghc::filesystem::path path() const { ghc::filesystem::path path() const {
return dirs::getIndexDir() / this->dirname(); return dirs::getIndexDir() / this->dirname();
} }
ghc::filesystem::path checksum() const {
// not storing this in the source's directory as that gets replaced by
// the newly fetched index
return dirs::getIndexDir() / (this->dirname() + ".checksum");
}
}; };
void IndexSourceImplDeleter::operator()(IndexSourceImpl* src) { void IndexSourceImplDeleter::operator()(IndexSourceImpl* src) {
@ -124,7 +118,7 @@ Result<IndexItemHandle> IndexItem::createFromDir(
.hash = root.has("mod").obj().has("hash").template get<std::string>(), .hash = root.has("mod").obj().has("hash").template get<std::string>(),
.platforms = platforms, .platforms = platforms,
}, },
.isFeatured = root.has("is-featured").template get<bool>(), .isFeatured = root.has("featured").template get<bool>(),
.tags = root.has("tags").template get<std::unordered_set<std::string>>() .tags = root.has("tags").template get<std::unordered_set<std::string>>()
}); });
if (checker.isError()) { if (checker.isError()) {
@ -219,6 +213,7 @@ void Index::onSourceUpdate(SourceUpdateEvent* event) {
switch (whatToPost) { switch (whatToPost) {
case Finished: { case Finished: {
log::debug("Index up-to-date");
// clear source statuses to allow updating index again // clear source statuses to allow updating index again
m_sourceStatuses.clear(); m_sourceStatuses.clear();
// post finish event // post finish event
@ -250,6 +245,7 @@ void Index::onSourceUpdate(SourceUpdateEvent* event) {
info += src + ": " + std::get<UpdateFailed>(status) + "\n"; info += src + ": " + std::get<UpdateFailed>(status) + "\n";
} }
} }
log::debug("Index update failed: {}", info);
// clear source statuses to allow updating index again // clear source statuses to allow updating index again
m_sourceStatuses.clear(); m_sourceStatuses.clear();
// post finish event // post finish event
@ -262,9 +258,14 @@ void Index::checkSourceUpdates(IndexSourceImpl* src) {
if (src->isUpToDate) { if (src->isUpToDate) {
return this->updateSourceFromLocal(src); return this->updateSourceFromLocal(src);
} }
log::debug("Checking updates for source {}", src->repository);
SourceUpdateEvent(src, UpdateProgress(0, "Checking status")).post(); SourceUpdateEvent(src, UpdateProgress(0, "Checking status")).post();
auto data = Mod::get()->getSavedMutable<IndexSaveData>("index");
auto oldSHA = data.sources[src->repository].downloadedCommitSHA; // read old commit SHA
// not using saved values for this one as we don't want to refetch
// index even if the game crashes
auto oldSHA = file::readString(src->checksum()).unwrapOr("");
web::AsyncWebRequest() web::AsyncWebRequest()
.join(fmt::format("index-update-{}", src->repository)) .join(fmt::format("index-update-{}", src->repository))
.header(fmt::format("If-None-Match: \"{}\"", oldSHA)) .header(fmt::format("If-None-Match: \"{}\"", oldSHA))
@ -285,8 +286,7 @@ void Index::checkSourceUpdates(IndexSourceImpl* src) {
} }
// otherwise save hash and download source // otherwise save hash and download source
else { else {
auto data = Mod::get()->getSavedMutable<IndexSaveData>("index"); (void)file::writeString(src->checksum(), newSHA);
data.sources[src->repository].downloadedCommitSHA = newSHA;
this->downloadSource(src); this->downloadSource(src);
} }
}) })
@ -299,6 +299,8 @@ void Index::checkSourceUpdates(IndexSourceImpl* src) {
} }
void Index::downloadSource(IndexSourceImpl* src) { void Index::downloadSource(IndexSourceImpl* src) {
log::debug("Downloading source {}", src->repository);
SourceUpdateEvent(src, UpdateProgress(0, "Beginning download")).post(); SourceUpdateEvent(src, UpdateProgress(0, "Beginning download")).post();
auto targetFile = dirs::getIndexDir() / fmt::format("{}.zip", src->dirname()); auto targetFile = dirs::getIndexDir() / fmt::format("{}.zip", src->dirname());
@ -353,6 +355,7 @@ void Index::downloadSource(IndexSourceImpl* src) {
} }
void Index::updateSourceFromLocal(IndexSourceImpl* src) { void Index::updateSourceFromLocal(IndexSourceImpl* src) {
log::debug("Updating local cache for source {}", src->repository);
SourceUpdateEvent(src, UpdateProgress(100, "Updating local cache")).post(); SourceUpdateEvent(src, UpdateProgress(100, "Updating local cache")).post();
// delete old items from this url if such exist // delete old items from this url if such exist
for (auto& [_, versions] : m_items) { for (auto& [_, versions] : m_items) {
@ -457,20 +460,19 @@ std::vector<IndexItemHandle> Index::getItems() const {
std::vector<IndexItemHandle> res; std::vector<IndexItemHandle> res;
for (auto& items : map::values(m_items)) { for (auto& items : map::values(m_items)) {
if (items.size()) { if (items.size()) {
auto item = items.rbegin()->second; res.push_back(items.rbegin()->second);
if (item->download.platforms.count(GEODE_PLATFORM_TARGET)) {
res.push_back(item);
}
} }
} }
return res; return res;
} }
std::vector<IndexItemHandle> Index::getAllItems() const { std::vector<IndexItemHandle> Index::getFeaturedItems() const {
std::vector<IndexItemHandle> res; std::vector<IndexItemHandle> res;
for (auto& items : map::values(m_items)) { for (auto& items : map::values(m_items)) {
if (items.size()) { if (items.size()) {
res.push_back(items.rbegin()->second); if (items.rbegin()->second->isFeatured) {
res.push_back(items.rbegin()->second);
}
} }
} }
return res; return res;
@ -549,6 +551,10 @@ bool Index::areUpdatesAvailable() const {
// Item installation // Item installation
Result<IndexInstallList> Index::getInstallList(IndexItemHandle item) const { Result<IndexInstallList> Index::getInstallList(IndexItemHandle item) const {
if (!item->download.platforms.count(GEODE_PLATFORM_TARGET)) {
return Err("Mod is not available on {}", GEODE_PLATFORM_NAME);
}
IndexInstallList list; IndexInstallList list;
list.target = item; list.target = item;
for (auto& dep : item->info.dependencies) { for (auto& dep : item->info.dependencies) {

View file

@ -185,7 +185,6 @@ CCArray* ModListLayer::createModCells(ModListType type, ModListQuery const& quer
if (auto match = queryMatch(query, item)) { if (auto match = queryMatch(query, item)) {
sorted.insert({ match.value(), item }); sorted.insert({ match.value(), item });
} }
if (!queryMatch(query, item)) continue;
} }
// add the mods sorted // add the mods sorted
@ -195,7 +194,19 @@ CCArray* ModListLayer::createModCells(ModListType type, ModListQuery const& quer
} break; } break;
case ModListType::Featured: { case ModListType::Featured: {
// todo: featured // sort the mods by match score
std::multimap<int, IndexItemHandle> sorted;
for (auto const& item : Index::get()->getFeaturedItems()) {
if (auto match = queryMatch(query, item)) {
sorted.insert({ match.value(), item });
}
}
// add the mods sorted
for (auto& [score, item] : ranges::reverse(sorted)) {
mods->addObject(IndexItemCell::create(item, this, this->getCellSize()));
}
} break; } break;
} }
return mods; return mods;