Merge pull request #18468 from hrydgard/more-retroachievements-tweaks

RetroAchievements: Show rich presence message on pause screen, restriction tweaks
This commit is contained in:
Henrik Rydgård 2023-12-03 17:53:21 +01:00 committed by GitHub
commit 1065e18521
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 71 additions and 53 deletions

View File

@ -310,7 +310,7 @@ static const ConfigSetting achievementSettings[] = {
ConfigSetting("AchievementsEncoreMode", &g_Config.bAchievementsEncoreMode, false, CfgFlag::DEFAULT),
ConfigSetting("AchievementsUnofficial", &g_Config.bAchievementsUnofficial, false, CfgFlag::DEFAULT),
ConfigSetting("AchievementsLogBadMemReads", &g_Config.bAchievementsLogBadMemReads, false, CfgFlag::DEFAULT),
ConfigSetting("bAchievementsSaveStateInChallengeMode", &g_Config.bAchievementsSaveStateInChallengeMode, false, CfgFlag::DEFAULT),
ConfigSetting("bAchievementsSaveStateInChallengeMode", &g_Config.bAchievementsSaveStateInHardcoreMode, false, CfgFlag::DEFAULT),
// Achievements login info. Note that password is NOT stored, only a login token.
// And that login token is stored separately from the ini, see NativeSaveSecret, but it can also be loaded

View File

@ -513,7 +513,7 @@ public:
bool bAchievementsUnofficial;
bool bAchievementsSoundEffects;
bool bAchievementsLogBadMemReads;
bool bAchievementsSaveStateInChallengeMode;
bool bAchievementsSaveStateInHardcoreMode;
// Positioning of the various notifications
int iAchievementsLeaderboardTrackerPos;

View File

@ -320,7 +320,7 @@ void __CheatDoState(PointerWrap &p) {
}
void hleCheat(u64 userdata, int cyclesLate) {
bool shouldBeEnabled = !Achievements::ChallengeModeActive() && g_Config.bEnableCheats;
bool shouldBeEnabled = !Achievements::HardcoreModeActive() && g_Config.bEnableCheats;
if (cheatsEnabled != shouldBeEnabled) {
// Okay, let's move to the desired state, then.
@ -1196,7 +1196,7 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat,
}
void CWCheatEngine::Run() {
if (Achievements::ChallengeModeActive()) {
if (Achievements::HardcoreModeActive()) {
return;
}
@ -1214,7 +1214,7 @@ bool CWCheatEngine::HasCheats() {
}
bool CheatsInEffect() {
if (!cheatEngine || !cheatsEnabled || Achievements::ChallengeModeActive())
if (!cheatEngine || !cheatsEnabled || Achievements::HardcoreModeActive())
return false;
return cheatEngine->HasCheats();
}

View File

@ -351,7 +351,7 @@ void __DisplaySetWasPaused() {
// TOOD: Should return 59.997?
static int FrameTimingLimit() {
bool challenge = Achievements::ChallengeModeActive();
bool challenge = Achievements::HardcoreModeActive();
auto fixRate = [=](int limit) {
int minRate = challenge ? 60 : 1;

View File

@ -77,6 +77,7 @@ std::string s_game_hash;
std::set<uint32_t> g_activeChallenges;
bool g_isIdentifying = false;
bool g_isLoggingIn = false;
bool g_hasRichPresence = false;
int g_loginResult;
double g_lastLoginAttemptTime;
@ -104,6 +105,19 @@ bool IsLoggedIn() {
return rc_client_get_user_info(g_rcClient) != nullptr && !g_isLoggingIn;
}
// This is the RetroAchievements game ID, rather than the PSP game ID.
static u32 GetGameID() {
if (!g_rcClient) {
return 0;
}
const rc_client_game_t *info = rc_client_get_game_info(g_rcClient);
if (!info) {
return 0;
}
return info->id; // 0 if not identified
}
bool EncoreModeActive() {
if (!g_rcClient) {
return false;
@ -118,15 +132,23 @@ bool UnofficialEnabled() {
return rc_client_get_unofficial_enabled(g_rcClient);
}
bool ChallengeModeActive() {
bool HardcoreModeActive() {
if (!g_rcClient) {
return false;
}
return IsLoggedIn() && rc_client_get_hardcore_enabled(g_rcClient);
// See "Enabling Hardcore" under https://github.com/RetroAchievements/rcheevos/wiki/rc_client-integration.
return IsLoggedIn() && rc_client_get_hardcore_enabled(g_rcClient) && rc_client_is_processing_required(g_rcClient);
}
bool WarnUserIfChallengeModeActive(bool isSaveStateAction, const char *message) {
if (!ChallengeModeActive() || (isSaveStateAction && g_Config.bAchievementsSaveStateInChallengeMode)) {
size_t GetRichPresenceMessage(char *buffer, size_t bufSize) {
if (!IsLoggedIn() || !rc_client_has_rich_presence(g_rcClient)) {
return (size_t)-1;
}
return rc_client_get_rich_presence_message(g_rcClient, buffer, bufSize);
}
bool WarnUserIfHardcoreModeActive(bool isSaveStateAction, const char *message) {
if (!HardcoreModeActive() || (isSaveStateAction && g_Config.bAchievementsSaveStateInHardcoreMode)) {
return false;
}
@ -148,19 +170,6 @@ bool IsBlockingExecution() {
return g_isLoggingIn || g_isIdentifying;
}
// This is the RetroAchievements game ID, rather than the PSP game ID.
static u32 GetGameID() {
if (!g_rcClient) {
return 0;
}
const rc_client_game_t *info = rc_client_get_game_info(g_rcClient);
if (!info) {
return 0;
}
return info->id; // 0 if not identified
}
bool IsActive() {
return GetGameID() != 0;
}
@ -730,7 +739,7 @@ std::string GetGameAchievementSummary() {
summaryString = ApplySafeSubstitutions(ac->T("Earned", "You have unlocked %1 of %2 achievements, earning %3 of %4 points"),
summary.num_unlocked_achievements, summary.num_core_achievements + summary.num_unofficial_achievements,
summary.points_unlocked, summary.points_core);
if (ChallengeModeActive()) {
if (HardcoreModeActive()) {
summaryString.append("\n");
summaryString.append(ac->T("Hardcore Mode"));
}

View File

@ -68,14 +68,17 @@ bool IsBlockingExecution();
//
// * Savestates
// * Slowdown time (though hard to fully prevent, could use crazy post shaders or software rendering...)
bool ChallengeModeActive();
bool HardcoreModeActive();
// Same as ChallengeModeActive but comes with a convenient user message. Don't use for every-frame checks or UI enablement,
// only for shortcut keys and commands. You should look up the message in I18NCat::ACHIEVEMENTS.
// If no message is specified, a standard "This feature is not available in Hardcore Mode" message will be shown.
// Also returns true if hardcore mode is active.
// Specify isSaveAction so we can still permit saves (but not loads) in hardcore mode if that option is enabled.
bool WarnUserIfChallengeModeActive(bool isSaveStateAction, const char *message = nullptr);
bool WarnUserIfHardcoreModeActive(bool isSaveStateAction, const char *message = nullptr);
// Returns the length of the string. If (size_t)-1, there's no message.
size_t GetRichPresenceMessage(char *buffer, size_t bufSize);
// The new API is so much nicer that we can use it directly instead of wrapping it. So let's expose the client.
// Will of course return nullptr if not active.

View File

@ -399,8 +399,8 @@ namespace SaveState
void Enqueue(SaveState::Operation op)
{
if (Achievements::ChallengeModeActive()) {
if (g_Config.bAchievementsSaveStateInChallengeMode && (op.type == SaveState::SAVESTATE_SAVE) || (op.type == SAVESTATE_SAVE_SCREENSHOT)) {
if (Achievements::HardcoreModeActive()) {
if (g_Config.bAchievementsSaveStateInHardcoreMode && (op.type == SaveState::SAVESTATE_SAVE) || (op.type == SAVESTATE_SAVE_SCREENSHOT)) {
// We allow saving in hardcore mode if this setting is on.
} else {
// Operation not allowed

View File

@ -368,7 +368,7 @@ void EmuScreen::bootComplete() {
System_Notify(SystemNotification::DISASSEMBLY);
NOTICE_LOG(BOOT, "Booted %s...", PSP_CoreParameter().fileToStart.c_str());
if (!Achievements::ChallengeModeActive()) {
if (!Achievements::HardcoreModeActive()) {
// Don't auto-load savestates in hardcore mode.
autoLoad();
}
@ -680,7 +680,7 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
break;
case VIRTKEY_FRAME_ADVANCE:
if (!Achievements::WarnUserIfChallengeModeActive(false)) {
if (!Achievements::WarnUserIfHardcoreModeActive(false)) {
if (down) {
// If game is running, pause emulation immediately. Otherwise, advance a single frame.
if (Core_IsStepping()) {
@ -738,7 +738,7 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
#endif
case VIRTKEY_REWIND:
if (down && !Achievements::WarnUserIfChallengeModeActive(false)) {
if (down && !Achievements::WarnUserIfHardcoreModeActive(false)) {
if (SaveState::CanRewind()) {
SaveState::Rewind(&AfterSaveStateAction);
} else {
@ -747,23 +747,23 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
}
break;
case VIRTKEY_SAVE_STATE:
if (down && !Achievements::WarnUserIfChallengeModeActive(true)) {
if (down && !Achievements::WarnUserIfHardcoreModeActive(true)) {
SaveState::SaveSlot(gamePath_, g_Config.iCurrentStateSlot, &AfterSaveStateAction);
}
break;
case VIRTKEY_LOAD_STATE:
if (down && !Achievements::WarnUserIfChallengeModeActive(false)) {
if (down && !Achievements::WarnUserIfHardcoreModeActive(false)) {
SaveState::LoadSlot(gamePath_, g_Config.iCurrentStateSlot, &AfterSaveStateAction);
}
break;
case VIRTKEY_PREVIOUS_SLOT:
if (down && !Achievements::WarnUserIfChallengeModeActive(true)) {
if (down && !Achievements::WarnUserIfHardcoreModeActive(true)) {
SaveState::PrevSlot();
System_PostUIMessage(UIMessage::SAVESTATE_DISPLAY_SLOT);
}
break;
case VIRTKEY_NEXT_SLOT:
if (down && !Achievements::WarnUserIfChallengeModeActive(true)) {
if (down && !Achievements::WarnUserIfHardcoreModeActive(true)) {
SaveState::NextSlot();
System_PostUIMessage(UIMessage::SAVESTATE_DISPLAY_SLOT);
}

View File

@ -200,7 +200,7 @@ SaveSlotView::SaveSlotView(const Path &gameFilename, int slot, bool vertical, UI
fv->OnClick.Handle(this, &SaveSlotView::OnScreenshotClick);
if (SaveState::HasSaveInSlot(gamePath_, slot)) {
if (!Achievements::ChallengeModeActive()) {
if (!Achievements::HardcoreModeActive()) {
loadStateButton_ = buttons->Add(new Button(pa->T("Load State"), new LinearLayoutParams(0.0, G_VCENTER)));
loadStateButton_->OnClick.Handle(this, &SaveSlotView::OnLoadState);
}
@ -288,7 +288,7 @@ void GamePauseScreen::CreateSavestateControls(UI::LinearLayout *leftColumnItems,
leftColumnItems->Add(new Spacer(0.0));
LinearLayout *buttonRow = leftColumnItems->Add(new LinearLayout(ORIENT_HORIZONTAL));
if (g_Config.bEnableStateUndo && !Achievements::ChallengeModeActive()) {
if (g_Config.bEnableStateUndo && !Achievements::HardcoreModeActive()) {
UI::Choice *loadUndoButton = buttonRow->Add(new Choice(pa->T("Undo last load")));
loadUndoButton->SetEnabled(SaveState::HasUndoLoad(gamePath_));
loadUndoButton->OnClick.Handle(this, &GamePauseScreen::OnLoadUndo);
@ -298,7 +298,7 @@ void GamePauseScreen::CreateSavestateControls(UI::LinearLayout *leftColumnItems,
saveUndoButton->OnClick.Handle(this, &GamePauseScreen::OnLastSaveUndo);
}
if (g_Config.iRewindSnapshotInterval > 0 && !Achievements::ChallengeModeActive()) {
if (g_Config.iRewindSnapshotInterval > 0 && !Achievements::HardcoreModeActive()) {
UI::Choice *rewindButton = buttonRow->Add(new Choice(pa->T("Rewind")));
rewindButton->SetEnabled(SaveState::CanRewind());
rewindButton->OnClick.Handle(this, &GamePauseScreen::OnRewind);
@ -324,13 +324,19 @@ void GamePauseScreen::CreateViews() {
LinearLayout *leftColumnItems = new LinearLayoutList(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
leftColumn->Add(leftColumnItems);
leftColumnItems->Add(new Spacer(0.0));
leftColumnItems->SetSpacing(5.0f);
leftColumnItems->Add(new Spacer(0.0f));
if (Achievements::IsActive()) {
leftColumnItems->Add(new GameAchievementSummaryView());
leftColumnItems->Add(new Spacer(5.0));
char buf[512];
size_t sz = Achievements::GetRichPresenceMessage(buf, sizeof(buf));
if (sz != (size_t)-1) {
leftColumnItems->Add(new TextView(std::string_view(buf, sz), new UI::LinearLayoutParams(Margins(5, 5))))->SetSmall(true);
}
}
if (!Achievements::ChallengeModeActive() || g_Config.bAchievementsSaveStateInChallengeMode) {
if (!Achievements::HardcoreModeActive() || g_Config.bAchievementsSaveStateInHardcoreMode) {
CreateSavestateControls(leftColumnItems, vertical);
} else {
// Let's show the active challenges.

View File

@ -380,7 +380,7 @@ void RetroAchievementsSettingsScreen::CreateDeveloperToolsTab(UI::ViewGroup *vie
viewGroup->Add(new CheckBox(&g_Config.bAchievementsEncoreMode, ac->T("Encore Mode")))->SetEnabledPtr(&g_Config.bAchievementsEnable);
viewGroup->Add(new CheckBox(&g_Config.bAchievementsUnofficial, ac->T("Unofficial achievements")))->SetEnabledPtr(&g_Config.bAchievementsEnable);
viewGroup->Add(new CheckBox(&g_Config.bAchievementsLogBadMemReads, ac->T("Log bad memory accesses")))->SetEnabledPtr(&g_Config.bAchievementsEnable);
viewGroup->Add(new CheckBox(&g_Config.bAchievementsSaveStateInChallengeMode, ac->T("Allow Save State in Hardcore Mode (but not Load State)")))->SetEnabledPtr(&g_Config.bAchievementsEnable);
viewGroup->Add(new CheckBox(&g_Config.bAchievementsSaveStateInHardcoreMode, ac->T("Allow Save State in Hardcore Mode (but not Load State)")))->SetEnabledPtr(&g_Config.bAchievementsEnable);
}
void MeasureAchievement(const UIContext &dc, const rc_client_achievement_t *achievement, AchievementRenderStyle style, float *w, float *h) {

View File

@ -74,9 +74,9 @@ namespace MainWindow {
bool loadStateEnableBool = menuEnableBool;
bool saveStateEnableBool = menuEnableBool;
if (Achievements::ChallengeModeActive()) {
if (Achievements::HardcoreModeActive()) {
loadStateEnableBool = false;
if (!g_Config.bAchievementsSaveStateInChallengeMode) {
if (!g_Config.bAchievementsSaveStateInHardcoreMode) {
saveStateEnableBool = false;
}
}
@ -518,7 +518,7 @@ namespace MainWindow {
}
break;
case ID_FILE_LOADSTATEFILE:
if (!Achievements::WarnUserIfChallengeModeActive(false)) {
if (!Achievements::WarnUserIfHardcoreModeActive(false)) {
if (W32Util::BrowseForFileName(true, hWnd, L"Load state", 0, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) {
SetCursor(LoadCursor(0, IDC_WAIT));
SaveState::Load(Path(fn), -1, SaveStateActionFinished);
@ -526,7 +526,7 @@ namespace MainWindow {
}
break;
case ID_FILE_SAVESTATEFILE:
if (!Achievements::WarnUserIfChallengeModeActive(true)) {
if (!Achievements::WarnUserIfHardcoreModeActive(true)) {
if (W32Util::BrowseForFileName(false, hWnd, L"Save state", 0, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) {
SetCursor(LoadCursor(0, IDC_WAIT));
SaveState::Save(Path(fn), -1, SaveStateActionFinished);
@ -536,7 +536,7 @@ namespace MainWindow {
case ID_FILE_SAVESTATE_NEXT_SLOT:
{
if (!Achievements::WarnUserIfChallengeModeActive(true)) {
if (!Achievements::WarnUserIfHardcoreModeActive(true)) {
SaveState::NextSlot();
System_PostUIMessage(UIMessage::SAVESTATE_DISPLAY_SLOT);
}
@ -545,7 +545,7 @@ namespace MainWindow {
case ID_FILE_SAVESTATE_NEXT_SLOT_HC:
{
if (!Achievements::WarnUserIfChallengeModeActive(true)) {
if (!Achievements::WarnUserIfHardcoreModeActive(true)) {
if (!KeyMap::PspButtonHasMappings(VIRTKEY_NEXT_SLOT)) {
SaveState::NextSlot();
System_PostUIMessage(UIMessage::SAVESTATE_DISPLAY_SLOT);
@ -559,13 +559,13 @@ namespace MainWindow {
case ID_FILE_SAVESTATE_SLOT_3:
case ID_FILE_SAVESTATE_SLOT_4:
case ID_FILE_SAVESTATE_SLOT_5:
if (!Achievements::WarnUserIfChallengeModeActive(true)) {
if (!Achievements::WarnUserIfHardcoreModeActive(true)) {
g_Config.iCurrentStateSlot = wmId - ID_FILE_SAVESTATE_SLOT_1;
}
break;
case ID_FILE_QUICKLOADSTATE:
if (!Achievements::WarnUserIfChallengeModeActive(false)) {
if (!Achievements::WarnUserIfHardcoreModeActive(false)) {
SetCursor(LoadCursor(0, IDC_WAIT));
SaveState::LoadSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished);
}
@ -573,7 +573,7 @@ namespace MainWindow {
case ID_FILE_QUICKLOADSTATE_HC:
{
if (!Achievements::WarnUserIfChallengeModeActive(false)) {
if (!Achievements::WarnUserIfHardcoreModeActive(false)) {
if (!KeyMap::PspButtonHasMappings(VIRTKEY_LOAD_STATE)) {
SetCursor(LoadCursor(0, IDC_WAIT));
SaveState::LoadSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished);
@ -583,7 +583,7 @@ namespace MainWindow {
}
case ID_FILE_QUICKSAVESTATE:
{
if (!Achievements::WarnUserIfChallengeModeActive(true)) {
if (!Achievements::WarnUserIfHardcoreModeActive(true)) {
SetCursor(LoadCursor(0, IDC_WAIT));
SaveState::SaveSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished);
}
@ -592,7 +592,7 @@ namespace MainWindow {
case ID_FILE_QUICKSAVESTATE_HC:
{
if (!Achievements::WarnUserIfChallengeModeActive(true)) {
if (!Achievements::WarnUserIfHardcoreModeActive(true)) {
if (!KeyMap::PspButtonHasMappings(VIRTKEY_SAVE_STATE))
{
SetCursor(LoadCursor(0, IDC_WAIT));