25
25
26
26
#include " ext/rcheevos/include/rcheevos.h"
27
27
#include " ext/rcheevos/include/rc_client.h"
28
+ #include " ext/rcheevos/include/rc_client_raintegration.h"
28
29
#include " ext/rcheevos/include/rc_api_user.h"
29
30
#include " ext/rcheevos/include/rc_api_info.h"
30
31
#include " ext/rcheevos/include/rc_api_request.h"
38
39
#include " Common/Log.h"
39
40
#include " Common/File/Path.h"
40
41
#include " Common/File/FileUtil.h"
41
- #include " Core/FileLoaders/LocalFileLoader.h"
42
- #include " Core/FileSystems/BlockDevices.h"
43
42
#include " Common/Net/HTTPClient.h"
44
43
#include " Common/System/OSD.h"
45
44
#include " Common/System/System.h"
55
54
#include " Core/MemMap.h"
56
55
#include " Core/Config.h"
57
56
#include " Core/CoreParameter.h"
58
- #include " Core/ELF/ParamSFO .h"
57
+ #include " Core/Core .h"
59
58
#include " Core/System.h"
59
+ #include " Core/FileLoaders/LocalFileLoader.h"
60
+ #include " Core/FileSystems/BlockDevices.h"
61
+ #include " Core/ELF/ParamSFO.h"
60
62
#include " Core/FileSystems/MetaFileSystem.h"
61
63
#include " Core/FileSystems/ISOFileSystem.h"
62
64
#include " Core/RetroAchievements.h"
63
65
66
+ #if RC_CLIENT_SUPPORTS_RAINTEGRATION
67
+
68
+ #include " Windows/MainWindow.h"
69
+
70
+ #endif
71
+
64
72
static bool HashISOFile (ISOFileSystem *fs, const std::string filename, md5_context *md5) {
65
73
int handle = fs->OpenFile (filename, FILEACCESS_READ);
66
74
if (handle < 0 ) {
67
75
return false ;
68
76
}
69
77
70
- uint32_t sz = fs->SeekFile (handle, 0 , FILEMOVE_END);
78
+ uint32_t sz = ( uint32_t ) fs->SeekFile (handle, 0 , FILEMOVE_END);
71
79
fs->SeekFile (handle, 0 , FILEMOVE_BEGIN);
72
80
if (!sz) {
73
81
return false ;
@@ -131,7 +139,7 @@ static Achievements::Statistics g_stats;
131
139
const std::string g_gameIconCachePrefix = " game:" ;
132
140
const std::string g_iconCachePrefix = " badge:" ;
133
141
134
- Path s_game_path ;
142
+ Path g_gamePath ;
135
143
std::string s_game_hash;
136
144
137
145
std::set<uint32_t > g_activeChallenges;
@@ -461,6 +469,90 @@ static void login_token_callback(int result, const char *error_message, rc_clien
461
469
g_isLoggingIn = false ;
462
470
}
463
471
472
+ bool RAIntegrationDirty () {
473
+ #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
474
+ return rc_client_raintegration_has_modifications (g_rcClient);
475
+ #else
476
+ return false ;
477
+ #endif
478
+ }
479
+
480
+ #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
481
+
482
+ static void raintegration_get_game_name_handler (char *buffer, uint32_t buffer_size, rc_client_t *client) {
483
+ snprintf (buffer, buffer_size, " %s" , g_gamePath.GetFilename ().c_str ());
484
+ }
485
+
486
+ static void raintegration_write_memory_handler (uint32_t address, uint8_t *buffer, uint32_t num_bytes, rc_client_t *client) {
487
+ // convert_retroachievements_address_to_real_address
488
+ uint32_t realAddress = address + PSP_MEMORY_OFFSET;
489
+ uint8_t *writePtr = Memory::GetPointerWriteRange (address, num_bytes);
490
+ if (writePtr) {
491
+ memcpy (writePtr, buffer, num_bytes);
492
+ }
493
+ }
494
+
495
+ static void raintegration_event_handler (const rc_client_raintegration_event_t *event, rc_client_t *client) {
496
+ switch (event->type ) {
497
+ case RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED:
498
+ // The checked state of one of the menu items has changed and should be reflected in the UI.
499
+ // Call the handy helper function if the menu was created by rc_client_raintegration_rebuild_submenu.
500
+ rc_client_raintegration_update_menu_item (client, event->menu_item );
501
+ break ;
502
+ case RC_CLIENT_RAINTEGRATION_EVENT_PAUSE:
503
+ // The toolkit has hit a breakpoint and wants to pause the emulator. Do so.
504
+ Core_EnableStepping (true , " ra_breakpoint" );
505
+ break ;
506
+ case RC_CLIENT_RAINTEGRATION_EVENT_HARDCORE_CHANGED:
507
+ // Hardcore mode has been changed (either directly by the user, or disabled through the use of the tools).
508
+ // The frontend doesn't necessarily need to know that this value changed, they can still query it whenever
509
+ // it's appropriate, but the event lets the frontend do things like enable/disable rewind or cheats.
510
+ // handle_hardcore_changed();
511
+ break ;
512
+ default :
513
+ ERROR_LOG (ACHIEVEMENTS, " Unsupported raintegration event %u\n " , event->type );
514
+ break ;
515
+ }
516
+ }
517
+
518
+ static void load_integration_callback (int result, const char *error_message, rc_client_t *client, void *userdata) {
519
+ auto ac = GetI18NCategory (I18NCat::ACHIEVEMENTS);
520
+
521
+ // If DLL not present, do nothing. User can still play without the toolkit.
522
+ switch (result) {
523
+ case RC_OK:
524
+ {
525
+ // DLL was loaded correctly.
526
+ g_OSD.Show (OSDType::MESSAGE_SUCCESS, ac->T (" RAIntegration DLL loaded." ));
527
+
528
+ rc_client_raintegration_set_event_handler (g_rcClient, &raintegration_event_handler);
529
+ rc_client_raintegration_set_write_memory_function (g_rcClient, &raintegration_write_memory_handler);
530
+ rc_client_raintegration_set_get_game_name_function (g_rcClient, &raintegration_get_game_name_handler);
531
+ HWND hWnd = (HWND)userdata;
532
+ rc_client_raintegration_rebuild_submenu (g_rcClient, GetMenu (hWnd));
533
+ break ;
534
+ }
535
+ case RC_MISSING_VALUE:
536
+ // This is fine, proceeding to login.
537
+ g_OSD.Show (OSDType::MESSAGE_WARNING, ac->T (" RAIntegration is enabled, but RAIntegration-x64.dll was not found." ));
538
+ break ;
539
+ case RC_ABORTED:
540
+ // This is fine, proceeding to login.
541
+ g_OSD.Show (OSDType::MESSAGE_WARNING, ac->T (" Wrong version of RAIntegration-x64.dll?" ));
542
+ break ;
543
+ default :
544
+ g_OSD.Show (OSDType::MESSAGE_ERROR, StringFromFormat (" RAIntegration init failed: %s" , error_message));
545
+ // Bailing.
546
+ return ;
547
+ }
548
+
549
+ // Things are ready to load a game. If the DLL was initialized, calling rc_client_begin_load_game will be redirected
550
+ // through the DLL so the toolkit has access to the game data. Similarly, things like rc_create_leaderboard_list will
551
+ // be redirected through the DLL to reflect any local changes made by the user.
552
+ TryLoginByToken (true );
553
+ }
554
+ #endif
555
+
464
556
void Initialize () {
465
557
if (!g_Config.bAchievementsEnable ) {
466
558
_dbg_assert_ (!g_rcClient);
@@ -477,14 +569,28 @@ void Initialize() {
477
569
478
570
// Provide a logging function to simplify debugging
479
571
rc_client_enable_logging (g_rcClient, RC_CLIENT_LOG_LEVEL_VERBOSE, log_message_callback);
480
-
481
572
if (!System_GetPropertyBool (SYSPROP_SUPPORTS_HTTPS)) {
482
573
// Disable SSL if not supported by our platform implementation.
483
574
rc_client_set_host (g_rcClient, " http://retroachievements.org" );
484
575
}
485
576
486
577
rc_client_set_event_handler (g_rcClient, event_handler_callback);
487
578
579
+ #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
580
+ if (g_Config.bAchievementsEnableRAIntegration ) {
581
+ wchar_t szFilePath[MAX_PATH];
582
+ GetModuleFileNameW (NULL , szFilePath, MAX_PATH);
583
+ for (int64_t i = wcslen (szFilePath) - 1 ; i > 0 ; i--) {
584
+ if (szFilePath[i] == ' \\ ' ) {
585
+ szFilePath[i] = ' \0 ' ;
586
+ break ;
587
+ }
588
+ }
589
+ HWND hWnd = (HWND)System_GetPropertyInt (SYSPROP_MAIN_WINDOW_HANDLE);
590
+ rc_client_begin_load_raintegration (g_rcClient, szFilePath, hWnd, " PPSSPP" , PPSSPP_GIT_VERSION, &load_integration_callback, hWnd);
591
+ return ;
592
+ }
593
+ #endif
488
594
TryLoginByToken (true );
489
595
}
490
596
@@ -551,7 +657,7 @@ static void login_password_callback(int result, const char *error_message, rc_cl
551
657
552
658
bool LoginAsync (const char *username, const char *password) {
553
659
auto di = GetI18NCategory (I18NCat::DIALOG);
554
- if (IsLoggedIn () || std::strlen (username) == 0 || std::strlen (password) == 0 || IsUsingRAIntegration () )
660
+ if (IsLoggedIn () || std::strlen (username) == 0 || std::strlen (password) == 0 )
555
661
return false ;
556
662
557
663
g_OSD.SetProgressBar (" cheevos_async_login" , di->T (" Logging in..." ), 0 , 0 , 0 , 0 .0f );
@@ -587,6 +693,9 @@ void UpdateSettings() {
587
693
588
694
bool Shutdown () {
589
695
g_activeChallenges.clear ();
696
+ #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
697
+ rc_client_unload_raintegration (g_rcClient);
698
+ #endif
590
699
rc_client_destroy (g_rcClient);
591
700
g_rcClient = nullptr ;
592
701
INFO_LOG (ACHIEVEMENTS, " Achievements shut down." );
@@ -832,6 +941,7 @@ void SetGame(const Path &path, IdentifiedFileType fileType, FileLoader *fileLoad
832
941
}
833
942
834
943
// The caller should hold off on executing game code until this turns false, checking with IsBlockingExecution()
944
+ g_gamePath = path;
835
945
g_isIdentifying = true ;
836
946
837
947
// TODO: Fish the block device out of the loading process somewhere else. Though, probably easier to just do it here.
@@ -861,6 +971,8 @@ void SetGame(const Path &path, IdentifiedFileType fileType, FileLoader *fileLoad
861
971
void UnloadGame () {
862
972
if (g_rcClient) {
863
973
rc_client_unload_game (g_rcClient);
974
+ g_gamePath.clear ();
975
+ s_game_hash.clear ();
864
976
}
865
977
}
866
978
0 commit comments