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,93 @@ 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
+ {
484
+ // snprintf(buffer, buffer_size, get_filename(g_loaded_game));
485
+ // remove_extension(buffer);
486
+ snprintf (buffer, buffer_size, " %s" , g_gamePath.GetFilename ().c_str ());
487
+ }
488
+
489
+ static void raintegration_write_memory_handler (uint32_t address, uint8_t * buffer, uint32_t num_bytes, rc_client_t * client) {
490
+ // convert_retroachievements_address_to_real_address
491
+ uint32_t realAddress = address + PSP_MEMORY_OFFSET;
492
+
493
+ uint8_t *writePtr = Memory::GetPointerWriteRange (address, num_bytes);
494
+ if (writePtr) {
495
+ memcpy (writePtr, buffer, num_bytes);
496
+ }
497
+ }
498
+
499
+ static void raintegration_event_handler (const rc_client_raintegration_event_t * event, rc_client_t * client) {
500
+ switch (event->type ) {
501
+ case RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED:
502
+ // The checked state of one of the menu items has changed and should be reflected in the UI.
503
+ // Call the handy helper function if the menu was created by rc_client_raintegration_rebuild_submenu.
504
+ rc_client_raintegration_update_menu_item (client, event->menu_item );
505
+ break ;
506
+ case RC_CLIENT_RAINTEGRATION_EVENT_PAUSE:
507
+ // The toolkit has hit a breakpoint and wants to pause the emulator. Do so.
508
+ Core_EnableStepping (true , " ra_breakpoint" );
509
+ break ;
510
+ case RC_CLIENT_RAINTEGRATION_EVENT_HARDCORE_CHANGED:
511
+ // Hardcore mode has been changed (either directly by the user, or disabled through the use of the tools).
512
+ // The frontend doesn't necessarily need to know that this value changed, they can still query it whenever
513
+ // it's appropriate, but the event lets the frontend do things like enable/disable rewind or cheats.
514
+ // handle_hardcore_changed();
515
+ break ;
516
+ default :
517
+ ERROR_LOG (ACHIEVEMENTS, " Unsupported raintegration event %u\n " , event->type );
518
+ break ;
519
+ }
520
+ }
521
+
522
+ static void load_integration_callback (int result, const char * error_message, rc_client_t * client, void * userdata) {
523
+ auto ac = GetI18NCategory (I18NCat::ACHIEVEMENTS);
524
+
525
+ // If DLL not present, do nothing. User can still play without the toolkit.
526
+ switch (result) {
527
+ case RC_MISSING_VALUE:
528
+ g_OSD.Show (OSDType::MESSAGE_WARNING, ac->T (" RAIntegration is enabled, but RAIntegration-x64.dll was not found." ));
529
+ break ;
530
+ default :
531
+ {
532
+ // If not successful, just report the error and bail. Shouldn't happen.
533
+ if (result != RC_OK) {
534
+ g_OSD.Show (OSDType::MESSAGE_ERROR, StringFromFormat (" RAIntegration init failed: %s" , error_message));
535
+ return ;
536
+ }
537
+
538
+ // DLL was loaded.
539
+ g_OSD.Show (OSDType::MESSAGE_INFO, ac->T (" RAIntegration DLL loaded." ));
540
+
541
+ // Hook up menu.
542
+ HWND hWnd = (HWND)userdata;
543
+ rc_client_raintegration_set_event_handler (g_rcClient, &raintegration_event_handler);
544
+ rc_client_raintegration_set_write_memory_function (g_rcClient, &raintegration_write_memory_handler);
545
+ rc_client_raintegration_set_get_game_name_function (g_rcClient, &raintegration_get_game_name_handler);
546
+ rc_client_raintegration_rebuild_submenu (g_rcClient, GetMenu (hWnd));
547
+ }
548
+ break ;
549
+ }
550
+
551
+ // Things are ready to load a game. If the DLL was initialized, calling rc_client_begin_load_game will be redirected
552
+ // through the DLL so the toolkit has access to the game data. Similarly, things like rc_create_leaderboard_list will
553
+ // be redirected through the DLL to reflect any local changes made by the user.
554
+
555
+ TryLoginByToken (true );
556
+ }
557
+ #endif
558
+
464
559
void Initialize () {
465
560
if (!g_Config.bAchievementsEnable ) {
466
561
_dbg_assert_ (!g_rcClient);
@@ -477,14 +572,27 @@ void Initialize() {
477
572
478
573
// Provide a logging function to simplify debugging
479
574
rc_client_enable_logging (g_rcClient, RC_CLIENT_LOG_LEVEL_VERBOSE, log_message_callback);
480
-
481
575
if (!System_GetPropertyBool (SYSPROP_SUPPORTS_HTTPS)) {
482
576
// Disable SSL if not supported by our platform implementation.
483
577
rc_client_set_host (g_rcClient, " http://retroachievements.org" );
484
578
}
485
579
486
580
rc_client_set_event_handler (g_rcClient, event_handler_callback);
487
581
582
+ #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
583
+ if (g_Config.bAchievementsEnableRAIntegration ) {
584
+ wchar_t szFilePath[MAX_PATH];
585
+ GetModuleFileNameW (NULL , szFilePath, MAX_PATH);
586
+ for (int64_t i = wcslen (szFilePath) - 1 ; i > 0 ; i--) {
587
+ if (szFilePath[i] == ' \\ ' ) {
588
+ szFilePath[i] = ' \0 ' ;
589
+ }
590
+ }
591
+ HWND hWnd = (HWND)System_GetPropertyInt (SYSPROP_MAIN_WINDOW_HANDLE);
592
+ rc_client_begin_load_raintegration (g_rcClient, szFilePath, hWnd, " PPSSPP" , " 1.0" , &load_integration_callback, hWnd);
593
+ return ;
594
+ }
595
+ #endif
488
596
TryLoginByToken (true );
489
597
}
490
598
@@ -551,7 +659,7 @@ static void login_password_callback(int result, const char *error_message, rc_cl
551
659
552
660
bool LoginAsync (const char *username, const char *password) {
553
661
auto di = GetI18NCategory (I18NCat::DIALOG);
554
- if (IsLoggedIn () || std::strlen (username) == 0 || std::strlen (password) == 0 || IsUsingRAIntegration () )
662
+ if (IsLoggedIn () || std::strlen (username) == 0 || std::strlen (password) == 0 )
555
663
return false ;
556
664
557
665
g_OSD.SetProgressBar (" cheevos_async_login" , di->T (" Logging in..." ), 0 , 0 , 0 , 0 .0f );
@@ -587,6 +695,9 @@ void UpdateSettings() {
587
695
588
696
bool Shutdown () {
589
697
g_activeChallenges.clear ();
698
+ #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
699
+ rc_client_unload_raintegration (g_rcClient);
700
+ #endif
590
701
rc_client_destroy (g_rcClient);
591
702
g_rcClient = nullptr ;
592
703
INFO_LOG (ACHIEVEMENTS, " Achievements shut down." );
@@ -832,6 +943,7 @@ void SetGame(const Path &path, IdentifiedFileType fileType, FileLoader *fileLoad
832
943
}
833
944
834
945
// The caller should hold off on executing game code until this turns false, checking with IsBlockingExecution()
946
+ g_gamePath = path;
835
947
g_isIdentifying = true ;
836
948
837
949
// TODO: Fish the block device out of the loading process somewhere else. Though, probably easier to just do it here.
@@ -861,6 +973,8 @@ void SetGame(const Path &path, IdentifiedFileType fileType, FileLoader *fileLoad
861
973
void UnloadGame () {
862
974
if (g_rcClient) {
863
975
rc_client_unload_game (g_rcClient);
976
+ g_gamePath.clear ();
977
+ s_game_hash.clear ();
864
978
}
865
979
}
866
980
0 commit comments