mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Second batch of fixes. Doesn't link yet and much work remains.
This commit is contained in:
parent
029b887491
commit
c9c1796dff
4 changed files with 144 additions and 93 deletions
|
@ -493,6 +493,12 @@ public:
|
|||
bool bAchievementsSoundEffects;
|
||||
bool bAchievementsNotifications;
|
||||
|
||||
// Achivements login info. Note that password is NOT stored, only a login token.
|
||||
// Still, we may wanna store it more securely than in PPSSPP.ini, especially on Android.
|
||||
std::string sAchievementsUserName;
|
||||
std::string sAchievementsToken;
|
||||
std::string sAchievementsLoginTimestamp;
|
||||
|
||||
// Various directories. Autoconfigured, not read from ini.
|
||||
Path currentDirectory; // The directory selected in the game browsing window.
|
||||
Path defaultCurrentDirectory; // Platform dependent, initialized at startup.
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
#include "ext/rcheevos/include/rcheevos.h"
|
||||
#include "ext/rcheevos/include/rc_api_user.h"
|
||||
|
@ -20,6 +21,7 @@
|
|||
|
||||
#include "Common/Log.h"
|
||||
#include "Common/File/Path.h"
|
||||
#include "Common/File/FileUtil.h"
|
||||
#include "Common/Net/HTTPClient.h"
|
||||
#include "Common/TimeUtil.h"
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
|
@ -28,6 +30,11 @@
|
|||
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/CoreParameter.h"
|
||||
#include "Core/ELF/ParamSFO.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "UI/Root.h"
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
// RA_Interface ends up including windows.h, with its silly macros.
|
||||
|
@ -38,18 +45,38 @@
|
|||
#endif
|
||||
|
||||
// Temporarily get rid of some compile errors, wanna do this last
|
||||
// Actually might be better to just make this a full blown wrapper.
|
||||
namespace Common {
|
||||
class HTTPDownloader {
|
||||
public:
|
||||
HTTPDownloader Create(const std::string &userAgent);
|
||||
static std::unique_ptr<HTTPDownloader> Create(const std::string &userAgent) {
|
||||
return std::unique_ptr<HTTPDownloader>(new HTTPDownloader());
|
||||
}
|
||||
class Request {
|
||||
public:
|
||||
typedef std::vector<uint8_t> Data;
|
||||
typedef std::function<void()> Callback;
|
||||
typedef std::function<void(s32 status_code, std::string content_type, Data data)> Callback;
|
||||
};
|
||||
|
||||
void PollRequests() {}
|
||||
void WaitForAllRequests() {}
|
||||
void CreateRequest(std::string &&url, Request::Callback &&callback) {}
|
||||
void CreatePostRequest(std::string &&url, const char *post_data, Request::Callback &&callback);
|
||||
|
||||
private:
|
||||
HTTPDownloader() {}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void OSDAddToast(float duration_s, const std::string &text) {
|
||||
// TODO: Improve.
|
||||
System_Toast(text.c_str());
|
||||
}
|
||||
void OSDAddNotification(float duration_s, const std::string &title, const std::string &summary, const std::string &iconImageData) {}
|
||||
|
||||
void OSDOpenBackgroundProgressDialog(const char *str_id, std::string message, s32 min, s32 max, s32 value);
|
||||
void OSDUpdateBackgroundProgressDialog(const char *str_id, std::string message, s32 min, s32 max, s32 value);
|
||||
void OSDCloseBackgroundProgressDialog(const char *str_id);
|
||||
|
||||
namespace Achievements {
|
||||
|
||||
|
@ -63,9 +90,9 @@ enum : s32
|
|||
};
|
||||
|
||||
// temporary sounds
|
||||
static constexpr const char *INFO_SOUND_NAME = "sfx_select.wav";
|
||||
static constexpr const char *UNLOCK_SOUND_NAME = "sfx_toggle_on.wav";
|
||||
static constexpr const char *LBSUBMIT_SOUND_NAME = "sfx_toggle_off.wav";
|
||||
static constexpr UI::UISound INFO_SOUND_NAME = UI::UISound::SELECT;
|
||||
static constexpr UI::UISound UNLOCK_SOUND_NAME = UI::UISound::TOGGLE_ON;
|
||||
static constexpr UI::UISound LBSUBMIT_SOUND_NAME = UI::UISound::TOGGLE_OFF;
|
||||
|
||||
static void FormattedError(const char *format, ...);
|
||||
static void LogFailedResponseJSON(const Common::HTTPDownloader::Request::Data &data);
|
||||
|
@ -111,6 +138,7 @@ static void UnlockAchievementCallback(s32 status_code, std::string content_type,
|
|||
Common::HTTPDownloader::Request::Data data);
|
||||
static void SubmitLeaderboardCallback(s32 status_code, std::string content_type,
|
||||
Common::HTTPDownloader::Request::Data data);
|
||||
static void ResetRuntime();
|
||||
|
||||
static bool s_active = false;
|
||||
static bool s_logged_in = false;
|
||||
|
@ -140,12 +168,15 @@ static std::atomic<u32> s_primed_achievement_count{0};
|
|||
|
||||
static bool s_has_rich_presence = false;
|
||||
static std::string s_rich_presence_string;
|
||||
static Instant s_last_ping_time = Instant::Uninitialized();
|
||||
static double s_last_ping_time;
|
||||
|
||||
static u32 s_last_queried_lboard = 0;
|
||||
static u32 s_submitting_lboard_id = 0;
|
||||
static std::optional<std::vector<Achievements::LeaderboardEntry>> s_lboard_entries;
|
||||
|
||||
// TODO: Add an icon cache as a string map. We won't cache achievement icons across sessions, let's just
|
||||
// download them as we go.
|
||||
|
||||
template<typename T>
|
||||
static const char *RAPIStructName();
|
||||
|
||||
|
@ -226,7 +257,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
DebugAssertMsg(!api_request.post_data, "Download request does not have POST data");
|
||||
_dbg_assert_msg_(!api_request.post_data, "Download request does not have POST data");
|
||||
Achievements::DownloadImage(api_request.url, std::move(cache_filename));
|
||||
return true;
|
||||
}
|
||||
|
@ -253,7 +284,7 @@ private:
|
|||
public:
|
||||
RAPIResponse(s32 status_code, Common::HTTPDownloader::Request::Data &data)
|
||||
{
|
||||
if (status_code != Common::HTTPDownloader::HTTP_OK || data.empty())
|
||||
if (status_code != 200 || data.empty())
|
||||
{
|
||||
FormattedError("%s failed: empty response and/or status code %d", RAPIStructName<T>(), status_code);
|
||||
LogFailedResponseJSON(data);
|
||||
|
@ -460,7 +491,8 @@ void Achievements::Initialize()
|
|||
s_http_downloader = Common::HTTPDownloader::Create(GetUserAgent().c_str());
|
||||
if (!s_http_downloader)
|
||||
{
|
||||
Host::ReportErrorAsync("Achievements Error", "Failed to create HTTPDownloader, cannot use achievements");
|
||||
// TODO: Also report to user
|
||||
ERROR_LOG(ACHIEVEMENTS, "Failed to create HTTPDownloader, cannot use achievements");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -469,13 +501,13 @@ void Achievements::Initialize()
|
|||
rc_runtime_init(&s_rcheevos_runtime);
|
||||
EnsureCacheDirectoriesExist();
|
||||
|
||||
s_last_ping_time.Reset();
|
||||
s_username = Host::GetBaseStringSettingValue("Cheevos", "Username");
|
||||
s_api_token = Host::GetBaseStringSettingValue("Cheevos", "Token");
|
||||
s_last_ping_time = time_now_d();
|
||||
s_username = g_Config.sAchievementsUserName;
|
||||
s_api_token = g_Config.sAchievementsToken;
|
||||
s_logged_in = (!s_username.empty() && !s_api_token.empty());
|
||||
|
||||
if (System::IsValid())
|
||||
GameChanged(System::GetDiscPath(), nullptr);
|
||||
// if (System::IsValid())
|
||||
GameChanged();
|
||||
}
|
||||
|
||||
void Achievements::UpdateSettings()
|
||||
|
@ -672,7 +704,7 @@ void Achievements::ResetRuntime()
|
|||
return;
|
||||
|
||||
std::unique_lock lock(s_achievements_mutex);
|
||||
Log_DevPrint("Resetting rcheevos state...");
|
||||
DEBUG_LOG(ACHIEVEMENTS, "Resetting rcheevos state...");
|
||||
rc_runtime_reset(&s_rcheevos_runtime);
|
||||
}
|
||||
|
||||
|
@ -709,7 +741,7 @@ void Achievements::FrameUpdate()
|
|||
{
|
||||
const s32 ping_frequency =
|
||||
g_Config.bAchievementsRichPresence ? RICH_PRESENCE_PING_FREQUENCY : NO_RICH_PRESENCE_PING_FREQUENCY;
|
||||
if (static_cast<s32>(s_last_ping_time.Elapsed()) >= ping_frequency)
|
||||
if (static_cast<s32>(time_now_d() - s_last_ping_time) >= ping_frequency)
|
||||
SendPing();
|
||||
}
|
||||
}
|
||||
|
@ -870,20 +902,15 @@ const std::string &Achievements::GetRichPresenceString()
|
|||
|
||||
void Achievements::EnsureCacheDirectoriesExist()
|
||||
{
|
||||
s_game_icon_cache_directory = g_Config.appCacheDirectory / "icon"; // Path::Combine(EmuFolders::Cache, "achievement_gameicon");
|
||||
s_achievement_icon_cache_directory = Path::Combine(EmuFolders::Cache, "achievement_badge");
|
||||
/*
|
||||
s_achievement_icon_cache_directory = g_Config.appCacheDirectory / "achievement_badge";
|
||||
|
||||
if (!FileSystem::DirectoryExists(s_game_icon_cache_directory.c_str()) &&
|
||||
!FileSystem::CreateDirectory(s_game_icon_cache_directory.c_str(), false))
|
||||
{
|
||||
FormattedError("Failed to create cache directory '%s'", s_game_icon_cache_directory.c_str());
|
||||
}
|
||||
|
||||
if (!FileSystem::DirectoryExists(s_achievement_icon_cache_directory.c_str()) &&
|
||||
!FileSystem::CreateDirectory(s_achievement_icon_cache_directory.c_str(), false))
|
||||
if (!File::Exists(s_achievement_icon_cache_directory.c_str()) &&
|
||||
!File::CreateDir(s_achievement_icon_cache_directory.c_str(), false))
|
||||
{
|
||||
FormattedError("Failed to create cache directory '%s'", s_achievement_icon_cache_directory.c_str());
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void Achievements::LoginCallback(s32 status_code, std::string content_type, Common::HTTPDownloader::Request::Data data)
|
||||
|
@ -902,10 +929,11 @@ void Achievements::LoginCallback(s32 status_code, std::string content_type, Comm
|
|||
std::string api_token(response.api_token);
|
||||
|
||||
// save to config
|
||||
Host::SetBaseStringSettingValue("Cheevos", "Username", username.c_str());
|
||||
Host::SetBaseStringSettingValue("Cheevos", "Token", api_token.c_str());
|
||||
Host::SetBaseStringSettingValue("Cheevos", "LoginTimestamp", fmt::format("{}", std::time(nullptr)).c_str());
|
||||
Host::CommitBaseSettingChanges();
|
||||
g_Config.sAchievementsUserName = username;
|
||||
g_Config.sAchievementsToken = api_token;
|
||||
g_Config.sAchievementsLoginTimestamp = StringFromFormat("%llu", (unsigned long long)std::time(nullptr));
|
||||
|
||||
g_Config.Save("AchievementsLogin");
|
||||
|
||||
if (s_active)
|
||||
{
|
||||
|
@ -922,7 +950,7 @@ void Achievements::LoginCallback(s32 status_code, std::string content_type, Comm
|
|||
void Achievements::LoginASyncCallback(s32 status_code, std::string content_type,
|
||||
Common::HTTPDownloader::Request::Data data)
|
||||
{
|
||||
ImGuiFullscreen::CloseBackgroundProgressDialog("cheevos_async_login");
|
||||
OSDCloseBackgroundProgressDialog("cheevos_async_login");
|
||||
|
||||
LoginCallback(status_code, std::move(content_type), std::move(data));
|
||||
}
|
||||
|
@ -944,8 +972,7 @@ bool Achievements::LoginAsync(const char *username, const char *password)
|
|||
if (s_logged_in || std::strlen(username) == 0 || std::strlen(password) == 0 || IsUsingRAIntegration())
|
||||
return false;
|
||||
|
||||
if (FullscreenUI::IsInitialized())
|
||||
ImGuiFullscreen::OpenBackgroundProgressDialog("cheevos_async_login", "Logging in to RetroAchivements...", 0, 0, 0);
|
||||
OSDOpenBackgroundProgressDialog("cheevos_async_login", "Logging in to RetroAchivements...", 0, 0, 0);
|
||||
|
||||
SendLogin(username, password, s_http_downloader.get(), LoginASyncCallback);
|
||||
return true;
|
||||
|
@ -967,7 +994,7 @@ bool Achievements::Login(const char *username, const char *password)
|
|||
}
|
||||
|
||||
// create a temporary downloader if we're not initialized
|
||||
AssertMsg(!s_active, "RetroAchievements is not active on login");
|
||||
_assert_msg_(!s_active, "RetroAchievements is not active on login");
|
||||
std::unique_ptr<Common::HTTPDownloader> http_downloader = Common::HTTPDownloader::Create(GetUserAgent().c_str());
|
||||
if (!http_downloader)
|
||||
return false;
|
||||
|
@ -975,7 +1002,7 @@ bool Achievements::Login(const char *username, const char *password)
|
|||
SendLogin(username, password, http_downloader.get(), LoginCallback);
|
||||
http_downloader->WaitForAllRequests();
|
||||
|
||||
return !Host::GetBaseStringSettingValue("Cheevos", "Token").empty();
|
||||
return !g_Config.sAchievementsToken.empty();
|
||||
}
|
||||
|
||||
void Achievements::Logout()
|
||||
|
@ -995,10 +1022,10 @@ void Achievements::Logout()
|
|||
}
|
||||
|
||||
// remove from config
|
||||
Host::DeleteBaseSettingValue("Cheevos", "Username");
|
||||
Host::DeleteBaseSettingValue("Cheevos", "Token");
|
||||
Host::DeleteBaseSettingValue("Cheevos", "LoginTimestamp");
|
||||
Host::CommitBaseSettingChanges();
|
||||
g_Config.sAchievementsUserName.clear();
|
||||
g_Config.sAchievementsToken.clear();
|
||||
g_Config.sAchievementsLoginTimestamp.clear();
|
||||
g_Config.Save("Achievements logout");
|
||||
}
|
||||
|
||||
void Achievements::DownloadImage(std::string url, std::string cache_filename)
|
||||
|
@ -1008,13 +1035,12 @@ void Achievements::DownloadImage(std::string url, std::string cache_filename)
|
|||
if (status_code != HTTP_OK)
|
||||
return;
|
||||
|
||||
if (!FileSystem::WriteBinaryFile(cache_filename.c_str(), data.data(), data.size()))
|
||||
{
|
||||
if (!File::WriteDataToFile(false, data.data(), data.size(), Path(cache_filename))) {
|
||||
ERROR_LOG(ACHIEVEMENTS, "Failed to write badge image to '%s'", cache_filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiFullscreen::InvalidateCachedTexture(cache_filename);
|
||||
// ImGuiFullscreen::InvalidateCachedTexture(cache_filename);
|
||||
};
|
||||
|
||||
s_http_downloader->CreateRequest(std::move(url), std::move(callback));
|
||||
|
@ -1046,16 +1072,9 @@ void Achievements::DisplayAchievementSummary()
|
|||
summary.append("Leaderboard submission is enabled.");
|
||||
}
|
||||
|
||||
/*
|
||||
Host::RunOnCPUThread([title = std::move(title), summary = std::move(summary), icon = s_game_icon]() {
|
||||
if (FullscreenUI::IsInitialized() && g_Config.bAchievementsNotifications)
|
||||
ImGuiFullscreen::AddNotification(10.0f, std::move(title), std::move(summary), std::move(icon));
|
||||
OSDAddNotification(10.0f, title, summary, s_game_icon);
|
||||
|
||||
// Technically not going through the resource API, but since we're passing this to something else, we can't.
|
||||
if (g_Config.bAchievementsSoundEffects)
|
||||
FrontendCommon::PlaySoundAsync(Path::Combine(EmuFolders::Resources, INFO_SOUND_NAME).c_str());
|
||||
});
|
||||
*/
|
||||
// play info sound?
|
||||
}
|
||||
|
||||
void Achievements::DisplayMasteredNotification()
|
||||
|
@ -1063,17 +1082,19 @@ void Achievements::DisplayMasteredNotification()
|
|||
if (!g_Config.bAchievementsNotifications)
|
||||
return;
|
||||
|
||||
std::string title(fmt::format("Mastered {}", s_game_title));
|
||||
std::string message(fmt::format("{} achievements, {} points", GetAchievementCount(), GetCurrentPointsForGame()));
|
||||
// TODO: Translation?
|
||||
std::string title = "Mastered " + s_game_title;
|
||||
std::string message = StringFromFormat("%d achievements, %d points", GetAchievementCount(), GetCurrentPointsForGame());
|
||||
|
||||
ImGuiFullscreen::AddNotification(20.0f, std::move(title), std::move(message), s_game_icon);
|
||||
OSDAddNotification(20.0f, title, message, s_game_icon);
|
||||
NOTICE_LOG(ACHIEVEMENTS, "%s", message.c_str());
|
||||
}
|
||||
|
||||
void Achievements::GetUserUnlocksCallback(s32 status_code, std::string content_type,
|
||||
Common::HTTPDownloader::Request::Data data)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return;
|
||||
// if (!System::IsValid())
|
||||
// return;
|
||||
|
||||
RAPIResponse<rc_api_fetch_user_unlocks_response_t, rc_api_process_fetch_user_unlocks_response,
|
||||
rc_api_destroy_fetch_user_unlocks_response>
|
||||
|
@ -1121,8 +1142,8 @@ void Achievements::GetUserUnlocks()
|
|||
void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
|
||||
Common::HTTPDownloader::Request::Data data)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return;
|
||||
// if (!System::IsValid())
|
||||
// return;
|
||||
|
||||
RAPIResponse<rc_api_fetch_game_data_response_t, rc_api_process_fetch_game_data_response,
|
||||
rc_api_destroy_fetch_game_data_response>
|
||||
|
@ -1137,16 +1158,17 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
|
|||
}
|
||||
|
||||
// ensure fullscreen UI is ready
|
||||
Host::RunOnCPUThread(FullscreenUI::Initialize);
|
||||
// Host::RunOnCPUThread(FullscreenUI::Initialize);
|
||||
|
||||
s_game_id = response.id;
|
||||
s_game_title = response.title;
|
||||
|
||||
// try for a icon
|
||||
/*
|
||||
if (response.image_name && std::strlen(response.image_name) > 0)
|
||||
{
|
||||
s_game_icon = Path::Combine(s_game_icon_cache_directory, fmt::format("{}.png", s_game_id));
|
||||
if (!FileSystem::FileExists(s_game_icon.c_str()))
|
||||
if (!File::Exists(s_game_icon))
|
||||
{
|
||||
RAPIRequest<rc_api_fetch_image_request_t, rc_api_init_fetch_image_request> request;
|
||||
request.image_name = response.image_name;
|
||||
|
@ -1154,6 +1176,7 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
|
|||
request.DownloadImage(s_game_icon);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// parse achievements
|
||||
for (u32 i = 0; i < response.num_achievements; i++)
|
||||
|
@ -1270,8 +1293,8 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
|
|||
void Achievements::GetLbInfoCallback(s32 status_code, std::string content_type,
|
||||
Common::HTTPDownloader::Request::Data data)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return;
|
||||
// if (!System::IsValid())
|
||||
// return;
|
||||
|
||||
RAPIResponse<rc_api_fetch_leaderboard_info_response_t, rc_api_process_fetch_leaderboard_info_response,
|
||||
rc_api_destroy_fetch_leaderboard_info_response>
|
||||
|
@ -1325,8 +1348,19 @@ void Achievements::GetPatches(u32 game_id)
|
|||
|
||||
std::string Achievements::GetGameHash(CDImage *image)
|
||||
{
|
||||
// According to https://docs.retroachievements.org/Game-Identification/, we should simply
|
||||
// concatenate param.sfo and eboot.bin, and hash the result, to obtain the game ID.
|
||||
|
||||
const char *paramSFO = "disc0:/PSP_GAME/PARAM.SFO";
|
||||
const char *ebootBIN = "disc0:/PSP_GAME/EBOOT.BIN";
|
||||
|
||||
|
||||
std::string paramSFOContents;
|
||||
std::string ebootContents;
|
||||
|
||||
std::string executable_name;
|
||||
std::vector<u8> executable_data;
|
||||
/*
|
||||
if (!System::ReadExecutableFromImage(image, &executable_name, &executable_data))
|
||||
return {};
|
||||
|
||||
|
@ -1348,15 +1382,15 @@ std::string Achievements::GetGameHash(CDImage *image)
|
|||
digest.Update(executable_name.c_str(), static_cast<u32>(executable_name.size()));
|
||||
if (hash_size > 0)
|
||||
digest.Update(executable_data.data(), hash_size);
|
||||
|
||||
u8 hash[16];
|
||||
digest.Final(hash);
|
||||
|
||||
std::string hash_str(StringUtil::StdStringFromFormat(
|
||||
*/
|
||||
u8 hash[16]{};
|
||||
// digest.Final(hash);
|
||||
size_t hash_size = 0;
|
||||
std::string hash_str(StringFromFormat(
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", hash[0], hash[1], hash[2], hash[3], hash[4],
|
||||
hash[5], hash[6], hash[7], hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]));
|
||||
|
||||
INFO_LOG(ACHIEVEMENTS, "Hash for '%s' (%zu bytes, %u bytes hashed): %s", executable_name.c_str(), executable_data.size(),
|
||||
INFO_LOG(ACHIEVEMENTS, "Hash for '%s' & '%s' (%zu bytes, %u bytes hashed): %s", paramSFO, ebootBIN, executable_data.size(),
|
||||
hash_size, hash_str.c_str());
|
||||
return hash_str;
|
||||
}
|
||||
|
@ -1364,8 +1398,8 @@ std::string Achievements::GetGameHash(CDImage *image)
|
|||
void Achievements::GetGameIdCallback(s32 status_code, std::string content_type,
|
||||
Common::HTTPDownloader::Request::Data data)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return;
|
||||
// if (!System::IsValid())
|
||||
// return;
|
||||
|
||||
RAPIResponse<rc_api_resolve_hash_response_t, rc_api_process_resolve_hash_response,
|
||||
rc_api_destroy_resolve_hash_response>
|
||||
|
@ -1374,7 +1408,7 @@ void Achievements::GetGameIdCallback(s32 status_code, std::string content_type,
|
|||
return;
|
||||
|
||||
const u32 game_id = response.game_id;
|
||||
Log_VerbosePrintf("Server returned GameID %u", game_id);
|
||||
INFO_LOG(ACHIEVEMENTS, "Server returned GameID % u", game_id);
|
||||
if (game_id == 0)
|
||||
{
|
||||
// We don't want to block saving/loading states when there's no achievements.
|
||||
|
@ -1385,8 +1419,13 @@ void Achievements::GetGameIdCallback(s32 status_code, std::string content_type,
|
|||
GetPatches(game_id);
|
||||
}
|
||||
|
||||
void Achievements::GameChanged(const std::string &path, CDImage *image)
|
||||
void Achievements::LeftGame() {
|
||||
// Should just uninitialize
|
||||
}
|
||||
|
||||
void Achievements::GameChanged()
|
||||
{
|
||||
/*
|
||||
if (!IsActive() || s_game_path == path)
|
||||
return;
|
||||
|
||||
|
@ -1422,7 +1461,7 @@ void Achievements::GameChanged(const std::string &path, CDImage *image)
|
|||
|
||||
if (!IsUsingRAIntegration() && s_http_downloader->HasAnyRequests())
|
||||
{
|
||||
if (image && System::IsValid())
|
||||
if (image)
|
||||
Host::DisplayLoadingScreen("Downloading achievements data...");
|
||||
|
||||
s_http_downloader->WaitForAllRequests();
|
||||
|
@ -1476,6 +1515,7 @@ void Achievements::GameChanged(const std::string &path, CDImage *image)
|
|||
|
||||
if (IsLoggedIn())
|
||||
SendGetGameId();
|
||||
*/
|
||||
}
|
||||
|
||||
void Achievements::SendGetGameId()
|
||||
|
@ -1490,8 +1530,8 @@ void Achievements::SendGetGameId()
|
|||
void Achievements::SendPlayingCallback(s32 status_code, std::string content_type,
|
||||
Common::HTTPDownloader::Request::Data data)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return;
|
||||
// if (!System::IsValid())
|
||||
// return;
|
||||
|
||||
RAPIResponse<rc_api_start_session_response_t, rc_api_process_start_session_response,
|
||||
rc_api_destroy_start_session_response>
|
||||
|
@ -1543,8 +1583,8 @@ void Achievements::UpdateRichPresence()
|
|||
void Achievements::SendPingCallback(s32 status_code, std::string content_type,
|
||||
Common::HTTPDownloader::Request::Data data)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return;
|
||||
// if (!System::IsValid())
|
||||
// return;
|
||||
|
||||
RAPIResponse<rc_api_ping_response_t, rc_api_process_ping_response, rc_api_destroy_ping_response> response(status_code,
|
||||
data);
|
||||
|
@ -1555,7 +1595,7 @@ void Achievements::SendPing()
|
|||
if (!HasActiveGame())
|
||||
return;
|
||||
|
||||
s_last_ping_time = Instant::Now();
|
||||
s_last_ping_time = time_now_d();
|
||||
|
||||
RAPIRequest<rc_api_ping_request_t, rc_api_init_ping_request> request;
|
||||
request.api_token = s_api_token.c_str();
|
||||
|
@ -1749,8 +1789,8 @@ void Achievements::DeactivateAchievement(Achievement *achievement)
|
|||
void Achievements::UnlockAchievementCallback(s32 status_code, std::string content_type,
|
||||
Common::HTTPDownloader::Request::Data data)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return;
|
||||
// if (!System::IsValid())
|
||||
// return;
|
||||
|
||||
RAPIResponse<rc_api_award_achievement_response_t, rc_api_process_award_achievement_response,
|
||||
rc_api_destroy_award_achievement_response>
|
||||
|
@ -1765,8 +1805,8 @@ void Achievements::UnlockAchievementCallback(s32 status_code, std::string conten
|
|||
void Achievements::SubmitLeaderboardCallback(s32 status_code, std::string content_type,
|
||||
Common::HTTPDownloader::Request::Data data)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return;
|
||||
// if (!System::IsValid())
|
||||
// return;
|
||||
|
||||
RAPIResponse<rc_api_submit_lboard_entry_response_t, rc_api_process_submit_lboard_entry_response,
|
||||
rc_api_destroy_submit_lboard_entry_response>
|
||||
|
@ -1782,7 +1822,7 @@ void Achievements::SubmitLeaderboardCallback(s32 status_code, std::string conten
|
|||
return;
|
||||
|
||||
const Leaderboard *lb = GetLeaderboardByID(std::exchange(s_submitting_lboard_id, 0u));
|
||||
if (!lb || !FullscreenUI::IsInitialized() || !g_settings.achievements_notifications)
|
||||
if (!lb || !g_Config.bAchievementsNotifications)
|
||||
return;
|
||||
|
||||
char submitted_score[128];
|
||||
|
@ -1790,15 +1830,16 @@ void Achievements::SubmitLeaderboardCallback(s32 status_code, std::string conten
|
|||
rc_runtime_format_lboard_value(submitted_score, sizeof(submitted_score), response.submitted_score, lb->format);
|
||||
rc_runtime_format_lboard_value(best_score, sizeof(best_score), response.best_score, lb->format);
|
||||
|
||||
std::string summary = fmt::format(
|
||||
Host::TranslateString("Achievements", "Your Score: {} (Best: {})\nLeaderboard Position: {} of {}").GetCharArray(),
|
||||
auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS);
|
||||
const char *formatString = ac->T("Your Score");
|
||||
std::string summary = StringFromFormat(formatString,
|
||||
submitted_score, best_score, response.new_rank, response.num_entries);
|
||||
|
||||
ImGuiFullscreen::AddNotification(10.0f, lb->title, std::move(summary), s_game_icon);
|
||||
OSDAddNotification(10.0f, lb->title, std::move(summary), s_game_icon);
|
||||
|
||||
// Technically not going through the resource API, but since we're passing this to something else, we can't.
|
||||
if (g_settings.achievements_sound_effects)
|
||||
FrontendCommon::PlaySoundAsync(Path::Combine(EmuFolders::Resources, LBSUBMIT_SOUND_NAME).c_str());
|
||||
if (g_Config.bAchievementsSoundEffects)
|
||||
UI::PlayUISound(LBSUBMIT_SOUND_NAME);
|
||||
}
|
||||
|
||||
void Achievements::UnlockAchievement(u32 achievement_id, bool add_notification /* = true*/)
|
||||
|
@ -1821,7 +1862,7 @@ void Achievements::UnlockAchievement(u32 achievement_id, bool add_notification /
|
|||
|
||||
INFO_LOG(ACHIEVEMENTS, "Achievement %s (%u) for game %u unlocked", achievement->title.c_str(), achievement_id, s_game_id);
|
||||
|
||||
if (FullscreenUI::IsInitialized() && g_Config.bAchievementsNotifications)
|
||||
if (g_Config.bAchievementsNotifications)
|
||||
{
|
||||
std::string title;
|
||||
switch (achievement->category)
|
||||
|
@ -1838,12 +1879,12 @@ void Achievements::UnlockAchievement(u32 achievement_id, bool add_notification /
|
|||
break;
|
||||
}
|
||||
|
||||
ImGuiFullscreen::AddNotification(15.0f, std::move(title), achievement->description,
|
||||
OSDAddNotification(15.0f, std::move(title), achievement->description,
|
||||
GetAchievementBadgePath(*achievement));
|
||||
}
|
||||
|
||||
if (g_Config.bAchievementsSoundEffects)
|
||||
FrontendCommon::PlaySoundAsync(Path::Combine(EmuFolders::Resources, UNLOCK_SOUND_NAME).c_str());
|
||||
UI::PlayUISound(UNLOCK_SOUND_NAME);
|
||||
|
||||
if (IsMastered())
|
||||
DisplayMasteredNotification();
|
||||
|
@ -1948,6 +1989,7 @@ const std::string &Achievements::GetAchievementBadgePath(const Achievement &achi
|
|||
return badge_path;
|
||||
|
||||
// well, this comes from the internet.... :)
|
||||
/*
|
||||
const std::string clean_name(Path::SanitizeFileName(achievement.badge_name));
|
||||
badge_path =
|
||||
Path::Combine(s_achievement_icon_cache_directory, fmt::format("{}{}.png", clean_name, use_locked ? "_lock" : ""));
|
||||
|
@ -1962,6 +2004,7 @@ const std::string &Achievements::GetAchievementBadgePath(const Achievement &achi
|
|||
request.image_type = use_locked ? RC_IMAGE_TYPE_ACHIEVEMENT_LOCKED : RC_IMAGE_TYPE_ACHIEVEMENT;
|
||||
request.DownloadImage(badge_path);
|
||||
}
|
||||
*/
|
||||
|
||||
return badge_path;
|
||||
}
|
||||
|
|
|
@ -127,7 +127,8 @@ bool LoginAsync(const char *username, const char *password);
|
|||
bool Login(const char *username, const char *password);
|
||||
void Logout();
|
||||
|
||||
void GameChanged(const std::string &path, CDImage *image);
|
||||
void GameChanged();
|
||||
void LeftGame();
|
||||
|
||||
/// Re-enables hardcode mode if it is enabled in the settings.
|
||||
bool ResetChallengeMode();
|
||||
|
|
|
@ -1278,4 +1278,5 @@ VR controllers = VR controllers
|
|||
|
||||
[Achievements]
|
||||
Earned = You have earned %d of %d achievements, and %d of %d points
|
||||
This game has no achievements = This game has no achievements
|
||||
This game has no achievements = This game has no achievements
|
||||
Your Score = Your Score: %d (Best: %d)\nLeaderboard Position: %d of %d
|
Loading…
Add table
Reference in a new issue