Compare commits

...

6 Commits

Author SHA1 Message Date
LillyJadeKatrin
cf20ec101c
Merge 48617a1466 into a27b845514 2025-06-07 11:56:49 -04:00
LillyJadeKatrin
48617a1466 Android Achievements - Hardcore disables
Disables state loading and emulation speeds below 100% when RetroAchievements hardcore mode is enabled.
2025-06-07 06:23:44 -04:00
LillyJadeKatrin
590df4d9b0 Add login to achievement settings 2025-06-07 06:23:20 -04:00
LillyJadeKatrin
7486518196 Add Achievements submenu to Android settings 2025-06-06 22:03:41 -04:00
LillyJadeKatrin
baabae4805 Init achievement manager in Android startup 2025-06-06 21:45:28 -04:00
JosJuice
3dd61facf0 Android: Clear listener in SwitchSettingViewHolder
If bind was called more than once for a SwitchSettingViewHolder, the
line `binding.settingSwitch.isChecked = setting.isChecked` would
accidentally trigger the listener registered during the previous bind
call.
2025-06-06 21:45:28 -04:00
16 changed files with 369 additions and 2 deletions

View File

@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
object AchievementModel {
@JvmStatic
external fun login(password: String)
@JvmStatic
external fun logout()
@JvmStatic
external fun isHardcoreModeActive(): Boolean
}

View File

@ -883,6 +883,42 @@ enum class BooleanSetting(
Settings.SECTION_LOGGER_OPTIONS, Settings.SECTION_LOGGER_OPTIONS,
"WriteToFile", "WriteToFile",
false false
),
ACHIEVEMENTS_ENABLED(
Settings.FILE_ACHIEVEMENTS,
Settings.SECTION_ACHIEVEMENTS,
"Enabled",
true
),
ACHIEVEMENTS_HARDCORE_ENABLED(
Settings.FILE_ACHIEVEMENTS,
Settings.SECTION_ACHIEVEMENTS,
"HardcoreEnabled",
false
),
ACHIEVEMENTS_UNOFFICIAL_ENABLED(
Settings.FILE_ACHIEVEMENTS,
Settings.SECTION_ACHIEVEMENTS,
"UnofficialEnabled",
false
),
ACHIEVEMENTS_ENCORE_ENABLED(
Settings.FILE_ACHIEVEMENTS,
Settings.SECTION_ACHIEVEMENTS,
"EncoreEnabled",
false
),
ACHIEVEMENTS_SPECTATOR_ENABLED(
Settings.FILE_ACHIEVEMENTS,
Settings.SECTION_ACHIEVEMENTS,
"SpectatorEnabled",
false
),
ACHIEVEMENTS_PROGRESS_ENABLED(
Settings.FILE_ACHIEVEMENTS,
Settings.SECTION_ACHIEVEMENTS,
"ProgressEnabled",
true
); );
override val isOverridden: Boolean override val isOverridden: Boolean
@ -943,7 +979,12 @@ enum class BooleanSetting(
MAIN_TIME_TRACKING, MAIN_TIME_TRACKING,
MAIN_EMULATE_SKYLANDER_PORTAL, MAIN_EMULATE_SKYLANDER_PORTAL,
MAIN_EMULATE_INFINITY_BASE, MAIN_EMULATE_INFINITY_BASE,
MAIN_EMULATE_WII_SPEAK MAIN_EMULATE_WII_SPEAK,
ACHIEVEMENTS_ENABLED,
ACHIEVEMENTS_HARDCORE_ENABLED,
ACHIEVEMENTS_UNOFFICIAL_ENABLED,
ACHIEVEMENTS_ENCORE_ENABLED,
ACHIEVEMENTS_SPECTATOR_ENABLED
) )
private val NOT_RUNTIME_EDITABLE: Set<BooleanSetting> = private val NOT_RUNTIME_EDITABLE: Set<BooleanSetting> =
HashSet(listOf(*NOT_RUNTIME_EDITABLE_ARRAY)) HashSet(listOf(*NOT_RUNTIME_EDITABLE_ARRAY))

View File

