mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
Merge pull request #11669 from LillyJadeKatrin/retroachievements-rcheevos-integration
Retroachievements rcheevos integration
This commit is contained in:
@ -112,6 +112,7 @@
|
||||
#define LOGGER_CONFIG "Logger.ini"
|
||||
#define DUALSHOCKUDPCLIENT_CONFIG "DSUClient.ini"
|
||||
#define FREELOOK_CONFIG "FreeLook.ini"
|
||||
#define RETROACHIEVEMENTS_CONFIG "RetroAchievements.ini"
|
||||
|
||||
// Files in the directory returned by GetUserPath(D_LOGS_IDX)
|
||||
#define MAIN_LOG "dolphin.log"
|
||||
|
@ -160,7 +160,8 @@ static const std::map<System, std::string> system_to_name = {
|
||||
{System::DualShockUDPClient, "DualShockUDPClient"},
|
||||
{System::FreeLook, "FreeLook"},
|
||||
{System::Session, "Session"},
|
||||
{System::GameSettingsOnly, "GameSettingsOnly"}};
|
||||
{System::GameSettingsOnly, "GameSettingsOnly"},
|
||||
{System::Achievements, "Achievements"}};
|
||||
|
||||
const std::string& GetSystemName(System system)
|
||||
{
|
||||
|
@ -34,6 +34,7 @@ enum class System
|
||||
FreeLook,
|
||||
Session,
|
||||
GameSettingsOnly,
|
||||
Achievements,
|
||||
};
|
||||
|
||||
constexpr std::array<LayerType, 7> SEARCH_ORDER{{
|
||||
|
@ -847,6 +847,8 @@ static void RebuildUserDirectories(unsigned int dir_index)
|
||||
s_user_paths[F_DUALSHOCKUDPCLIENTCONFIG_IDX] =
|
||||
s_user_paths[D_CONFIG_IDX] + DUALSHOCKUDPCLIENT_CONFIG;
|
||||
s_user_paths[F_FREELOOKCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + FREELOOK_CONFIG;
|
||||
s_user_paths[F_RETROACHIEVEMENTSCONFIG_IDX] =
|
||||
s_user_paths[D_CONFIG_IDX] + RETROACHIEVEMENTS_CONFIG;
|
||||
s_user_paths[F_MAINLOG_IDX] = s_user_paths[D_LOGS_IDX] + MAIN_LOG;
|
||||
s_user_paths[F_MEM1DUMP_IDX] = s_user_paths[D_DUMP_IDX] + MEM1_DUMP;
|
||||
s_user_paths[F_MEM2DUMP_IDX] = s_user_paths[D_DUMP_IDX] + MEM2_DUMP;
|
||||
|
@ -85,6 +85,7 @@ enum
|
||||
F_DUALSHOCKUDPCLIENTCONFIG_IDX,
|
||||
F_FREELOOKCONFIG_IDX,
|
||||
F_GBABIOS_IDX,
|
||||
F_RETROACHIEVEMENTSCONFIG_IDX,
|
||||
NUM_PATH_INDICES
|
||||
};
|
||||
|
||||
|
114
Source/Core/Core/AchievementManager.cpp
Normal file
114
Source/Core/Core/AchievementManager.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
// Copyright 2023 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
#include "Core/AchievementManager.h"
|
||||
#include "Common/HttpRequest.h"
|
||||
#include "Common/WorkQueueThread.h"
|
||||
#include "Config/AchievementSettings.h"
|
||||
#include "Core/Core.h"
|
||||
|
||||
AchievementManager* AchievementManager::GetInstance()
|
||||
{
|
||||
static AchievementManager s_instance;
|
||||
return &s_instance;
|
||||
}
|
||||
|
||||
void AchievementManager::Init()
|
||||
{
|
||||
if (!m_is_runtime_initialized && Config::Get(Config::RA_ENABLED))
|
||||
{
|
||||
rc_runtime_init(&m_runtime);
|
||||
m_is_runtime_initialized = true;
|
||||
m_queue.Reset("AchievementManagerQueue", [](const std::function<void()>& func) { func(); });
|
||||
LoginAsync("", [](ResponseType r_type) {});
|
||||
}
|
||||
}
|
||||
|
||||
AchievementManager::ResponseType AchievementManager::Login(const std::string& password)
|
||||
{
|
||||
return VerifyCredentials(password);
|
||||
}
|
||||
|
||||
void AchievementManager::LoginAsync(const std::string& password, const LoginCallback& callback)
|
||||
{
|
||||
m_queue.EmplaceItem([this, password, callback] { callback(VerifyCredentials(password)); });
|
||||
}
|
||||
|
||||
bool AchievementManager::IsLoggedIn() const
|
||||
{
|
||||
return m_login_data.response.succeeded;
|
||||
}
|
||||
|
||||
void AchievementManager::Logout()
|
||||
{
|
||||
Config::SetBaseOrCurrent(Config::RA_API_TOKEN, "");
|
||||
rc_api_destroy_login_response(&m_login_data);
|
||||
m_login_data.response.succeeded = 0;
|
||||
}
|
||||
|
||||
void AchievementManager::Shutdown()
|
||||
{
|
||||
m_is_runtime_initialized = false;
|
||||
m_queue.Shutdown();
|
||||
// DON'T log out - keep those credentials for next run.
|
||||
rc_api_destroy_login_response(&m_login_data);
|
||||
m_login_data.response.succeeded = 0;
|
||||
rc_runtime_destroy(&m_runtime);
|
||||
}
|
||||
|
||||
AchievementManager::ResponseType AchievementManager::VerifyCredentials(const std::string& password)
|
||||
{
|
||||
std::string username = Config::Get(Config::RA_USERNAME);
|
||||
std::string api_token = Config::Get(Config::RA_API_TOKEN);
|
||||
rc_api_login_request_t login_request = {
|
||||
.username = username.c_str(), .api_token = api_token.c_str(), .password = password.c_str()};
|
||||
ResponseType r_type = Request<rc_api_login_request_t, rc_api_login_response_t>(
|
||||
login_request, &m_login_data, rc_api_init_login_request, rc_api_process_login_response);
|
||||
if (r_type == ResponseType::SUCCESS)
|
||||
Config::SetBaseOrCurrent(Config::RA_API_TOKEN, m_login_data.api_token);
|
||||
return r_type;
|
||||
}
|
||||
|
||||
// Every RetroAchievements API call, with only a partial exception for fetch_image, follows
|
||||
// the same design pattern (here, X is the name of the call):
|
||||
// Create a specific rc_api_X_request_t struct and populate with the necessary values
|
||||
// Call rc_api_init_X_request to convert this into a generic rc_api_request_t struct
|
||||
// Perform the HTTP request using the url and post_data in the rc_api_request_t struct
|
||||
// Call rc_api_process_X_response to convert the raw string HTTP response into a
|
||||
// rc_api_X_response_t struct
|
||||
// Use the data in the rc_api_X_response_t struct as needed
|
||||
// Call rc_api_destroy_X_response when finished with the response struct to free memory
|
||||
template <typename RcRequest, typename RcResponse>
|
||||
AchievementManager::ResponseType AchievementManager::Request(
|
||||
RcRequest rc_request, RcResponse* rc_response,
|
||||
const std::function<int(rc_api_request_t*, const RcRequest*)>& init_request,
|
||||
const std::function<int(RcResponse*, const char*)>& process_response)
|
||||
{
|
||||
rc_api_request_t api_request;
|
||||
Common::HttpRequest http_request;
|
||||
init_request(&api_request, &rc_request);
|
||||
auto http_response = http_request.Post(api_request.url, api_request.post_data);
|
||||
rc_api_destroy_request(&api_request);
|
||||
if (http_response.has_value() && http_response->size() > 0)
|
||||
{
|
||||
const std::string response_str(http_response->begin(), http_response->end());
|
||||
process_response(rc_response, response_str.c_str());
|
||||
if (rc_response->response.succeeded)
|
||||
{
|
||||
return ResponseType::SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logout();
|
||||
return ResponseType::INVALID_CREDENTIALS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ResponseType::CONNECTION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
54
Source/Core/Core/AchievementManager.h
Normal file
54
Source/Core/Core/AchievementManager.h
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright 2023 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <rcheevos/include/rc_api_user.h>
|
||||
#include <rcheevos/include/rc_runtime.h>
|
||||
|
||||
#include "Common/Event.h"
|
||||
#include "Common/WorkQueueThread.h"
|
||||
|
||||
class AchievementManager
|
||||
{
|
||||
public:
|
||||
enum class ResponseType
|
||||
{
|
||||
SUCCESS,
|
||||
INVALID_CREDENTIALS,
|
||||
CONNECTION_FAILED,
|
||||
UNKNOWN_FAILURE
|
||||
};
|
||||
using LoginCallback = std::function<void(ResponseType)>;
|
||||
|
||||
static AchievementManager* GetInstance();
|
||||
void Init();
|
||||
ResponseType Login(const std::string& password);
|
||||
void LoginAsync(const std::string& password, const LoginCallback& callback);
|
||||
bool IsLoggedIn() const;
|
||||
void Logout();
|
||||
void Shutdown();
|
||||
|
||||
private:
|
||||
AchievementManager() = default;
|
||||
|
||||
ResponseType VerifyCredentials(const std::string& password);
|
||||
|
||||
template <typename RcRequest, typename RcResponse>
|
||||
ResponseType Request(RcRequest rc_request, RcResponse* rc_response,
|
||||
const std::function<int(rc_api_request_t*, const RcRequest*)>& init_request,
|
||||
const std::function<int(RcResponse*, const char*)>& process_response);
|
||||
|
||||
rc_runtime_t m_runtime{};
|
||||
bool m_is_runtime_initialized = false;
|
||||
rc_api_login_response_t m_login_data{};
|
||||
Common::WorkQueueThread<std::function<void()>> m_queue;
|
||||
}; // class AchievementManager
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
@ -1,4 +1,6 @@
|
||||
add_library(core
|
||||
AchievementManager.cpp
|
||||
AchievementManager.h
|
||||
ActionReplay.cpp
|
||||
ActionReplay.h
|
||||
ARDecrypt.cpp
|
||||
@ -21,6 +23,8 @@ add_library(core
|
||||
CheatSearch.cpp
|
||||
CheatSearch.h
|
||||
CommonTitles.h
|
||||
Config/AchievementSettings.cpp
|
||||
Config/AchievementSettings.h
|
||||
Config/DefaultLocale.cpp
|
||||
Config/DefaultLocale.h
|
||||
Config/FreeLookSettings.cpp
|
||||
@ -747,3 +751,8 @@ if(MSVC)
|
||||
# Add precompiled header
|
||||
target_link_libraries(core PRIVATE use_pch)
|
||||
endif()
|
||||
|
||||
if(USE_RETRO_ACHIEVEMENTS)
|
||||
target_link_libraries(core PRIVATE rcheevos)
|
||||
target_compile_definitions(core PRIVATE -DUSE_RETRO_ACHIEVEMENTS)
|
||||
endif()
|
16
Source/Core/Core/Config/AchievementSettings.cpp
Normal file
16
Source/Core/Core/Config/AchievementSettings.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2023 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Core/Config/AchievementSettings.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Common/Config/Config.h"
|
||||
|
||||
namespace Config
|
||||
{
|
||||
// Configuration Information
|
||||
const Info<bool> RA_ENABLED{{System::Achievements, "Achievements", "Enabled"}, false};
|
||||
const Info<std::string> RA_USERNAME{{System::Achievements, "Achievements", "Username"}, ""};
|
||||
const Info<std::string> RA_API_TOKEN{{System::Achievements, "Achievements", "ApiToken"}, ""};
|
||||
} // namespace Config
|
14
Source/Core/Core/Config/AchievementSettings.h
Normal file
14
Source/Core/Core/Config/AchievementSettings.h
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2023 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/Config/Config.h"
|
||||
|
||||
namespace Config
|
||||
{
|
||||
// Configuration Information
|
||||
extern const Info<bool> RA_ENABLED;
|
||||
extern const Info<std::string> RA_USERNAME;
|
||||
extern const Info<std::string> RA_API_TOKEN;
|
||||
} // namespace Config
|
@ -94,6 +94,7 @@ const std::map<Config::System, int> system_to_ini = {
|
||||
{Config::System::Debugger, F_DEBUGGERCONFIG_IDX},
|
||||
{Config::System::DualShockUDPClient, F_DUALSHOCKUDPCLIENTCONFIG_IDX},
|
||||
{Config::System::FreeLook, F_FREELOOKCONFIG_IDX},
|
||||
{Config::System::Achievements, F_RETROACHIEVEMENTSCONFIG_IDX},
|
||||
// Config::System::Session should not be added to this list
|
||||
};
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Common/Config/Config.h"
|
||||
#include "Core/Config/AchievementSettings.h"
|
||||
#include "Core/Config/GraphicsSettings.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Config/UISettings.h"
|
||||
@ -37,6 +38,12 @@ bool IsSettingSaveable(const Config::Location& config_location)
|
||||
&Config::WIIMOTE_3_SOURCE.GetLocation(),
|
||||
&Config::WIIMOTE_4_SOURCE.GetLocation(),
|
||||
&Config::WIIMOTE_BB_SOURCE.GetLocation(),
|
||||
|
||||
// Achievements
|
||||
|
||||
&Config::RA_ENABLED.GetLocation(),
|
||||
&Config::RA_USERNAME.GetLocation(),
|
||||
&Config::RA_API_TOKEN.GetLocation(),
|
||||
};
|
||||
|
||||
return std::any_of(begin(s_setting_saveable), end(s_setting_saveable),
|
||||
|
@ -161,6 +161,7 @@
|
||||
<ClInclude Include="Common\WindowsRegistry.h" />
|
||||
<ClInclude Include="Common\WindowSystemInfo.h" />
|
||||
<ClInclude Include="Common\WorkQueueThread.h" />
|
||||
<ClInclude Include="Core\AchievementManager.h" />
|
||||
<ClInclude Include="Core\ActionReplay.h" />
|
||||
<ClInclude Include="Core\ARDecrypt.h" />
|
||||
<ClInclude Include="Core\Boot\Boot.h" />
|
||||
@ -172,6 +173,7 @@
|
||||
<ClInclude Include="Core\CheatGeneration.h" />
|
||||
<ClInclude Include="Core\CheatSearch.h" />
|
||||
<ClInclude Include="Core\CommonTitles.h" />
|
||||
<ClInclude Include="Core\Config\AchievementSettings.h" />
|
||||
<ClInclude Include="Core\Config\DefaultLocale.h" />
|
||||
<ClInclude Include="Core\Config\FreeLookSettings.h" />
|
||||
<ClInclude Include="Core\Config\GraphicsSettings.h" />
|
||||
@ -795,6 +797,7 @@
|
||||
<ClCompile Include="Common\UPnP.cpp" />
|
||||
<ClCompile Include="Common\WindowsRegistry.cpp" />
|
||||
<ClCompile Include="Common\Version.cpp" />
|
||||
<ClCompile Include="Core\AchievementManager.cpp" />
|
||||
<ClCompile Include="Core\ActionReplay.cpp" />
|
||||
<ClCompile Include="Core\ARDecrypt.cpp" />
|
||||
<ClCompile Include="Core\Boot\Boot_BS2Emu.cpp" />
|
||||
@ -805,6 +808,7 @@
|
||||
<ClCompile Include="Core\BootManager.cpp" />
|
||||
<ClCompile Include="Core\CheatGeneration.cpp" />
|
||||
<ClCompile Include="Core\CheatSearch.cpp" />
|
||||
<ClCompile Include="Core\Config\AchievementSettings.cpp" />
|
||||
<ClCompile Include="Core\Config\DefaultLocale.cpp" />
|
||||
<ClCompile Include="Core\Config\FreeLookSettings.cpp" />
|
||||
<ClCompile Include="Core\Config\GraphicsSettings.cpp" />
|
||||
|
@ -52,6 +52,7 @@
|
||||
<Import Project="$(ExternalsDir)minizip\exports.props" />
|
||||
<Import Project="$(ExternalsDir)picojson\exports.props" />
|
||||
<Import Project="$(ExternalsDir)pugixml\exports.props" />
|
||||
<Import Project="$(ExternalsDir)rcheevos\exports.props" />
|
||||
<Import Project="$(ExternalsDir)SDL\exports.props" />
|
||||
<Import Project="$(ExternalsDir)SFML\exports.props" />
|
||||
<Import Project="$(ExternalsDir)soundtouch\exports.props" />
|
||||
|
@ -686,4 +686,9 @@ endif()
|
||||
|
||||
if(USE_DISCORD_PRESENCE)
|
||||
target_compile_definitions(dolphin-emu PRIVATE -DUSE_DISCORD_PRESENCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_RETRO_ACHIEVEMENTS)
|
||||
target_link_libraries(dolphin-emu PRIVATE rcheevos)
|
||||
target_compile_definitions(dolphin-emu PRIVATE -DUSE_RETRO_ACHIEVEMENTS)
|
||||
endif()
|
||||
|
@ -436,6 +436,7 @@
|
||||
<Import Project="$(ExternalsDir)mbedtls\exports.props" />
|
||||
<Import Project="$(ExternalsDir)mGBA\exports.props" />
|
||||
<Import Project="$(ExternalsDir)picojson\exports.props" />
|
||||
<Import Project="$(ExternalsDir)rcheevos\exports.props" />
|
||||
<Import Project="$(ExternalsDir)SFML\exports.props" />
|
||||
<Import Project="$(ExternalsDir)soundtouch\exports.props" />
|
||||
<Import Project="$(ExternalsDir)zstd\exports.props" />
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "Common/Version.h"
|
||||
#include "Common/WindowSystemInfo.h"
|
||||
|
||||
#include "Core/AchievementManager.h"
|
||||
#include "Core/Boot/Boot.h"
|
||||
#include "Core/BootManager.h"
|
||||
#include "Core/CommonTitles.h"
|
||||
@ -222,6 +223,11 @@ MainWindow::MainWindow(std::unique_ptr<BootParameters> boot_parameters,
|
||||
|
||||
InitControllers();
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
// This has to be done before CreateComponents() so it's initialized.
|
||||
AchievementManager::GetInstance()->Init();
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
CreateComponents();
|
||||
|
||||
ConnectGameList();
|
||||
@ -301,6 +307,10 @@ MainWindow::~MainWindow()
|
||||
Settings::Instance().ResetNetPlayClient();
|
||||
Settings::Instance().ResetNetPlayServer();
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
AchievementManager::GetInstance()->Shutdown();
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
delete m_render_widget;
|
||||
delete m_netplay_dialog;
|
||||
|
||||
|
Reference in New Issue
Block a user