Skip to content

Commit

Permalink
Load Badges From Cache
Browse files Browse the repository at this point in the history
If a badge is found in the cache when it is fetched, that file is loaded and a network request is not made.
  • Loading branch information
LillyJadeKatrin committed Jun 30, 2024
1 parent 3a224de commit b35e4f5
Showing 1 changed file with 44 additions and 4 deletions.
48 changes: 44 additions & 4 deletions Source/Core/Core/AchievementManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <rcheevos/include/rc_hash.h>

#include "Common/Assert.h"
#include "Common/BitUtils.h"
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/Image.h"
Expand Down Expand Up @@ -961,6 +962,12 @@ u32 AchievementManager::MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_
return num_bytes;
}

template <size_t length>
void UpdateFromArray(Common::SHA1::Context& context, const std::array<u8, length>& data)
{
context.Update(data.data(), data.size());
}

void AchievementManager::FetchBadge(AchievementManager::Badge* badge, u32 badge_type,
const AchievementManager::BadgeNameFunction function,
const UpdatedItems callback_data)
Expand All @@ -987,6 +994,38 @@ void AchievementManager::FetchBadge(AchievementManager::Badge* badge, u32 badge_
if (name_to_fetch.empty())
return;
}

std::string cache_base = File::GetUserPath(D_RETROACHIEVEMENTSCACHE_IDX);
auto context = Common::SHA1::CreateContext();
UpdateFromArray(*context, Common::BitCastToArray<u8>(badge_type));
context->Update(std::vector<u8>(name_to_fetch.begin(), name_to_fetch.end()));
auto name_hash = context->Finish();
std::string filename;
for (size_t ix = 0; ix < name_hash.size(); ix++)
{
u8 upper = name_hash[ix] / 16;
filename.append(1, upper + ((upper > 9) ? 'A' - 10 : '0'));
u8 lower = name_hash[ix] % 16;
filename.append(1, lower + ((lower > 9) ? 'A' - 10 : '0'));
}
std::string cache_path = fmt::format("{}/{}.png", cache_base, filename);

AchievementManager::Badge tmp_badge;
if (LoadPNGTexture(&tmp_badge, cache_path))
{
std::lock_guard lg{m_lock};
if (function(*this).empty() || name_to_fetch != function(*this))
{
INFO_LOG_FMT(ACHIEVEMENTS, "Requested outdated badge id {}.", name_to_fetch);
return;
}
*badge = tmp_badge;
m_update_callback(callback_data);
if (m_display_welcome_message && badge_type == RC_IMAGE_TYPE_GAME)
DisplayWelcomeMessage();
return;
}

rc_api_fetch_image_request_t icon_request = {.image_name = name_to_fetch.c_str(),
.image_type = badge_type};
Badge fetched_badge;
Expand Down Expand Up @@ -1023,11 +1062,12 @@ void AchievementManager::FetchBadge(AchievementManager::Badge* badge, u32 badge_
ERROR_LOG_FMT(ACHIEVEMENTS, "Badge '{}' failed to load", name_to_fetch);
}

std::string cache_base = File::GetUserPath(D_RETROACHIEVEMENTSCACHE_IDX);
std::string cache_path = fmt::format("{}/{}-{}.png", cache_base, badge_type, name_to_fetch);
if (!Common::SavePNG(cache_path, badge->data.data(), Common::ImageByteFormat::RGBA,
badge->width, badge->height, badge->width * 4))
std::string temp_path = fmt::format("{}/temp.png", cache_base);
if (!Common::SavePNG(temp_path, badge->data.data(), Common::ImageByteFormat::RGBA, badge->width,
badge->height, badge->width * 4) ||
!File::Rename(temp_path, cache_path))
{
File::Delete(temp_path);
WARN_LOG_FMT(ACHIEVEMENTS, "Failed to cache badge '{}-{}.png'", badge_type, name_to_fetch);
}

Expand Down

0 comments on commit b35e4f5

Please sign in to comment.