mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-11-08 04:22:39 +01:00
[cheats] add runtime cheats toggles with master code support (#4334)
add per-cheat runtime toggles (thread-safe). add master code handling (master code cannot be disabled, as noted in Atmosphere's implementation). add configurable global / per-game initial states for cheat entries. remove fixed opcode limits and do some fixes to text parsing / file loading. do not run debug log while cheat logging is not enabled, to reduce performance impacts. update the `Using Cheats` document to reflect the changes. - [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions). - [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md) - [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability. ------------------- Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4334 Reviewed-by: lizzie <lizzie@eden-emu.dev> Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Reviewed-by: John <john@eden-emu.dev>
This commit is contained in:
parent
b4d5760014
commit
69665063a9
24 changed files with 365 additions and 55 deletions
|
|
@ -34,6 +34,13 @@ import org.yuzu.yuzu_emu.applets.web.WebBrowser
|
|||
* with the native side of the Yuzu code.
|
||||
*/
|
||||
object NativeLibrary {
|
||||
@Keep
|
||||
class RuntimeCheat(
|
||||
val id: Int,
|
||||
val name: String,
|
||||
val enabled: Boolean,
|
||||
val isMaster: Boolean
|
||||
)
|
||||
@Keep
|
||||
data class UpdateResult(
|
||||
var tag: String = "",
|
||||
|
|
@ -197,6 +204,9 @@ object NativeLibrary {
|
|||
*/
|
||||
external fun isPaused(): Boolean
|
||||
|
||||
external fun getRuntimeCheats(): Array<RuntimeCheat>
|
||||
external fun setRuntimeCheatEnabled(id: Int, enabled: Boolean): Boolean
|
||||
|
||||
/**
|
||||
* Returns the performance stats for the current game
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||
FASTMEM("cpuopt_fastmem"),
|
||||
FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives"),
|
||||
CORE_SYNC_CORE_SPEED("sync_core_speed"),
|
||||
ENABLE_CHEATS_BY_DEFAULT("enable_cheats_by_default"),
|
||||
RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
|
||||
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
|
||||
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
|
||||
|
|
|
|||
|
|
@ -316,6 +316,13 @@ abstract class SettingsItem(
|
|||
descriptionId = R.string.use_sync_core_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.ENABLE_CHEATS_BY_DEFAULT,
|
||||
titleId = R.string.enable_cheats_by_default,
|
||||
descriptionId = R.string.enable_cheats_by_default_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.REGION_INDEX,
|
||||
|
|
|
|||
|
|
@ -510,6 +510,7 @@ class SettingsFragmentPresenter(
|
|||
add(IntSetting.FAST_CPU_TIME.key)
|
||||
add(IntSetting.FAST_GPU_TIME.key)
|
||||
add(BooleanSetting.CORE_SYNC_CORE_SPEED.key)
|
||||
add(BooleanSetting.ENABLE_CHEATS_BY_DEFAULT.key)
|
||||
|
||||
add(IntSetting.MEMORY_LAYOUT.key)
|
||||
add(BooleanSetting.USE_CUSTOM_CPU_TICKS.key)
|
||||
|
|
|
|||
|
|
@ -734,6 +734,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_quick_settings)?.isVisible =
|
||||
BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean()
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_cheats)?.isVisible = false
|
||||
|
||||
binding.pausedIcon.setOnClickListener {
|
||||
if (this::emulationState.isInitialized && emulationState.isPaused) {
|
||||
|
|
@ -817,6 +818,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
|
||||
R.id.menu_load_amiibo -> handleLoadAmiiboSelection()
|
||||
|
||||
R.id.menu_cheats -> {
|
||||
binding.drawerLayout.closeDrawer(binding.inGameMenu)
|
||||
showRuntimeCheatDialog()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_controls -> {
|
||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
||||
null,
|
||||
|
|
@ -962,6 +969,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
|
||||
emulationState.updateSurface()
|
||||
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_cheats)?.isVisible =
|
||||
NativeLibrary.getRuntimeCheats().isNotEmpty()
|
||||
updateShowStatsOverlay()
|
||||
updateSocOverlay()
|
||||
|
||||
|
|
@ -987,6 +996,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
}
|
||||
emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_cheats)?.isVisible = false
|
||||
binding.loadingText.setText(R.string.shutting_down)
|
||||
ViewUtils.showView(binding.loadingIndicator)
|
||||
ViewUtils.hideView(binding.inputContainer)
|
||||
|
|
@ -1119,6 +1129,45 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
NativePostProcessing.persist()
|
||||
}
|
||||
|
||||
private fun showRuntimeCheatDialog() {
|
||||
val cheats = NativeLibrary.getRuntimeCheats()
|
||||
if (cheats.isEmpty()) return
|
||||
|
||||
val names = cheats.map { it.name.ifEmpty { getString(R.string.unnamed_cheat) } }.toTypedArray()
|
||||
lateinit var dialog: androidx.appcompat.app.AlertDialog
|
||||
dialog = MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.cheats)
|
||||
.setMultiChoiceItems(names, cheats.map { it.enabled }.toBooleanArray()) { _, which, enabled ->
|
||||
if (cheats[which].isMaster) {
|
||||
dialog.listView.setItemChecked(which, true)
|
||||
} else if (!NativeLibrary.setRuntimeCheatEnabled(cheats[which].id, enabled)) {
|
||||
dialog.listView.setItemChecked(which, !enabled)
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.disable_all_cheats) { _, _ ->
|
||||
cheats.forEach {
|
||||
if (!it.isMaster) NativeLibrary.setRuntimeCheatEnabled(it.id, false)
|
||||
}
|
||||
}
|
||||
.setNeutralButton(R.string.enable_all_cheats) { _, _ ->
|
||||
cheats.forEach {
|
||||
if (!it.isMaster) NativeLibrary.setRuntimeCheatEnabled(it.id, true)
|
||||
}
|
||||
}
|
||||
.setPositiveButton(R.string.done, null)
|
||||
.create()
|
||||
dialog.setOnShowListener {
|
||||
val listView = dialog.listView
|
||||
fun updateMasterVisuals() = repeat(listView.childCount) { index ->
|
||||
listView.getChildAt(index).alpha =
|
||||
if (cheats[listView.firstVisiblePosition + index].isMaster) 0.38f else 1f
|
||||
}
|
||||
listView.setOnScrollChangeListener { _, _, _, _, _ -> updateMasterVisuals() }
|
||||
updateMasterVisuals()
|
||||
}
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
private fun addQuickSettings() {
|
||||
binding.quickSettingsSheet.apply {
|
||||
val container = binding.quickSettingsSheet.findViewById<ViewGroup>(R.id.quick_settings_container)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ extern "C" {
|
|||
#include "core/file_sys/submission_package.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
#include "core/file_sys/vfs/vfs_real.h"
|
||||
#include "core/memory/dmnt_cheat_types.h"
|
||||
#include "core/frontend/applets/cabinet.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
#include "core/frontend/applets/error.h"
|
||||
|
|
@ -946,6 +947,31 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused(JNIEnv* env, jclass claz
|
|||
return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused());
|
||||
}
|
||||
|
||||
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getRuntimeCheats(JNIEnv* env, jclass clazz) {
|
||||
const auto cheats = EmulationSession::GetInstance().System().GetRuntimeCheats();
|
||||
const auto runtime_cheat_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary$RuntimeCheat");
|
||||
const auto constructor = env->GetMethodID(runtime_cheat_class, "<init>", "(ILjava/lang/String;ZZ)V");
|
||||
auto result = env->NewObjectArray(static_cast<jsize>(cheats.size()), runtime_cheat_class, nullptr);
|
||||
for (jsize i = 0; i < static_cast<jsize>(cheats.size()); ++i) {
|
||||
const auto& cheat = cheats[i];
|
||||
const auto name = Common::Android::ToJString(env, cheat.name);
|
||||
const auto item = env->NewObject(runtime_cheat_class, constructor, static_cast<jint>(cheat.id), name,
|
||||
static_cast<jboolean>(cheat.enabled),
|
||||
static_cast<jboolean>(cheat.is_master));
|
||||
env->SetObjectArrayElement(result, i, item);
|
||||
env->DeleteLocalRef(name);
|
||||
env->DeleteLocalRef(item);
|
||||
}
|
||||
env->DeleteLocalRef(runtime_cheat_class);
|
||||
return result;
|
||||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setRuntimeCheatEnabled(JNIEnv* env, jclass clazz,
|
||||
jint id, jboolean enabled) {
|
||||
return static_cast<jboolean>(EmulationSession::GetInstance().System().SetCheatEnabled(
|
||||
static_cast<u32>(id), static_cast<bool>(enabled)));
|
||||
}
|
||||
|
||||
jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletCaptureBuffer(JNIEnv* env, jclass clazz) {
|
||||
using namespace VideoCore::Capture;
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@
|
|||
android:icon="@drawable/ic_nfc"
|
||||
android:title="@string/load_amiibo" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_cheats"
|
||||
android:icon="@drawable/ic_code"
|
||||
android:title="@string/cheats" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_overlay_controls"
|
||||
|
|
|
|||
|
|
@ -840,6 +840,12 @@
|
|||
<string name="preferences_graphics">Graphics</string>
|
||||
<string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string>
|
||||
<string name="quick_settings">Quick Settings</string>
|
||||
<string name="cheats">Cheats</string>
|
||||
<string name="enable_all_cheats">Enable All Cheats</string>
|
||||
<string name="disable_all_cheats">Disable All Cheats</string>
|
||||
<string name="unnamed_cheat">Unnamed Cheat</string>
|
||||
<string name="enable_cheats_by_default">Enable cheats by default</string>
|
||||
<string name="enable_cheats_by_default_description">Enable regular cheats when a game starts</string>
|
||||
<string name="enable_quick_settings">Enable Quick Settings</string>
|
||||
<string name="enable_quick_settings_description">Allow access to quick settings menu via swipe and menu button</string>
|
||||
<string name="preferences_audio">Audio</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue