Merge pull request #11669 from LillyJadeKatrin/retroachievements-rcheevos-integration

Retroachievements rcheevos integration
This commit is contained in:
Pierre Bourdon 2023-04-04 12:34:20 +02:00 committed by GitHub
commit b63b574a3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 398 additions and 2 deletions

3
.gitmodules vendored
View File

@ -51,3 +51,6 @@
[submodule "Externals/gtest"]
path = Externals/gtest
url = https://github.com/google/googletest.git
[submodule "Externals/rcheevos/rcheevos"]
path = Externals/rcheevos/rcheevos
url = https://github.com/RetroAchievements/rcheevos.git

View File

@ -72,6 +72,7 @@ option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence, show the current gam
option(USE_MGBA "Enables GBA controllers emulation using libmgba" ON)
option(ENABLE_AUTOUPDATE "Enables support for automatic updates" ON)
option(STEAM "Creates a build for Steam" OFF)
option(USE_RETRO_ACHIEVEMENTS "Enables integration with retroachievements.org" ON)
# Maintainers: if you consider blanket disabling this for your users, please
# consider the following points:
@ -975,6 +976,10 @@ add_subdirectory(Externals/rangeset)
add_subdirectory(Externals/FatFs)
if (USE_RETRO_ACHIEVEMENTS)
add_subdirectory(Externals/rcheevos)
endif()
########################################
# Pre-build events: Define configuration variables and write SCM info header
#

49
Externals/rcheevos/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,49 @@
add_library(rcheevos
rcheevos/include/rc_api_editor.h
rcheevos/include/rc_api_info.h
rcheevos/include/rc_api_request.h
rcheevos/include/rc_api_runtime.h
rcheevos/include/rc_api_user.h
rcheevos/include/rc_consoles.h
rcheevos/include/rc_error.h
rcheevos/include/rc_hash.h
rcheevos/include/rcheevos.h
rcheevos/include/rc_runtime.h
rcheevos/include/rc_runtime_types.h
rcheevos/include/rc_url.h
rcheevos/src/rapi/rc_api_common.c
rcheevos/src/rapi/rc_api_common.h
rcheevos/src/rapi/rc_api_editor.c
rcheevos/src/rapi/rc_api_info.c
rcheevos/src/rapi/rc_api_runtime.c
rcheevos/src/rapi/rc_api_user.c
rcheevos/src/rcheevos/alloc.c
rcheevos/src/rcheevos/compat.c
rcheevos/src/rcheevos/condition.c
rcheevos/src/rcheevos/condset.c
rcheevos/src/rcheevos/consoleinfo.c
rcheevos/src/rcheevos/format.c
rcheevos/src/rcheevos/lboard.c
rcheevos/src/rcheevos/memref.c
rcheevos/src/rcheevos/operand.c
rcheevos/src/rcheevos/rc_compat.h
rcheevos/src/rcheevos/rc_internal.h
rcheevos/src/rcheevos/rc_validate.c
rcheevos/src/rcheevos/rc_validate.h
rcheevos/src/rcheevos/richpresence.c
rcheevos/src/rcheevos/runtime.c
rcheevos/src/rcheevos/runtime_progress.c
rcheevos/src/rcheevos/trigger.c
rcheevos/src/rcheevos/value.c
rcheevos/src/rhash/hash.c
rcheevos/src/rhash/md5.c
rcheevos/src/rhash/md5.h
rcheevos/src/rurl/url.c
)
target_include_directories(rcheevos PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/rcheevos/include")
target_include_directories(rcheevos INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")
target_compile_definitions(rcheevos PRIVATE "RC_DISABLE_LUA=1" "RCHEEVOS_URL_SSL")
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
target_compile_definitions(rcheevos PRIVATE "_CRT_SECURE_NO_WARNINGS")
endif()

13
Externals/rcheevos/exports.props vendored Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(ExternalsDir)rcheevos;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="$(ExternalsDir)rcheevos\rcheevos.vcxproj">
<Project>{CC99A910-3752-4465-95AA-7DC240D92A99}</Project>
</ProjectReference>
</ItemGroup>
</Project>

1
Externals/rcheevos/rcheevos vendored Submodule

@ -0,0 +1 @@
Subproject commit c5304a61bcf256ae80fcd1c8f64ad9646aaea757

71
Externals/rcheevos/rcheevos.vcxproj vendored Normal file
View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<Import Project="..\..\Source\VSProps\Base.Macros.props" />
<Import Project="$(VSPropsDir)Base.Targets.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{CC99A910-3752-4465-95AA-7DC240D92A99}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VSPropsDir)Configuration.StaticLibrary.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VSPropsDir)Base.props" />
<Import Project="$(VSPropsDir)ClDisableAllWarnings.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<ClCompile Include="rcheevos\src\rapi\rc_api_common.c" />
<ClCompile Include="rcheevos\src\rapi\rc_api_editor.c" />
<ClCompile Include="rcheevos\src\rapi\rc_api_info.c" />
<ClCompile Include="rcheevos\src\rapi\rc_api_runtime.c" />
<ClCompile Include="rcheevos\src\rapi\rc_api_user.c" />
<ClCompile Include="rcheevos\src\rcheevos\alloc.c" />
<ClCompile Include="rcheevos\src\rcheevos\compat.c" />
<ClCompile Include="rcheevos\src\rcheevos\condition.c" />
<ClCompile Include="rcheevos\src\rcheevos\condset.c" />
<ClCompile Include="rcheevos\src\rcheevos\consoleinfo.c" />
<ClCompile Include="rcheevos\src\rcheevos\format.c" />
<ClCompile Include="rcheevos\src\rcheevos\lboard.c" />
<ClCompile Include="rcheevos\src\rcheevos\memref.c" />
<ClCompile Include="rcheevos\src\rcheevos\operand.c" />
<ClCompile Include="rcheevos\src\rcheevos\rc_validate.c" />
<ClCompile Include="rcheevos\src\rcheevos\richpresence.c" />
<ClCompile Include="rcheevos\src\rcheevos\runtime.c" />
<ClCompile Include="rcheevos\src\rcheevos\runtime_progress.c" />
<ClCompile Include="rcheevos\src\rcheevos\trigger.c" />
<ClCompile Include="rcheevos\src\rcheevos\value.c" />
<ClCompile Include="rcheevos\src\rhash\hash.c" />
<ClCompile Include="rcheevos\src\rhash\md5.c" />
<ClCompile Include="rcheevos\src\rurl\url.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="rcheevos\include\rcheevos.h" />
<ClInclude Include="rcheevos\include\rc_api_editor.h" />
<ClInclude Include="rcheevos\include\rc_api_info.h" />
<ClInclude Include="rcheevos\include\rc_api_request.h" />
<ClInclude Include="rcheevos\include\rc_api_runtime.h" />
<ClInclude Include="rcheevos\include\rc_api_user.h" />
<ClInclude Include="rcheevos\include\rc_consoles.h" />
<ClInclude Include="rcheevos\include\rc_error.h" />
<ClInclude Include="rcheevos\include\rc_hash.h" />
<ClInclude Include="rcheevos\include\rc_runtime.h" />
<ClInclude Include="rcheevos\include\rc_runtime_types.h" />
<ClInclude Include="rcheevos\include\rc_url.h" />
<ClInclude Include="rcheevos\src\rapi\rc_api_common.h" />
<ClInclude Include="rcheevos\src\rcheevos\rc_compat.h" />
<ClInclude Include="rcheevos\src\rcheevos\rc_internal.h" />
<ClInclude Include="rcheevos\src\rcheevos\rc_validate.h" />
<ClInclude Include="rcheevos\src\rhash\md5.h" />
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>RC_DISABLE_LUA;RCHEEVOS_URL_SSL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)rcheevos\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -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"

View File

@ -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)
{

View File

@ -34,6 +34,7 @@ enum class System
FreeLook,
Session,
GameSettingsOnly,
Achievements,
};
constexpr std::array<LayerType, 7> SEARCH_ORDER{{

View File

@ -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;

View File

@ -85,6 +85,7 @@ enum
F_DUALSHOCKUDPCLIENTCONFIG_IDX,
F_FREELOOKCONFIG_IDX,
F_GBABIOS_IDX,
F_RETROACHIEVEMENTSCONFIG_IDX,
NUM_PATH_INDICES
};

View 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

View 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

View File

@ -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()

View 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

View 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

View File

@ -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
};

