Cheevos: Add RAIntergration support
This commit is contained in:
parent
8b61fb8b58
commit
9a5ef2d0a2
|
@ -0,0 +1 @@
|
|||
*.o
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 RetroAchievements.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,83 @@
|
|||
#ifndef RA_CONSOLES_H
|
||||
#define RA_CONSOLES_H
|
||||
|
||||
/* this list should match the list in rcheevos/include/rconsoles.h */
|
||||
enum ConsoleID
|
||||
{
|
||||
UnknownConsoleID = 0,
|
||||
MegaDrive = 1,
|
||||
N64 = 2,
|
||||
SNES = 3,
|
||||
GB = 4,
|
||||
GBA = 5,
|
||||
GBC = 6,
|
||||
NES = 7,
|
||||
PCEngine = 8,
|
||||
SegaCD = 9,
|
||||
Sega32X = 10,
|
||||
MasterSystem = 11,
|
||||
PlayStation = 12,
|
||||
Lynx = 13,
|
||||
NeoGeoPocket = 14,
|
||||
GameGear = 15,
|
||||
GameCube = 16,
|
||||
Jaguar = 17,
|
||||
DS = 18,
|
||||
WII = 19,
|
||||
WIIU = 20,
|
||||
PlayStation2 = 21,
|
||||
Xbox = 22,
|
||||
MagnavoxOdyssey = 23,
|
||||
PokemonMini = 24,
|
||||
Atari2600 = 25,
|
||||
MSDOS = 26,
|
||||
Arcade = 27,
|
||||
VirtualBoy = 28,
|
||||
MSX = 29,
|
||||
C64 = 30,
|
||||
ZX81 = 31,
|
||||
Oric = 32,
|
||||
SG1000 = 33,
|
||||
VIC20 = 34,
|
||||
Amiga = 35,
|
||||
AtariST = 36,
|
||||
AmstradCPC = 37,
|
||||
AppleII = 38,
|
||||
Saturn = 39,
|
||||
Dreamcast = 40,
|
||||
PSP = 41,
|
||||
CDi = 42,
|
||||
ThreeDO = 43,
|
||||
Colecovision = 44,
|
||||
Intellivision = 45,
|
||||
Vectrex = 46,
|
||||
PC8800 = 47,
|
||||
PC9800 = 48,
|
||||
PCFX = 49,
|
||||
Atari5200 = 50,
|
||||
Atari7800 = 51,
|
||||
X68K = 52,
|
||||
WonderSwan = 53,
|
||||
CassetteVision = 54,
|
||||
SuperCassetteVision = 55,
|
||||
NeoGeoCD = 56,
|
||||
FairchildChannelF = 57,
|
||||
FMTowns = 58,
|
||||
ZXSpectrum = 59,
|
||||
GameAndWatch = 60,
|
||||
NokiaNGage = 61,
|
||||
Nintendo3DS = 62,
|
||||
Supervision = 63,
|
||||
SharpX1 = 64,
|
||||
Tic80 = 65,
|
||||
ThomsonTO8 = 66,
|
||||
PC6000 = 67,
|
||||
Pico = 68,
|
||||
MegaDuck = 69,
|
||||
Zeebo = 70,
|
||||
Arduboy = 71,
|
||||
|
||||
NumConsoleIDs
|
||||
};
|
||||
|
||||
#endif /* !RA_CONSOLES_H */
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef RA_EMULATORS_H
|
||||
#define RA_EMULATORS_H
|
||||
|
||||
enum EmulatorID
|
||||
{
|
||||
RA_Gens = 0,
|
||||
RA_Project64 = 1,
|
||||
RA_Snes9x = 2,
|
||||
RA_VisualboyAdvance = 3,
|
||||
RA_Nester = 4,
|
||||
RA_FCEUX = 5,
|
||||
RA_PCE = 6,
|
||||
RA_Libretro = 7,
|
||||
RA_Meka = 8,
|
||||
RA_QUASI88 = 9,
|
||||
RA_AppleWin = 10,
|
||||
RA_Oricutron = 11,
|
||||
|
||||
NumEmulatorIDs,
|
||||
UnknownEmulator = NumEmulatorIDs
|
||||
};
|
||||
|
||||
#endif /* !RA_EMULATORS_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,368 @@
|
|||
#ifndef RA_INTERFACE_H
|
||||
#define RA_INTERFACE_H
|
||||
|
||||
#include <wtypes.h> /* HWND */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/******************************
|
||||
* Initialization *
|
||||
******************************/
|
||||
|
||||
/**
|
||||
* Loads and initializes the DLL.
|
||||
*
|
||||
* Must be called before using any of the other functions. Will automatically download the DLL
|
||||
* if not found, or prompt the user to upgrade if a newer version is available
|
||||
*
|
||||
* @param hMainHWND the handle of the main window
|
||||
* @param nEmulatorID the unique idenfier of the emulator
|
||||
* @param sClientVersion the current version of the emulator (will be validated against the minimum version for the specified emulator ID)
|
||||
*/
|
||||
extern void RA_Init(HWND hMainHWND, int nEmulatorID, const char* sClientVersion);
|
||||
|
||||
/**
|
||||
* Loads and initializes the DLL.
|
||||
*
|
||||
* Must be called before using any of the other functions. Will automatically download the DLL
|
||||
* if not found, or prompt the user to upgrade if a newer version is available
|
||||
*
|
||||
* @param hMainHWND the handle of the main window
|
||||
* @param sClientName the name of the client, displayed in the title bar and included in the User-Agent for API calls
|
||||
* @param sClientVersion the current version of the client
|
||||
*/
|
||||
extern void RA_InitClient(HWND hMainHWND, const char* sClientName, const char* sClientVersion);
|
||||
|
||||
/**
|
||||
* Defines callbacks that the DLL can use to interact with the client.
|
||||
*
|
||||
* @param fpUnusedIsActive [no longer used] returns non-zero if a game is running
|
||||
* @param fpCauseUnpause unpauses the emulator
|
||||
* @param fpCausePause pauses the emulator
|
||||
* @param fpRebuildMenu notifies the client that the popup menu has changed (@see RA_CreatePopupMenu)
|
||||
* @param fpEstimateTitle gets a short description for the game being loaded (parameter is a 256-byte buffer to fill)
|
||||
* @param fpResetEmulator resets the emulator
|
||||
* @param fpLoadROM [currently unused] tells the emulator to load a specific game
|
||||
*/
|
||||
extern void RA_InstallSharedFunctions(int (*fpUnusedIsActive)(void),
|
||||
void (*fpCauseUnpause)(void), void (*fpCausePause)(void), void (*fpRebuildMenu)(void),
|
||||
void (*fpEstimateTitle)(char*), void (*fpResetEmulator)(void), void (*fpLoadROM)(const char*));
|
||||
|
||||
/**
|
||||
* Tells the DLL to use UpdateWindow instead of InvalidateRect when the UI needs to be repainted. This is primarily
|
||||
* necessary when integrating with an emulator using the SDL library as it keeps the message queue flooded so the
|
||||
* InvalidateRect messages never get turned into WM_PAINT messages.
|
||||
*
|
||||
* @param bEnable non-zero if InvalidateRect calls should be replaced with UpdateWindow
|
||||
*/
|
||||
extern void RA_SetForceRepaint(int bEnable);
|
||||
|
||||
/**
|
||||
* Creates a popup menu that can be appended to the main menu of the emulator.
|
||||
*
|
||||
* @return handle to the menu. if not attached to the program menu, caller must destroy it themselves.
|
||||
*/
|
||||
extern HMENU RA_CreatePopupMenu(void);
|
||||
|
||||
/* Resource values for menu items - needed by MFC ON_COMMAND_RANGE macros or WM_COMMAND WndProc handlers
|
||||
* they're not all currently used, allowing additional items without forcing recompilation of the emulators
|
||||
*/
|
||||
#define IDM_RA_MENUSTART 1700
|
||||
#define IDM_RA_MENUEND 1739
|
||||
|
||||
/**
|
||||
* Called when a menu item in the popup menu is selected.
|
||||
*
|
||||
* @param nID the ID of the menu item (will be between IDM_RA_MENUSTART and IDM_RA_MENUEND)
|
||||
*/
|
||||
extern void RA_InvokeDialog(LPARAM nID);
|
||||
|
||||
/**
|
||||
* Provides additional information to include in the User-Agent string for API calls.
|
||||
*
|
||||
* This is primarily used to identify dependencies or configurations (such as libretro core versions)
|
||||
*
|
||||
* @param sDetail the additional information to include
|
||||
*/
|
||||
extern void RA_SetUserAgentDetail(const char* sDetail);
|
||||
|
||||
/**
|
||||
* Attempts to log in to the retroachievements.org site.
|
||||
*
|
||||
* Prompts the user for their login credentials and performs the login. If they've previously logged in and have
|
||||
* chosen to store their credentials, the login occurs without prompting.
|
||||
*
|
||||
* @param bBlocking if zero, control is returned to the calling process while the login request is processed by the server.
|
||||
*/
|
||||
extern void RA_AttemptLogin(int bBlocking);
|
||||
|
||||
/**
|
||||
* Specifies the console associated to the emulator.
|
||||
*
|
||||
* May be called just before loading a game if the emulator supports multiple consoles.
|
||||
*
|
||||
* @param nConsoleID the unique identifier of the console associated to the game being loaded.
|
||||
*/
|
||||
extern void RA_SetConsoleID(unsigned int nConsoleID);
|
||||
|
||||
/**
|
||||
* Resets memory references created by previous calls to RA_InstallMemoryBank.
|
||||
*/
|
||||
extern void RA_ClearMemoryBanks(void);
|
||||
|
||||
typedef unsigned char (RA_ReadMemoryFunc)(unsigned int nAddress);
|
||||
typedef void (RA_WriteMemoryFunc)(unsigned int nAddress, unsigned char nValue);
|
||||
/**
|
||||
* Exposes a block of memory to the DLL.
|
||||
*
|
||||
* The blocks of memory expected by the DLL are unique per console ID. To identify the correct map for a console,
|
||||
* view the consoleinfo.c file in the rcheevos repository.
|
||||
*
|
||||
* @param nBankID the index of the bank to update. will replace any existing bank at that index.
|
||||
* @param pReader a function to read from the bank. parameter is the offset within the bank to read from.
|
||||
* @param pWriter a function to write to the bank. parameters are the offset within the bank to write to and an 8-bit value to write.
|
||||
* @param nBankSize the size of the bank.
|
||||
*/
|
||||
extern void RA_InstallMemoryBank(int nBankID, RA_ReadMemoryFunc pReader, RA_WriteMemoryFunc pWriter, int nBankSize);
|
||||
|
||||
/**
|
||||
* Deinitializes and unloads the DLL.
|
||||
*/
|
||||
extern void RA_Shutdown(void);
|
||||
|
||||
|
||||
|
||||
/******************************
|
||||
* Overlay *
|
||||
******************************/
|
||||
|
||||
/**
|
||||
* Determines if the overlay is fully visible.
|
||||
*
|
||||
* Precursor check before calling RA_NavigateOverlay
|
||||
*
|
||||
* @return non-zero if the overlay is fully visible, zero if it is not.
|
||||
*/
|
||||
extern int RA_IsOverlayFullyVisible(void);
|
||||
|
||||
/**
|
||||
* Called to show or hide the overlay.
|
||||
*
|
||||
* @param bIsPaused true to show the overlay, false to hide it.
|
||||
*/
|
||||
extern void RA_SetPaused(bool bIsPaused);
|
||||
|
||||
struct ControllerInput
|
||||
{
|
||||
int m_bUpPressed;
|
||||
int m_bDownPressed;
|
||||
int m_bLeftPressed;
|
||||
int m_bRightPressed;
|
||||
int m_bConfirmPressed; /* Usually C or A */
|
||||
int m_bCancelPressed; /* Usually B */
|
||||
int m_bQuitPressed; /* Usually Start */
|
||||
};
|
||||
|
||||
/**
|
||||
* Passes controller input to the overlay.
|
||||
*
|
||||
* Does nothing if the overlay is not fully visible.
|
||||
*
|
||||
* @param pInput pointer to a ControllerInput structure indicating which inputs are active.
|
||||
*/
|
||||
extern void RA_NavigateOverlay(struct ControllerInput* pInput);
|
||||
|
||||
/**
|
||||
* [deprecated] Updates the overlay for a single frame.
|
||||
*
|
||||
* This function just calls RA_NavigateOverlay. Updating and rendering is now handled internally to the DLL.
|
||||
*/
|
||||
extern void RA_UpdateRenderOverlay(HDC, struct ControllerInput* pInput, float, RECT*, bool, bool);
|
||||
|
||||
/**
|
||||
* Updates the handle to the main window.
|
||||
*
|
||||
* The main window handle is used to anchor the overlay. If the client recreates the handle as the result of switching
|
||||
* from windowed mode to full screen, or for any other reason, it should call this to reattach the overlay.
|
||||
*
|
||||
* @param hMainHWND the new handle of the main window
|
||||
*/
|
||||
extern void RA_UpdateHWnd(HWND hMainHWND);
|
||||
|
||||
|
||||
|
||||
/******************************
|
||||
* Game Management *
|
||||
******************************/
|
||||
|
||||
/**
|
||||
* Identifies the game associated to a block of memory.
|
||||
*
|
||||
* The block of memory is the fully buffered game file. If more complicated identification is required, the caller
|
||||
* needs to link against rcheevos/rhash directly to generate the hash, and call RA_IdentifyHash with the result.
|
||||
* Can be called when switching discs to ensure the additional discs are still associated to the loaded game.
|
||||
*
|
||||
* @param pROMData the contents of the game file
|
||||
* @param nROMSize the size of the game file
|
||||
* @return the unique identifier of the game, 0 if no association available.
|
||||
*/
|
||||
extern unsigned int RA_IdentifyRom(BYTE* pROMData, unsigned int nROMSize);
|
||||
|
||||
/**
|
||||
* Identifies the game associated to a pre-generated hash.
|
||||
*
|
||||
* Used when the hash algorithm is something other than full file.
|
||||
* Can be called when switching discs to ensure the additional discs are still associated to the loaded game.
|
||||
*
|
||||
* @param sHash the hash generated by rcheevos/rhash
|
||||
* @return the unique identifier of the game, 0 if no association available.
|
||||
*/
|
||||
extern unsigned int RA_IdentifyHash(const char* sHash);
|
||||
|
||||
/**
|
||||
* Fetches all retroachievements related data for the specified game.
|
||||
*
|
||||
* @param nGameId the unique identifier of the game to activate
|
||||
*/
|
||||
extern void RA_ActivateGame(unsigned int nGameId);
|
||||
|
||||
/**
|
||||
* Identifies and activates the game associated to a block of memory.
|
||||
*
|
||||
* Functions as a call to RA_IdentifyRom followed by a call to RA_ActivateGame.
|
||||
*
|
||||
* @param pROMData the contents of the game file
|
||||
* @param nROMSize the size of the game file
|
||||
*/
|
||||
extern void RA_OnLoadNewRom(BYTE* pROMData, unsigned int nROMSize);
|
||||
|
||||
/**
|
||||
* Called before unloading the game to allow the user to save any changes they might have.
|
||||
*
|
||||
* @param bIsQuitting non-zero to change the messaging to indicate the emulator is closing.
|
||||
* @return zero to abort the unload. non-zero to continue.
|
||||
*/
|
||||
extern int RA_ConfirmLoadNewRom(int bIsQuitting);
|
||||
|
||||
|
||||
|
||||
/******************************
|
||||
* Runtime Functionality *
|
||||
******************************/
|
||||
|
||||
/**
|
||||
* Does all achievement-related processing for a single frame.
|
||||
*/
|
||||
extern void RA_DoAchievementsFrame(void);
|
||||
|
||||
/**
|
||||
* Temporarily disables forced updating of tool windows.
|
||||
*
|
||||
* Primarily used while fast-forwarding.
|
||||
*/
|
||||
extern void RA_SuspendRepaint(void);
|
||||
|
||||
/**
|
||||
* Resumes forced updating of tool windows.
|
||||
*/
|
||||
extern void RA_ResumeRepaint(void);
|
||||
|
||||
/**
|
||||
* [deprecated] Used to be used to ensure the asynchronous server calls are processed on the UI thread.
|
||||
* That's all managed within the DLL now. Calling this function does nothing.
|
||||
*/
|
||||
extern void RA_HandleHTTPResults(void);
|
||||
|
||||
/**
|
||||
* Adds flavor text to the application title bar.
|
||||
*
|
||||
* Application title bar is managed by the DLL. Value will be "ClientName - Version - Flavor Text - Username"
|
||||
*
|
||||
* @param sCustomMessage the flavor text to include in the title bar.
|
||||
*/
|
||||
extern void RA_UpdateAppTitle(const char* sCustomMessage);
|
||||
|
||||
/**
|
||||
* Get the user name of the currently logged in user.
|
||||
*
|
||||
* @return user name of the currently logged in user, empty if no user is logged in.
|
||||
*/
|
||||
const char* RA_UserName(void);
|
||||
|
||||
/**
|
||||
* Determines if the user is currently playing with hardcore enabled.
|
||||
*
|
||||
* The client should disable any features that would give the player an unfair advantage if this returns non-zero.
|
||||
* Things like loading states, using cheats, modifying RAM, disabling rendering layers, viewing decoded tilemaps, etc.
|
||||
*
|
||||
* @return non-zero if hardcore mode is currently active.
|
||||
*/
|
||||
extern int RA_HardcoreModeIsActive(void);
|
||||
|
||||
/**
|
||||
* Warns the user they're about to do something that will disable hardcore mode.
|
||||
*
|
||||
* @param sActivity what the user is about to do (i.e. "load a state").
|
||||
* @return non-zero if the user disabled hardcore and the activity is allowed.
|
||||
* zero if the user declined to disable hardcore and the activity should be aborted.
|
||||
*/
|
||||
extern int RA_WarnDisableHardcore(const char* sActivity);
|
||||
|
||||
/**
|
||||
* Disables hardcore mode without prompting or notifying the user.
|
||||
*
|
||||
* Should only be called if the client does its own prompting/notification.
|
||||
* Typically used when an activity cannot be aborted.
|
||||
*/
|
||||
extern void RA_DisableHardcore(void);
|
||||
|
||||
/**
|
||||
* Notifies the DLL that the game has been reset.
|
||||
*
|
||||
* Disables active leaderboards and resets hit counts on all active achievements.
|
||||
*/
|
||||
extern void RA_OnReset(void);
|
||||
|
||||
/**
|
||||
* Notifies the DLL that a save state has been created.
|
||||
*
|
||||
* Creates a .rap file next to the state file that contains achievement-related information for the save state.
|
||||
*
|
||||
* @param sFilename full path to the save state file.
|
||||
*/
|
||||
extern void RA_OnSaveState(const char* sFilename);
|
||||
|
||||
/**
|
||||
* Notifies the DLL that a save state has been loaded.
|
||||
*
|
||||
* Loads the .rap file next to the state file that contains achievement-related information for the save state being loaded.
|
||||
*
|
||||
* @param sFilename full path to the save state file.
|
||||
*/
|
||||
extern void RA_OnLoadState(const char* sFilename);
|
||||
|
||||
/**
|
||||
* Captures the current state of the achievement runtime for inclusion in a save state.
|
||||
*
|
||||
* @param pBuffer buffer to write achievement state information to
|
||||
* @param nBufferSize the size of the buffer
|
||||
* @return the number of bytes needed to capture the achievement state. if less than nBufferSize, pBuffer
|
||||
* will not be populated. the function should be called again with a larger buffer.
|
||||
*/
|
||||
extern int RA_CaptureState(char* pBuffer, int nBufferSize);
|
||||
|
||||
/**
|
||||
* Restores the state of the achievement runtime from a previously captured state.
|
||||
*
|
||||
* @param pBuffer buffer containing previously serialized achievement state information
|
||||
*/
|
||||
extern void RA_RestoreState(const char* pBuffer);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif // !RA_INTERFACE_H
|
|
@ -0,0 +1,5 @@
|
|||
# RAInterface
|
||||
|
||||
This code is intended to be loaded into another repository as a submodule.
|
||||
|
||||
An emulator should include RA_Interface.cpp in its build and link against winhttp.lib. Then, the emulator can be modified to call the hooks provided in RA_Interface.cpp at appropriate times to integrate with the RetroAchievements server via the RA_Integration.dll. See wiki for more details.
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\msvc\vsprops\Configurations.props" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{E4357877-D459-45C7-B8F6-DCBB587BB528}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="RA_Consoles.h" />
|
||||
<ClInclude Include="RA_Emulators.h" />
|
||||
<ClInclude Include="RA_Interface.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="RA_Interface.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\msvc\vsprops\StaticLibrary.props" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="..\msvc\vsprops\Targets.props" />
|
||||
</Project>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClInclude Include="RA_Emulators.h" />
|
||||
<ClInclude Include="RA_Interface.h" />
|
||||
<ClInclude Include="RA_Consoles.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="RA_Interface.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -26,10 +26,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "src\core\core.vcxpr
|
|||
{EE054E08-3799-4A59-A422-18259C105FFD} = {EE054E08-3799-4A59-A422-18259C105FFD}
|
||||
{BB08260F-6FBC-46AF-8924-090EE71360C6} = {BB08260F-6FBC-46AF-8924-090EE71360C6}
|
||||
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB} = {8906836E-F06E-46E8-B11A-74E5E8C7B8FB}
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528} = {E4357877-D459-45C7-B8F6-DCBB587BB528}
|
||||
{ED601289-AC1A-46B8-A8ED-17DB9EB73423} = {ED601289-AC1A-46B8-A8ED-17DB9EB73423}
|
||||
{09553C96-9F39-49BF-8AE6-7ACBD07C410C} = {09553C96-9F39-49BF-8AE6-7ACBD07C410C}
|
||||
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035} = {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}
|
||||
{7FF9FDB9-D504-47DB-A16A-B08071999620} = {7FF9FDB9-D504-47DB-A16A-B08071999620}
|
||||
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64} = {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stb", "dep\stb\stb.vcxproj", "{ED601289-AC1A-46B8-A8ED-17DB9EB73423}"
|
||||
|
@ -68,7 +70,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "frontend-common", "src\fron
|
|||
{933118A9-68C5-47B4-B151-B03C93961623} = {933118A9-68C5-47B4-B151-B03C93961623}
|
||||
{868B98C8-65A1-494B-8346-250A73A48C0A} = {868B98C8-65A1-494B-8346-250A73A48C0A}
|
||||
{3773F4CC-614E-4028-8595-22E08CA649E3} = {3773F4CC-614E-4028-8595-22E08CA649E3}
|
||||
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64} = {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xxhash", "dep\xxhash\xxhash.vcxproj", "{09553C96-9F39-49BF-8AE6-7ACBD07C410C}"
|
||||
|
@ -100,6 +101,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rcheevos", "dep\rcheevos\rc
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "duckstation-regtest", "src\duckstation-regtest\duckstation-regtest.vcxproj", "{3029310E-4211-4C87-801A-72E130A648EF}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rainterface", "dep\rainterface\rainterface.vcxproj", "{E4357877-D459-45C7-B8F6-DCBB587BB528}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
|
@ -912,6 +915,42 @@ Global
|
|||
{3029310E-4211-4C87-801A-72E130A648EF}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
|
||||
{3029310E-4211-4C87-801A-72E130A648EF}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
|
||||
{3029310E-4211-4C87-801A-72E130A648EF}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Debug|x64.Build.0 = Debug|x64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Debug|x86.Build.0 = Debug|Win32
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast|ARM64.ActiveCfg = DebugFast|ARM64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast|ARM64.Build.0 = DebugFast|ARM64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast|x64.ActiveCfg = DebugFast|x64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast|x64.Build.0 = DebugFast|x64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast|x86.ActiveCfg = DebugFast|Win32
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast|x86.Build.0 = DebugFast|Win32
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugUWP|x64.Build.0 = DebugUWP|x64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugUWP|x86.Build.0 = DebugUWP|Win32
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|x64.ActiveCfg = Release|x64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|x64.Build.0 = Release|x64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|x86.ActiveCfg = Release|Win32
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|x86.Build.0 = Release|Win32
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG|ARM64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.ReleaseLTCG|ARM64.Build.0 = ReleaseLTCG|ARM64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.ReleaseLTCG|x86.Build.0 = ReleaseLTCG|Win32
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -935,6 +974,7 @@ Global
|
|||
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB} = {BA490C0E-497D-4634-A21E-E65012006385}
|
||||
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3} = {BA490C0E-497D-4634-A21E-E65012006385}
|
||||
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64} = {BA490C0E-497D-4634-A21E-E65012006385}
|
||||
{E4357877-D459-45C7-B8F6-DCBB587BB528} = {BA490C0E-497D-4634-A21E-E65012006385}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {26E40B32-7C1D-48D0-95F4-1A500E054028}
|
||||
|
|
|
@ -22,11 +22,16 @@
|
|||
#include "scmversion/scmversion.h"
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
Log_SetChannel(Cheevos);
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
#include "RA_Interface.h"
|
||||
#endif
|
||||
|
||||
namespace Cheevos {
|
||||
|
||||
enum : s32
|
||||
|
@ -60,6 +65,11 @@ static bool s_unofficial_test_mode = false;
|
|||
static bool s_use_first_disc_from_playlist = true;
|
||||
static bool s_rich_presence_enabled = false;
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
bool g_using_raintegration = false;
|
||||
bool g_raintegration_initialized = false;
|
||||
#endif
|
||||
|
||||
static rc_runtime_t s_rcheevos_runtime;
|
||||
static std::unique_ptr<FrontendCommon::HTTPDownloader> s_http_downloader;
|
||||
|
||||
|
@ -244,6 +254,10 @@ bool Initialize(bool test_mode, bool use_first_disc_from_playlist, bool enable_r
|
|||
|
||||
g_active = true;
|
||||
g_challenge_mode = challenge_mode;
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
g_using_raintegration = false;
|
||||
#endif
|
||||
|
||||
s_test_mode = test_mode;
|
||||
s_unofficial_test_mode = include_unofficial;
|
||||
s_use_first_disc_from_playlist = use_first_disc_from_playlist;
|
||||
|
@ -266,6 +280,14 @@ void Reset()
|
|||
if (!g_active)
|
||||
return;
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
if (IsUsingRAIntegration())
|
||||
{
|
||||
RA_OnReset();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Log_DevPrint("Resetting rcheevos state...");
|
||||
rc_runtime_reset(&s_rcheevos_runtime);
|
||||
}
|
||||
|
@ -298,6 +320,16 @@ void Update()
|
|||
|
||||
if (HasActiveGame())
|
||||
{
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
if (IsUsingRAIntegration())
|
||||
{
|
||||
if (g_raintegration_initialized)
|
||||
RA_DoAchievementsFrame();
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
rc_runtime_do_frame(&s_rcheevos_runtime, &CheevosEventHandler, &CheevosPeek, nullptr, nullptr);
|
||||
UpdateRichPresence();
|
||||
|
||||
|
@ -332,7 +364,20 @@ bool DoState(StateWrapper& sw)
|
|||
{
|
||||
// reset runtime, no data (state might've been created without cheevos)
|
||||
Log_DevPrintf("State is missing cheevos data, resetting runtime");
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
if (IsUsingRAIntegration())
|
||||
{
|
||||
if (g_raintegration_initialized)
|
||||
RA_OnReset();
|
||||
}
|
||||
else
|
||||
{
|
||||
rc_runtime_reset(&s_rcheevos_runtime);
|
||||
}
|
||||
#else
|
||||
rc_runtime_reset(&s_rcheevos_runtime);
|
||||
#endif
|
||||
|
||||
return !sw.HasError();
|
||||
}
|
||||
|
||||
|
@ -341,22 +386,54 @@ bool DoState(StateWrapper& sw)
|
|||
if (sw.HasError())
|
||||
return false;
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
if (IsUsingRAIntegration() && g_raintegration_initialized)
|
||||
{
|
||||
RA_RestoreState(reinterpret_cast<const char*>(data.get()));
|
||||
}
|
||||
else
|
||||
{
|
||||
const int result = rc_runtime_deserialize_progress(&s_rcheevos_runtime, data.get(), nullptr);
|
||||
if (result != RC_OK)
|
||||
{
|
||||
Log_WarningPrintf("Failed to deserialize cheevos state (%d), resetting", result);
|
||||
rc_runtime_reset(&s_rcheevos_runtime);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 data_size;
|
||||
std::unique_ptr<u8[]> data;
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
if (IsUsingRAIntegration())
|
||||
{
|
||||
if (g_raintegration_initialized)
|
||||
{
|
||||
const int size = RA_CaptureState(nullptr, 0);
|
||||
|
||||
data_size = (size >= 0) ? static_cast<u32>(size) : 0;
|
||||
data = std::unique_ptr<u8[]>(new u8[data_size]);
|
||||
|
||||
const int result = RA_CaptureState(reinterpret_cast<char*>(data.get()), static_cast<int>(data_size));
|
||||
if (result != static_cast<int>(data_size))
|
||||
{
|
||||
Log_WarningPrint("Failed to serialize cheevos state from RAIntegration.");
|
||||
data_size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// internally this happens twice.. not great.
|
||||
const int size = rc_runtime_progress_size(&s_rcheevos_runtime, nullptr);
|
||||
|
||||
u32 data_size = (size >= 0) ? static_cast<u32>(size) : 0;
|
||||
std::unique_ptr<u8[]> data(new u8[data_size]);
|
||||
data_size = (size >= 0) ? static_cast<u32>(size) : 0;
|
||||
data = std::unique_ptr<u8[]>(new u8[data_size]);
|
||||
|
||||
const int result = rc_runtime_serialize_progress(data.get(), &s_rcheevos_runtime, nullptr);
|
||||
if (result != RC_OK)
|
||||
|
@ -365,6 +442,8 @@ bool DoState(StateWrapper& sw)
|
|||
Log_WarningPrintf("Failed to serialize cheevos state (%d)", result);
|
||||
data_size = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
sw.Do(&data_size);
|
||||
if (data_size > 0)
|
||||
|
@ -468,7 +547,7 @@ bool LoginAsync(const char* username, const char* password)
|
|||
{
|
||||
s_http_downloader->WaitForAllRequests();
|
||||
|
||||
if (s_logged_in || std::strlen(username) == 0 || std::strlen(password) == 0)
|
||||
if (s_logged_in || std::strlen(username) == 0 || std::strlen(password) == 0 || IsUsingRAIntegration())
|
||||
return false;
|
||||
|
||||
if (ImGuiFullscreen::IsInitialized())
|
||||
|
@ -487,7 +566,7 @@ bool Login(const char* username, const char* password)
|
|||
if (g_active)
|
||||
s_http_downloader->WaitForAllRequests();
|
||||
|
||||
if (s_logged_in || std::strlen(username) == 0 || std::strlen(password) == 0)
|
||||
if (s_logged_in || std::strlen(username) == 0 || std::strlen(password) == 0 || IsUsingRAIntegration())
|
||||
return false;
|
||||
|
||||
if (g_active)
|
||||
|
@ -1016,7 +1095,9 @@ static void GetGameIdCallback(s32 status_code, const FrontendCommon::HTTPDownloa
|
|||
|
||||
const u32 game_id = (doc.HasMember("GameID") && doc["GameID"].IsUint()) ? doc["GameID"].GetUint() : 0;
|
||||
Log_InfoPrintf("Server returned GameID %u", game_id);
|
||||
if (game_id != 0)
|
||||
if (game_id == 0)
|
||||
return;
|
||||
|
||||
GetPatches(game_id);
|
||||
}
|
||||
|
||||
|
@ -1089,6 +1170,14 @@ void GameChanged(const std::string& path, CDImage* image)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
if (IsUsingRAIntegration())
|
||||
{
|
||||
RAIntegration::GameChanged();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
char url[256];
|
||||
int res = rc_url_get_gameid(url, sizeof(url), s_game_hash.c_str());
|
||||
Assert(res == 0);
|
||||
|
@ -1492,4 +1581,184 @@ unsigned CheevosPeek(unsigned address, unsigned num_bytes, void* ud)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
|
||||
#include "RA_Consoles.h"
|
||||
|
||||
static int RACallbackIsActive();
|
||||
static void RACallbackCauseUnpause();
|
||||
static void RACallbackCausePause();
|
||||
static void RACallbackRebuildMenu();
|
||||
static void RACallbackEstimateTitle(char* buf);
|
||||
static void RACallbackResetEmulator();
|
||||
static void RACallbackLoadROM(const char* unused);
|
||||
static unsigned char RACallbackReadMemory(unsigned int address);
|
||||
static void RACallbackWriteMemory(unsigned int address, unsigned char value);
|
||||
|
||||
void SwitchToRAIntegration()
|
||||
{
|
||||
g_using_raintegration = true;
|
||||
g_raintegration_initialized = false;
|
||||
g_active = true;
|
||||
s_logged_in = true;
|
||||
}
|
||||
|
||||
static void InitializeRAIntegration(void* main_window_handle)
|
||||
{
|
||||
RA_InitClient((HWND)main_window_handle, "DuckStation", g_scm_tag_str);
|
||||
RA_SetUserAgentDetail(Cheevos::GetUserAgent().c_str());
|
||||
|
||||
RA_InstallSharedFunctions(RACallbackIsActive, RACallbackCauseUnpause, RACallbackCausePause, RACallbackRebuildMenu,
|
||||
RACallbackEstimateTitle, RACallbackResetEmulator, RACallbackLoadROM);
|
||||
RA_SetConsoleID(PlayStation);
|
||||
|
||||
// Apparently this has to be done early, or the memory inspector doesn't work.
|
||||
// That's a bit unfortunate, because the RAM size can vary between games, and depending on the option.
|
||||
RA_InstallMemoryBank(0, RACallbackReadMemory, RACallbackWriteMemory, Bus::RAM_2MB_SIZE);
|
||||
|
||||
// Fire off a login anyway. Saves going into the menu and doing it.
|
||||
RA_AttemptLogin(0);
|
||||
|
||||
g_challenge_mode = RA_HardcoreModeIsActive() != 0;
|
||||
g_raintegration_initialized = true;
|
||||
|
||||
// this is pretty lame, but we may as well persist until we exit anyway
|
||||
std::atexit(RA_Shutdown);
|
||||
}
|
||||
|
||||
void RAIntegration::MainWindowChanged(void* new_handle)
|
||||
{
|
||||
if (g_raintegration_initialized)
|
||||
{
|
||||
RA_UpdateHWnd((HWND)new_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeRAIntegration(new_handle);
|
||||
}
|
||||
|
||||
void RAIntegration::GameChanged()
|
||||
{
|
||||
g_game_id = RA_IdentifyHash(s_game_hash.c_str());
|
||||
RA_ActivateGame(g_game_id);
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, const char*>> RAIntegration::GetMenuItems()
|
||||
{
|
||||
// NOTE: I *really* don't like doing this. But sadly it's the only way we can integrate with Qt.
|
||||
static constexpr int IDM_RA_RETROACHIEVEMENTS = 1700;
|
||||
static constexpr int IDM_RA_OVERLAYSETTINGS = 1701;
|
||||
static constexpr int IDM_RA_FILES_MEMORYBOOKMARKS = 1703;
|
||||
static constexpr int IDM_RA_FILES_ACHIEVEMENTS = 1704;
|
||||
static constexpr int IDM_RA_FILES_MEMORYFINDER = 1705;
|
||||
static constexpr int IDM_RA_FILES_LOGIN = 1706;
|
||||
static constexpr int IDM_RA_FILES_LOGOUT = 1707;
|
||||
static constexpr int IDM_RA_FILES_ACHIEVEMENTEDITOR = 1708;
|
||||
static constexpr int IDM_RA_HARDCORE_MODE = 1710;
|
||||
static constexpr int IDM_RA_REPORTBROKENACHIEVEMENTS = 1711;
|
||||
static constexpr int IDM_RA_GETROMCHECKSUM = 1712;
|
||||
static constexpr int IDM_RA_OPENUSERPAGE = 1713;
|
||||
static constexpr int IDM_RA_OPENGAMEPAGE = 1714;
|
||||
static constexpr int IDM_RA_PARSERICHPRESENCE = 1716;
|
||||
static constexpr int IDM_RA_TOGGLELEADERBOARDS = 1717;
|
||||
static constexpr int IDM_RA_NON_HARDCORE_WARNING = 1718;
|
||||
|
||||
std::vector<std::pair<int, const char*>> ret;
|
||||
|
||||
const char* username = RA_UserName();
|
||||
if (!username || std::strlen(username) == 0)
|
||||
{
|
||||
ret.emplace_back(IDM_RA_FILES_LOGIN, "&Login");
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.emplace_back(IDM_RA_FILES_LOGOUT, "Log&out");
|
||||
ret.emplace_back(0, nullptr);
|
||||
ret.emplace_back(IDM_RA_OPENUSERPAGE, "Open my &User Page");
|
||||
ret.emplace_back(IDM_RA_OPENGAMEPAGE, "Open this &Game's Page");
|
||||
ret.emplace_back(0, nullptr);
|
||||
ret.emplace_back(IDM_RA_HARDCORE_MODE, "&Hardcore Mode");
|
||||
ret.emplace_back(IDM_RA_NON_HARDCORE_WARNING, "Non-Hardcore &Warning");
|
||||
ret.emplace_back(0, nullptr);
|
||||
ret.emplace_back(IDM_RA_TOGGLELEADERBOARDS, "Enable &Leaderboards");
|
||||
ret.emplace_back(IDM_RA_OVERLAYSETTINGS, "O&verlay Settings");
|
||||
ret.emplace_back(0, nullptr);
|
||||
ret.emplace_back(IDM_RA_FILES_ACHIEVEMENTS, "Assets Li&st");
|
||||
ret.emplace_back(IDM_RA_FILES_ACHIEVEMENTEDITOR, "Assets &Editor");
|
||||
ret.emplace_back(IDM_RA_FILES_MEMORYFINDER, "&Memory Inspector");
|
||||
ret.emplace_back(IDM_RA_FILES_MEMORYBOOKMARKS, "Memory &Bookmarks");
|
||||
ret.emplace_back(IDM_RA_PARSERICHPRESENCE, "Rich &Presence Monitor");
|
||||
ret.emplace_back(0, nullptr);
|
||||
ret.emplace_back(IDM_RA_REPORTBROKENACHIEVEMENTS, "&Report Achievement Problem");
|
||||
ret.emplace_back(IDM_RA_GETROMCHECKSUM, "View Game H&ash");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RAIntegration::ActivateMenuItem(int item)
|
||||
{
|
||||
RA_InvokeDialog(item);
|
||||
}
|
||||
|
||||
int RACallbackIsActive()
|
||||
{
|
||||
return static_cast<int>(HasActiveGame());
|
||||
}
|
||||
|
||||
void RACallbackCauseUnpause()
|
||||
{
|
||||
if (System::IsValid())
|
||||
g_host_interface->PauseSystem(false);
|
||||
}
|
||||
|
||||
void RACallbackCausePause()
|
||||
{
|
||||
if (System::IsValid())
|
||||
g_host_interface->PauseSystem(true);
|
||||
}
|
||||
|
||||
void RACallbackRebuildMenu()
|
||||
{
|
||||
// unused, we build the menu on demand
|
||||
}
|
||||
|
||||
void RACallbackEstimateTitle(char* buf)
|
||||
{
|
||||
StringUtil::Strlcpy(buf, System::GetRunningTitle(), 256);
|
||||
}
|
||||
|
||||
void RACallbackResetEmulator()
|
||||
{
|
||||
g_challenge_mode = RA_HardcoreModeIsActive() != 0;
|
||||
if (System::IsValid())
|
||||
g_host_interface->ResetSystem();
|
||||
}
|
||||
|
||||
void RACallbackLoadROM(const char* unused)
|
||||
{
|
||||
// unused
|
||||
UNREFERENCED_PARAMETER(unused);
|
||||
}
|
||||
|
||||
unsigned char RACallbackReadMemory(unsigned int address)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return 0;
|
||||
|
||||
u8 value = 0;
|
||||
CPU::SafeReadMemoryByte(address, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void RACallbackWriteMemory(unsigned int address, unsigned char value)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return;
|
||||
|
||||
CPU::SafeWriteMemoryByte(address, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Cheevos
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class CDImage;
|
||||
class StateWrapper;
|
||||
|
@ -51,6 +53,25 @@ extern bool g_active;
|
|||
extern bool g_challenge_mode;
|
||||
extern u32 g_game_id;
|
||||
|
||||
// RAIntegration only exists for Windows, so no point checking it on other platforms.
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
|
||||
extern bool g_using_raintegration;
|
||||
|
||||
static ALWAYS_INLINE bool IsUsingRAIntegration()
|
||||
{
|
||||
return g_using_raintegration;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static ALWAYS_INLINE bool IsUsingRAIntegration()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE bool IsActive()
|
||||
{
|
||||
return g_active;
|
||||
|
@ -123,4 +144,15 @@ TinyString GetAchievementProgressText(const Achievement& achievement);
|
|||
void UnlockAchievement(u32 achievement_id, bool add_notification = true);
|
||||
void SubmitLeaderboard(u32 leaderboard_id, int value);
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
void SwitchToRAIntegration();
|
||||
|
||||
namespace RAIntegration {
|
||||
void MainWindowChanged(void* new_handle);
|
||||
void GameChanged();
|
||||
std::vector<std::pair<int, const char*>> GetMenuItems();
|
||||
void ActivateMenuItem(int item);
|
||||
} // namespace RAIntegration
|
||||
#endif
|
||||
|
||||
} // namespace Cheevos
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WITH_CHEEVOS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="'$(Platform)'=='x64' Or '$(Platform)'=='ARM' Or '$(Platform)'=='ARM64'">WITH_RECOMPILER=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="('$(BuildingForUWP)'!='true' And '$(Platform)'!='ARM64')">WITH_RAINTEGRATION=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM' Or '$(Platform)'=='ARM64')">WITH_RECOMPILER=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM64') And ('$(BuildingForUWP)'!='true')">WITH_MMAP_FASTMEM=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xxhash\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\rcheevos\include;$(SolutionDir)dep\rapidjson\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="('$(BuildingForUWP)'!='true' And '$(Platform)'!='ARM64')">$(SolutionDir)dep\rainterface;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
||||
<AdditionalIncludeDirectories Condition="'$(Platform)'=='x64'">$(SolutionDir)dep\xbyak\xbyak;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Platform)'=='ARM' Or '$(Platform)'=='ARM64'">$(SolutionDir)dep\vixl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
@ -18,6 +20,7 @@
|
|||
<ItemDefinitionGroup>
|
||||
<Lib>
|
||||
<AdditionalDependencies>$(RootBuildDir)rcheevos\rcheevos.lib;$(RootBuildDir)imgui\imgui.lib;$(RootBuildDir)stb\stb.lib;$(RootBuildDir)vulkan-loader\vulkan-loader.lib;$(RootBuildDir)xxhash\xxhash.lib;$(RootBuildDir)zlib\zlib.lib;$(RootBuildDir)common\common.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies Condition="('$(BuildingForUWP)'!='true' And '$(Platform)'!='ARM64')">$(RootBuildDir)rainterface\rainterface.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies Condition="'$(Platform)'=='ARM64'">$(RootBuildDir)vixl\vixl.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
#include "scmversion/scmversion.h"
|
||||
#include "settingsdialog.h"
|
||||
#include "settingwidgetbinder.h"
|
||||
|
||||
#ifdef WITH_CHEEVOS
|
||||
#include "core/cheevos.h"
|
||||
#endif
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
@ -101,6 +106,11 @@ void MainWindow::initializeAndShow()
|
|||
switchToGameListView();
|
||||
|
||||
show();
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
if (Cheevos::IsUsingRAIntegration())
|
||||
Cheevos::RAIntegration::MainWindowChanged((void*)winId());
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::reportError(const QString& message)
|
||||
|
@ -991,6 +1001,33 @@ void MainWindow::setupAdditionalUi()
|
|||
connect(action, &QAction::triggered,
|
||||
[scale]() { QtHostInterface::GetInstance()->requestRenderWindowScale(scale); });
|
||||
}
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
if (Cheevos::IsUsingRAIntegration())
|
||||
{
|
||||
QMenu* raMenu = new QMenu(QStringLiteral("RAIntegration"), m_ui.menuDebug);
|
||||
connect(raMenu, &QMenu::aboutToShow, this, [this, raMenu]() {
|
||||
raMenu->clear();
|
||||
|
||||
const auto items = Cheevos::RAIntegration::GetMenuItems();
|
||||
for (const auto& [id, title] : items)
|
||||
{
|
||||
if (id == 0)
|
||||
{
|
||||
raMenu->addSeparator();
|
||||
continue;
|
||||
}
|
||||
|
||||
QAction* raAction = raMenu->addAction(QString::fromUtf8(title));
|
||||
connect(raAction, &QAction::triggered, this, [id]() {
|
||||
QtHostInterface::GetInstance()->executeOnEmulationThread(
|
||||
[id]() { Cheevos::RAIntegration::ActivateMenuItem(id); });
|
||||
});
|
||||
}
|
||||
});
|
||||
m_ui.menuDebug->insertMenu(m_ui.menuCPUExecutionMode->menuAction(), raMenu);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::updateEmulationActions(bool starting, bool running, bool cheevos_challenge_mode)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#ifdef WITH_CHEEVOS
|
||||
#include "achievementsettingswidget.h"
|
||||
#include "core/cheevos.h"
|
||||
#endif
|
||||
|
||||
static constexpr char DEFAULT_SETTING_HELP_TEXT[] = "";
|
||||
|
@ -45,6 +46,7 @@ SettingsDialog::SettingsDialog(QtHostInterface* host_interface, QWidget* parent
|
|||
m_advanced_settings = new AdvancedSettingsWidget(host_interface, m_ui.settingsContainer, this);
|
||||
|
||||
#ifdef WITH_CHEEVOS
|
||||
if (!Cheevos::IsUsingRAIntegration())
|
||||
m_achievement_settings = new AchievementSettingsWidget(host_interface, m_ui.settingsContainer, this);
|
||||
#endif
|
||||
|
||||
|
@ -62,7 +64,18 @@ SettingsDialog::SettingsDialog(QtHostInterface* host_interface, QWidget* parent
|
|||
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::AudioSettings), m_audio_settings);
|
||||
|
||||
#ifdef WITH_CHEEVOS
|
||||
if (Cheevos::IsUsingRAIntegration())
|
||||
{
|
||||
QLabel* placeholder_label =
|
||||
new QLabel(QStringLiteral("RAIntegration is being used, built-in RetroAchievements support is disabled."),
|
||||
m_ui.settingsContainer);
|
||||
placeholder_label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::AchievementSettings), placeholder_label);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::AchievementSettings), m_achievement_settings);
|
||||
}
|
||||
#else
|
||||
QLabel* placeholder_label =
|
||||
new QLabel(tr("This DuckStation build was not compiled with RetroAchievements support."), m_ui.settingsContainer);
|
||||
|
|
|
@ -113,6 +113,11 @@ bool CommonHostInterface::Initialize()
|
|||
CreateImGuiContext();
|
||||
|
||||
#ifdef WITH_CHEEVOS
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
if (GetBoolSettingValue("Cheevos", "UseRAIntegration", false))
|
||||
Cheevos::SwitchToRAIntegration();
|
||||
#endif
|
||||
|
||||
UpdateCheevosActive();
|
||||
#endif
|
||||
|
||||
|
@ -3287,6 +3292,10 @@ void CommonHostInterface::SetDefaultSettings(SettingsInterface& si)
|
|||
si.SetBoolValue("Cheevos", "UseFirstDiscFromPlaylist", true);
|
||||
si.DeleteValue("Cheevos", "Username");
|
||||
si.DeleteValue("Cheevos", "Token");
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
si.SetBoolValue("Cheevos", "UseRAIntegration", false);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -4377,6 +4386,11 @@ void CommonHostInterface::UpdateCheevosActive()
|
|||
const bool cheevos_rich_presence = GetBoolSettingValue("Cheevos", "RichPresence", true);
|
||||
const bool cheevos_hardcore = GetBoolSettingValue("Cheevos", "ChallengeMode", false);
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
if (Cheevos::IsUsingRAIntegration())
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (cheevos_enabled != Cheevos::IsActive() || cheevos_test_mode != Cheevos::IsTestModeActive() ||
|
||||
cheevos_unofficial_test_mode != Cheevos::IsUnofficialTestModeActive() ||
|
||||
cheevos_use_first_disc_from_playlist != Cheevos::IsUsingFirstDiscFromPlaylist() ||
|
||||
|
|
|
@ -2328,6 +2328,17 @@ void DrawSettingsWindow()
|
|||
|
||||
case SettingsPage::AchievementsSetings:
|
||||
{
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
if (Cheevos::IsUsingRAIntegration())
|
||||
{
|
||||
BeginMenuButtons();
|
||||
ActiveButton(ICON_FA_BAN " RAIntegration is being used instead of the built-in cheevos implementation.",
|
||||
false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
|
||||
EndMenuButtons();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_CHEEVOS
|
||||
BeginMenuButtons();
|
||||
|
||||
|
|
Loading…
Reference in New Issue