1
0
mirror of https://github.com/dolphin-emu/dolphin synced 2024-06-28 22:46:42 +00:00

Compare commits

...

3 Commits

Author SHA1 Message Date
LillyJadeKatrin
37a9019bca
Merge 917d32d921 into 10a95a4d5b 2024-06-25 20:47:13 -04:00
LillyJadeKatrin
917d32d921 Handle Pausing in AchievementManager
There are two pieces of functionality to be added here. One, we want to disallow pausing too frequently, as it may be used as an artificial slowdown. This is handled within the client, which can tell us if a pause is allowed. Two, we want to call rc_client_idle on a periodic basis so the connection with the server can be maintained even while the emulator is paused.
2024-06-25 20:36:20 -04:00
JosJuice
01b44837f4 Android: Track whether app is in foreground 2024-06-23 18:16:33 -04:00
8 changed files with 133 additions and 6 deletions

View File

@ -6,6 +6,7 @@ import android.app.Application;
import android.content.Context;
import android.hardware.usb.UsbManager;
import org.dolphinemu.dolphinemu.utils.ActivityTracker;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
import org.dolphinemu.dolphinemu.utils.Java_GCAdapter;
import org.dolphinemu.dolphinemu.utils.Java_WiimoteAdapter;
@ -20,6 +21,7 @@ public class DolphinApplication extends Application
{
super.onCreate();
application = this;
registerActivityLifecycleCallbacks(new ActivityTracker());
VolleyUtil.init(getApplicationContext());
System.loadLibrary("main");

View File

@ -0,0 +1,41 @@
package org.dolphinemu.dolphinemu.utils
import android.app.Activity
import android.app.Application.ActivityLifecycleCallbacks
import android.os.Bundle
class ActivityTracker : ActivityLifecycleCallbacks {
val resumedActivities = HashSet<Activity>()
var backgroundExecutionAllowed = false
override fun onActivityCreated(activity: Activity, bundle: Bundle?) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityResumed(activity: Activity) {
resumedActivities.add(activity)
if (!backgroundExecutionAllowed && !resumedActivities.isEmpty()) {
backgroundExecutionAllowed = true
setBackgroundExecutionAllowedNative(true)
}
}
override fun onActivityPaused(activity: Activity) {
resumedActivities.remove(activity)
if (backgroundExecutionAllowed && resumedActivities.isEmpty()) {
backgroundExecutionAllowed = false
setBackgroundExecutionAllowedNative(false)
}
}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
companion object {
@JvmStatic
external fun setBackgroundExecutionAllowedNative(allowed: Boolean)
}
}

View File

@ -0,0 +1,21 @@
// Copyright 2024 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <jni.h>
#include "Common/Logging/Log.h"
#include "Core/AchievementManager.h"
extern "C" {
JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_utils_ActivityTracker_setBackgroundExecutionAllowedNative(
JNIEnv*, jclass, jboolean allowed)
{
// This is called with allowed == false when the app goes into the background.
// We use this to stop continuously running background threads so we don't waste battery.
INFO_LOG_FMT(CORE, "SetBackgroundExecutionAllowed {}", allowed);
AchievementManager::GetInstance().SetBackgroundExecutionAllowed(allowed);
}
}

View File

@ -1,4 +1,5 @@
add_library(main SHARED
ActivityTracker.cpp
Cheats/ARCheat.cpp
Cheats/Cheats.h
Cheats/GeckoCheat.cpp
@ -11,6 +12,7 @@ add_library(main SHARED
GameList/GameFile.cpp
GameList/GameFile.h
GameList/GameFileCache.cpp
GpuDriver.cpp
Host.cpp
Host.h
InfinityConfig.cpp
@ -32,7 +34,6 @@ add_library(main SHARED
RiivolutionPatches.cpp
SkylanderConfig.cpp
WiiUtils.cpp
GpuDriver.cpp
)
target_link_libraries(main

View File

@ -46,7 +46,10 @@ void AchievementManager::Init()
LoadDefaultBadges();
if (!m_client && Config::Get(Config::RA_ENABLED))
{
m_client = rc_client_create(MemoryVerifier, Request);
{
std::lock_guard lg{m_lock};
m_client = rc_client_create(MemoryVerifier, Request);
}
std::string host_url = Config::Get(Config::RA_HOST_URL);
if (!host_url.empty())
rc_client_set_host(m_client, host_url.c_str());
@ -158,6 +161,13 @@ bool AchievementManager::IsGameLoaded() const
return game_info && game_info->id != 0;
}
void AchievementManager::SetBackgroundExecutionAllowed(bool allowed)
{
m_background_execution_allowed = allowed;
if (allowed && Core::GetState(*AchievementManager::GetInstance().m_system) == Core::State::Paused)
DoIdle();
}
void AchievementManager::FetchPlayerBadge()
{
FetchBadge(&m_player_badge, RC_IMAGE_TYPE_USER,
@ -242,6 +252,41 @@ void AchievementManager::DoFrame()
}
}
bool AchievementManager::CanPause()
{
u32 frames_to_next_pause = 0;
bool can_pause = rc_client_can_pause(m_client, &frames_to_next_pause);
if (!can_pause)
{
OSD::AddMessage("Cannot spam pausing in hardcore mode.", OSD::Duration::VERY_LONG,
OSD::Color::RED);
OSD::AddMessage(
fmt::format("Can pause in {} seconds.", static_cast<float>(frames_to_next_pause) / 60),
OSD::Duration::VERY_LONG, OSD::Color::RED);
}
return can_pause;
}
void AchievementManager::DoIdle()
{
std::thread([this]() {
while (true)
{
Common::SleepCurrentThread(1000);
std::lock_guard lg{m_lock};
if (!m_system || Core::GetState(*m_system) != Core::State::Paused)
return;
if (!m_background_execution_allowed)
return;
Core::QueueHostJob([this](Core::System& system) {
if (!m_client || !IsGameLoaded())
return;
rc_client_idle(m_client);
});
}
}).detach();
}
std::recursive_mutex& AchievementManager::GetLock()
{
return m_lock;
@ -440,8 +485,8 @@ void AchievementManager::CloseGame()
void AchievementManager::Logout()
{
{
std::lock_guard lg{m_lock};
CloseGame();
std::lock_guard lg{m_lock};
m_player_badge.width = 0;
m_player_badge.height = 0;
m_player_badge.data.clear();
@ -457,6 +502,7 @@ void AchievementManager::Shutdown()
if (m_client)
{
CloseGame();
std::lock_guard lg{m_lock};
m_queue.Shutdown();
// DON'T log out - keep those credentials for next run.
rc_client_destroy(m_client);

View File

@ -96,12 +96,16 @@ public:
bool HasAPIToken() const;
void LoadGame(const std::string& file_path, const DiscIO::Volume* volume);
bool IsGameLoaded() const;
void SetBackgroundExecutionAllowed(bool allowed);
void FetchPlayerBadge();
void FetchGameBadges();
void DoFrame();
bool CanPause();
void DoIdle();
std::recursive_mutex& GetLock();
void SetHardcoreMode();
bool IsHardcoreModeActive() const;
@ -193,6 +197,7 @@ private:
Badge m_default_game_badge;
Badge m_default_unlocked_badge;
Badge m_default_locked_badge;
std::atomic_bool m_background_execution_allowed = true;
Badge m_player_badge;
Hash m_game_hash{};
u32 m_game_id = 0;
@ -239,6 +244,8 @@ public:
constexpr void LoadGame(const std::string&, const DiscIO::Volume*) {}
constexpr void SetBackgroundExecutionAllowed(bool allowed) {}
constexpr void DoFrame() {}
constexpr void CloseGame() {}

View File

@ -358,7 +358,7 @@ static void CPUSetInitialExecutionState(bool force_paused = false)
// SetState must be called on the host thread, so we defer it for later.
QueueHostJob([force_paused](Core::System& system) {
bool paused = SConfig::GetInstance().bBootToPause || force_paused;
SetState(system, paused ? State::Paused : State::Running);
SetState(system, paused ? State::Paused : State::Running, true, true);
Host_UpdateDisasmDialog();
Host_UpdateMainFrame();
Host_Message(HostMessageID::WMUserCreate);
@ -698,7 +698,8 @@ static void EmuThread(Core::System& system, std::unique_ptr<BootParameters> boot
// Set or get the running state
void SetState(Core::System& system, State state, bool report_state_change)
void SetState(Core::System& system, State state, bool report_state_change,
bool initial_execution_state)
{
// State cannot be controlled until the CPU Thread is operational
if (s_state.load() != State::Running)
@ -707,11 +708,18 @@ void SetState(Core::System& system, State state, bool report_state_change)
switch (state)
{
case State::Paused:
#ifdef USE_RETRO_ACHIEVEMENTS
if (!initial_execution_state && !AchievementManager::GetInstance().CanPause())
return;
#endif // USE_RETRO_ACHIEVEMENTS
// NOTE: GetState() will return State::Paused immediately, even before anything has
// stopped (including the CPU).
system.GetCPU().EnableStepping(true); // Break
Wiimote::Pause();
ResetRumble();
#ifdef USE_RETRO_ACHIEVEMENTS
AchievementManager::GetInstance().DoIdle();
#endif // USE_RETRO_ACHIEVEMENTS
break;
case State::Running:
{

View File

@ -148,7 +148,8 @@ bool IsHostThread();
bool WantsDeterminism();
// [NOT THREADSAFE] For use by Host only
void SetState(Core::System& system, State state, bool report_state_change = true);
void SetState(Core::System& system, State state, bool report_state_change = true,
bool initial_execution_state = false);
State GetState(Core::System& system);
void SaveScreenShot();