@ -120,6 +120,7 @@ class Settings : Closeable {
const val FILE_GFX = "GFX" const val FILE_GFX = "GFX"
const val FILE_LOGGER = "Logger" const val FILE_LOGGER = "Logger"
const val FILE_WIIMOTE = "WiimoteNew" const val FILE_WIIMOTE = "WiimoteNew"
const val FILE_ACHIEVEMENTS = "RetroAchievements"
const val FILE_GAME_SETTINGS_ONLY = "GameSettingsOnly" const val FILE_GAME_SETTINGS_ONLY = "GameSettingsOnly"
const val SECTION_INI_ANDROID = "Android" const val SECTION_INI_ANDROID = "Android"
const val SECTION_INI_ANDROID_OVERLAY_BUTTONS = "AndroidOverlayButtons" const val SECTION_INI_ANDROID_OVERLAY_BUTTONS = "AndroidOverlayButtons"
@ -138,5 +139,6 @@ class Settings : Closeable {
const val SECTION_EMULATED_USB_DEVICES = "EmulatedUSBDevices" const val SECTION_EMULATED_USB_DEVICES = "EmulatedUSBDevices"
const val SECTION_STEREOSCOPY = "Stereoscopy" const val SECTION_STEREOSCOPY = "Stereoscopy"
const val SECTION_ANALYTICS = "Analytics" const val SECTION_ANALYTICS = "Analytics"
const val SECTION_ACHIEVEMENTS = "Achievements"
} }
} }

View File

@ -80,6 +80,18 @@ enum class StringSetting(
Settings.SECTION_GFX_SETTINGS, Settings.SECTION_GFX_SETTINGS,
"DriverLibName", "DriverLibName",
"" ""
),
ACHIEVEMENTS_USERNAME(
Settings.FILE_ACHIEVEMENTS,
Settings.SECTION_ACHIEVEMENTS,
"Username",
""
),
ACHIEVEMENTS_API_TOKEN(
Settings.FILE_ACHIEVEMENTS,
Settings.SECTION_ACHIEVEMENTS,
"ApiToken",
""
); );
override val isOverridden: Boolean override val isOverridden: Boolean

View File

@ -0,0 +1,51 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import org.dolphinemu.dolphinemu.databinding.FragmentLoginBinding
import org.dolphinemu.dolphinemu.features.settings.model.AchievementModel.login
import org.dolphinemu.dolphinemu.features.settings.model.NativeConfig
import org.dolphinemu.dolphinemu.features.settings.model.StringSetting
class LoginFragment : DialogFragment() {
private var _binding: FragmentLoginBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentLoginBinding.inflate(inflater, container, false)
binding.usernameInput.setText(
StringSetting.ACHIEVEMENTS_USERNAME.string
)
return binding.getRoot()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.buttonCancel.setOnClickListener { onCancelClicked() }
binding.buttonLogin.setOnClickListener { onLoginClicked() }
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private fun onCancelClicked() {
dismiss()
}
private fun onLoginClicked() {
StringSetting.ACHIEVEMENTS_USERNAME.setString(NativeConfig.LAYER_BASE_OR_CURRENT,
binding.usernameInput.text.toString())
login(binding.passwordInput.text.toString())
dismiss()
}
}

View File