View File

@ -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),

View File

@ -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" />

View File

@ -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" />

View File

@ -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()

View File

@ -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" />

View File

@ -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;

View File

@ -45,6 +45,7 @@
<PreprocessorDefinitions Condition="'$(AutoUpdate)'!='false'">AUTOUPDATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>HAVE_SDL2;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Steam)'=='true'">STEAM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>USE_RETRO_ACHIEVEMENTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<!-- Warnings one may want to ignore when using Level4.
4201 nonstandard extension used : nameless struct/union

View File

@ -87,6 +87,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FatFs", "..\Externals\FatFs
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spng", "..\Externals\libspng\spng.vcxproj", "{447B7B1E-1D74-4AEF-B2B9-6EB41C5D5313}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rcheevos", "..\Externals\rcheevos\rcheevos.vcxproj", "{CC99A910-3752-4465-95AA-7DC240D92A99}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@ -419,6 +421,14 @@ Global
{447B7B1E-1D74-4AEF-B2B9-6EB41C5D5313}.Release|ARM64.Build.0 = Release|ARM64
{447B7B1E-1D74-4AEF-B2B9-6EB41C5D5313}.Release|x64.ActiveCfg = Release|x64
{447B7B1E-1D74-4AEF-B2B9-6EB41C5D5313}.Release|x64.Build.0 = Release|x64
{CC99A910-3752-4465-95AA-7DC240D92A99}.Debug|ARM64.ActiveCfg = Debug|ARM64
{CC99A910-3752-4465-95AA-7DC240D92A99}.Debug|ARM64.Build.0 = Debug|ARM64
{CC99A910-3752-4465-95AA-7DC240D92A99}.Debug|x64.ActiveCfg = Debug|x64
{CC99A910-3752-4465-95AA-7DC240D92A99}.Debug|x64.Build.0 = Debug|x64
{CC99A910-3752-4465-95AA-7DC240D92A99}.Release|ARM64.ActiveCfg = Release|ARM64
{CC99A910-3752-4465-95AA-7DC240D92A99}.Release|ARM64.Build.0 = Release|ARM64
{CC99A910-3752-4465-95AA-7DC240D92A99}.Release|x64.ActiveCfg = Release|x64
{CC99A910-3752-4465-95AA-7DC240D92A99}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -455,6 +465,7 @@ Global
{8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{3F17D282-A77D-4931-B844-903AD0809A5E} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{447B7B1E-1D74-4AEF-B2B9-6EB41C5D5313} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{CC99A910-3752-4465-95AA-7DC240D92A99} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {64B0A343-3B94-4522-9C24-6937FE5EFB22}