|
7 | 7 |
|
8 | 8 | #include <fmt/format.h> |
9 | 9 |
|
| 10 | +#include <rcheevos/include/rc_api_info.h> |
10 | 11 | #include <rcheevos/include/rc_hash.h> |
11 | 12 |
|
12 | 13 | #include "Common/HttpRequest.h" |
@@ -268,9 +269,15 @@ void AchievementManager::ActivateDeactivateLeaderboards() |
268 | 269 | for (u32 ix = 0; ix < m_game_data.num_leaderboards; ix++) |
269 | 270 | { |
270 | 271 | auto leaderboard = m_game_data.leaderboards[ix]; |
| 272 | + u32 leaderboard_id = leaderboard.id; |
271 | 273 | if (m_is_game_loaded && leaderboards_enabled && hardcore_mode_enabled) |
272 | 274 | { |
273 | | - rc_runtime_activate_lboard(&m_runtime, leaderboard.id, leaderboard.definition, nullptr, 0); |
| 275 | + rc_runtime_activate_lboard(&m_runtime, leaderboard_id, leaderboard.definition, nullptr, 0); |
| 276 | + m_queue.EmplaceItem([this, leaderboard_id] { |
| 277 | + FetchBoardInfo(leaderboard_id); |
| 278 | + if (m_update_callback) |
| 279 | + m_update_callback(); |
| 280 | + }); |
274 | 281 | } |
275 | 282 | else |
276 | 283 | { |
@@ -712,7 +719,7 @@ AchievementManager::GetAchievementProgress(AchievementId achievement_id, u32* va |
712 | 719 | return ResponseType::SUCCESS; |
713 | 720 | } |
714 | 721 |
|
715 | | -const std::unordered_map<AchievementId, AchievementManager::LeaderboardStatus>& |
| 722 | +const std::unordered_map<AchievementManager::AchievementId, AchievementManager::LeaderboardStatus>& |
716 | 723 | AchievementManager::GetLeaderboardsInfo() const |
717 | 724 | { |
718 | 725 | return m_leaderboard_map; |
@@ -962,6 +969,90 @@ AchievementManager::ResponseType AchievementManager::FetchUnlockData(bool hardco |
962 | 969 | return r_type; |
963 | 970 | } |
964 | 971 |
|
| 972 | +AchievementManager::ResponseType AchievementManager::FetchBoardInfo(AchievementId leaderboard_id) |
| 973 | +{ |
| 974 | + std::string username = Config::Get(Config::RA_USERNAME); |
| 975 | + LeaderboardStatus lboard{}; |
| 976 | + |
| 977 | + { |
| 978 | + rc_api_fetch_leaderboard_info_response_t board_info{}; |
| 979 | + const rc_api_fetch_leaderboard_info_request_t fetch_board_request = { |
| 980 | + .leaderboard_id = leaderboard_id, .count = 4, .first_entry = 1, .username = nullptr}; |
| 981 | + const ResponseType r_type = |
| 982 | + Request<rc_api_fetch_leaderboard_info_request_t, rc_api_fetch_leaderboard_info_response_t>( |
| 983 | + fetch_board_request, &board_info, rc_api_init_fetch_leaderboard_info_request, |
| 984 | + rc_api_process_fetch_leaderboard_info_response); |
| 985 | + if (r_type != ResponseType::SUCCESS) |
| 986 | + { |
| 987 | + ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to fetch info for leaderboard ID {}.", leaderboard_id); |
| 988 | + rc_api_destroy_fetch_leaderboard_info_response(&board_info); |
| 989 | + return r_type; |
| 990 | + } |
| 991 | + lboard.name = board_info.title; |
| 992 | + lboard.description = board_info.description; |
| 993 | + lboard.entries.clear(); |
| 994 | + for (u32 i = 0; i < board_info.num_entries; ++i) |
| 995 | + { |
| 996 | + const auto& org_entry = board_info.entries[i]; |
| 997 | + LeaderboardEntry dest_entry = |
| 998 | + LeaderboardEntry{.username = org_entry.username, .rank = org_entry.rank}; |
| 999 | + if (rc_runtime_format_lboard_value(dest_entry.score.data(), FORMAT_SIZE, org_entry.score, |
| 1000 | + board_info.format) == 0) |
| 1001 | + { |
| 1002 | + ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to format leaderboard score {}.", org_entry.score); |
| 1003 | + strncpy(dest_entry.score.data(), fmt::format("{}", org_entry.score).c_str(), FORMAT_SIZE); |
| 1004 | + } |
| 1005 | + lboard.entries[org_entry.index] = dest_entry; |
| 1006 | + } |
| 1007 | + rc_api_destroy_fetch_leaderboard_info_response(&board_info); |
| 1008 | + } |
| 1009 | + |
| 1010 | + { |
| 1011 | + // Retrieve, if exists, the player's entry, the two entries above the player, and the two |
| 1012 | + // entries below the player, for a total of five entries. Technically I only need one entry |
| 1013 | + // below, but the API is ambiguous what happens if an even number and a username are provided. |
| 1014 | + rc_api_fetch_leaderboard_info_response_t board_info{}; |
| 1015 | + const rc_api_fetch_leaderboard_info_request_t fetch_board_request = { |
| 1016 | + .leaderboard_id = leaderboard_id, |
| 1017 | + .count = 5, |
| 1018 | + .first_entry = 0, |
| 1019 | + .username = username.c_str()}; |
| 1020 | + const ResponseType r_type = |
| 1021 | + Request<rc_api_fetch_leaderboard_info_request_t, rc_api_fetch_leaderboard_info_response_t>( |
| 1022 | + fetch_board_request, &board_info, rc_api_init_fetch_leaderboard_info_request, |
| 1023 | + rc_api_process_fetch_leaderboard_info_response); |
| 1024 | + if (r_type != ResponseType::SUCCESS) |
| 1025 | + { |
| 1026 | + ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to fetch info for leaderboard ID {}.", leaderboard_id); |
| 1027 | + rc_api_destroy_fetch_leaderboard_info_response(&board_info); |
| 1028 | + return r_type; |
| 1029 | + } |
| 1030 | + for (u32 i = 0; i < board_info.num_entries; ++i) |
| 1031 | + { |
| 1032 | + const auto& org_entry = board_info.entries[i]; |
| 1033 | + LeaderboardEntry dest_entry = |
| 1034 | + LeaderboardEntry{.username = org_entry.username, .rank = org_entry.rank}; |
| 1035 | + if (rc_runtime_format_lboard_value(dest_entry.score.data(), FORMAT_SIZE, org_entry.score, |
| 1036 | + board_info.format) == 0) |
| 1037 | + { |
| 1038 | + ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to format leaderboard score {}.", org_entry.score); |
| 1039 | + strncpy(dest_entry.score.data(), fmt::format("{}", org_entry.score).c_str(), FORMAT_SIZE); |
| 1040 | + } |
| 1041 | + lboard.entries[org_entry.index] = dest_entry; |
| 1042 | + if (org_entry.username == username) |
| 1043 | + lboard.player_index = org_entry.index; |
| 1044 | + } |
| 1045 | + rc_api_destroy_fetch_leaderboard_info_response(&board_info); |
| 1046 | + } |
| 1047 | + |
| 1048 | + { |
| 1049 | + std::lock_guard lg{m_lock}; |
| 1050 | + m_leaderboard_map[leaderboard_id] = lboard; |
| 1051 | + } |
| 1052 | + |
| 1053 | + return ResponseType::SUCCESS; |
| 1054 | +} |
| 1055 | + |
965 | 1056 | void AchievementManager::ActivateDeactivateAchievement(AchievementId id, bool enabled, |
966 | 1057 | bool unofficial, bool encore) |
967 | 1058 | { |
@@ -1205,7 +1296,12 @@ void AchievementManager::HandleLeaderboardTriggeredEvent(const rc_runtime_event_ |
1205 | 1296 | m_game_data.leaderboards[ix].title), |
1206 | 1297 | OSD::Duration::VERY_LONG, OSD::Color::YELLOW); |
1207 | 1298 | } |
1208 | | - return; |
| 1299 | + m_queue.EmplaceItem([this, event_id] { |
| 1300 | + FetchBoardInfo(event_id); |
| 1301 | + if (m_update_callback) |
| 1302 | + m_update_callback(); |
| 1303 | + }); |
| 1304 | + break; |
1209 | 1305 | } |
1210 | 1306 | } |
1211 | 1307 | ERROR_LOG_FMT(ACHIEVEMENTS, "Invalid leaderboard triggered event with id {}.", event_id); |
|
0 commit comments