@ -14,6 +14,7 @@ enum class MenuTag {
CONFIG_GAME_CUBE("config_gamecube"), CONFIG_GAME_CUBE("config_gamecube"),
CONFIG_SERIALPORT1("config_serialport1"), CONFIG_SERIALPORT1("config_serialport1"),
CONFIG_WII("config_wii"), CONFIG_WII("config_wii"),
CONFIG_ACHIEVEMENTS("config_achievements"),
CONFIG_ADVANCED("config_advanced"), CONFIG_ADVANCED("config_advanced"),
CONFIG_LOG("config_log"), CONFIG_LOG("config_log"),
DEBUG("debug"), DEBUG("debug"),

View File

@ -264,6 +264,7 @@ class SettingsFragment : Fragment(), SettingsFragmentView {
titles[MenuTag.CONFIG_GAME_CUBE] = R.string.gamecube_submenu titles[MenuTag.CONFIG_GAME_CUBE] = R.string.gamecube_submenu
titles[MenuTag.CONFIG_SERIALPORT1] = R.string.serialport1_submenu titles[MenuTag.CONFIG_SERIALPORT1] = R.string.serialport1_submenu
titles[MenuTag.CONFIG_WII] = R.string.wii_submenu titles[MenuTag.CONFIG_WII] = R.string.wii_submenu
titles[MenuTag.CONFIG_ACHIEVEMENTS] = R.string.achievements_submenu
titles[MenuTag.CONFIG_ADVANCED] = R.string.advanced_submenu titles[MenuTag.CONFIG_ADVANCED] = R.string.advanced_submenu
titles[MenuTag.DEBUG] = R.string.debug_submenu titles[MenuTag.DEBUG] = R.string.debug_submenu
titles[MenuTag.GRAPHICS] = R.string.graphics_settings titles[MenuTag.GRAPHICS] = R.string.graphics_settings

View File

@ -31,6 +31,7 @@ import org.dolphinemu.dolphinemu.features.input.ui.ProfileDialog
import org.dolphinemu.dolphinemu.features.input.ui.ProfileDialogPresenter import org.dolphinemu.dolphinemu.features.input.ui.ProfileDialogPresenter
import org.dolphinemu.dolphinemu.features.settings.model.* import org.dolphinemu.dolphinemu.features.settings.model.*
import org.dolphinemu.dolphinemu.features.settings.model.view.* import org.dolphinemu.dolphinemu.features.settings.model.view.*
import org.dolphinemu.dolphinemu.features.settings.model.AchievementModel.logout
import org.dolphinemu.dolphinemu.model.GpuDriverMetadata import org.dolphinemu.dolphinemu.model.GpuDriverMetadata
import org.dolphinemu.dolphinemu.ui.main.MainPresenter import org.dolphinemu.dolphinemu.ui.main.MainPresenter
import org.dolphinemu.dolphinemu.utils.* import org.dolphinemu.dolphinemu.utils.*
@ -111,6 +112,7 @@ class SettingsFragmentPresenter(
MenuTag.CONFIG_PATHS -> addPathsSettings(sl) MenuTag.CONFIG_PATHS -> addPathsSettings(sl)
MenuTag.CONFIG_GAME_CUBE -> addGameCubeSettings(sl) MenuTag.CONFIG_GAME_CUBE -> addGameCubeSettings(sl)
MenuTag.CONFIG_WII -> addWiiSettings(sl) MenuTag.CONFIG_WII -> addWiiSettings(sl)
MenuTag.CONFIG_ACHIEVEMENTS -> addAchievementSettings(sl);
MenuTag.CONFIG_ADVANCED -> addAdvancedSettings(sl) MenuTag.CONFIG_ADVANCED -> addAdvancedSettings(sl)
MenuTag.GRAPHICS -> addGraphicsSettings(sl) MenuTag.GRAPHICS -> addGraphicsSettings(sl)
MenuTag.CONFIG_SERIALPORT1 -> addSerialPortSubSettings(sl, serialPort1Type) MenuTag.CONFIG_SERIALPORT1 -> addSerialPortSubSettings(sl, serialPort1Type)
@ -200,6 +202,7 @@ class SettingsFragmentPresenter(
sl.add(SubmenuSetting(context, R.string.paths_submenu, MenuTag.CONFIG_PATHS)) sl.add(SubmenuSetting(context, R.string.paths_submenu, MenuTag.CONFIG_PATHS))
sl.add(SubmenuSetting(context, R.string.gamecube_submenu, MenuTag.CONFIG_GAME_CUBE)) sl.add(SubmenuSetting(context, R.string.gamecube_submenu, MenuTag.CONFIG_GAME_CUBE))
sl.add(SubmenuSetting(context, R.string.wii_submenu, MenuTag.CONFIG_WII)) sl.add(SubmenuSetting(context, R.string.wii_submenu, MenuTag.CONFIG_WII))
sl.add(SubmenuSetting(context, R.string.achievements_submenu, MenuTag.CONFIG_ACHIEVEMENTS))
sl.add(SubmenuSetting(context, R.string.advanced_submenu, MenuTag.CONFIG_ADVANCED)) sl.add(SubmenuSetting(context, R.string.advanced_submenu, MenuTag.CONFIG_ADVANCED))
sl.add(SubmenuSetting(context, R.string.log_submenu, MenuTag.CONFIG_LOG)) sl.add(SubmenuSetting(context, R.string.log_submenu, MenuTag.CONFIG_LOG))
sl.add(SubmenuSetting(context, R.string.debug_submenu, MenuTag.DEBUG)) sl.add(SubmenuSetting(context, R.string.debug_submenu, MenuTag.DEBUG))
@ -248,7 +251,7 @@ class SettingsFragmentPresenter(
FloatSetting.MAIN_EMULATION_SPEED, FloatSetting.MAIN_EMULATION_SPEED,
R.string.speed_limit, R.string.speed_limit,
0, 0,
0f, if (AchievementModel.isHardcoreModeActive()) 100f else 0f,
200f, 200f,
"%", "%",
1f, 1f,
@ -914,6 +917,108 @@ class SettingsFragmentPresenter(
) )
} }
private fun addAchievementSettings(sl: ArrayList<SettingsItem>) {
val achievementsEnabledSetting: AbstractBooleanSetting = object : AbstractBooleanSetting {
override val boolean: Boolean
get() = BooleanSetting.ACHIEVEMENTS_ENABLED.boolean
override fun setBoolean(settings: Settings, newValue: Boolean) {
BooleanSetting.ACHIEVEMENTS_ENABLED.setBoolean(settings, newValue)
loadSettingsList()
}
override val isOverridden: Boolean
get() = BooleanSetting.ACHIEVEMENTS_ENABLED.isOverridden
override val isRuntimeEditable: Boolean
get() = BooleanSetting.ACHIEVEMENTS_ENABLED.isRuntimeEditable
override fun delete(settings: Settings): Boolean {
val result = BooleanSetting.ACHIEVEMENTS_ENABLED.delete(settings)
loadSettingsList()
return result
}
}
sl.add(
SwitchSetting(
context,
achievementsEnabledSetting,
R.string.achievements_enabled,
0
)
)
if (BooleanSetting.ACHIEVEMENTS_ENABLED.boolean) {
if (StringSetting.ACHIEVEMENTS_API_TOKEN.string == "") {
sl.add(
RunRunnable(
context,
R.string.achievements_login,
0,
0,
0,
false
) {
fragmentView.showDialogFragment(LoginFragment())
loadSettingsList()
})
} else {
sl.add(
RunRunnable(
context,
R.string.achievements_logout,
0,
0,
0,
false
) {
logout()
loadSettingsList()
})
}
sl.add(
SwitchSetting(
context,
BooleanSetting.ACHIEVEMENTS_HARDCORE_ENABLED,
R.string.achievements_hardcore_enabled,
0
)
)
sl.add(
SwitchSetting(
context,
BooleanSetting.ACHIEVEMENTS_UNOFFICIAL_ENABLED,
R.string.achievements_unofficial_enabled,
0
)
)
sl.add(
SwitchSetting(
context,
BooleanSetting.ACHIEVEMENTS_ENCORE_ENABLED,
R.string.achievements_encore_enabled,
0
)
)
sl.add(
SwitchSetting(
context,
BooleanSetting.ACHIEVEMENTS_SPECTATOR_ENABLED,
R.string.achievements_spectator_enabled,
0
)
)
sl.add(
SwitchSetting(
context,
BooleanSetting.ACHIEVEMENTS_PROGRESS_ENABLED,
R.string.achievements_progress_enabled,
0
)
)
}
}
private fun addAdvancedSettings(sl: ArrayList<SettingsItem>) { private fun addAdvancedSettings(sl: ArrayList<SettingsItem>) {
val SYNC_GPU_NEVER = 0 val SYNC_GPU_NEVER = 0
val SYNC_GPU_ON_IDLE_SKIP = 1 val SYNC_GPU_ON_IDLE_SKIP = 1

View File

@ -32,6 +32,9 @@ class SwitchSettingViewHolder(
binding.textSettingName.text = item.name binding.textSettingName.text = item.name
binding.textSettingDescription.text = item.description binding.textSettingDescription.text = item.description
// Make sure we don't trigger any listener set earlier
binding.settingSwitch.setOnCheckedChangeListener(null)
binding.settingSwitch.isChecked = setting.isChecked binding.settingSwitch.isChecked = setting.isChecked
binding.settingSwitch.isEnabled = setting.isEditable binding.settingSwitch.isEnabled = setting.isEditable

View File

@ -19,6 +19,7 @@ import org.dolphinemu.dolphinemu.NativeLibrary
import org.dolphinemu.dolphinemu.R import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.activities.EmulationActivity import org.dolphinemu.dolphinemu.activities.EmulationActivity
import org.dolphinemu.dolphinemu.databinding.FragmentIngameMenuBinding import org.dolphinemu.dolphinemu.databinding.FragmentIngameMenuBinding
import org.dolphinemu.dolphinemu.features.settings.model.AchievementModel
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting import org.dolphinemu.dolphinemu.features.settings.model.IntSetting
import org.dolphinemu.dolphinemu.utils.InsetsHelper import org.dolphinemu.dolphinemu.utils.InsetsHelper
@ -114,11 +115,16 @@ class MenuFragment : Fragment(), View.OnClickListener {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
val savestatesEnabled = BooleanSetting.MAIN_ENABLE_SAVESTATES.boolean val savestatesEnabled = BooleanSetting.MAIN_ENABLE_SAVESTATES.boolean
val hardcoreEnabled = AchievementModel.isHardcoreModeActive()
val savestateVisibility = if (savestatesEnabled) View.VISIBLE else View.GONE val savestateVisibility = if (savestatesEnabled) View.VISIBLE else View.GONE
binding.menuQuicksave.visibility = savestateVisibility binding.menuQuicksave.visibility = savestateVisibility
binding.menuQuickload.visibility = savestateVisibility binding.menuQuickload.visibility = savestateVisibility
binding.menuEmulationSaveRoot.visibility = savestateVisibility binding.menuEmulationSaveRoot.visibility = savestateVisibility
binding.menuEmulationLoadRoot.visibility = savestateVisibility binding.menuEmulationLoadRoot.visibility = savestateVisibility
// While technically the option is still enabled, AchievementManager
// will block the load and send a message to the screen.
binding.menuQuickload.paint.isStrikeThruText = hardcoreEnabled
binding.menuEmulationLoadRoot.paint.isStrikeThruText = hardcoreEnabled
} }
override fun onDestroyView() { override fun onDestroyView() {

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root"
android:minWidth="320dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/username"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/spacing_large"
android:layout_marginVertical="@dimen/spacing_small"
android:paddingTop="@dimen/spacing_medlarge"
app:layout_constraintBottom_toTopOf="@id/password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/username_input"
android:hint="@string/achievements_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:importantForAutofill="no"
android:inputType="text"
android:minHeight="48dp"
android:textAlignment="viewStart" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/spacing_large"
app:layout_constraintBottom_toTopOf="@id/button_cancel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/username">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/password_input"
android:hint="@string/achievements_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:importantForAutofill="no"
android:inputType="textPassword"
android:textAlignment="viewStart" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/button_cancel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/spacing_large"
android:text="@string/cancel"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/button_login"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/password" />
<Button
android:id="@+id/button_login"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/spacing_large"
android:text="@string/ok"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/button_cancel"
app:layout_constraintTop_toBottomOf="@id/password" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -77,6 +77,7 @@
<string name="enable_cheats">Enable Cheats</string> <string name="enable_cheats">Enable Cheats</string>
<string name="speed_limit">Speed Limit (0% = Unlimited)</string> <string name="speed_limit">Speed Limit (0% = Unlimited)</string>
<string name="overclock_warning">WARNING: Changing this from the default (100%) WILL break games and cause glitches. Please do not report bugs that occur with a non-default clock.</string> <string name="overclock_warning">WARNING: Changing this from the default (100%) WILL break games and cause glitches. Please do not report bugs that occur with a non-default clock.</string>
<string name="achievements_submenu">RetroAchievements</string>
<string name="gamecube_submenu">GameCube</string> <string name="gamecube_submenu">GameCube</string>
<string name="ipl_settings">IPL Settings</string> <string name="ipl_settings">IPL Settings</string>
<string name="skip_main_menu">Skip Main Menu</string> <string name="skip_main_menu">Skip Main Menu</string>
@ -952,4 +953,17 @@ It can efficiently compress both junk data and encrypted Wii data.
<string name="mute_wii_speak">Mute Wii Speak</string> <string name="mute_wii_speak">Mute Wii Speak</string>
<string name="wii_speak_permission_warning">Missing Microphone Permission</string> <string name="wii_speak_permission_warning">Missing Microphone Permission</string>
<string name="wii_speak_permission_warning_description">Wii Speak emulation requires microphone permission. You might need to restart the game for the permission to be effective.</string> <string name="wii_speak_permission_warning_description">Wii Speak emulation requires microphone permission. You might need to restart the game for the permission to be effective.</string>
<!-- Achievements -->
<string name="achievements_enabled">Enable Achievements</string>
<string name="achievements_hardcore_enabled">Enable Hardcore Mode</string>
<string name="achievements_unofficial_enabled">Enable Unofficial Achievements</string>
<string name="achievements_encore_enabled">Enable Encore Mode</string>
<string name="achievements_spectator_enabled">Enable Spectator Mode</string>
<string name="achievements_discord_presence_enabled">Enable Discord Presence</string>
<string name="achievements_progress_enabled">Enable Progress Notifications</string>
<string name="achievements_username">Username</string>
<string name="achievements_password">Password</string>
<string name="achievements_login">Log In</string>
<string name="achievements_logout">Log Out</string>
</resources> </resources>

View File

@ -0,0 +1,31 @@
// Copyright 2025 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <jni.h>
#include "Core/AchievementManager.h"
#include "jni/AndroidCommon/AndroidCommon.h"
extern "C" {
JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_AchievementModel_login(JNIEnv* env, jclass,
jstring password)
{
AchievementManager::GetInstance().Login(GetJString(env, password));
}
JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_AchievementModel_logout(JNIEnv* env, jclass)
{
AchievementManager::GetInstance().Logout();
}
JNIEXPORT jboolean JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_AchievementModel_isHardcoreModeActive(
JNIEnv* env, jclass)
{
return AchievementManager::GetInstance().IsHardcoreModeActive();
}
} // extern "C"

View File

@ -1,4 +1,5 @@
add_library(main SHARED add_library(main SHARED
AchievementAdapter.cpp
ActivityTracker.cpp ActivityTracker.cpp
Cheats/ARCheat.cpp Cheats/ARCheat.cpp
Cheats/Cheats.h Cheats/Cheats.h

View File

@ -48,6 +48,10 @@ static Config::Location GetLocation(JNIEnv* env, jstring file, jstring section,
{ {
system = Config::System::GameSettingsOnly; system = Config::System::GameSettingsOnly;
} }
else if (decoded_file == "RetroAchievements")
{
system = Config::System::Achievements;
}
else else
{ {
ASSERT(false); ASSERT(false);

View File

@ -34,6 +34,7 @@
#include "Common/Version.h" #include "Common/Version.h"
#include "Common/WindowSystemInfo.h" #include "Common/WindowSystemInfo.h"
#include "Core/AchievementManager.h"
#include "Core/Boot/Boot.h" #include "Core/Boot/Boot.h"
#include "Core/BootManager.h" #include "Core/BootManager.h"
#include "Core/CommonTitles.h" #include "Core/CommonTitles.h"
@ -577,6 +578,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Initialize(J
WiimoteReal::InitAdapterClass(); WiimoteReal::InitAdapterClass();
UICommon::Init(); UICommon::Init();
UICommon::InitControllers(WindowSystemInfo(WindowSystemType::Android, nullptr, nullptr, nullptr)); UICommon::InitControllers(WindowSystemInfo(WindowSystemType::Android, nullptr, nullptr, nullptr));
AchievementManager::GetInstance().Init(nullptr);
} }
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReportStartToAnalytics(JNIEnv*, JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReportStartToAnalytics(JNIEnv*,