Merge branch 'master' into new-shortcut

master
Franco M 2023-11-04 21:28:16 +07:00 committed by GitHub
commit 728aca7703
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
217 changed files with 21240 additions and 14543 deletions

@ -8,8 +8,17 @@ ccache -s
BUILD_FLAVOR=mainline BUILD_FLAVOR=mainline
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks"
base64 --decode <<< "${ANDROID_KEYSTORE_B64}" > "${ANDROID_KEYSTORE_FILE}"
fi
cd src/android cd src/android
chmod +x ./gradlew chmod +x ./gradlew
./gradlew "assemble${BUILD_FLAVOR}Release" "bundle${BUILD_FLAVOR}Release" ./gradlew "assemble${BUILD_FLAVOR}Release" "bundle${BUILD_FLAVOR}Release"
ccache -s ccache -s
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
rm "${ANDROID_KEYSTORE_FILE}"
fi

@ -13,15 +13,3 @@ cp src/android/app/build/outputs/apk/"${BUILD_FLAVOR}/release/app-${BUILD_FLAVOR
"artifacts/${REV_NAME}.apk" "artifacts/${REV_NAME}.apk"
cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}Release"/"app-${BUILD_FLAVOR}-release.aab" \ cp src/android/app/build/outputs/bundle/"${BUILD_FLAVOR}Release"/"app-${BUILD_FLAVOR}-release.aab" \
"artifacts/${REV_NAME}.aab" "artifacts/${REV_NAME}.aab"
if [ -n "${ANDROID_KEYSTORE_B64}" ]
then
echo "Signing apk..."
base64 --decode <<< "${ANDROID_KEYSTORE_B64}" > ks.jks
apksigner sign --ks ks.jks \
--ks-key-alias "${ANDROID_KEY_ALIAS}" \
--ks-pass env:ANDROID_KEYSTORE_PASS "artifacts/${REV_NAME}.apk"
else
echo "No keystore specified, not signing the APK files."
fi

@ -19,6 +19,7 @@ cmake .. \
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \ -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
-DENABLE_QT_TRANSLATION=ON \ -DENABLE_QT_TRANSLATION=ON \
-DUSE_DISCORD_PRESENCE=ON \ -DUSE_DISCORD_PRESENCE=ON \
-DYUZU_CRASH_DUMPS=ON \
-DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \
-DYUZU_USE_BUNDLED_FFMPEG=ON \ -DYUZU_USE_BUNDLED_FFMPEG=ON \
-GNinja -GNinja

@ -23,6 +23,7 @@ cmake .. \
-DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \
-DYUZU_USE_BUNDLED_FFMPEG=ON \ -DYUZU_USE_BUNDLED_FFMPEG=ON \
-DYUZU_ENABLE_LTO=ON \ -DYUZU_ENABLE_LTO=ON \
-DYUZU_CRASH_DUMPS=ON \
-GNinja -GNinja
ninja ninja

@ -17,7 +17,6 @@ cmake .. \
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \ -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
-DENABLE_QT_TRANSLATION=ON \ -DENABLE_QT_TRANSLATION=ON \
-DUSE_CCACHE=ON \ -DUSE_CCACHE=ON \
-DYUZU_CRASH_DUMPS=ON \
-DYUZU_USE_BUNDLED_SDL2=OFF \ -DYUZU_USE_BUNDLED_SDL2=OFF \
-DYUZU_USE_EXTERNAL_SDL2=OFF \ -DYUZU_USE_EXTERNAL_SDL2=OFF \
-DYUZU_TESTS=OFF \ -DYUZU_TESTS=OFF \

5
.gitmodules vendored

@ -32,7 +32,7 @@
path = externals/xbyak path = externals/xbyak
url = https://github.com/herumi/xbyak.git url = https://github.com/herumi/xbyak.git
[submodule "opus"] [submodule "opus"]
path = externals/opus/opus path = externals/opus
url = https://github.com/xiph/opus.git url = https://github.com/xiph/opus.git
[submodule "SDL"] [submodule "SDL"]
path = externals/SDL path = externals/SDL
@ -58,3 +58,6 @@
[submodule "VulkanMemoryAllocator"] [submodule "VulkanMemoryAllocator"]
path = externals/VulkanMemoryAllocator path = externals/VulkanMemoryAllocator
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
[submodule "breakpad"]
path = externals/breakpad
url = https://github.com/yuzu-emu/breakpad.git

@ -52,7 +52,7 @@ option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android"
CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF) CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF)
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF) CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}") option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}")
@ -139,9 +139,6 @@ if (YUZU_USE_BUNDLED_VCPKG)
if (YUZU_TESTS) if (YUZU_TESTS)
list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests") list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests")
endif() endif()
if (YUZU_CRASH_DUMPS)
list(APPEND VCPKG_MANIFEST_FEATURES "dbghelp")
endif()
if (ENABLE_WEB_SERVICE) if (ENABLE_WEB_SERVICE)
list(APPEND VCPKG_MANIFEST_FEATURES "web-service") list(APPEND VCPKG_MANIFEST_FEATURES "web-service")
endif() endif()
@ -551,6 +548,18 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG)
find_package(FFmpeg 4.3 REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS}) find_package(FFmpeg 4.3 REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS})
endif() endif()
if (WIN32 AND YUZU_CRASH_DUMPS)
set(BREAKPAD_VER "breakpad-c89f9dd")
download_bundled_external("breakpad/" ${BREAKPAD_VER} BREAKPAD_PREFIX)
set(BREAKPAD_CLIENT_INCLUDE_DIR "${BREAKPAD_PREFIX}/include")
set(BREAKPAD_CLIENT_LIBRARY "${BREAKPAD_PREFIX}/lib/libbreakpad_client.lib")
add_library(libbreakpad_client INTERFACE IMPORTED)
target_link_libraries(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_LIBRARY}")
target_include_directories(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_INCLUDE_DIR}")
endif()
# Prefer the -pthread flag on Linux. # Prefer the -pthread flag on Linux.
set(THREADS_PREFER_PTHREAD_FLAG ON) set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
@ -570,13 +579,6 @@ elseif (WIN32)
# PSAPI is the Process Status API # PSAPI is the Process Status API
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version) set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version)
endif() endif()
if (YUZU_CRASH_DUMPS)
find_library(DBGHELP_LIBRARY dbghelp)
if ("${DBGHELP_LIBRARY}" STREQUAL "DBGHELP_LIBRARY-NOTFOUND")
message(FATAL_ERROR "YUZU_CRASH_DUMPS enabled but dbghelp library not found")
endif()
endif()
elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$") elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$")
set(PLATFORM_LIBRARIES rt) set(PLATFORM_LIBRARIES rt)
endif() endif()

1695
dist/languages/ar.ts vendored

File diff suppressed because it is too large Load Diff

848
dist/languages/ca.ts vendored

File diff suppressed because it is too large Load Diff

856
dist/languages/cs.ts vendored

File diff suppressed because it is too large Load Diff

856
dist/languages/da.ts vendored

File diff suppressed because it is too large Load Diff

997
dist/languages/de.ts vendored

File diff suppressed because it is too large Load Diff

856
dist/languages/el.ts vendored

File diff suppressed because it is too large Load Diff

890
dist/languages/es.ts vendored

File diff suppressed because it is too large Load Diff

874
dist/languages/fr.ts vendored

File diff suppressed because it is too large Load Diff

1685
dist/languages/hu.ts vendored

File diff suppressed because it is too large Load Diff

856
dist/languages/id.ts vendored

File diff suppressed because it is too large Load Diff

864
dist/languages/it.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

850
dist/languages/nb.ts vendored

File diff suppressed because it is too large Load Diff

850
dist/languages/nl.ts vendored

File diff suppressed because it is too large Load Diff

850
dist/languages/pl.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

856
dist/languages/sv.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

850
dist/languages/uk.ts vendored

File diff suppressed because it is too large Load Diff

850
dist/languages/vi.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -13,3 +13,4 @@ Exec=yuzu %f
Categories=Game;Emulator;Qt; Categories=Game;Emulator;Qt;
MimeType=application/x-nx-nro;application/x-nx-nso;application/x-nx-nsp;application/x-nx-xci; MimeType=application/x-nx-nro;application/x-nx-nso;application/x-nx-nsp;application/x-nx-xci;
Keywords=Nintendo;Switch; Keywords=Nintendo;Switch;
StartupWMClass=yuzu

@ -134,6 +134,10 @@ endif()
# Opus # Opus
if (NOT TARGET Opus::opus) if (NOT TARGET Opus::opus)
set(OPUS_BUILD_TESTING OFF)
set(OPUS_BUILD_PROGRAMS OFF)
set(OPUS_INSTALL_PKG_CONFIG_MODULE OFF)
set(OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF)
add_subdirectory(opus) add_subdirectory(opus)
endif() endif()
@ -189,3 +193,105 @@ if (ANDROID)
add_subdirectory(libadrenotools) add_subdirectory(libadrenotools)
endif() endif()
endif() endif()
# Breakpad
# https://github.com/microsoft/vcpkg/blob/master/ports/breakpad/CMakeLists.txt
if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client)
set(BREAKPAD_WIN32_DEFINES
NOMINMAX
UNICODE
WIN32_LEAN_AND_MEAN
_CRT_SECURE_NO_WARNINGS
_CRT_SECURE_NO_DEPRECATE
_CRT_NONSTDC_NO_DEPRECATE
)
# libbreakpad
add_library(libbreakpad STATIC)
file(GLOB_RECURSE LIBBREAKPAD_SOURCES breakpad/src/processor/*.cc)
file(GLOB_RECURSE LIBDISASM_SOURCES breakpad/src/third_party/libdisasm/*.c)
list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "_unittest|_selftest|synth_minidump|/tests|/testdata|/solaris|microdump_stackwalk|minidump_dump|minidump_stackwalk")
if (WIN32)
list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "/linux|/mac|/android")
target_compile_definitions(libbreakpad PRIVATE ${BREAKPAD_WIN32_DEFINES})
target_include_directories(libbreakpad PRIVATE "${CMAKE_GENERATOR_INSTANCE}/DIA SDK/include")
elseif (APPLE)
list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "/linux|/windows|/android")
else()
list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "/mac|/windows|/android")
endif()
target_sources(libbreakpad PRIVATE ${LIBBREAKPAD_SOURCES} ${LIBDISASM_SOURCES})
target_include_directories(libbreakpad
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src
${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src/third_party/libdisasm
)
# libbreakpad_client
add_library(libbreakpad_client STATIC)
file(GLOB LIBBREAKPAD_COMMON_SOURCES breakpad/src/common/*.cc breakpad/src/common/*.c breakpad/src/client/*.cc)
if (WIN32)
file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES breakpad/src/client/windows/*.cc breakpad/src/common/windows/*.cc)
list(FILTER LIBBREAKPAD_COMMON_SOURCES EXCLUDE REGEX "language.cc|path_helper.cc|stabs_to_module.cc|stabs_reader.cc|minidump_file_writer.cc")
target_include_directories(libbreakpad_client PRIVATE "${CMAKE_GENERATOR_INSTANCE}/DIA SDK/include")
target_compile_definitions(libbreakpad_client PRIVATE ${BREAKPAD_WIN32_DEFINES})
elseif (APPLE)
target_compile_definitions(libbreakpad_client PRIVATE HAVE_MACH_O_NLIST_H)
file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES breakpad/src/client/mac/*.cc breakpad/src/common/mac/*.cc)
list(APPEND LIBBREAKPAD_CLIENT_SOURCES breakpad/src/common/mac/MachIPC.mm)
else()
target_compile_definitions(libbreakpad_client PUBLIC -DHAVE_A_OUT_H)
file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES breakpad/src/client/linux/*.cc breakpad/src/common/linux/*.cc)
endif()
list(APPEND LIBBREAKPAD_CLIENT_SOURCES ${LIBBREAKPAD_COMMON_SOURCES})
list(FILTER LIBBREAKPAD_CLIENT_SOURCES EXCLUDE REGEX "/sender|/tests|/unittests|/testcases|_unittest|_test")
target_sources(libbreakpad_client PRIVATE ${LIBBREAKPAD_CLIENT_SOURCES})
target_include_directories(libbreakpad_client PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src)
if (WIN32)
target_link_libraries(libbreakpad_client PRIVATE wininet.lib)
elseif (APPLE)
find_library(CoreFoundation_FRAMEWORK CoreFoundation)
target_link_libraries(libbreakpad_client PRIVATE ${CoreFoundation_FRAMEWORK})
else()
find_library(PTHREAD_LIBRARIES pthread)
target_compile_definitions(libbreakpad_client PRIVATE HAVE_GETCONTEXT=1)
if (PTHREAD_LIBRARIES)
target_link_libraries(libbreakpad_client PRIVATE ${PTHREAD_LIBRARIES})
endif()
endif()
# Host tools for symbol processing
if (LINUX)
find_package(ZLIB REQUIRED)
add_executable(minidump_stackwalk breakpad/src/processor/minidump_stackwalk.cc)
target_link_libraries(minidump_stackwalk PRIVATE libbreakpad libbreakpad_client)
add_executable(dump_syms
breakpad/src/common/dwarf_cfi_to_module.cc
breakpad/src/common/dwarf_cu_to_module.cc
breakpad/src/common/dwarf_line_to_module.cc
breakpad/src/common/dwarf_range_list_handler.cc
breakpad/src/common/language.cc
breakpad/src/common/module.cc
breakpad/src/common/path_helper.cc
breakpad/src/common/stabs_reader.cc
breakpad/src/common/stabs_to_module.cc
breakpad/src/common/dwarf/bytereader.cc
breakpad/src/common/dwarf/dwarf2diehandler.cc
breakpad/src/common/dwarf/dwarf2reader.cc
breakpad/src/common/dwarf/elf_reader.cc
breakpad/src/common/linux/crc32.cc
breakpad/src/common/linux/dump_symbols.cc
breakpad/src/common/linux/elf_symbols_to_module.cc
breakpad/src/common/linux/elfutils.cc
breakpad/src/common/linux/file_id.cc
breakpad/src/common/linux/linux_libc_support.cc
breakpad/src/common/linux/memory_mapped_file.cc
breakpad/src/common/linux/safe_readlink.cc
breakpad/src/tools/linux/dump_syms/dump_syms.cc)
target_link_libraries(dump_syms PRIVATE libbreakpad_client ZLIB::ZLIB)
endif()
endif()

2
externals/SDL vendored

@ -1 +1 @@
Subproject commit 031912c4b6c5db80b443f04aa56fec3e4e645153 Subproject commit cc016b0046d563287f0aa9f09b958b5e70d43696

@ -1 +1 @@
Subproject commit ed857118e243fdc0f3a100f00ac9919e874cfe63 Subproject commit df60f0316899460eeaaefa06d2dd7e4e300c1604

@ -1 +1 @@
Subproject commit 9b0fc3e7b02afe97895eb3e945fe800c3a7485ac Subproject commit 2f382df218d7e8516dee3b3caccb819a62b571a2

@ -0,0 +1 @@
Subproject commit c89f9dddc793f19910ef06c13e4fd240da4e7a59

@ -1 +1 @@
Subproject commit 6d963fbe8d415399d65e94db7910bbd22fe3741c Subproject commit a609330e4c6374f741d3b369269f7848255e1954

2
externals/cpp-jwt vendored

@ -1 +1 @@
Subproject commit e12ef06218596b52d9b5d6e1639484866a8e7067 Subproject commit 10ef5735d842b31025f1257ae78899f50a40fb14

@ -1 +1 @@
Subproject commit 7da378033a7764f955516f75194856d87bbcd7a5 Subproject commit 0df09e2f6b61c2d7ad2f2053d4f020a5c33e0378

@ -1 +1 @@
Subproject commit 6b6b9e593dd4d3aaf75f48d40a13ef03bdef9fdb Subproject commit 9c1294eaddb88cb0e044c675ccae059a85fc9c6c

@ -1 +1 @@
Subproject commit 1e80a47dffbda813604f0913e2ad68c7054c14e4 Subproject commit 9cecf0643da0846e77f64d10a126d9f48b9e05e8

@ -49,11 +49,6 @@ if (MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux") OR APPLE)
set(LIBUSB_INCLUDE_DIRS "${LIBUSB_SRC_DIR}/libusb" CACHE PATH "libusb headers path" FORCE) set(LIBUSB_INCLUDE_DIRS "${LIBUSB_SRC_DIR}/libusb" CACHE PATH "libusb headers path" FORCE)
# MINGW: causes "externals/libusb/libusb/libusb/os/windows_winusb.c:1427:2: error: conversion to non-scalar type requested", so cannot statically link it for now.
if (NOT MINGW)
set(LIBUSB_CFLAGS "-DGUID_DEVINTERFACE_USB_DEVICE=\\(GUID\\){0xA5DCBF10,0x6530,0x11D2,{0x90,0x1F,0x00,0xC0,0x4F,0xB9,0x51,0xED}}")
endif()
make_directory("${LIBUSB_PREFIX}") make_directory("${LIBUSB_PREFIX}")
add_custom_command( add_custom_command(
@ -146,8 +141,6 @@ else() # MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
target_include_directories(usb BEFORE PRIVATE libusb/msvc) target_include_directories(usb BEFORE PRIVATE libusb/msvc)
endif() endif()
# Works around other libraries providing their own definition of USB GUIDs (e.g. SDL2)
target_compile_definitions(usb PRIVATE "-DGUID_DEVINTERFACE_USB_DEVICE=(GUID){ 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}}")
else() else()
target_include_directories(usb target_include_directories(usb
# turns out other projects also have "config.h", so make sure the # turns out other projects also have "config.h", so make sure the

@ -1 +1 @@
Subproject commit c6a35c56016ea2ab2f19115d2ea1e85e0edae155 Subproject commit c060e9ce30ac2e3ffb49d94209c4dae77b6642f7

1
externals/opus vendored

@ -0,0 +1 @@
Subproject commit 101a71e03bbf860aaafb7090a0e440675cb27660

@ -1,259 +0,0 @@
# SPDX-FileCopyrightText: 2019 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
cmake_minimum_required(VERSION 3.8)
project(opus)
option(OPUS_STACK_PROTECTOR "Use stack protection" OFF)
option(OPUS_USE_ALLOCA "Use alloca for stack arrays (on non-C99 compilers)" OFF)
option(OPUS_CUSTOM_MODES "Enable non-Opus modes, e.g. 44.1 kHz & 2^n frames" OFF)
option(OPUS_FIXED_POINT "Compile as fixed-point (for machines without a fast enough FPU)" OFF)
option(OPUS_ENABLE_FLOAT_API "Compile with the floating point API (for machines with float library" ON)
include(opus/opus_functions.cmake)
if(OPUS_STACK_PROTECTOR)
if(NOT MSVC) # GC on by default on MSVC
check_and_set_flag(STACK_PROTECTION_STRONG -fstack-protector-strong)
endif()
else()
if(MSVC)
check_and_set_flag(BUFFER_SECURITY_CHECK /GS-)
endif()
endif()
add_library(opus
# CELT sources
opus/celt/bands.c
opus/celt/celt.c
opus/celt/celt_decoder.c
opus/celt/celt_encoder.c
opus/celt/celt_lpc.c
opus/celt/cwrs.c
opus/celt/entcode.c
opus/celt/entdec.c
opus/celt/entenc.c
opus/celt/kiss_fft.c
opus/celt/laplace.c
opus/celt/mathops.c
opus/celt/mdct.c
opus/celt/modes.c
opus/celt/pitch.c
opus/celt/quant_bands.c
opus/celt/rate.c
opus/celt/vq.c
# SILK sources
opus/silk/A2NLSF.c
opus/silk/CNG.c
opus/silk/HP_variable_cutoff.c
opus/silk/LPC_analysis_filter.c
opus/silk/LPC_fit.c
opus/silk/LPC_inv_pred_gain.c
opus/silk/LP_variable_cutoff.c
opus/silk/NLSF2A.c
opus/silk/NLSF_VQ.c
opus/silk/NLSF_VQ_weights_laroia.c
opus/silk/NLSF_decode.c
opus/silk/NLSF_del_dec_quant.c
opus/silk/NLSF_encode.c
opus/silk/NLSF_stabilize.c
opus/silk/NLSF_unpack.c
opus/silk/NSQ.c
opus/silk/NSQ_del_dec.c
opus/silk/PLC.c
opus/silk/VAD.c
opus/silk/VQ_WMat_EC.c
opus/silk/ana_filt_bank_1.c
opus/silk/biquad_alt.c
opus/silk/bwexpander.c
opus/silk/bwexpander_32.c
opus/silk/check_control_input.c
opus/silk/code_signs.c
opus/silk/control_SNR.c
opus/silk/control_audio_bandwidth.c
opus/silk/control_codec.c
opus/silk/dec_API.c
opus/silk/decode_core.c
opus/silk/decode_frame.c
opus/silk/decode_indices.c
opus/silk/decode_parameters.c
opus/silk/decode_pitch.c
opus/silk/decode_pulses.c
opus/silk/decoder_set_fs.c
opus/silk/enc_API.c
opus/silk/encode_indices.c
opus/silk/encode_pulses.c
opus/silk/gain_quant.c
opus/silk/init_decoder.c
opus/silk/init_encoder.c
opus/silk/inner_prod_aligned.c
opus/silk/interpolate.c
opus/silk/lin2log.c
opus/silk/log2lin.c
opus/silk/pitch_est_tables.c
opus/silk/process_NLSFs.c
opus/silk/quant_LTP_gains.c
opus/silk/resampler.c
opus/silk/resampler_down2.c
opus/silk/resampler_down2_3.c
opus/silk/resampler_private_AR2.c
opus/silk/resampler_private_IIR_FIR.c
opus/silk/resampler_private_down_FIR.c
opus/silk/resampler_private_up2_HQ.c
opus/silk/resampler_rom.c
opus/silk/shell_coder.c
opus/silk/sigm_Q15.c
opus/silk/sort.c
opus/silk/stereo_LR_to_MS.c
opus/silk/stereo_MS_to_LR.c
opus/silk/stereo_decode_pred.c
opus/silk/stereo_encode_pred.c
opus/silk/stereo_find_predictor.c
opus/silk/stereo_quant_pred.c
opus/silk/sum_sqr_shift.c
opus/silk/table_LSF_cos.c
opus/silk/tables_LTP.c
opus/silk/tables_NLSF_CB_NB_MB.c
opus/silk/tables_NLSF_CB_WB.c
opus/silk/tables_gain.c
opus/silk/tables_other.c
opus/silk/tables_pitch_lag.c
opus/silk/tables_pulses_per_block.c
# Opus sources
opus/src/analysis.c
opus/src/mapping_matrix.c
opus/src/mlp.c
opus/src/mlp_data.c
opus/src/opus.c
opus/src/opus_decoder.c
opus/src/opus_encoder.c
opus/src/opus_multistream.c
opus/src/opus_multistream_decoder.c
opus/src/opus_multistream_encoder.c
opus/src/opus_projection_decoder.c
opus/src/opus_projection_encoder.c
opus/src/repacketizer.c
)
if (DEBUG)
target_sources(opus PRIVATE opus/silk/debug.c)
endif()
if (OPUS_FIXED_POINT)
target_sources(opus PRIVATE
opus/silk/fixed/LTP_analysis_filter_FIX.c
opus/silk/fixed/LTP_scale_ctrl_FIX.c
opus/silk/fixed/apply_sine_window_FIX.c
opus/silk/fixed/autocorr_FIX.c
opus/silk/fixed/burg_modified_FIX.c
opus/silk/fixed/corrMatrix_FIX.c
opus/silk/fixed/encode_frame_FIX.c
opus/silk/fixed/find_LPC_FIX.c
opus/silk/fixed/find_LTP_FIX.c
opus/silk/fixed/find_pitch_lags_FIX.c
opus/silk/fixed/find_pred_coefs_FIX.c
opus/silk/fixed/k2a_FIX.c
opus/silk/fixed/k2a_Q16_FIX.c
opus/silk/fixed/noise_shape_analysis_FIX.c
opus/silk/fixed/pitch_analysis_core_FIX.c
opus/silk/fixed/prefilter_FIX.c
opus/silk/fixed/process_gains_FIX.c
opus/silk/fixed/regularize_correlations_FIX.c
opus/silk/fixed/residual_energy16_FIX.c
opus/silk/fixed/residual_energy_FIX.c
opus/silk/fixed/schur64_FIX.c
opus/silk/fixed/schur_FIX.c
opus/silk/fixed/solve_LS_FIX.c
opus/silk/fixed/vector_ops_FIX.c
opus/silk/fixed/warped_autocorrelation_FIX.c
)
else()
target_sources(opus PRIVATE
opus/silk/float/LPC_analysis_filter_FLP.c
opus/silk/float/LPC_inv_pred_gain_FLP.c
opus/silk/float/LTP_analysis_filter_FLP.c
opus/silk/float/LTP_scale_ctrl_FLP.c
opus/silk/float/apply_sine_window_FLP.c
opus/silk/float/autocorrelation_FLP.c
opus/silk/float/burg_modified_FLP.c
opus/silk/float/bwexpander_FLP.c
opus/silk/float/corrMatrix_FLP.c
opus/silk/float/encode_frame_FLP.c
opus/silk/float/energy_FLP.c
opus/silk/float/find_LPC_FLP.c
opus/silk/float/find_LTP_FLP.c
opus/silk/float/find_pitch_lags_FLP.c
opus/silk/float/find_pred_coefs_FLP.c
opus/silk/float/inner_product_FLP.c
opus/silk/float/k2a_FLP.c
opus/silk/float/noise_shape_analysis_FLP.c
opus/silk/float/pitch_analysis_core_FLP.c
opus/silk/float/process_gains_FLP.c
opus/silk/float/regularize_correlations_FLP.c
opus/silk/float/residual_energy_FLP.c
opus/silk/float/scale_copy_vector_FLP.c
opus/silk/float/scale_vector_FLP.c
opus/silk/float/schur_FLP.c
opus/silk/float/sort_FLP.c
opus/silk/float/warped_autocorrelation_FLP.c
opus/silk/float/wrappers_FLP.c
)
endif()
target_compile_definitions(opus PRIVATE OPUS_BUILD ENABLE_HARDENING)
if(NOT MSVC)
if(MINGW)
target_compile_definitions(opus PRIVATE _FORTIFY_SOURCE=0)
else()
target_compile_definitions(opus PRIVATE _FORTIFY_SOURCE=2)
endif()
endif()
# It is strongly recommended to uncomment one of these VAR_ARRAYS: Use C99
# variable-length arrays for stack allocation USE_ALLOCA: Use alloca() for stack
# allocation If none is defined, then the fallback is a non-threadsafe global
# array
if(OPUS_USE_ALLOCA OR MSVC)
target_compile_definitions(opus PRIVATE USE_ALLOCA)
else()
target_compile_definitions(opus PRIVATE VAR_ARRAYS)
endif()
if(OPUS_CUSTOM_MODES)
target_compile_definitions(opus PRIVATE CUSTOM_MODES)
endif()
if(NOT OPUS_ENABLE_FLOAT_API)
target_compile_definitions(opus PRIVATE DISABLE_FLOAT_API)
endif()
target_compile_definitions(opus
PUBLIC
-DOPUS_VERSION="\\"1.3.1\\""
PRIVATE
# Use C99 intrinsics to speed up float-to-int conversion
HAVE_LRINTF
)
if (FIXED_POINT)
target_compile_definitions(opus PRIVATE -DFIXED_POINT=1 -DDISABLE_FLOAT_API)
endif()
target_include_directories(opus
PUBLIC
opus/include
PRIVATE
opus/celt
opus/silk
opus/silk/fixed
opus/silk/float
opus/src
)
add_library(Opus::opus ALIAS opus)

@ -1 +0,0 @@
Subproject commit ad8fe90db79b7d2a135e3dfd2ed6631b0c5662ab

2
externals/vcpkg vendored

@ -1 +1 @@
Subproject commit cbf56573a987527b39272e88cbdd11389b78c6e4 Subproject commit ef2eef17340f3fbd679327d286fad06dd6e838ed

@ -47,6 +47,10 @@ android {
jniLibs.useLegacyPackaging = true jniLibs.useLegacyPackaging = true
} }
androidResources {
generateLocaleConfig = true
}
defaultConfig { defaultConfig {
// TODO If this is ever modified, change application_id in strings.xml // TODO If this is ever modified, change application_id in strings.xml
applicationId = "org.yuzu.yuzu_emu" applicationId = "org.yuzu.yuzu_emu"

@ -26,7 +26,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:supportsRtl="true" android:supportsRtl="true"
android:isGame="true" android:isGame="true"
android:appCategory="game" android:appCategory="game"
android:localeConfig="@xml/locales_config"
android:banner="@drawable/tv_banner" android:banner="@drawable/tv_banner"
android:fullBackupContent="@xml/data_extraction_rules" android:fullBackupContent="@xml/data_extraction_rules"
android:dataExtractionRules="@xml/data_extraction_rules_api_31" android:dataExtractionRules="@xml/data_extraction_rules_api_31"

@ -5,6 +5,7 @@ package org.yuzu.yuzu_emu
import android.app.Dialog import android.app.Dialog
import android.content.DialogInterface import android.content.DialogInterface
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.Html import android.text.Html
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
@ -16,7 +17,7 @@ import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import org.yuzu.yuzu_emu.activities.EmulationActivity import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.utils.DocumentsTree.Companion.isNativePath import org.yuzu.yuzu_emu.utils.DocumentsTree
import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.Log import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable
@ -68,7 +69,7 @@ object NativeLibrary {
@Keep @Keep
@JvmStatic @JvmStatic
fun openContentUri(path: String?, openmode: String?): Int { fun openContentUri(path: String?, openmode: String?): Int {
return if (isNativePath(path!!)) { return if (DocumentsTree.isNativePath(path!!)) {
YuzuApplication.documentsTree!!.openContentUri(path, openmode) YuzuApplication.documentsTree!!.openContentUri(path, openmode)
} else { } else {
FileUtil.openContentUri(path, openmode) FileUtil.openContentUri(path, openmode)
@ -78,7 +79,7 @@ object NativeLibrary {
@Keep @Keep
@JvmStatic @JvmStatic
fun getSize(path: String?): Long { fun getSize(path: String?): Long {
return if (isNativePath(path!!)) { return if (DocumentsTree.isNativePath(path!!)) {
YuzuApplication.documentsTree!!.getFileSize(path) YuzuApplication.documentsTree!!.getFileSize(path)
} else { } else {
FileUtil.getFileSize(path) FileUtil.getFileSize(path)
@ -88,23 +89,41 @@ object NativeLibrary {
@Keep @Keep
@JvmStatic @JvmStatic
fun exists(path: String?): Boolean { fun exists(path: String?): Boolean {
return if (isNativePath(path!!)) { return if (DocumentsTree.isNativePath(path!!)) {
YuzuApplication.documentsTree!!.exists(path) YuzuApplication.documentsTree!!.exists(path)
} else { } else {
FileUtil.exists(path) FileUtil.exists(path, suppressLog = true)
} }
} }
@Keep @Keep
@JvmStatic @JvmStatic
fun isDirectory(path: String?): Boolean { fun isDirectory(path: String?): Boolean {
return if (isNativePath(path!!)) { return if (DocumentsTree.isNativePath(path!!)) {
YuzuApplication.documentsTree!!.isDirectory(path) YuzuApplication.documentsTree!!.isDirectory(path)
} else { } else {
FileUtil.isDirectory(path) FileUtil.isDirectory(path)
} }
} }
@Keep
@JvmStatic
fun getParentDirectory(path: String): String =
if (DocumentsTree.isNativePath(path)) {
YuzuApplication.documentsTree!!.getParentDirectory(path)
} else {
path
}
@Keep
@JvmStatic
fun getFilename(path: String): String =
if (DocumentsTree.isNativePath(path)) {
YuzuApplication.documentsTree!!.getFilename(path)
} else {
FileUtil.getFilename(Uri.parse(path))
}
/** /**
* Returns true if pro controller isn't available and handheld is * Returns true if pro controller isn't available and handheld is
*/ */
@ -215,32 +234,6 @@ object NativeLibrary {
external fun initGameIni(gameID: String?) external fun initGameIni(gameID: String?)
/**
* Gets the embedded icon within the given ROM.
*
* @param filename the file path to the ROM.
* @return a byte array containing the JPEG data for the icon.
*/
external fun getIcon(filename: String): ByteArray
/**
* Gets the embedded title of the given ISO/ROM.
*
* @param filename The file path to the ISO/ROM.
* @return the embedded title of the ISO/ROM.
*/
external fun getTitle(filename: String): String
external fun getDescription(filename: String): String
external fun getGameId(filename: String): String
external fun getRegions(filename: String): String
external fun getCompany(filename: String): String
external fun isHomebrew(filename: String): Boolean
external fun setAppDirectory(directory: String) external fun setAppDirectory(directory: String)
/** /**
@ -259,7 +252,7 @@ object NativeLibrary {
external fun reloadKeys(): Boolean external fun reloadKeys(): Boolean
external fun initializeEmulation() external fun initializeSystem(reload: Boolean)
external fun defaultCPUCore(): Int external fun defaultCPUCore(): Int
@ -293,11 +286,6 @@ object NativeLibrary {
*/ */
external fun stopEmulation() external fun stopEmulation()
/**
* Resets the in-memory ROM metadata cache.
*/
external fun resetRomMetadata()
/** /**
* Returns true if emulation is running (or is paused). * Returns true if emulation is running (or is paused).
*/ */
@ -474,12 +462,12 @@ object NativeLibrary {
} }
fun setEmulationActivity(emulationActivity: EmulationActivity?) { fun setEmulationActivity(emulationActivity: EmulationActivity?) {
Log.verbose("[NativeLibrary] Registering EmulationActivity.") Log.debug("[NativeLibrary] Registering EmulationActivity.")
sEmulationActivity = WeakReference(emulationActivity) sEmulationActivity = WeakReference(emulationActivity)
} }
fun clearEmulationActivity() { fun clearEmulationActivity() {
Log.verbose("[NativeLibrary] Unregistering EmulationActivity.") Log.debug("[NativeLibrary] Unregistering EmulationActivity.")
sEmulationActivity.clear() sEmulationActivity.clear()
} }
@ -517,6 +505,36 @@ object NativeLibrary {
*/ */
external fun initializeEmptyUserDirectory() external fun initializeEmptyUserDirectory()
/**
* Gets the launch path for a given applet. It is the caller's responsibility to also
* set the system's current applet ID before trying to launch the nca given by this function.
*
* @param id The applet entry ID
* @return The applet's launch path
*/
external fun getAppletLaunchPath(id: Long): String
/**
* Sets the system's current applet ID before launching.
*
* @param appletId One of the ids in the Service::AM::Applets::AppletId enum
*/
external fun setCurrentAppletId(appletId: Int)
/**
* Sets the cabinet mode for launching the cabinet applet.
*
* @param cabinetMode One of the modes that corresponds to the enum in Service::NFP::CabinetMode
*/
external fun setCabinetMode(cabinetMode: Int)
/**
* Checks whether NAND contents are available and valid.
*
* @return 'true' if firmware is available
*/
external fun isFirmwareAvailable(): Boolean
/** /**
* Button type for use in onTouchEvent * Button type for use in onTouchEvent
*/ */

@ -11,6 +11,7 @@ import java.io.File
import org.yuzu.yuzu_emu.utils.DirectoryInitialization import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.DocumentsTree import org.yuzu.yuzu_emu.utils.DocumentsTree
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.Log
fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
@ -49,6 +50,7 @@ class YuzuApplication : Application() {
DirectoryInitialization.start() DirectoryInitialization.start()
GpuDriverHelper.initializeDriverParameters() GpuDriverHelper.initializeDriverParameters()
NativeLibrary.logDeviceInfo() NativeLibrary.logDeviceInfo()
Log.logDeviceInfo()
createNotificationChannels() createNotificationChannels()
} }

@ -45,9 +45,9 @@ import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.model.EmulationViewModel import org.yuzu.yuzu_emu.model.EmulationViewModel
import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
import org.yuzu.yuzu_emu.utils.ForegroundService import org.yuzu.yuzu_emu.utils.ForegroundService
import org.yuzu.yuzu_emu.utils.InputHandler import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.MemoryUtil import org.yuzu.yuzu_emu.utils.MemoryUtil
import org.yuzu.yuzu_emu.utils.NfcReader import org.yuzu.yuzu_emu.utils.NfcReader
import org.yuzu.yuzu_emu.utils.ThemeHelper import org.yuzu.yuzu_emu.utils.ThemeHelper
@ -57,17 +57,16 @@ import kotlin.math.roundToInt
class EmulationActivity : AppCompatActivity(), SensorEventListener { class EmulationActivity : AppCompatActivity(), SensorEventListener {
private lateinit var binding: ActivityEmulationBinding private lateinit var binding: ActivityEmulationBinding
private var controllerMappingHelper: ControllerMappingHelper? = null
var isActivityRecreated = false var isActivityRecreated = false
private lateinit var nfcReader: NfcReader private lateinit var nfcReader: NfcReader
private lateinit var inputHandler: InputHandler
private val gyro = FloatArray(3) private val gyro = FloatArray(3)
private val accel = FloatArray(3) private val accel = FloatArray(3)
private var motionTimestamp: Long = 0 private var motionTimestamp: Long = 0
private var flipMotionOrientation: Boolean = false private var flipMotionOrientation: Boolean = false
private var controllerIds = InputHandler.getGameControllerIds()
private val actionPause = "ACTION_EMULATOR_PAUSE" private val actionPause = "ACTION_EMULATOR_PAUSE"
private val actionPlay = "ACTION_EMULATOR_PLAY" private val actionPlay = "ACTION_EMULATOR_PLAY"
private val actionMute = "ACTION_EMULATOR_MUTE" private val actionMute = "ACTION_EMULATOR_MUTE"
@ -82,6 +81,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
Log.gameLaunched = true
ThemeHelper.setTheme(this) ThemeHelper.setTheme(this)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -95,8 +95,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
isActivityRecreated = savedInstanceState != null isActivityRecreated = savedInstanceState != null
controllerMappingHelper = ControllerMappingHelper()
// Set these options now so that the SurfaceView the game renders into is the right size. // Set these options now so that the SurfaceView the game renders into is the right size.
enableFullscreenImmersive() enableFullscreenImmersive()
@ -105,12 +103,11 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
nfcReader = NfcReader(this) nfcReader = NfcReader(this)
nfcReader.initialize() nfcReader.initialize()
inputHandler = InputHandler() InputHandler.initialize()
inputHandler.initialize()
val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
if (!preferences.getBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, false)) { if (!preferences.getBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, false)) {
if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.Gb)) { if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.totalMemory)) {
Toast.makeText( Toast.makeText(
this, this,
getString( getString(
@ -162,6 +159,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
super.onResume() super.onResume()
nfcReader.startScanning() nfcReader.startScanning()
startMotionSensorListener() startMotionSensorListener()
InputHandler.updateControllerIds()
buildPictureInPictureParams() buildPictureInPictureParams()
} }
@ -195,7 +193,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
return super.dispatchKeyEvent(event) return super.dispatchKeyEvent(event)
} }
return inputHandler.dispatchKeyEvent(event) return InputHandler.dispatchKeyEvent(event)
} }
override fun dispatchGenericMotionEvent(event: MotionEvent): Boolean { override fun dispatchGenericMotionEvent(event: MotionEvent): Boolean {
@ -210,7 +208,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
return true return true
} }
return inputHandler.dispatchGenericMotionEvent(event) return InputHandler.dispatchGenericMotionEvent(event)
} }
override fun onSensorChanged(event: SensorEvent) { override fun onSensorChanged(event: SensorEvent) {

@ -0,0 +1,90 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.databinding.CardAppletOptionBinding
import org.yuzu.yuzu_emu.model.Applet
import org.yuzu.yuzu_emu.model.AppletInfo
import org.yuzu.yuzu_emu.model.Game
class AppletAdapter(val activity: FragmentActivity, var applets: List<Applet>) :
RecyclerView.Adapter<AppletAdapter.AppletViewHolder>(),
View.OnClickListener {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): AppletAdapter.AppletViewHolder {
CardAppletOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.apply { root.setOnClickListener(this@AppletAdapter) }
.also { return AppletViewHolder(it) }
}
override fun onBindViewHolder(holder: AppletViewHolder, position: Int) =
holder.bind(applets[position])
override fun getItemCount(): Int = applets.size
override fun onClick(view: View) {
val applet = (view.tag as AppletViewHolder).applet
val appletPath = NativeLibrary.getAppletLaunchPath(applet.appletInfo.entryId)
if (appletPath.isEmpty()) {
Toast.makeText(
YuzuApplication.appContext,
R.string.applets_error_applet,
Toast.LENGTH_SHORT
).show()
return
}
if (applet.appletInfo == AppletInfo.Cabinet) {
view.findNavController()
.navigate(R.id.action_appletLauncherFragment_to_cabinetLauncherDialogFragment)
return
}
NativeLibrary.setCurrentAppletId(applet.appletInfo.appletId)
val appletGame = Game(
title = YuzuApplication.appContext.getString(applet.titleId),
path = appletPath
)
val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame)
view.findNavController().navigate(action)
}
inner class AppletViewHolder(val binding: CardAppletOptionBinding) :
RecyclerView.ViewHolder(binding.root) {
lateinit var applet: Applet
init {
itemView.tag = this
}
fun bind(applet: Applet) {
this.applet = applet
binding.title.setText(applet.titleId)
binding.description.setText(applet.descriptionId)
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
binding.icon.context.resources,
applet.iconId,
binding.icon.context.theme
)
)
}
}
}

@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.databinding.DialogListItemBinding
import org.yuzu.yuzu_emu.model.CabinetMode
import org.yuzu.yuzu_emu.adapters.CabinetLauncherDialogAdapter.CabinetModeViewHolder
import org.yuzu.yuzu_emu.model.AppletInfo
import org.yuzu.yuzu_emu.model.Game
class CabinetLauncherDialogAdapter(val fragment: Fragment) :
RecyclerView.Adapter<CabinetModeViewHolder>(),
View.OnClickListener {
private val cabinetModes = CabinetMode.values().copyOfRange(1, CabinetMode.values().size)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CabinetModeViewHolder {
DialogListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.apply { root.setOnClickListener(this@CabinetLauncherDialogAdapter) }
.also { return CabinetModeViewHolder(it) }
}
override fun getItemCount(): Int = cabinetModes.size
override fun onBindViewHolder(holder: CabinetModeViewHolder, position: Int) =
holder.bind(cabinetModes[position])
override fun onClick(view: View) {
val mode = (view.tag as CabinetModeViewHolder).cabinetMode
val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.Cabinet.entryId)
NativeLibrary.setCurrentAppletId(AppletInfo.Cabinet.appletId)
NativeLibrary.setCabinetMode(mode.id)
val appletGame = Game(
title = YuzuApplication.appContext.getString(R.string.cabinet_applet),
path = appletPath
)
val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame)
fragment.findNavController().navigate(action)
}
inner class CabinetModeViewHolder(val binding: DialogListItemBinding) :
RecyclerView.ViewHolder(binding.root) {
lateinit var cabinetMode: CabinetMode
init {
itemView.tag = this
}
fun bind(cabinetMode: CabinetMode) {
this.cabinetMode = cabinetMode
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
binding.icon.context.resources,
cabinetMode.iconId,
binding.icon.context.theme
)
)
binding.title.setText(cabinetMode.titleId)
}
}
}

@ -147,7 +147,7 @@ class GameAdapter(private val activity: AppCompatActivity) :
private class DiffCallback : DiffUtil.ItemCallback<Game>() { private class DiffCallback : DiffUtil.ItemCallback<Game>() {
override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean { override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean {
return oldItem.gameId == newItem.gameId return oldItem.programId == newItem.programId
} }
override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean { override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean {

@ -0,0 +1,113 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.AppletAdapter
import org.yuzu.yuzu_emu.databinding.FragmentAppletLauncherBinding
import org.yuzu.yuzu_emu.model.Applet
import org.yuzu.yuzu_emu.model.AppletInfo
import org.yuzu.yuzu_emu.model.HomeViewModel
class AppletLauncherFragment : Fragment() {
private var _binding: FragmentAppletLauncherBinding? = null
private val binding get() = _binding!!
private val homeViewModel: HomeViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentAppletLauncherBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = true)
homeViewModel.setStatusBarShadeVisibility(visible = false)
binding.toolbarApplets.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
}
val applets = listOf(
Applet(
R.string.album_applet,
R.string.album_applet_description,
R.drawable.ic_album,
AppletInfo.PhotoViewer
),
Applet(
R.string.cabinet_applet,
R.string.cabinet_applet_description,
R.drawable.ic_nfc,
AppletInfo.Cabinet
),
Applet(
R.string.mii_edit_applet,
R.string.mii_edit_applet_description,
R.drawable.ic_mii,
AppletInfo.MiiEdit
)
)
binding.listApplets.apply {
layoutManager = GridLayoutManager(
requireContext(),
resources.getInteger(R.integer.grid_columns)
)
adapter = AppletAdapter(requireActivity(), applets)
}
setInsets()
}
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
) { _: View, windowInsets: WindowInsetsCompat ->
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right
val mlpAppBar = binding.toolbarApplets.layoutParams as ViewGroup.MarginLayoutParams
mlpAppBar.leftMargin = leftInsets
mlpAppBar.rightMargin = rightInsets
binding.toolbarApplets.layoutParams = mlpAppBar
val mlpListApplets =
binding.listApplets.layoutParams as ViewGroup.MarginLayoutParams
mlpListApplets.leftMargin = leftInsets
mlpListApplets.rightMargin = rightInsets
binding.listApplets.layoutParams = mlpListApplets
binding.listApplets.updatePadding(bottom = barInsets.bottom)
windowInsets
}
}

@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.CabinetLauncherDialogAdapter
import org.yuzu.yuzu_emu.databinding.DialogListBinding
class CabinetLauncherDialogFragment : DialogFragment() {
private lateinit var binding: DialogListBinding
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
binding = DialogListBinding.inflate(layoutInflater)
binding.dialogList.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = CabinetLauncherDialogAdapter(this@CabinetLauncherDialogFragment)
}
return MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.cabinet_launcher)
.setView(binding.root)
.create()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return binding.root
}
}

@ -15,6 +15,7 @@ import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.os.SystemClock
import android.view.* import android.view.*
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
@ -25,6 +26,7 @@ import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
@ -156,6 +158,32 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.showFpsText.setTextColor(Color.YELLOW) binding.showFpsText.setTextColor(Color.YELLOW)
binding.doneControlConfig.setOnClickListener { stopConfiguringControls() } binding.doneControlConfig.setOnClickListener { stopConfiguringControls() }
binding.drawerLayout.addDrawerListener(object : DrawerListener {
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
binding.surfaceInputOverlay.dispatchTouchEvent(
MotionEvent.obtain(
SystemClock.uptimeMillis(),
SystemClock.uptimeMillis() + 100,
MotionEvent.ACTION_UP,
0f,
0f,
0
)
)
}
override fun onDrawerOpened(drawerView: View) {
// No op
}
override fun onDrawerClosed(drawerView: View) {
// No op
}
override fun onDrawerStateChanged(newState: Int) {
// No op
}
})
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text = binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text =
game.title game.title
@ -284,6 +312,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
ViewUtils.showView(binding.surfaceInputOverlay) ViewUtils.showView(binding.surfaceInputOverlay)
ViewUtils.hideView(binding.loadingIndicator) ViewUtils.hideView(binding.loadingIndicator)
emulationState.updateSurface()
// Setup overlay // Setup overlay
updateShowFpsOverlay() updateShowFpsOverlay()
} }
@ -776,6 +806,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
} }
@Synchronized
fun updateSurface() {
if (surface != null) {
NativeLibrary.surfaceChanged(surface)
}
}
@Synchronized @Synchronized
fun clearSurface() { fun clearSurface() {
if (surface == null) { if (surface == null) {

@ -26,10 +26,11 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
import org.yuzu.yuzu_emu.BuildConfig import org.yuzu.yuzu_emu.BuildConfig
import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.HomeSettingAdapter import org.yuzu.yuzu_emu.adapters.HomeSettingAdapter
import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding
@ -41,6 +42,7 @@ import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.ui.main.MainActivity import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.Log
class HomeSettingsFragment : Fragment() { class HomeSettingsFragment : Fragment() {
private var _binding: FragmentHomeSettingsBinding? = null private var _binding: FragmentHomeSettingsBinding? = null
@ -83,28 +85,6 @@ class HomeSettingsFragment : Fragment() {
} }
) )
) )
add(
HomeSetting(
R.string.open_user_folder,
R.string.open_user_folder_description,
R.drawable.ic_folder_open,
{ openFileManager() }
)
)
add(
HomeSetting(
R.string.preferences_theme,
R.string.theme_and_color_description,
R.drawable.ic_palette,
{
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
null,
Settings.MenuTag.SECTION_THEME
)
binding.root.findNavController().navigate(action)
}
)
)
add( add(
HomeSetting( HomeSetting(
R.string.gpu_driver_manager, R.string.gpu_driver_manager,
@ -120,6 +100,20 @@ class HomeSettingsFragment : Fragment() {
driverViewModel.selectedDriverMetadata driverViewModel.selectedDriverMetadata
) )
) )
add(
HomeSetting(
R.string.applets,
R.string.applets_description,
R.drawable.ic_applet,
{
binding.root.findNavController()
.navigate(R.id.action_homeSettingsFragment_to_appletLauncherFragment)
},
{ NativeLibrary.isFirmwareAvailable() },
R.string.applets_error_firmware,
R.string.applets_error_description
)
)
add( add(
HomeSetting( HomeSetting(
R.string.manage_yuzu_data, R.string.manage_yuzu_data,
@ -155,6 +149,28 @@ class HomeSettingsFragment : Fragment() {
{ shareLog() } { shareLog() }
) )
) )
add(
HomeSetting(
R.string.open_user_folder,
R.string.open_user_folder_description,
R.drawable.ic_folder_open,
{ openFileManager() }
)
)
add(
HomeSetting(
R.string.preferences_theme,
R.string.theme_and_color_description,
R.drawable.ic_palette,
{
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
null,
Settings.MenuTag.SECTION_THEME
)
binding.root.findNavController().navigate(action)
}
)
)
add( add(
HomeSetting( HomeSetting(
R.string.about, R.string.about,
@ -186,7 +202,8 @@ class HomeSettingsFragment : Fragment() {
} }
binding.homeSettingsList.apply { binding.homeSettingsList.apply {
layoutManager = LinearLayoutManager(requireContext()) layoutManager =
GridLayoutManager(requireContext(), resources.getInteger(R.integer.grid_columns))
adapter = HomeSettingAdapter( adapter = HomeSettingAdapter(
requireActivity() as AppCompatActivity, requireActivity() as AppCompatActivity,
viewLifecycleOwner, viewLifecycleOwner,
@ -296,19 +313,32 @@ class HomeSettingsFragment : Fragment() {
} }
} }
// Share the current log if we just returned from a game but share the old log
// if we just started the app and the old log exists.
private fun shareLog() { private fun shareLog() {
val file = DocumentFile.fromSingleUri( val currentLog = DocumentFile.fromSingleUri(
mainActivity, mainActivity,
DocumentsContract.buildDocumentUri( DocumentsContract.buildDocumentUri(
DocumentProvider.AUTHORITY, DocumentProvider.AUTHORITY,
"${DocumentProvider.ROOT_ID}/log/yuzu_log.txt" "${DocumentProvider.ROOT_ID}/log/yuzu_log.txt"
) )
)!! )!!
if (file.exists()) { val oldLog = DocumentFile.fromSingleUri(
mainActivity,
DocumentsContract.buildDocumentUri(
DocumentProvider.AUTHORITY,
"${DocumentProvider.ROOT_ID}/log/yuzu_log.txt.old.txt"
)
)!!
val intent = Intent(Intent.ACTION_SEND) val intent = Intent(Intent.ACTION_SEND)
.setDataAndType(file.uri, FileUtil.TEXT_PLAIN) .setDataAndType(currentLog.uri, FileUtil.TEXT_PLAIN)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.putExtra(Intent.EXTRA_STREAM, file.uri) if (!Log.gameLaunched && oldLog.exists()) {
intent.putExtra(Intent.EXTRA_STREAM, oldLog.uri)
startActivity(Intent.createChooser(intent, getText(R.string.share_log)))
} else if (currentLog.exists()) {
intent.putExtra(Intent.EXTRA_STREAM, currentLog.uri)
startActivity(Intent.createChooser(intent, getText(R.string.share_log))) startActivity(Intent.createChooser(intent, getText(R.string.share_log)))
} else { } else {
Toast.makeText( Toast.makeText(

@ -8,6 +8,7 @@ import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.Html
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
@ -32,7 +33,9 @@ class MessageDialogFragment : DialogFragment() {
if (titleId != 0) dialog.setTitle(titleId) if (titleId != 0) dialog.setTitle(titleId)
if (titleString.isNotEmpty()) dialog.setTitle(titleString) if (titleString.isNotEmpty()) dialog.setTitle(titleString)
if (descriptionId != 0) dialog.setMessage(descriptionId) if (descriptionId != 0) {
dialog.setMessage(Html.fromHtml(getString(descriptionId), Html.FROM_HTML_MODE_LEGACY))
}
if (descriptionString.isNotEmpty()) dialog.setMessage(descriptionString) if (descriptionString.isNotEmpty()) dialog.setMessage(descriptionString)
if (helpLinkId != 0) { if (helpLinkId != 0) {

@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.model
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import org.yuzu.yuzu_emu.R
data class Applet(
@StringRes val titleId: Int,
@StringRes val descriptionId: Int,
@DrawableRes val iconId: Int,
val appletInfo: AppletInfo,
val cabinetMode: CabinetMode = CabinetMode.None
)
// Combination of Common::AM::Applets::AppletId enum and the entry id
enum class AppletInfo(val appletId: Int, val entryId: Long = 0) {
None(0x00),
Application(0x01),
OverlayDisplay(0x02),
QLaunch(0x03),
Starter(0x04),
Auth(0x0A),
Cabinet(0x0B, 0x0100000000001002),
Controller(0x0C),
DataErase(0x0D),
Error(0x0E),
NetConnect(0x0F),
ProfileSelect(0x10),
SoftwareKeyboard(0x11),
MiiEdit(0x12, 0x0100000000001009),
Web(0x13),
Shop(0x14),
PhotoViewer(0x015, 0x010000000000100D),
Settings(0x16),
OfflineWeb(0x17),
LoginShare(0x18),
WebAuth(0x19),
MyPage(0x1A)
}
// Matches enum in Service::NFP::CabinetMode with extra metadata
enum class CabinetMode(
val id: Int,
@StringRes val titleId: Int = 0,
@DrawableRes val iconId: Int = 0
) {
None(-1),
StartNicknameAndOwnerSettings(0, R.string.cabinet_nickname_and_owner, R.drawable.ic_edit),
StartGameDataEraser(1, R.string.cabinet_game_data_eraser, R.drawable.ic_refresh),
StartRestorer(2, R.string.cabinet_restorer, R.drawable.ic_restore),
StartFormatter(3, R.string.cabinet_formatter, R.drawable.ic_clear)
}

@ -11,16 +11,15 @@ import kotlinx.serialization.Serializable
@Parcelize @Parcelize
@Serializable @Serializable
class Game( class Game(
val title: String, val title: String = "",
val description: String,
val regions: String,
val path: String, val path: String,
val gameId: String, val programId: String = "",
val company: String, val developer: String = "",
val isHomebrew: Boolean val version: String = "",
val isHomebrew: Boolean = false
) : Parcelable { ) : Parcelable {
val keyAddedToLibraryTime get() = "${gameId}_AddedToLibraryTime" val keyAddedToLibraryTime get() = "${programId}_AddedToLibraryTime"
val keyLastPlayedTime get() = "${gameId}_LastPlayed" val keyLastPlayedTime get() = "${programId}_LastPlayed"
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (other !is Game) { if (other !is Game) {
@ -32,11 +31,9 @@ class Game(
override fun hashCode(): Int { override fun hashCode(): Int {
var result = title.hashCode() var result = title.hashCode()
result = 31 * result + description.hashCode()
result = 31 * result + regions.hashCode()
result = 31 * result + path.hashCode() result = 31 * result + path.hashCode()
result = 31 * result + gameId.hashCode() result = 31 * result + programId.hashCode()
result = 31 * result + company.hashCode() result = 31 * result + developer.hashCode()
result = 31 * result + isHomebrew.hashCode() result = 31 * result + isHomebrew.hashCode()
return result return result
} }

@ -14,15 +14,13 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.MissingFieldException
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.utils.GameHelper import org.yuzu.yuzu_emu.utils.GameHelper
import org.yuzu.yuzu_emu.utils.GameMetadata
@OptIn(ExperimentalSerializationApi::class)
class GamesViewModel : ViewModel() { class GamesViewModel : ViewModel() {
val games: StateFlow<List<Game>> get() = _games val games: StateFlow<List<Game>> get() = _games
private val _games = MutableStateFlow(emptyList<Game>()) private val _games = MutableStateFlow(emptyList<Game>())
@ -49,19 +47,25 @@ class GamesViewModel : ViewModel() {
// Retrieve list of cached games // Retrieve list of cached games
val storedGames = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) val storedGames = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
.getStringSet(GameHelper.KEY_GAMES, emptySet()) .getStringSet(GameHelper.KEY_GAMES, emptySet())
viewModelScope.launch {
withContext(Dispatchers.IO) {
if (storedGames!!.isNotEmpty()) { if (storedGames!!.isNotEmpty()) {
val deserializedGames = mutableSetOf<Game>() val deserializedGames = mutableSetOf<Game>()
storedGames.forEach { storedGames.forEach {
val game: Game val game: Game
try { try {
game = Json.decodeFromString(it) game = Json.decodeFromString(it)
} catch (e: MissingFieldException) { } catch (e: Exception) {
// We don't care about any errors related to parsing the game cache
return@forEach return@forEach
} }
val gameExists = val gameExists =
DocumentFile.fromSingleUri(YuzuApplication.appContext, Uri.parse(game.path)) DocumentFile.fromSingleUri(
?.exists() YuzuApplication.appContext,
Uri.parse(game.path)
)?.exists()
if (gameExists == true) { if (gameExists == true) {
deserializedGames.add(game) deserializedGames.add(game)
} }
@ -70,6 +74,8 @@ class GamesViewModel : ViewModel() {
} }
reloadGames(false) reloadGames(false)
} }
}
}
fun setGames(games: List<Game>) { fun setGames(games: List<Game>) {
val sortedList = games.sortedWith( val sortedList = games.sortedWith(
@ -106,7 +112,7 @@ class GamesViewModel : ViewModel() {
viewModelScope.launch { viewModelScope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
NativeLibrary.resetRomMetadata() GameMetadata.resetMetadata()
setGames(GameHelper.getGames()) setGames(GameHelper.getGames())
_isReloading.value = false _isReloading.value = false

@ -403,6 +403,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
} else { } else {
firmwarePath.deleteRecursively() firmwarePath.deleteRecursively()
cacheFirmwareDir.copyRecursively(firmwarePath, true) cacheFirmwareDir.copyRecursively(firmwarePath, true)
NativeLibrary.initializeSystem(true)
getString(R.string.save_file_imported_success) getString(R.string.save_file_imported_success)
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -648,7 +649,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
} }
// Reinitialize relevant data // Reinitialize relevant data
NativeLibrary.initializeEmulation() NativeLibrary.initializeSystem(true)
gamesViewModel.reloadGames(false) gamesViewModel.reloadGames(false)
return@newInstance getString(R.string.user_data_import_success) return@newInstance getString(R.string.user_data_import_success)

@ -1,70 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
import android.view.InputDevice
import android.view.KeyEvent
import android.view.MotionEvent
/**
* Some controllers have incorrect mappings. This class has special-case fixes for them.
*/
class ControllerMappingHelper {
/**
* Some controllers report extra button presses that can be ignored.
*/
fun shouldKeyBeIgnored(inputDevice: InputDevice, keyCode: Int): Boolean {
return if (isDualShock4(inputDevice)) {
// The two analog triggers generate analog motion events as well as a keycode.
// We always prefer to use the analog values, so throw away the button press
keyCode == KeyEvent.KEYCODE_BUTTON_L2 || keyCode == KeyEvent.KEYCODE_BUTTON_R2
} else {
false
}
}
/**
* Scale an axis to be zero-centered with a proper range.
*/
fun scaleAxis(inputDevice: InputDevice, axis: Int, value: Float): Float {
if (isDualShock4(inputDevice)) {
// Android doesn't have correct mappings for this controller's triggers. It reports them
// as RX & RY, centered at -1.0, and with a range of [-1.0, 1.0]
// Scale them to properly zero-centered with a range of [0.0, 1.0].
if (axis == MotionEvent.AXIS_RX || axis == MotionEvent.AXIS_RY) {
return (value + 1) / 2.0f
}
} else if (isXboxOneWireless(inputDevice)) {
// Same as the DualShock 4, the mappings are missing.
if (axis == MotionEvent.AXIS_Z || axis == MotionEvent.AXIS_RZ) {
return (value + 1) / 2.0f
}
if (axis == MotionEvent.AXIS_GENERIC_1) {
// This axis is stuck at ~.5. Ignore it.
return 0.0f
}
} else if (isMogaPro2Hid(inputDevice)) {
// This controller has a broken axis that reports a constant value. Ignore it.
if (axis == MotionEvent.AXIS_GENERIC_1) {
return 0.0f
}
}
return value
}
// Sony DualShock 4 controller
private fun isDualShock4(inputDevice: InputDevice): Boolean {
return inputDevice.vendorId == 0x54c && inputDevice.productId == 0x9cc
}
// Microsoft Xbox One controller
private fun isXboxOneWireless(inputDevice: InputDevice): Boolean {
return inputDevice.vendorId == 0x45e && inputDevice.productId == 0x2e0
}
// Moga Pro 2 HID
private fun isMogaPro2Hid(inputDevice: InputDevice): Boolean {
return inputDevice.vendorId == 0x20d6 && inputDevice.productId == 0x6271
}
}

@ -15,7 +15,7 @@ object DirectoryInitialization {
fun start() { fun start() {
if (!areDirectoriesReady) { if (!areDirectoriesReady) {
initializeInternalStorage() initializeInternalStorage()
NativeLibrary.initializeEmulation() NativeLibrary.initializeSystem(false)
areDirectoriesReady = true areDirectoriesReady = true
} }
} }

@ -42,6 +42,23 @@ class DocumentsTree {
return node != null && node.isDirectory return node != null && node.isDirectory
} }
fun getParentDirectory(filepath: String): String {
val node = resolvePath(filepath)!!
val parentNode = node.parent
if (parentNode != null && parentNode.isDirectory) {
return parentNode.uri!!.toString()
}
return node.uri!!.toString()
}
fun getFilename(filepath: String): String {
val node = resolvePath(filepath)
if (node != null) {
return node.name!!
}
return filepath
}
private fun resolvePath(filepath: String): DocumentsNode? { private fun resolvePath(filepath: String): DocumentsNode? {
val tokens = StringTokenizer(filepath, File.separator, false) val tokens = StringTokenizer(filepath, File.separator, false)
var iterator = root var iterator = root

@ -144,7 +144,7 @@ object FileUtil {
* @param path Native content uri path * @param path Native content uri path
* @return bool * @return bool
*/ */
fun exists(path: String?): Boolean { fun exists(path: String?, suppressLog: Boolean = false): Boolean {
var c: Cursor? = null var c: Cursor? = null
try { try {
val mUri = Uri.parse(path) val mUri = Uri.parse(path)
@ -152,7 +152,9 @@ object FileUtil {
c = context.contentResolver.query(mUri, columns, null, null, null) c = context.contentResolver.query(mUri, columns, null, null, null)
return c!!.count > 0 return c!!.count > 0
} catch (e: Exception) { } catch (e: Exception) {
if (!suppressLog) {
Log.info("[FileUtil] Cannot find file from given path, error: " + e.message) Log.info("[FileUtil] Cannot find file from given path, error: " + e.message)
}
} finally { } finally {
closeQuietly(c) closeQuietly(c)
} }

@ -71,27 +71,26 @@ object GameHelper {
fun getGame(uri: Uri, addedToLibrary: Boolean): Game { fun getGame(uri: Uri, addedToLibrary: Boolean): Game {
val filePath = uri.toString() val filePath = uri.toString()
var name = NativeLibrary.getTitle(filePath) var name = GameMetadata.getTitle(filePath)
// If the game's title field is empty, use the filename. // If the game's title field is empty, use the filename.
if (name.isEmpty()) { if (name.isEmpty()) {
name = FileUtil.getFilename(uri) name = FileUtil.getFilename(uri)
} }
var gameId = NativeLibrary.getGameId(filePath) var programId = GameMetadata.getProgramId(filePath)
// If the game's ID field is empty, use the filename without extension. // If the game's ID field is empty, use the filename without extension.
if (gameId.isEmpty()) { if (programId.isEmpty()) {
gameId = name.substring(0, name.lastIndexOf(".")) programId = name.substring(0, name.lastIndexOf("."))
} }
val newGame = Game( val newGame = Game(
name, name,
NativeLibrary.getDescription(filePath).replace("\n", " "),
NativeLibrary.getRegions(filePath),
filePath, filePath,
gameId, programId,
NativeLibrary.getCompany(filePath), GameMetadata.getDeveloper(filePath),
NativeLibrary.isHomebrew(filePath) GameMetadata.getVersion(filePath),
GameMetadata.getIsHomebrew(filePath)
) )
if (addedToLibrary) { if (addedToLibrary) {

@ -18,7 +18,6 @@ import coil.key.Keyer
import coil.memory.MemoryCache import coil.memory.MemoryCache
import coil.request.ImageRequest import coil.request.ImageRequest
import coil.request.Options import coil.request.Options
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.Game
@ -36,7 +35,7 @@ class GameIconFetcher(
} }
private fun decodeGameIcon(uri: String): Bitmap? { private fun decodeGameIcon(uri: String): Bitmap? {
val data = NativeLibrary.getIcon(uri) val data = GameMetadata.getIcon(uri)
return BitmapFactory.decodeByteArray( return BitmapFactory.decodeByteArray(
data, data,
0, 0,

@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
object GameMetadata {
external fun getTitle(path: String): String
external fun getProgramId(path: String): String
external fun getDeveloper(path: String): String
external fun getVersion(path: String): String
external fun getIcon(path: String): ByteArray
external fun getIsHomebrew(path: String): Boolean
external fun resetMetadata()
}

@ -3,17 +3,24 @@
package org.yuzu.yuzu_emu.utils package org.yuzu.yuzu_emu.utils
import android.view.InputDevice
import android.view.KeyEvent import android.view.KeyEvent
import android.view.MotionEvent import android.view.MotionEvent
import kotlin.math.sqrt import kotlin.math.sqrt
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
class InputHandler { object InputHandler {
private var controllerIds = getGameControllerIds()
fun initialize() { fun initialize() {
// Connect first controller // Connect first controller
NativeLibrary.onGamePadConnectEvent(getPlayerNumber(NativeLibrary.Player1Device)) NativeLibrary.onGamePadConnectEvent(getPlayerNumber(NativeLibrary.Player1Device))
} }
fun updateControllerIds() {
controllerIds = getGameControllerIds()
}
fun dispatchKeyEvent(event: KeyEvent): Boolean { fun dispatchKeyEvent(event: KeyEvent): Boolean {
val button: Int = when (event.device.vendorId) { val button: Int = when (event.device.vendorId) {
0x045E -> getInputXboxButtonKey(event.keyCode) 0x045E -> getInputXboxButtonKey(event.keyCode)
@ -35,7 +42,7 @@ class InputHandler {
} }
return NativeLibrary.onGamePadButtonEvent( return NativeLibrary.onGamePadButtonEvent(
getPlayerNumber(event.device.controllerNumber), getPlayerNumber(event.device.controllerNumber, event.deviceId),
button, button,
action action
) )
@ -58,9 +65,14 @@ class InputHandler {
return true return true
} }
private fun getPlayerNumber(index: Int): Int { private fun getPlayerNumber(index: Int, deviceId: Int = -1): Int {
var deviceIndex = index
if (deviceId != -1) {
deviceIndex = controllerIds[deviceId] ?: 0
}
// TODO: Joycons are handled as different controllers. Find a way to merge them. // TODO: Joycons are handled as different controllers. Find a way to merge them.
return when (index) { return when (deviceIndex) {
2 -> NativeLibrary.Player2Device 2 -> NativeLibrary.Player2Device
3 -> NativeLibrary.Player3Device 3 -> NativeLibrary.Player3Device
4 -> NativeLibrary.Player4Device 4 -> NativeLibrary.Player4Device
@ -238,7 +250,7 @@ class InputHandler {
} }
private fun setGenericAxisInput(event: MotionEvent, axis: Int) { private fun setGenericAxisInput(event: MotionEvent, axis: Int) {
val playerNumber = getPlayerNumber(event.device.controllerNumber) val playerNumber = getPlayerNumber(event.device.controllerNumber, event.deviceId)
when (axis) { when (axis) {
MotionEvent.AXIS_X, MotionEvent.AXIS_Y -> MotionEvent.AXIS_X, MotionEvent.AXIS_Y ->
@ -297,7 +309,7 @@ class InputHandler {
private fun setJoyconAxisInput(event: MotionEvent, axis: Int) { private fun setJoyconAxisInput(event: MotionEvent, axis: Int) {
// Joycon support is half dead. Right joystick doesn't work // Joycon support is half dead. Right joystick doesn't work
val playerNumber = getPlayerNumber(event.device.controllerNumber) val playerNumber = getPlayerNumber(event.device.controllerNumber, event.deviceId)
when (axis) { when (axis) {
MotionEvent.AXIS_X, MotionEvent.AXIS_Y -> MotionEvent.AXIS_X, MotionEvent.AXIS_Y ->
@ -325,7 +337,7 @@ class InputHandler {
} }
private fun setRazerAxisInput(event: MotionEvent, axis: Int) { private fun setRazerAxisInput(event: MotionEvent, axis: Int) {
val playerNumber = getPlayerNumber(event.device.controllerNumber) val playerNumber = getPlayerNumber(event.device.controllerNumber, event.deviceId)
when (axis) { when (axis) {
MotionEvent.AXIS_X, MotionEvent.AXIS_Y -> MotionEvent.AXIS_X, MotionEvent.AXIS_Y ->
@ -362,4 +374,33 @@ class InputHandler {
) )
} }
} }
fun getGameControllerIds(): Map<Int, Int> {
val gameControllerDeviceIds = mutableMapOf<Int, Int>()
val deviceIds = InputDevice.getDeviceIds()
var controllerSlot = 1
deviceIds.forEach { deviceId ->
InputDevice.getDevice(deviceId)?.apply {
// Don't over-assign controllers
if (controllerSlot >= 8) {
return gameControllerDeviceIds
}
// Verify that the device has gamepad buttons, control sticks, or both.
if (sources and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD ||
sources and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK
) {
// This device is a game controller. Store its device ID.
if (deviceId and id and vendorId and productId != 0) {
// Additionally filter out devices that have no ID
gameControllerDeviceIds
.takeIf { !it.contains(deviceId) }
?.put(deviceId, controllerSlot)
controllerSlot++
}
}
}
}
return gameControllerDeviceIds
}
} }

@ -3,38 +3,29 @@
package org.yuzu.yuzu_emu.utils package org.yuzu.yuzu_emu.utils
import android.util.Log import android.os.Build
import org.yuzu.yuzu_emu.BuildConfig
/**
* Contains methods that call through to [android.util.Log], but
* with the same TAG automatically provided. Also no-ops VERBOSE and DEBUG log
* levels in release builds.
*/
object Log { object Log {
private const val TAG = "Yuzu Frontend" // Tracks whether we should share the old log or the current log
var gameLaunched = false
fun verbose(message: String) { external fun debug(message: String)
if (BuildConfig.DEBUG) {
Log.v(TAG, message)
}
}
fun debug(message: String) { external fun warning(message: String)
if (BuildConfig.DEBUG) {
Log.d(TAG, message)
}
}
fun info(message: String) { external fun info(message: String)
Log.i(TAG, message)
}
fun warning(message: String) { external fun error(message: String)
Log.w(TAG, message)
}
fun error(message: String) { external fun critical(message: String)
Log.e(TAG, message)
fun logDeviceInfo() {
info("Device Manufacturer - ${Build.MANUFACTURER}")
info("Device Model - ${Build.MODEL}")
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
info("SoC Manufacturer - ${Build.SOC_MANUFACTURER}")
info("SoC Model - ${Build.SOC_MODEL}")
}
info("Total System Memory - ${MemoryUtil.getDeviceRAM()}")
} }
} }

@ -27,7 +27,7 @@ object MemoryUtil {
const val Pb = Tb * 1024 const val Pb = Tb * 1024
const val Eb = Pb * 1024 const val Eb = Pb * 1024
private fun bytesToSizeUnit(size: Float): String = private fun bytesToSizeUnit(size: Float, roundUp: Boolean = false): String =
when { when {
size < Kb -> { size < Kb -> {
context.getString( context.getString(
@ -39,63 +39,59 @@ object MemoryUtil {
size < Mb -> { size < Mb -> {
context.getString( context.getString(
R.string.memory_formatted, R.string.memory_formatted,
(size / Kb).hundredths, if (roundUp) ceil(size / Kb) else (size / Kb).hundredths,
context.getString(R.string.memory_kilobyte) context.getString(R.string.memory_kilobyte)
) )
} }
size < Gb -> { size < Gb -> {
context.getString( context.getString(
R.string.memory_formatted, R.string.memory_formatted,
(size / Mb).hundredths, if (roundUp) ceil(size / Mb) else (size / Mb).hundredths,
context.getString(R.string.memory_megabyte) context.getString(R.string.memory_megabyte)
) )
} }
size < Tb -> { size < Tb -> {
context.getString( context.getString(
R.string.memory_formatted, R.string.memory_formatted,
(size / Gb).hundredths, if (roundUp) ceil(size / Gb) else (size / Gb).hundredths,
context.getString(R.string.memory_gigabyte) context.getString(R.string.memory_gigabyte)
) )
} }
size < Pb -> { size < Pb -> {
context.getString( context.getString(
R.string.memory_formatted, R.string.memory_formatted,
(size / Tb).hundredths, if (roundUp) ceil(size / Tb) else (size / Tb).hundredths,
context.getString(R.string.memory_terabyte) context.getString(R.string.memory_terabyte)
) )
} }
size < Eb -> { size < Eb -> {
context.getString( context.getString(
R.string.memory_formatted, R.string.memory_formatted,
(size / Pb).hundredths, if (roundUp) ceil(size / Pb) else (size / Pb).hundredths,
context.getString(R.string.memory_petabyte) context.getString(R.string.memory_petabyte)
) )
} }
else -> { else -> {
context.getString( context.getString(
R.string.memory_formatted, R.string.memory_formatted,
(size / Eb).hundredths, if (roundUp) ceil(size / Eb) else (size / Eb).hundredths,
context.getString(R.string.memory_exabyte) context.getString(R.string.memory_exabyte)
) )
} }
} }
// Devices are unlikely to have 0.5GB increments of memory so we'll just round up to account for val totalMemory: Float
// the potential error created by memInfo.totalMem
private val totalMemory: Float
get() { get() {
val memInfo = ActivityManager.MemoryInfo() val memInfo = ActivityManager.MemoryInfo()
with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) { with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) {
getMemoryInfo(memInfo) getMemoryInfo(memInfo)
} }
return ceil( return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
memInfo.advertisedMem.toFloat() memInfo.advertisedMem.toFloat()
} else { } else {
memInfo.totalMem.toFloat() memInfo.totalMem.toFloat()
} }
)
} }
fun isLessThan(minimum: Int, size: Float): Boolean = fun isLessThan(minimum: Int, size: Float): Boolean =
@ -109,5 +105,7 @@ object MemoryUtil {
else -> totalMemory < Kb && totalMemory < minimum else -> totalMemory < Kb && totalMemory < minimum
} }
fun getDeviceRAM(): String = bytesToSizeUnit(totalMemory) // Devices are unlikely to have 0.5GB increments of memory so we'll just round up to account for
// the potential error created by memInfo.totalMem
fun getDeviceRAM(): String = bytesToSizeUnit(totalMemory, true)
} }

@ -14,8 +14,11 @@ add_library(yuzu-android SHARED
id_cache.cpp id_cache.cpp
id_cache.h id_cache.h
native.cpp native.cpp
native.h
native_config.cpp native_config.cpp
uisettings.cpp uisettings.cpp
game_metadata.cpp
native_log.cpp
) )
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})

@ -0,0 +1,112 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <core/core.h>
#include <core/file_sys/patch_manager.h>
#include <core/loader/nro.h>
#include <jni.h>
#include "core/loader/loader.h"
#include "jni/android_common/android_common.h"
#include "native.h"
struct RomMetadata {
std::string title;
u64 programId;
std::string developer;
std::string version;
std::vector<u8> icon;
bool isHomebrew;
};
std::unordered_map<std::string, RomMetadata> m_rom_metadata_cache;
RomMetadata CacheRomMetadata(const std::string& path) {
const auto file =
Core::GetGameFileFromPath(EmulationSession::GetInstance().System().GetFilesystem(), path);
auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
RomMetadata entry;
loader->ReadTitle(entry.title);
loader->ReadProgramId(entry.programId);
loader->ReadIcon(entry.icon);
const FileSys::PatchManager pm{
entry.programId, EmulationSession::GetInstance().System().GetFileSystemController(),
EmulationSession::GetInstance().System().GetContentProvider()};
const auto control = pm.GetControlMetadata();
if (control.first != nullptr) {
entry.developer = control.first->GetDeveloperName();
entry.version = control.first->GetVersionString();
} else {
FileSys::NACP nacp;
if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
entry.developer = nacp.GetDeveloperName();
} else {
entry.developer = "";
}
entry.version = "1.0.0";
}
if (loader->GetFileType() == Loader::FileType::NRO) {
auto loader_nro = reinterpret_cast<Loader::AppLoader_NRO*>(loader.get());
entry.isHomebrew = loader_nro->IsHomebrew();
} else {
entry.isHomebrew = false;
}
m_rom_metadata_cache[path] = entry;
return entry;
}
RomMetadata GetRomMetadata(const std::string& path) {
if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
return search->second;
}
return CacheRomMetadata(path);
}
extern "C" {
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getTitle(JNIEnv* env, jobject obj,
jstring jpath) {
return ToJString(env, GetRomMetadata(GetJString(env, jpath)).title);
}
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getProgramId(JNIEnv* env, jobject obj,
jstring jpath) {
return ToJString(env, std::to_string(GetRomMetadata(GetJString(env, jpath)).programId));
}
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getDeveloper(JNIEnv* env, jobject obj,
jstring jpath) {
return ToJString(env, GetRomMetadata(GetJString(env, jpath)).developer);
}
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getVersion(JNIEnv* env, jobject obj,
jstring jpath) {
return ToJString(env, GetRomMetadata(GetJString(env, jpath)).version);
}
jbyteArray Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIcon(JNIEnv* env, jobject obj,
jstring jpath) {
auto icon_data = GetRomMetadata(GetJString(env, jpath)).icon;
jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size()));
env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon),
reinterpret_cast<jbyte*>(icon_data.data()));
return icon;
}
jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsHomebrew(JNIEnv* env, jobject obj,
jstring jpath) {
return static_cast<jboolean>(GetRomMetadata(GetJString(env, jpath)).isHomebrew);
}
void Java_org_yuzu_yuzu_1emu_utils_GameMetadata_resetMetadata(JNIEnv* env, jobject obj) {
return m_rom_metadata_cache.clear();
}
} // extern "C"

@ -33,7 +33,6 @@
#include "core/crypto/key_manager.h" #include "core/crypto/key_manager.h"
#include "core/file_sys/card_image.h" #include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h" #include "core/file_sys/content_archive.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/submission_package.h" #include "core/file_sys/submission_package.h"
#include "core/file_sys/vfs.h" #include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_real.h" #include "core/file_sys/vfs_real.h"
@ -48,63 +47,55 @@
#include "core/hid/emulated_controller.h" #include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h" #include "core/hid/hid_core.h"
#include "core/hid/hid_types.h" #include "core/hid/hid_types.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/applets/applets.h" #include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/perf_stats.h"
#include "jni/android_common/android_common.h" #include "jni/android_common/android_common.h"
#include "jni/applets/software_keyboard.h"
#include "jni/config.h" #include "jni/config.h"
#include "jni/emu_window/emu_window.h"
#include "jni/id_cache.h" #include "jni/id_cache.h"
#include "video_core/rasterizer_interface.h" #include "jni/native.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#define jconst [[maybe_unused]] const auto #define jconst [[maybe_unused]] const auto
#define jauto [[maybe_unused]] auto #define jauto [[maybe_unused]] auto
namespace { static EmulationSession s_instance;
class EmulationSession final { EmulationSession::EmulationSession() {
public:
EmulationSession() {
m_vfs = std::make_shared<FileSys::RealVfsFilesystem>(); m_vfs = std::make_shared<FileSys::RealVfsFilesystem>();
} }
~EmulationSession() = default; EmulationSession& EmulationSession::GetInstance() {
static EmulationSession& GetInstance() {
return s_instance; return s_instance;
} }
const Core::System& System() const { const Core::System& EmulationSession::System() const {
return m_system; return m_system;
} }
Core::System& System() { Core::System& EmulationSession::System() {
return m_system; return m_system;
} }
const EmuWindow_Android& Window() const { const EmuWindow_Android& EmulationSession::Window() const {
return *m_window; return *m_window;
} }
EmuWindow_Android& Window() { EmuWindow_Android& EmulationSession::Window() {
return *m_window; return *m_window;
} }
ANativeWindow* NativeWindow() const { ANativeWindow* EmulationSession::NativeWindow() const {
return m_native_window; return m_native_window;
} }
void SetNativeWindow(ANativeWindow* native_window) { void EmulationSession::SetNativeWindow(ANativeWindow* native_window) {
m_native_window = native_window; m_native_window = native_window;
} }
int InstallFileToNand(std::string filename, std::string file_extension) { int EmulationSession::InstallFileToNand(std::string filename, std::string file_extension) {
jconst copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, jconst copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
std::size_t block_size) { std::size_t block_size) {
if (src == nullptr || dest == nullptr) { if (src == nullptr || dest == nullptr) {
@ -153,8 +144,8 @@ public:
return InstallError; return InstallError;
} }
jconst res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry( jconst res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry(*nsp, true,
*nsp, true, copy_func); copy_func);
switch (res) { switch (res) {
case FileSys::InstallResult::Success: case FileSys::InstallResult::Success:
@ -168,7 +159,8 @@ public:
} }
} }
void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir, void EmulationSession::InitializeGpuDriver(const std::string& hook_lib_dir,
const std::string& custom_driver_dir,
const std::string& custom_driver_name, const std::string& custom_driver_name,
const std::string& file_redirect_dir) { const std::string& file_redirect_dir) {
#ifdef ARCHITECTURE_arm64 #ifdef ARCHITECTURE_arm64
@ -191,8 +183,7 @@ public:
// Try to load the system driver. // Try to load the system driver.
if (!handle) { if (!handle) {
handle = handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
nullptr, nullptr, file_redirect_dir_, nullptr); nullptr, nullptr, file_redirect_dir_, nullptr);
} }
@ -200,27 +191,27 @@ public:
#endif #endif
} }
bool IsRunning() const { bool EmulationSession::IsRunning() const {
return m_is_running; return m_is_running;
} }
bool IsPaused() const { bool EmulationSession::IsPaused() const {
return m_is_running && m_is_paused; return m_is_running && m_is_paused;
} }
const Core::PerfStatsResults& PerfStats() const { const Core::PerfStatsResults& EmulationSession::PerfStats() const {
std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex); std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
return m_perf_stats; return m_perf_stats;
} }
void SurfaceChanged() { void EmulationSession::SurfaceChanged() {
if (!IsRunning()) { if (!IsRunning()) {
return; return;
} }
m_window->OnSurfaceChanged(m_native_window); m_window->OnSurfaceChanged(m_native_window);
} }
void ConfigureFilesystemProvider(const std::string& filepath) { void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath) {
const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::Mode::Read); const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::Mode::Read);
if (!file) { if (!file) {
return; return;
@ -256,15 +247,30 @@ public:
} }
} }
Core::SystemResultStatus InitializeEmulation(const std::string& filepath) { void EmulationSession::InitializeSystem(bool reload) {
if (!reload) {
// Initialize logging system
Common::Log::Initialize();
Common::Log::SetColorConsoleBackendEnabled(true);
Common::Log::Start();
}
// Initialize filesystem.
m_system.SetFilesystem(m_vfs);
m_system.GetUserChannel().clear();
m_manual_provider = std::make_unique<FileSys::ManualContentProvider>();
m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
m_system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual,
m_manual_provider.get());
m_system.GetFileSystemController().CreateFactories(*m_vfs);
}
Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath) {
std::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
// Create the render window. // Create the render window.
m_window = std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window, m_window =
m_vulkan_library); std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window, m_vulkan_library);
m_system.SetFilesystem(m_vfs);
m_system.GetUserChannel().clear();
// Initialize system. // Initialize system.
jauto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>(); jauto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
@ -286,11 +292,6 @@ public:
}); });
// Initialize filesystem. // Initialize filesystem.
m_manual_provider = std::make_unique<FileSys::ManualContentProvider>();
m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
m_system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual,
m_manual_provider.get());
m_system.GetFileSystemController().CreateFactories(*m_vfs);
ConfigureFilesystemProvider(filepath); ConfigureFilesystemProvider(filepath);
// Initialize account manager // Initialize account manager
@ -310,7 +311,7 @@ public:
return Core::SystemResultStatus::Success; return Core::SystemResultStatus::Success;
} }
void ShutdownEmulation() { void EmulationSession::ShutdownEmulation() {
std::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
m_is_running = false; m_is_running = false;
@ -333,25 +334,25 @@ public:
m_window.reset(); m_window.reset();
} }
void PauseEmulation() { void EmulationSession::PauseEmulation() {
std::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
m_system.Pause(); m_system.Pause();
m_is_paused = true; m_is_paused = true;
} }
void UnPauseEmulation() { void EmulationSession::UnPauseEmulation() {
std::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
m_system.Run(); m_system.Run();
m_is_paused = false; m_is_paused = false;
} }
void HaltEmulation() { void EmulationSession::HaltEmulation() {
std::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
m_is_running = false; m_is_running = false;
m_cv.notify_one(); m_cv.notify_one();
} }
void RunEmulation() { void EmulationSession::RunEmulation() {
{ {
std::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
m_is_running = true; m_is_running = true;
@ -361,8 +362,7 @@ public:
if (Settings::values.use_disk_shader_cache.GetValue()) { if (Settings::values.use_disk_shader_cache.GetValue()) {
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
m_system.Renderer().ReadRasterizer()->LoadDiskResources( m_system.Renderer().ReadRasterizer()->LoadDiskResources(
m_system.GetApplicationProcessProgramID(), std::stop_token{}, m_system.GetApplicationProcessProgramID(), std::stop_token{}, LoadDiskCacheProgress);
LoadDiskCacheProgress);
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
} }
@ -391,23 +391,7 @@ public:
} }
} }
std::string GetRomTitle(const std::string& path) { bool EmulationSession::IsHandheldOnly() {
return GetRomMetadata(path).title;
}
std::vector<u8> GetRomIcon(const std::string& path) {
return GetRomMetadata(path).icon;
}
bool GetIsHomebrew(const std::string& path) {
return GetRomMetadata(path).isHomebrew;
}
void ResetRomMetadata() {
m_rom_metadata_cache.clear();
}
bool IsHandheldOnly() {
jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag(); jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag();
if (npad_style_set.fullkey == 1) { if (npad_style_set.fullkey == 1) {
@ -421,18 +405,17 @@ public:
return !Settings::IsDockedMode(); return !Settings::IsDockedMode();
} }
void SetDeviceType([[maybe_unused]] int index, int type) { void EmulationSession::SetDeviceType([[maybe_unused]] int index, int type) {
jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type)); controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type));
} }
void OnGamepadConnectEvent([[maybe_unused]] int index) { void EmulationSession::OnGamepadConnectEvent([[maybe_unused]] int index) {
jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
// Ensure that player1 is configured correctly and handheld disconnected // Ensure that player1 is configured correctly and handheld disconnected
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) { if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) {
jauto handheld = jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
@ -443,8 +426,7 @@ public:
// Ensure that handheld is configured correctly and player 1 disconnected // Ensure that handheld is configured correctly and player 1 disconnected
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) { if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) {
jauto player1 = jauto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) { if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) {
player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
@ -458,110 +440,35 @@ public:
} }
} }
void OnGamepadDisconnectEvent([[maybe_unused]] int index) { void EmulationSession::OnGamepadDisconnectEvent([[maybe_unused]] int index) {
jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
controller->Disconnect(); controller->Disconnect();
} }
SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard() { SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() {
return m_software_keyboard; return m_software_keyboard;
} }
private: void EmulationSession::LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress,
struct RomMetadata { int max) {
std::string title;
std::vector<u8> icon;
bool isHomebrew;
};
RomMetadata GetRomMetadata(const std::string& path) {
if (jauto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
return search->second;
}
return CacheRomMetadata(path);
}
RomMetadata CacheRomMetadata(const std::string& path) {
jconst file = Core::GetGameFileFromPath(m_vfs, path);
jauto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
RomMetadata entry;
loader->ReadTitle(entry.title);
loader->ReadIcon(entry.icon);
if (loader->GetFileType() == Loader::FileType::NRO) {
jauto loader_nro = reinterpret_cast<Loader::AppLoader_NRO*>(loader.get());
entry.isHomebrew = loader_nro->IsHomebrew();
} else {
entry.isHomebrew = false;
}
m_rom_metadata_cache[path] = entry;
return entry;
}
private:
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max) {
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(), env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(),
IDCache::GetDiskCacheLoadProgress(), static_cast<jint>(stage), IDCache::GetDiskCacheLoadProgress(), static_cast<jint>(stage),
static_cast<jint>(progress), static_cast<jint>(max)); static_cast<jint>(progress), static_cast<jint>(max));
} }
static void OnEmulationStarted() { void EmulationSession::OnEmulationStarted() {
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnEmulationStarted());
IDCache::GetOnEmulationStarted());
} }
static void OnEmulationStopped(Core::SystemResultStatus result) { void EmulationSession::OnEmulationStopped(Core::SystemResultStatus result) {
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnEmulationStopped(),
IDCache::GetOnEmulationStopped(), static_cast<jint>(result)); static_cast<jint>(result));
} }
private:
static EmulationSession s_instance;
// Frontend management
std::unordered_map<std::string, RomMetadata> m_rom_metadata_cache;
// Window management
std::unique_ptr<EmuWindow_Android> m_window;
ANativeWindow* m_native_window{};
// Core emulation
Core::System m_system;
InputCommon::InputSubsystem m_input_subsystem;
Common::DetachedTasks m_detached_tasks;
Core::PerfStatsResults m_perf_stats{};
std::shared_ptr<FileSys::VfsFilesystem> m_vfs;
Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
std::atomic<bool> m_is_running = false;
std::atomic<bool> m_is_paused = false;
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
// GPU driver parameters
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
// Synchronization
std::condition_variable_any m_cv;
mutable std::mutex m_perf_stats_mutex;
mutable std::mutex m_mutex;
};
/*static*/ EmulationSession EmulationSession::s_instance;
} // Anonymous namespace
static Core::SystemResultStatus RunEmulation(const std::string& filepath) { static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
Common::Log::Initialize();
Common::Log::SetColorConsoleBackendEnabled(true);
Common::Log::Start();
MicroProfileOnThreadCreate("EmuThread"); MicroProfileOnThreadCreate("EmuThread");
SCOPE_EXIT({ MicroProfileShutdown(); }); SCOPE_EXIT({ MicroProfileShutdown(); });
@ -657,10 +564,6 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_stopEmulation(JNIEnv* env, jclass cla
EmulationSession::GetInstance().HaltEmulation(); EmulationSession::GetInstance().HaltEmulation();
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_resetRomMetadata(JNIEnv* env, jclass clazz) {
EmulationSession::GetInstance().ResetRomMetadata();
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning(JNIEnv* env, jclass clazz) { jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning(JNIEnv* env, jclass clazz) {
return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning()); return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning());
} }
@ -766,52 +669,16 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass c
} }
} }
jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass clazz, void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz,
jstring j_filename) { jboolean reload) {
jauto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename));
jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size()));
env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon),
reinterpret_cast<jbyte*>(icon_data.data()));
return icon;
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle(JNIEnv* env, jclass clazz,
jstring j_filename) {
jauto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename));
return env->NewStringUTF(title.c_str());
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDescription(JNIEnv* env, jclass clazz,
jstring j_filename) {
return j_filename;
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId(JNIEnv* env, jclass clazz,
jstring j_filename) {
return j_filename;
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions(JNIEnv* env, jclass clazz,
jstring j_filename) {
return env->NewStringUTF("");
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany(JNIEnv* env, jclass clazz,
jstring j_filename) {
return env->NewStringUTF("");
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew(JNIEnv* env, jclass clazz,
jstring j_filename) {
return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename));
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation(JNIEnv* env, jclass clazz) {
// Create the default config.ini. // Create the default config.ini.
Config{}; Config{};
// Initialize the emulated system. // Initialize the emulated system.
if (!reload) {
EmulationSession::GetInstance().System().Initialize(); EmulationSession::GetInstance().System().Initialize();
} }
EmulationSession::GetInstance().InitializeSystem(reload);
}
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) { jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) {
return {}; return {};
@ -898,4 +765,49 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
} }
} }
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletLaunchPath(JNIEnv* env, jclass clazz,
jlong jid) {
auto bis_system =
EmulationSession::GetInstance().System().GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
return ToJString(env, "");
}
auto applet_nca =
bis_system->GetEntry(static_cast<u64>(jid), FileSys::ContentRecordType::Program);
if (!applet_nca) {
return ToJString(env, "");
}
return ToJString(env, applet_nca->GetFullPath());
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz,
jint jappletId) {
EmulationSession::GetInstance().System().GetAppletManager().SetCurrentAppletId(
static_cast<Service::AM::Applets::AppletId>(jappletId));
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass clazz,
jint jcabinetMode) {
EmulationSession::GetInstance().System().GetAppletManager().SetCabinetMode(
static_cast<Service::NFP::CabinetMode>(jcabinetMode));
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isFirmwareAvailable(JNIEnv* env, jclass clazz) {
auto bis_system =
EmulationSession::GetInstance().System().GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
return false;
}
// Query an applet to see if it's available
auto applet_nca =
bis_system->GetEntry(0x010000000000100Dull, FileSys::ContentRecordType::Program);
if (!applet_nca) {
return false;
}
return true;
}
} // extern "C" } // extern "C"

@ -0,0 +1,85 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <android/native_window_jni.h>
#include "common/detached_tasks.h"
#include "core/core.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/perf_stats.h"
#include "jni/applets/software_keyboard.h"
#include "jni/emu_window/emu_window.h"
#include "video_core/rasterizer_interface.h"
#pragma once
class EmulationSession final {
public:
explicit EmulationSession();
~EmulationSession() = default;
static EmulationSession& GetInstance();
const Core::System& System() const;
Core::System& System();
const EmuWindow_Android& Window() const;
EmuWindow_Android& Window();
ANativeWindow* NativeWindow() const;
void SetNativeWindow(ANativeWindow* native_window);
void SurfaceChanged();
int InstallFileToNand(std::string filename, std::string file_extension);
void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir,
const std::string& custom_driver_name,
const std::string& file_redirect_dir);
bool IsRunning() const;
bool IsPaused() const;
void PauseEmulation();
void UnPauseEmulation();
void HaltEmulation();
void RunEmulation();
void ShutdownEmulation();
const Core::PerfStatsResults& PerfStats() const;
void ConfigureFilesystemProvider(const std::string& filepath);
void InitializeSystem(bool reload);
Core::SystemResultStatus InitializeEmulation(const std::string& filepath);
bool IsHandheldOnly();
void SetDeviceType([[maybe_unused]] int index, int type);
void OnGamepadConnectEvent([[maybe_unused]] int index);
void OnGamepadDisconnectEvent([[maybe_unused]] int index);
SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard();
private:
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max);
static void OnEmulationStarted();
static void OnEmulationStopped(Core::SystemResultStatus result);
private:
// Window management
std::unique_ptr<EmuWindow_Android> m_window;
ANativeWindow* m_native_window{};
// Core emulation
Core::System m_system;
InputCommon::InputSubsystem m_input_subsystem;
Common::DetachedTasks m_detached_tasks;
Core::PerfStatsResults m_perf_stats{};
std::shared_ptr<FileSys::VfsFilesystem> m_vfs;
Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
std::atomic<bool> m_is_running = false;
std::atomic<bool> m_is_paused = false;
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
// GPU driver parameters
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
// Synchronization
std::condition_variable_any m_cv;
mutable std::mutex m_perf_stats_mutex;
mutable std::mutex m_mutex;
};

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <common/logging/log.h>
#include <jni.h>
#include "android_common/android_common.h"
extern "C" {
void Java_org_yuzu_yuzu_1emu_utils_Log_debug(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_DEBUG(Frontend, "{}", GetJString(env, jmessage));
}
void Java_org_yuzu_yuzu_1emu_utils_Log_warning(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_WARNING(Frontend, "{}", GetJString(env, jmessage));
}
void Java_org_yuzu_yuzu_1emu_utils_Log_info(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_INFO(Frontend, "{}", GetJString(env, jmessage));
}
void Java_org_yuzu_yuzu_1emu_utils_Log_error(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_ERROR(Frontend, "{}", GetJString(env, jmessage));
}
void Java_org_yuzu_yuzu_1emu_utils_Log_critical(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_CRITICAL(Frontend, "{}", GetJString(env, jmessage));
}
} // extern "C"

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z" />
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M17,16l-4,-4V8.82C14.16,8.4 15,7.3 15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6c0,1.3 0.84,2.4 2,2.82V12l-4,4H3v5h5v-3.05l4,-4.2 4,4.2V21h5v-5h-4z" />
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" />
</vector>

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M9,13m-1.25,0a1.25,1.25 0,1 1,2.5 0a1.25,1.25 0,1 1,-2.5 0" />
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M20.77,8.58l-0.92,2.01c0.09,0.46 0.15,0.93 0.15,1.41 0,4.41 -3.59,8 -8,8s-8,-3.59 -8,-8c0,-0.05 0.01,-0.1 0,-0.14 2.6,-0.98 4.69,-2.99 5.74,-5.55C11.58,8.56 14.37,10 17.5,10c0.45,0 0.89,-0.04 1.33,-0.1l-0.6,-1.32 -0.88,-1.93 -1.93,-0.88 -2.79,-1.27 2.79,-1.27 0.71,-0.32C14.87,2.33 13.47,2 12,2 6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10c0,-1.47 -0.33,-2.87 -0.9,-4.13l-0.33,0.71z" />
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M15,13m-1.25,0a1.25,1.25 0,1 1,2.5 0a1.25,1.25 0,1 1,-2.5 0" />
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M20.6,5.6L19.5,8l-1.1,-2.4L16,4.5l2.4,-1.1L19.5,1l1.1,2.4L23,4.5z" />
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z" />
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z" />
</vector>

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="?attr/materialCardViewOutlinedStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center"
android:padding="24dp">
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="20dp"
android:layout_gravity="center_vertical"
app:tint="?attr/colorOnSurface" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_gravity="center_vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
tools:text="@string/applets" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/description"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:textAlignment="viewStart"
tools:text="@string/applets_description" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

@ -1,63 +1,54 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
style="?attr/materialCardViewElevatedStyle"
android:id="@+id/card_game" android:id="@+id/card_game"
style="?attr/materialCardViewElevatedStyle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
android:clickable="true" android:clickable="true"
android:clipToPadding="false" android:clipToPadding="false"
android:focusable="true" android:focusable="true"
android:transitionName="card_game" android:transitionName="card_game"
android:layout_gravity="center" app:cardCornerRadius="4dp"
app:cardElevation="0dp" app:cardElevation="0dp">
app:cardCornerRadius="12dp">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="6dp"> android:padding="6dp">
<com.google.android.material.card.MaterialCardView <com.google.android.material.imageview.ShapeableImageView
style="?attr/materialCardViewElevatedStyle" android:id="@+id/image_game_screen"
android:id="@+id/card_game_art"
android:layout_width="150dp" android:layout_width="150dp"
android:layout_height="150dp" android:layout_height="150dp"
app:cardCornerRadius="4dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent"
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.ExtraSmall"
<ImageView
android:id="@+id/image_game_screen"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:src="@drawable/default_icon" /> tools:src="@drawable/default_icon" />
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.Material3.TitleMedium"
android:id="@+id/text_game_title" android:id="@+id/text_game_title"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="center" android:textAlignment="center"
android:textSize="14sp" android:textSize="14sp"
android:singleLine="true" app:layout_constraintEnd_toEndOf="@+id/image_game_screen"
android:marqueeRepeatLimit="marquee_forever" app:layout_constraintStart_toStartOf="@+id/image_game_screen"
android:ellipsize="none" app:layout_constraintTop_toBottomOf="@+id/image_game_screen"
android:requiresFadingEdge="horizontal"
app:layout_constraintEnd_toEndOf="@+id/card_game_art"
app:layout_constraintStart_toStartOf="@+id/card_game_art"
app:layout_constraintTop_toBottomOf="@+id/card_game_art"
tools:text="The Legend of Zelda: Skyward Sword" /> tools:text="The Legend of Zelda: Skyward Sword" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -16,7 +16,8 @@
<LinearLayout <LinearLayout
android:id="@+id/option_layout" android:id="@+id/option_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<ImageView <ImageView
android:id="@+id/option_icon" android:id="@+id/option_icon"

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/dialog_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:fadeScrollbars="false"
android:paddingVertical="12dp"
android:scrollbars="vertical" />
</androidx.appcompat.widget.LinearLayoutCompat>

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:paddingHorizontal="24dp"
android:paddingVertical="16dp">
<ImageView
android:id="@+id/icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center"
tools:src="@drawable/ic_nfc" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_gravity="center_vertical|start"
android:textAlignment="viewStart"
tools:text="List option" />
</LinearLayout>

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_applets"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_applets"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_applets"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/ic_back"
app:title="@string/applets" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_applets"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -25,6 +25,9 @@
<action <action
android:id="@+id/action_homeSettingsFragment_to_driverManagerFragment" android:id="@+id/action_homeSettingsFragment_to_driverManagerFragment"
app:destination="@id/driverManagerFragment" /> app:destination="@id/driverManagerFragment" />
<action
android:id="@+id/action_homeSettingsFragment_to_appletLauncherFragment"
app:destination="@id/appletLauncherFragment" />
</fragment> </fragment>
<fragment <fragment
@ -102,5 +105,17 @@
android:id="@+id/driverManagerFragment" android:id="@+id/driverManagerFragment"
android:name="org.yuzu.yuzu_emu.fragments.DriverManagerFragment" android:name="org.yuzu.yuzu_emu.fragments.DriverManagerFragment"
android:label="DriverManagerFragment" /> android:label="DriverManagerFragment" />
<fragment
android:id="@+id/appletLauncherFragment"
android:name="org.yuzu.yuzu_emu.fragments.AppletLauncherFragment"
android:label="AppletLauncherFragment" >
<action
android:id="@+id/action_appletLauncherFragment_to_cabinetLauncherDialogFragment"
app:destination="@id/cabinetLauncherDialogFragment" />
</fragment>
<dialog
android:id="@+id/cabinetLauncherDialogFragment"
android:name="org.yuzu.yuzu_emu.fragments.CabinetLauncherDialogFragment"
android:label="CabinetLauncherDialogFragment" />
</navigation> </navigation>

@ -0,0 +1,385 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="emulation_notification_channel_name">المحاكي نشط</string>
<string name="emulation_notification_channel_description">اظهار اشعار دائم عندما يكون المحاكي نشطاً</string>
<string name="emulation_notification_running">يوزو يعمل</string>
<string name="notice_notification_channel_name">الإشعارات والأخطاء</string>
<string name="notice_notification_channel_description">اظهار اشعار عند حصول اي مشكلة.</string>
<string name="notification_permission_not_granted">لم يتم منح إذن الإشعار</string>
<!-- Setup strings -->
<string name="welcome">مرحبًا</string>
<string name="welcome_description">والانتقال إلى المحاكاة <b>يوزو</b> تعرف على كيفية إعداد.</string>
<string name="get_started">لنبدأ</string>
<string name="keys">المفاتيح</string>
<string name="keys_description">اختر ملف &lt;b>prod.keys&lt;/b> من الزر ادناه</string>
<string name="select_keys">إختيار المفاتيح</string>
<string name="games">الألعاب</string>
<string name="games_description">اختر مجلد &lt;b>العابك&lt;/b> من الزر ادناه.</string>
<string name="done">إنهاء</string>
<string name="done_description">كل شيء جاهز./n استمتع بألعابك!</string>
<string name="text_continue">استمر</string>
<string name="next">التالي</string>
<string name="back">عودة</string>
<string name="add_games">إضافة ألعاب</string>
<string name="add_games_description">إختار مجلد ألعابك</string>
<string name="step_complete">مكتمل</string>
<!-- Home strings -->
<string name="home_games">الألعاب</string>
<string name="home_search">البحث</string>
<string name="home_settings">الإعدادات</string>
<string name="empty_gamelist">لم يتم العثور على ملفات او لم يتم تحديد مسار العاب.</string>
<string name="search_and_filter_games">بحث وتصفية الألعاب</string>
<string name="select_games_folder">تحديد مجلد الألعاب</string>
<string name="select_games_folder_description">يسمح لـ يوزو بملء قائمة الألعاب</string>
<string name="add_games_warning">تخطُ اختيار مجلد الالعاب؟</string>
<string name="add_games_warning_description">لن يتم عرض الألعاب في قائمة الألعاب إذا لم يتم تحديد مجلد</string>
<string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string>
<string name="home_search_games">البحث عن ألعاب</string>
<string name="search_settings">إعدادات البحث</string>
<string name="games_dir_selected">تم تحديد مجلد الألعاب</string>
<string name="install_prod_keys">تثبيت prod.keys</string>
<string name="install_prod_keys_description">مطلوب لفك تشفير ألعاب البيع بالتجزئة</string>
<string name="install_prod_keys_warning">تخطي إضافة المفاتيح؟</string>
<string name="install_prod_keys_warning_description">مطلوب مفاتيح صالحة لمحاكاة ألعاب البيع بالتجزئة. ستعمل تطبيقات البيرة المنزلية فقط إذا تابعت</string>
<string name="install_prod_keys_warning_help">https://yuzu-emu.org/help/quickstart/#guide-introduction</string>
<string name="notifications">التنبيهات</string>
<string name="notifications_description">امنح إذن الإشعار باستخدام الزر أدناه</string>
<string name="give_permission">منح الإذن</string>
<string name="notification_warning">تخطي منح إذن الإشعارات؟</string>
<string name="notification_warning_description">لن يتمكن يوزو من إشعارك بالمعلومات المهمة</string>
<string name="permission_denied">تم رفض الإذن</string>
<string name="permission_denied_description">لقد رفضت هذا الإذن عدة مرات ويتعين عليك الآن منحه يدويًا في إعدادات النظام</string>
<string name="about">حول</string>
<string name="about_description">بناء الإصدار، والاعتمادات، وأكثر من ذلك</string>
<string name="warning_help">مساعدة</string>
<string name="warning_skip">تخطي</string>
<string name="warning_cancel">إلغاء</string>
<string name="install_amiibo_keys">تثبيت مفاتيح أميبو</string>
<string name="install_amiibo_keys_description">مطلوب لاستخدام أميبو في اللعبة</string>
<string name="invalid_keys_file">تم تحديد ملف مفاتيح غير صالح</string>
<string name="install_keys_success">تم تثبيت المفاتيح بنجاح</string>
<string name="reading_keys_failure">خطأ في قراءة مفاتيح التشفير</string>
<string name="invalid_keys_error">مفاتيح التشفير غير صالحة</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">الملف المحدد غير صحيح أو تالف. يرجى إعادة المفاتيح الخاصة بك</string>
<string name="install_gpu_driver">GPU تثبيت برنامج تشغيل</string>
<string name="install_gpu_driver_description">قم بتثبيت برامج تشغيل بديلة للحصول على أداء أو دقة أفضل</string>
<string name="advanced_settings">إعدادات متقدمة</string>
<string name="advanced_settings_game">إعدادات متقدمة: %1$s</string>
<string name="settings_description">تكوين إعدادات المحاكي</string>
<string name="search_recently_played">لعبت مؤخرا</string>
<string name="search_recently_added">أضيف مؤخرا</string>
<string name="search_retail">بيع بالتجزئة</string>
<string name="search_homebrew">البيرة المنزلية</string>
<string name="open_user_folder">فتح مجلد يوزو</string>
<string name="open_user_folder_description">إدارة ملفات يوزو الداخلية</string>
<string name="theme_and_color_description">تعديل مظهر التطبيق</string>
<string name="no_file_manager">لم يتم العثور على مدير الملفات</string>
<string name="notification_no_directory_link">لا يمكن فتح مجلد يوزو</string>
<string name="notification_no_directory_link_description">الرجاء تحديد موقع مجلد المستخدم باستخدام اللوحة الجانبية لمدير الملفات يدويًا</string>
<string name="manage_save_data">إدارة حفظ البيانات</string>
<string name="manage_save_data_description">حفظ البيانات التي تم العثور عليها. يرجى اختيار أحد الخيارات التالية</string>
<string name="import_export_saves_description">استيراد أو تصدير ملفات الحفظ</string>
<string name="save_file_imported_success">تم الاستيراد بنجاح</string>
<string name="save_file_invalid_zip_structure">بنية مجلد الحفظ غير صالحة</string>
<string name="save_file_invalid_zip_structure_description">يجب أن يكون اسم المجلد الفرعي الأول هو معرف عنوان اللعبة.</string>
<string name="import_saves">استيراد</string>
<string name="export_saves">تصدير</string>
<string name="install_firmware">تثبيت البرامج الثابتة</string>
<string name="firmware_installing">تثبيت البرامج الثابتة</string>
<string name="firmware_installed_success">تم تثبيت البرامج الثابتة بنجاح</string>
<string name="firmware_installed_failure">فشل تثبيت البرامج الثابتة</string>
<string name="share_log">مشاركة سجلات التصحيح</string>
<string name="share_log_description">مشاركة ملف سجل يوزو لتصحيح المشكلات</string>
<string name="share_log_missing">لم يتم العثور على ملف السجل</string>
<string name="install_game_content">تثبيت محتوى اللعبة</string>
<string name="install_game_content_description">DLC قم بتثبيت تحديثات اللعبة أو</string>
<string name="installing_game_content">جارٍ تثبيت المحتوى</string>
<string name="install_game_content_failure_base">لا يُسمح بتثبيت الألعاب الأساسية لتجنب التعارضات المحتملة.</string>
<string name="install_game_content_success_install">%1$d تم التثبيت بنجاح</string>
<string name="install_game_content_success_overwrite">%1$d تمت الكتابة فوقه بنجاح</string>
<string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string>
<string name="custom_driver_not_supported">برامج التشغيل المخصصة غير مدعومة</string>
<string name="custom_driver_not_supported_description">تحميل برنامج التشغيل المخصص غير معتمد حاليًا لهذا الجهاز.\nحدد هذا الخيار مرة أخرى في المستقبل لمعرفة ما إذا تمت إضافة الدعم!</string>
<string name="manage_yuzu_data">إدارة بيانات يوزو</string>
<string name="manage_yuzu_data_description">استيراد/تصدير البرامج الثابتة والمفاتيح وبيانات المستخدم والمزيد!</string>
<string name="share_save_file">مشاركة ملف الحفظ</string>
<string name="export_save_failed">فشل تصدير الحفظ</string>
<string name="copied_to_clipboard">نسخ إلى الحافظة</string>
<string name="about_app_description">محاكي سويتش مفتوح المصدر</string>
<string name="contributors">المساهمين</string>
<string name="contributors_link">https://github.com/yuzu-emu/yuzu/graphs/contributors</string>
<string name="licenses_description">المشاريع التي تجعل تطبيق يوزو لنظام أندرويد ممكنًا</string>
<string name="build">البناء</string>
<string name="user_data">بيانات المستخدم</string>
<string name="exporting_user_data">جارٍ تصدير بيانات المستخدم</string>
<string name="importing_user_data">جارٍ استيراد بيانات المستخدم</string>
<string name="import_user_data">استيراد بيانات المستخدم</string>
<string name="invalid_yuzu_backup">نسخة احتياطية يوزو غير صالحة</string>
<string name="user_data_export_success">تم تصدير بيانات المستخدم بنجاح</string>
<string name="user_data_import_success">تم استيراد بيانات المستخدم بنجاح</string>
<string name="user_data_export_cancelled">تم إلغاء التصدير</string>
<string name="support_link">https://discord.gg/u77vRWY</string>
<string name="website_link">https://yuzu-emu.org/</string>
<string name="github_link">https://github.com/yuzu-emu</string>
<!-- Early access upgrade strings -->
<string name="early_access">الوصول المبكر</string>
<string name="get_early_access">احصل على الوصول المبكر</string>
<string name="play_store_link">https://play.google.com/store/apps/details?id=org.yuzu.yuzu_emu.ea</string>
<string name="get_early_access_description">الميزات المتطورة، والوصول المبكر إلى التحديثات، وأكثر من ذلك</string>
<string name="early_access_benefits">مزايا الوصول المبكر</string>
<string name="cutting_edge_features">ميزات متطورة</string>
<string name="early_access_updates">الوصول المبكر إلى التحديثات</string>
<string name="no_manual_installation">لا يوجد التثبيت اليدوي</string>
<string name="prioritized_support">الدعم ذو الأولوية</string>
<string name="helping_game_preservation">المساعدة في الحفاظ على اللعبة</string>
<string name="our_eternal_gratitude">امتناننا الأبدي</string>
<string name="are_you_interested">هل انت مهتم؟</string>
<!-- General settings strings -->
<string name="frame_limit_enable">الحد من السرعة</string>
<string name="frame_limit_enable_description">يحد من سرعة المحاكاة بنسبة محددة من السرعة العادية</string>
<string name="frame_limit_slider">الحد من السرعة في المئة</string>
<string name="frame_limit_slider_description">يحدد النسبة المئوية للحد من سرعة المحاكاة. 100% هي السرعة الطبيعية. ستؤدي القيم الأعلى أو الأدنى إلى زيادة أو تقليل حد السرعة.</string>
<string name="cpu_accuracy">دقة وحدة المعالجة المركزية</string>
<string name="value_with_units">%1$s%2$s</string>
<!-- System settings strings -->
<string name="use_docked_mode">وضع الإرساء</string>
<string name="use_docked_mode_description">زيادة الدقة، وانخفاض الأداء. يتم استخدام الوضع المحمول عند تعطيله، مما يؤدي إلى خفض الدقة وزيادة الأداء.</string>
<string name="emulated_region">المنطقة التي تمت محاكاتها</string>
<string name="emulated_language">لغة المحاكاه</string>
<string name="select_rtc_date">حدد التاريخ و الساعة في الوقت الحقيقي</string>
<string name="select_rtc_time">حدد وقت الساعة في الوقت الفعلي</string>
<string name="use_custom_rtc">ساعة مخصصة في الوقت الحقيقي</string>
<string name="use_custom_rtc_description">يسمح لك بتعيين ساعة مخصصة في الوقت الفعلي منفصلة عن وقت النظام الحالي لديك</string>
<string name="set_custom_rtc">تعيين ساعة مخصصة في الوقت الحقيقي</string>
<!-- Graphics settings strings -->
<string name="renderer_accuracy">مستوى الدقة</string>
<string name="renderer_resolution">(Handheld/Docked) الدقة</string>
<string name="renderer_vsync">VSync وضع</string>
<string name="renderer_screen_layout">الاتجاه</string>
<string name="renderer_aspect_ratio">تناسب الابعاد</string>
<string name="renderer_anti_aliasing">طريقة مكافحة التعرج</string>
<string name="renderer_asynchronous_shaders">استخدم تظليل غير متزامن</string>
<string name="renderer_asynchronous_shaders_description">يجمع التظليل بشكل غير متزامن، مما يقلل من التأتأة ولكنه قد يؤدي إلى حدوث بعض الأخطاء.</string>
<string name="renderer_reactive_flushing">استخدم التنظيف التفاعلي</string>
<string name="renderer_reactive_flushing_description">تحسين دقة العرض في بعض الألعاب على حساب الأداء</string>
<string name="use_disk_shader_cache_description">يقلل من التأتأة عن طريق تخزين وتحميل التظليلات التي تم إنشاؤها محليًا.</string>
<!-- Debug settings strings -->
<string name="cpu">وحدة المعالج المركزية</string>
<string name="cpu_debug_mode">تصحيح أخطاء وحدة المعالجة المركزية</string>
<string name="cpu_debug_mode_description">يضع وحدة المعالجة المركزية في وضع التصحيح البطيء.</string>
<string name="gpu">GPU</string>
<string name="renderer_api">API</string>
<string name="renderer_debug">تصحيح الأخطاء الرسومية</string>
<string name="renderer_debug_description">يضبط واجهة برمجة تطبيقات الرسومات على وضع تصحيح الأخطاء البطيء.</string>
<string name="fastmem">Fastmem</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">محرك الإخراج</string>
<string name="audio_volume">حجم</string>
<string name="audio_volume_description">يحدد حجم إخراج الصوت</string>
<!-- Miscellaneous -->
<string name="slider_default">افتراضي</string>
<string name="ini_saved">الإعدادات المحفوظة</string>
<string name="gameid_saved">الإعدادات المحفوظة لـ %1$s</string>
<string name="unimplemented_menu">القائمة غير المنفذة</string>
<string name="loading">جاري تحميل</string>
<string name="shutting_down">إيقاف تشغيل</string>
<string name="reset_setting_confirmation">هل تريد إعادة تعيين هذا الإعداد مرة أخرى إلى قيمته الافتراضية؟</string>
<string name="reset_to_default">إعادة تعيين إلى الافتراضي</string>
<string name="reset_all_settings">إعادة تعيين جميع الإعدادات؟</string>
<string name="reset_all_settings_description">سيتم إعادة تعيين كافة الإعدادات المتقدمة إلى تكوينها الافتراضي. هذا لا يمكن التراجع عنها.</string>
<string name="settings_reset">إعادة تعيين الأعدادات</string>
<string name="close">إغلاق</string>
<string name="learn_more">معرفة المزيد</string>
<string name="auto">تلقائي</string>
<string name="submit">إرسال</string>
<string name="string_null">قيمه خاليه</string>
<string name="string_import">استيراد</string>
<string name="export">تصدير</string>
<string name="export_failed">فشل التصدير</string>
<string name="import_failed">فشل الاستيراد</string>
<string name="cancelling">إلغاء</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">GPU حدد برنامج تشغيل</string>
<string name="select_gpu_driver_title">الحالي الخاص بك؟ GPU هل ترغب في استبدال برنامج تشغيل</string>
<string name="select_gpu_driver_install">تثبيت</string>
<string name="select_gpu_driver_default">افتراضي</string>
<string name="select_gpu_driver_use_default">يستخدم تعريف معالج الرسوميات الافتراضي</string>
<string name="select_gpu_driver_error">تم تحديد برنامج تشغيل غير صالح ، باستخدام النظام الافتراضي</string>
<string name="system_gpu_driver">تعريف معالج الرسوميات الخاص بالنظام</string>
<string name="installing_driver">جارٍ تثبيت برنامج التشغيل…</string>
<!-- Preferences Screen -->
<string name="preferences_settings">إعدادات</string>
<string name="preferences_general">عام</string>
<string name="preferences_system">النظام</string>
<string name="preferences_graphics">الرسوميات</string>
<string name="preferences_audio">الصوت</string>
<string name="preferences_theme">السمة واللون</string>
<string name="preferences_debug">تصحيح الأخطاء</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">الخاص بك ROM تم تشفير</string>
<string name="loader_error_video_core">حدث خطأ أثناء تهيئة مركز الفيديو</string>
<string name="loader_error_invalid_format">ROM غير قادر على تحميل</string>
<string name="loader_error_file_not_found">غير موجود ROM ملف</string>
<!-- Emulation Menu -->
<string name="emulation_exit">الخروج من المحاكاة</string>
<string name="emulation_done">منجز</string>
<string name="emulation_fps_counter">عداد إطار/ثانية</string>
<string name="emulation_toggle_controls">تبديل عناصر التحكم</string>
<string name="emulation_rel_stick_center">مركز العصا النسبي</string>
<string name="emulation_dpad_slide">مزلاق أزرار الاتجاهات</string>
<string name="emulation_haptics">الاهتزازات الديناميكية</string>
<string name="emulation_show_overlay">عرض التراكب</string>
<string name="emulation_toggle_all">تبديل الكل</string>
<string name="emulation_control_adjust">ضبط التراكب</string>
<string name="emulation_control_scale">حجم</string>
<string name="emulation_control_opacity">العتامه</string>
<string name="emulation_touch_overlay_reset">إعادة تعيين التراكب</string>
<string name="emulation_touch_overlay_edit">تحرير التراكب</string>
<string name="emulation_pause">إيقاف المحاكاة مؤقتًا</string>
<string name="emulation_unpause">إلغاء الإيقاف المؤقت للمضاهاة</string>
<string name="emulation_input_overlay">خيارات التراكب</string>
<string name="load_settings">جارٍ تحميل الإعدادات</string>
<!-- Software keyboard -->
<string name="software_keyboard">لوحة المفاتيح البرمجية</string>
<!-- Errors and warnings -->
<string name="abort_button">إلغاء</string>
<string name="continue_button">استمر</string>
<string name="system_archive_not_found">لم يتم العثور على أرشيف النظام</string>
<string name="system_archive_general">أرشيف النظام</string>
<string name="save_load_error">خطأ في الحفظ/التحميل</string>
<string name="fatal_error">خطا فادح</string>
<string name="performance_warning">سيؤدي إيقاف تشغيل هذا الإعداد إلى تقليل أداء المحاكاة بشكل ملحوظ! للحصول على أفضل تجربة، يوصى بترك هذا الإعداد ممكنًا.</string>
<string name="memory_formatted">%1$s %2$s</string>
<string name="no_game_present">لا توجد لعبة قابلة للتمهيد</string>
<!-- Region Names -->
<string name="region_japan">اليابان</string>
<string name="region_usa">الولايات المتحدة الأمريكية</string>
<string name="region_europe">أوروبا</string>
<string name="region_australia">أستراليا</string>
<string name="region_china">الصين</string>
<string name="region_korea">كوريا</string>
<string name="region_taiwan">تايوان</string>
<!-- Memory Sizes -->
<string name="memory_byte">Byte</string>
<string name="memory_kilobyte">KB</string>
<string name="memory_megabyte">MB</string>
<string name="memory_gigabyte">GB</string>
<string name="memory_terabyte">TB</string>
<string name="memory_petabyte">PB</string>
<string name="memory_exabyte">EB</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>
<string name="renderer_none">لاشيء</string>
<!-- Renderer Accuracy -->
<string name="renderer_accuracy_normal">عادي</string>
<string name="renderer_accuracy_high">عالي</string>
<string name="renderer_accuracy_extreme">Extreme (بطيء)</string>
<!-- Resolutions -->
<string name="resolution_half">0.5X (360p/540p)</string>
<string name="resolution_three_quarter">0.75X (540p/810p)</string>
<string name="resolution_one">1X (720p/1080p)</string>
<string name="resolution_two">2X (1440p/2160p) (بطيء)</string>
<string name="resolution_three">3X (2160p/3240p) (بطيء)</string>
<string name="resolution_four">4X (2880p/4320p) (بطيء)</string>
<!-- Renderer VSync -->
<string name="renderer_vsync_immediate">Immediate (Off)</string>
<string name="renderer_vsync_mailbox">Mailbox</string>
<string name="renderer_vsync_fifo">FIFO (On)</string>
<string name="renderer_vsync_fifo_relaxed">FIFO Relaxed</string>
<!-- Scaling Filters -->
<string name="scaling_filter_nearest_neighbor">Nearest Neighbor</string>
<string name="scaling_filter_bilinear">Bilinear</string>
<string name="scaling_filter_bicubic">Bicubic</string>
<string name="scaling_filter_gaussian">Gaussian</string>
<string name="scaling_filter_scale_force">ScaleForce</string>
<string name="scaling_filter_fsr">AMD FidelityFX™ Super Resolution</string>
<!-- Anti-Aliasing -->
<string name="anti_aliasing_none">لا شيء</string>
<string name="anti_aliasing_fxaa">FXAA</string>
<string name="anti_aliasing_smaa">SMAA</string>
<!-- Screen Layouts -->
<string name="screen_layout_landscape">افقي</string>
<string name="screen_layout_portrait">عمودي</string>
<string name="screen_layout_auto">تلقائي</string>
<!-- Aspect Ratios -->
<string name="ratio_default">(16:9) افتراضي</string>
<string name="ratio_force_four_three">4:3 فرض</string>
<string name="ratio_force_twenty_one_nine">21:9 فرض</string>
<string name="ratio_force_sixteen_ten">16:10 فرض</string>
<string name="ratio_stretch">تمتد إلى النافذة</string>
<!-- CPU Accuracy -->
<string name="cpu_accuracy_accurate">دقه</string>
<string name="cpu_accuracy_unsafe">غير آمن</string>
<string name="cpu_accuracy_paranoid">Paranoid (Slow)</string>
<!-- Gamepad Buttons -->
<string name="gamepad_d_pad">أزرار الاتجاهات</string>
<string name="gamepad_left_stick">العصا اليسرى</string>
<string name="gamepad_right_stick">العصا اليمنى</string>
<string name="gamepad_home">شاشة الإستقبال</string>
<string name="gamepad_screenshot">لقطة شاشة</string>
<!-- Disk shader cache -->
<string name="preparing_shaders">تحضير التظليل</string>
<string name="building_shaders">بناء التظليل</string>
<!-- Theme options -->
<string name="change_app_theme">تغيير سمة التطبيق</string>
<string name="theme_default">افتراضي</string>
<string name="theme_material_you">Material You</string>
<!-- Theme Modes -->
<string name="change_theme_mode">تغيير وضع السمة</string>
<string name="theme_mode_follow_system">اتبع النظام</string>
<string name="theme_mode_light">فاتح</string>
<string name="theme_mode_dark">غامق</string>
<!-- Audio output engines -->
<string name="cubeb">cubeb</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">خلفيات سوداء</string>
<string name="use_black_backgrounds_description">عند استخدام المظهر الداكن، قم بتطبيق خلفيات سوداء.</string>
<!-- Picture-In-Picture -->
<string name="picture_in_picture">صورة داخل صورة</string>
<string name="picture_in_picture_description">تصغير النافذة عند وضعها في الخلفية</string>
<string name="pause">توقف</string>
<string name="play">تشغيل</string>
<string name="mute">كتم</string>
<string name="unmute">إلغاء الكتم</string>
<!-- Licenses screen strings -->
<string name="licenses">التراخيص</string>
<string name="license_fidelityfx_fsr_description">AMD ترقية عالية الجودة من</string>
</resources>

@ -0,0 +1,336 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">ئەم نەرمەکاڵایە یارییەکانی کۆنسۆلی نینتێندۆ سویچ کارپێدەکات. هیچ ناونیشانێکی یاری و کلیلی تێدا نییە..&lt;br /&gt;&lt;br /&gt;پێش ئەوەی دەست پێ بکەیت، تکایە شوێنی فایلی <![CDATA[<b> prod.keys </b>]]> دیاریبکە لە نێو کۆگای ئامێرەکەت.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">زیاتر فێربە</a>]]></string>
<string name="emulation_notification_channel_name">ئیمولەیشن کارایە</string>
<string name="emulation_notification_channel_description">ئاگادارکردنەوەیەکی بەردەوام نیشان دەدات کاتێک ئیمولەیشن کاردەکات.</string>
<string name="emulation_notification_running">یوزو کاردەکات</string>
<string name="notice_notification_channel_name">ئاگاداری و هەڵەکان</string>
<string name="notice_notification_channel_description">ئاگادارکردنەوەکان پیشان دەدات کاتێک شتێک بە هەڵەدا دەچێت.</string>
<string name="notification_permission_not_granted">مۆڵەتی ئاگادارکردنەوە نەدراوە!</string>
<!-- Setup strings -->
<string name="welcome">بەخێربێیت!</string>
<string name="welcome_description">فێربە چۆن &lt;b>yuzu&lt;/b> ڕێکبخەیت و بچییە ناو ئیمولەیشن.</string>
<string name="get_started">دەست پێبکە</string>
<string name="keys">کلیلەکان</string>
<string name="keys_description">فایلی &lt;b>prod.keys&lt;/b> هەڵبژێرە بە دوگمەی خوارەوە.</string>
<string name="select_keys">کلیلەکان هەڵبژێرە</string>
<string name="games">یاریەکان</string>
<string name="games_description">فۆڵدەری &lt;b>Games&lt;/b> هەڵبژێرە بە دوگمەی خوارەوە.</string>
<string name="done">تەواو</string>
<string name="done_description">تۆ تەواو ئامادەیت.\nچێژ لە یارییەکانت وەربگرە!</string>
<string name="text_continue">بەردەوام بوون</string>
<string name="next">دواتر</string>
<string name="back">گەڕانەوە</string>
<string name="add_games">زیادکردنی یاری</string>
<string name="add_games_description">فۆڵدەری یارییەکانت هەڵبژێرە</string>
<!-- Home strings -->
<string name="home_games">یاریەکان</string>
<string name="home_search">گەڕان</string>
<string name="home_settings">ڕێکخستنەکان</string>
<string name="empty_gamelist">تا ئێستا هیچ فایلێک نەدۆزراوەتەوە یان هیچ ناونیشانێکی یاری هەڵنەبژێردراوە.</string>
<string name="search_and_filter_games">گەڕان و فلتەرکردنی یارییەکان</string>
<string name="select_games_folder">فۆڵدەری یارییەکان هەڵبژێرە</string>
<string name="select_games_folder_description">ڕێگە بە یوزو دەدات بۆ پڕکردنەوەی لیستی یارییەکان</string>
<string name="add_games_warning">هەڵبژاردنی فۆڵدەری یارییەکان تێپەڕدەکەیت؟</string>
<string name="add_games_warning_description">یارییەکان لە لیستی یارییەکاندا پیشان نادرێن ئەگەر فۆڵدەرێک هەڵنەبژێردرێت.</string>
<string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string>
<string name="home_search_games">گەڕان بەدوای یارییەکاندا</string>
<string name="games_dir_selected">ناونیشانی یارییەکان هەڵبژێردرا</string>
<string name="install_prod_keys">دابمەزرێنە prod.keys</string>
<string name="install_prod_keys_description">پێویستە بۆ کۆدکردنەوەى یارییە تاکەکەسییەکان</string>
<string name="install_prod_keys_warning">زیادکردنی کلیلەکان تێپەڕدەکەیت؟</string>
<string name="install_prod_keys_warning_description">کلیلی دروست پێویستە بۆ وەرگرتنی یارییەکانی تاکەکەسی. تەنها ئەپەکانی homebrew کاردەکەن ئەگەر بەردەوام بیت.</string>
<string name="install_prod_keys_warning_help">https://yuzu-emu.org/help/quickstart/#guide-introduction</string>
<string name="notifications">ئاگادارکردنەوەکان</string>
<string name="notifications_description">بە دوگمەی خوارەوە مۆڵەتی ئاگادارکردنەوەکە بدە.</string>
<string name="give_permission">مۆڵەت بدە</string>
<string name="notification_warning">پێدانی مۆڵەتی ئاگادارکردنەوە تێپەڕدەکەیت؟</string>
<string name="notification_warning_description">یوزو ناتوانێت لە زانیاری گرنگ ئاگادارت بکاتەوە.</string>
<string name="permission_denied">مۆڵەت پێدان ڕەتکرایەوە</string>
<string name="permission_denied_description">زۆر جار ئەم مۆڵەتەت ڕەتکردۆتەوە و ئێستا دەبێت بە دەستی ڕێگەپێدان بکەیت لە ڕێکخستنەکانی سیستەمدا.</string>
<string name="about">دەربارە</string>
<string name="about_description">وەشانی دروستکردن، بیتبێن و زۆر شتیتر</string>
<string name="warning_help">یارمەتی</string>
<string name="warning_skip">پەڕاندن</string>
<string name="warning_cancel">ڕەتکردنەوە</string>
<string name="install_amiibo_keys">دامەزراندنی کلیلی Amiibo</string>
<string name="install_amiibo_keys_description">پێویستە بۆ بەکارهێنانی Amiibo لە یاریدا</string>
<string name="invalid_keys_file">فایلی کلیلێکی نادروست هەڵبژێردرا</string>
<string name="install_keys_success">کلیلەکان بە سەرکەوتوویی دامەزران</string>
<string name="reading_keys_failure">هەڵە لە خوێندنەوەی کۆدکردنی کلیل</string>
<string name="install_prod_keys_failure_extension_description">دڵنیابەوە کە فایلی کلیلەکانت درێژکراوەی .keys ی هەیە و دووبارە هەوڵبدەرەوە.</string>
<string name="install_amiibo_keys_failure_extension_description">دڵنیابە کە فایلی کلیلەکانت درێژکراوەی .bin ی هەیە و دووبارە هەوڵبدەرەوە.</string>
<string name="invalid_keys_error">کلیلی کۆدکردنی نادروستە</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">فایلە هەڵبژێردراوەکە هەڵەیە یان تێکچووە. تکایە دووبارە کلیلەکانت دەربێنەوە.</string>
<string name="install_gpu_driver">دامەزراندنی وەگەڕخەری GPU</string>
<string name="install_gpu_driver_description">دامەزراندنی وەگەڕخەری بەدیل بۆ ئەوەی بە ئەگەرێکی زۆرەوە کارایی باشتر یان وردبینی هەبێت</string>
<string name="advanced_settings">ڕێکخستنە پێشکەوتووەکان</string>
<string name="settings_description">سازدانی ڕێکخستنەکانی ئیمولەیتەر</string>
<string name="search_recently_played">بەم دواییە یاری کردووە</string>
<string name="search_recently_added">بەم دواییە زیادکرا</string>
<string name="search_retail">بەتاک</string>
<string name="search_homebrew">هۆم بریو</string>
<string name="open_user_folder">کردنەوەی فۆڵدەری یوزو</string>
<string name="open_user_folder_description">بەڕێوەبردنی فایلە ناوخۆییەکانی یوزو</string>
<string name="theme_and_color_description">دەستکاری کردنی شێوازی ئەپەکە</string>
<string name="no_file_manager">هیچ فایل بەڕێوەبەرێک نەدۆزرایەوە</string>
<string name="notification_no_directory_link">نەتوانرا ناونیشانی یوزو بکرێتەوە</string>
<string name="notification_no_directory_link_description">تکایە شوێنی فۆڵدەری بەکارهێنەر لەگەڵ پانێڵی لایەنی فایل بەڕێوەبارەکان بە دەست بدۆزەرەوە.</string>
<string name="manage_save_data">بەڕێوەبردنی داتای پاشەکەوتکراو</string>
<string name="manage_save_data_description">داتای پاشەکەوتکراو دۆزراوە. تکایە لە خوارەوە بژاردەیەک هەڵبژێرە.</string>
<string name="import_export_saves_description">هاوردەکردن یان هەناردەکردنی فایلی پاشەکەوتکراو</string>
<string name="save_file_imported_success">بە سەرکەوتوویی هاوردە کرا</string>
<string name="save_file_invalid_zip_structure">پێکهاتەی شوێنی پاشەکەوتکراو نادروستە</string>
<string name="save_file_invalid_zip_structure_description">ناوی یەکەمی فۆڵدەر دەبێت ناسنامەی ناونیشانی یارییەکە بێت.</string>
<string name="import_saves">هاوردەکردن</string>
<string name="export_saves">هەناردەکردن</string>
<string name="install_firmware">دامەزراندنی پتەوواڵا</string>
<string name="install_firmware_description">پتەوواڵا دەبێت لە ئەرشیفی زیپدا بێت و پێویستە بۆ بووتکردنی هەندێک یاری</string>
<string name="firmware_installing">دامەزرانی پتەوواڵا</string>
<string name="firmware_installed_success">پتەوواڵا بە سەرکەوتوویی دامەزرا</string>
<string name="firmware_installed_failure">دامەزراندنی پتەوواڵا شکستی هێنا</string>
<string name="share_log">هاوبەشی پێکردنی لۆگەکانی چاککردنەوە</string>
<string name="share_log_description">فایلە لۆگەکەی یوزو هاوبەش بکە بۆ چاککردنی کێشەکان</string>
<string name="share_log_missing">هیچ فایلێکی لۆگ نەدۆزراوە</string>
<string name="install_game_content">دامەزراندنی ناوەڕۆکی یاری</string>
<string name="install_game_content_description">دامەزراندنی نوێکاری یارییەکان یان DLC</string>
<string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string>
<!-- About screen strings -->
<string name="gaia_is_not_real">گایا ڕاستەقینە نییە</string>
<string name="copied_to_clipboard">کۆپی کرا بۆ تەختەی نووسین</string>
<string name="about_app_description">ئیمۆلیتەرێکی سەرچاوە-کراوەی سویچ</string>
<string name="contributors">بەشداربووان</string>
<string name="contributors_description">دروستکراوە لەگەڵ \u2764 لەلایەن تیمەکەی یوزو</string>
<string name="contributors_link">https://github.com/yuzu-emu/yuzu/graphs/contributors</string>
<string name="licenses_description">ئەو پڕۆژانەی کە یوزوی بۆ ئەندرۆید ڕەخساند</string>
<string name="build">بونیات</string>
<string name="support_link">https://discord.gg/u77vRWY</string>
<string name="website_link">https://yuzu-emu.org/</string>
<string name="github_link">https://github.com/yuzu-emu</string>
<!-- Early access upgrade strings -->
<string name="early_access">بەزوویی دەسپێگەشتن</string>
<string name="get_early_access">بەدەستهێنانی بەزوویی دەسپێگەشتن</string>
<string name="play_store_link">https://play.google.com/store/apps/details?id=org.yuzu.yuzu_emu.ea</string>
<string name="get_early_access_description">تایبەتمەندییە پێشکەوتووەکان، بەزوویی دەستگەیشتن بە نوێکارییەکان و زۆر شتی تر</string>
<string name="early_access_benefits">سوودەکانی بەزوویی دەسپێگەشتن</string>
<string name="cutting_edge_features">تایبەتمەندییە پێشکەوتووەکان</string>
<string name="early_access_updates">زوو دەستگەیشتن بە نوێکارییەکان</string>
<string name="no_manual_installation">چیتر دامەزراندنی دەستی نییە</string>
<string name="prioritized_support">پشتگیری لە پێشینە</string>
<string name="helping_game_preservation">یارمەتیدانی پاراستنی یارییەکان</string>
<string name="our_eternal_gratitude">سوپاس و پێزانینی هەمیشەییمان</string>
<string name="are_you_interested">ئایا تۆ خوازیاریت؟</string>
<!-- General settings strings -->
<string name="frame_limit_enable">سنووردارکردنی خێرایی</string>
<string name="frame_limit_enable_description">خێرایی ئیمولەیشن سنووردار دەکات بۆ ڕێژەیەکی دیاریکراو لە خێرایی ئاسایی.</string>
<string name="frame_limit_slider">سنووردارکردنی لەسەدای خێرایی</string>
<string name="frame_limit_slider_description">ڕێژەی سەدی دیاری دەکات بۆ سنووردارکردنی خێرایی ئیمولەیشن. 100% خێرایی ئاساییە. بەهایی بەرزتر یان نزمتر دەبێتە هۆی زیاد یان کەمکردنەوەی سنووری خێرایی.</string>
<string name="cpu_accuracy">وردی CPU</string>
<!-- System settings strings -->
<string name="use_docked_mode">دۆخی دۆککراو</string>
<string name="use_docked_mode_description">ڕوونی زیاد دەکات، کارایی کەم دەکاتەوە. دۆخی دەستی بەکاردێت کاتێک لەکاردەخرێت، ئەمەش ڕوونی دادەبەزێنێت و کارایی زیاد دەکات.</string>
<string name="emulated_region">ناوچەی ئیمولەیشن</string>
<string name="emulated_language">زمانی ئیمولەیتەر</string>
<string name="select_rtc_date">هەڵبژاردنی بەرواری RTC</string>
<string name="select_rtc_time">هەڵبژاردنی کاتی RTC</string>
<string name="use_custom_rtc">RTCی تایبەتمەند</string>
<string name="use_custom_rtc_description">ڕێگەت پێدەدات کاتژمێرێکی کاتی ڕاستەقینەی تایبەتمەند دابنێیت کە جیاوازە لە کاتی ئێستای سیستەمەکەت.</string>
<string name="set_custom_rtc">دانانی RTCی تایبەتمەند</string>
<!-- Graphics settings strings -->
<string name="renderer_accuracy">ئاستی وردبینی</string>
<string name="renderer_resolution">ڕوونی (دۆخی دەستی/دۆخی دۆک)</string>
<string name="renderer_vsync">دۆخی VSync</string>
<string name="renderer_aspect_ratio">ڕێژەی ڕووبەری شاشە</string>
<string name="renderer_scaling_filter">فلتەری گونجاندنی پەنجەرە</string>
<string name="renderer_anti_aliasing">شێوازی دژە-خاوڕۆیی</string>
<string name="renderer_force_max_clock">ناچاریکردن بۆ زۆرترین کاتژمێر (تەنها ئەدرینۆ)</string>
<string name="renderer_force_max_clock_description">GPU ناچار دەکات بە زۆرترین کاتژمێر کاربکات (هێشتا سنووردارکردنی گەرمی جێبەجێ دەکرێت).</string>
<string name="renderer_asynchronous_shaders">بەکارهێنانی سێبەری ناهاوسەنگ</string>
<string name="renderer_asynchronous_shaders_description">سێبەرەکان بە شێوەیەکی ناهاوسەنگ کۆدەکاتەوە، پچڕپچڕی کەمدەکاتەوە بەڵام لەوانەیە گلێچ دروستکا.</string>
<string name="renderer_reactive_flushing">بەکارهێنانی بەرپێچدەرەوە</string>
<string name="renderer_reactive_flushing_description">وردی ڕێندەرکردن لە هەندێک یاریدا باشتر دەکات لەسەر تێچووی کارایی.</string>
<string name="use_disk_shader_cache">بیرگەخێرای سێبەری دیسک</string>
<string name="use_disk_shader_cache_description">پچڕپچڕی کەمدەکاتەوە بە هەڵگرتن و بارکردنی سێبەری دروستکراو لە ناوخۆدا.</string>
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
<string name="renderer_api">API گرافیک</string>
<string name="renderer_debug">چاککردنەوەی گرافیک</string>
<string name="renderer_debug_description">API ی گرافیکەکان ڕێکدەخات بۆ دۆخی چاککردنی خاو.</string>
<string name="audio_volume">قەبارەی دەنگی</string>
<string name="audio_volume_description">دیاریکردنی قەبارەی دەنگی دەرچووی بیستۆک و بزوێنەری دەنگی دەرەکی.</string>
<!-- Miscellaneous -->
<string name="slider_default">بنەڕەت</string>
<string name="ini_saved">ڕێکخستنە پاشەکەوتکراوەکان</string>
<string name="gameid_saved">ڕێکخستنە پاشەکەوتکراوەکان بۆ %1$s</string>
<string name="error_saving">هەڵە لە پاشەکەوتکردن %1$s.ini: %2$s</string>
<string name="loading">بارکردن...</string>
<string name="reset_setting_confirmation">ئایا دەتەوێت ئەم ڕێکخستنە بگەڕێنیتەوە بۆ بەهای بنەڕەتی خۆی؟</string>
<string name="reset_to_default">دوبارە ڕێکخستنەوەی بۆ بنەڕەت</string>
<string name="reset_all_settings">هەموو ڕێکخستنەکان دوبارە ڕێک دەخاتەوە؟</string>
<string name="reset_all_settings_description">هەموو ڕێکخستنە پێشکەوتووەکان دەگەڕێنەوە بۆ ڕێکخستنی بنەڕەتی خۆیان. پاشگەز بوونەوەی نییه.</string>
<string name="settings_reset">دوبارە ڕێککردنەوەی ڕێکخستنەکان</string>
<string name="close">داخستن</string>
<string name="learn_more">زیاتر فێربە</string>
<string name="auto">خودکار</string>
<string name="submit">پێشکەشکردن</string>
<string name="string_import">هاوردەکردن</string>
<string name="export">هەناردەکردن</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">هەڵبژاردنی وەگەڕخەری GPU</string>
<string name="select_gpu_driver_title">حەز دەکەیت وەگەڕخەری GPU ی ئێستات بگۆڕیت؟</string>
<string name="select_gpu_driver_install">دامەزراندن</string>
<string name="select_gpu_driver_default">بنەڕەت</string>
<string name="select_gpu_driver_use_default">بەکارهێنانی وەگەڕخەری GPU ی بنەڕەت</string>
<string name="select_gpu_driver_error">وەگەڕخەری نادروست هەڵبژێردرا، بە بەکارهێنانی بنەڕەتی سیستەم!</string>
<string name="system_gpu_driver">وەگەڕخەری GPU ی سیستەم</string>
<string name="installing_driver">دامەزراندنی وەگەڕخەر...</string>
<!-- Preferences Screen -->
<string name="preferences_settings">ڕێکخستنەکان</string>
<string name="preferences_general">گشتی</string>
<string name="preferences_system">سیستەم</string>
<string name="preferences_graphics">گرافیک</string>
<string name="preferences_audio">دەنگ</string>
<string name="preferences_theme">ڕەنگ و ڕووکار</string>
<string name="preferences_debug">چاککردنەوە</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">ڕۆمەکەت کۆدکراوە</string>
<string name="loader_error_encrypted_keys_description"><![CDATA[تکایە دڵنیابەوە لەدامەزراوی <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> فایلەکەت بۆ ئەوەی بتوانرێت یارییەکان کۆد بکرێنەوە.]]></string>
<string name="loader_error_video_core">هەڵەیەک لە دەستپێکردنی ناوەکی ڤیدیۆکەدا ڕوویدا</string>
<string name="loader_error_video_core_description">ئەمەش بەزۆری بەهۆی وەگەڕخەرێکی ناتەبای GPU ەوەیە. دامەزراندنی وەگەڕخەری GPU ی تایبەتمەندکراو لەوانەیە ئەم کێشەیە چارەسەر بکات.</string>
<string name="loader_error_invalid_format">ناتوانرێت ڕۆم باربکرێت</string>
<string name="loader_error_file_not_found">فایلی ڕۆم بوونی نییە</string>
<!-- Emulation Menu -->
<string name="emulation_exit">دەرچوون لە ئیمولەیشن</string>
<string name="emulation_done">تەواو</string>
<string name="emulation_fps_counter">FPS ژمێر</string>
<string name="emulation_toggle_controls">گۆڕینی کۆنتڕۆڵ</string>
<string name="emulation_rel_stick_center">ناوەندی گێڕ بەنزیکەیی</string>
<string name="emulation_dpad_slide">خلیسکانی 4 دوگمەکە</string>
<string name="emulation_haptics">لەرینەوەی پەنجەلێدان</string>
<string name="emulation_show_overlay">نیشاندانی داپۆشەر</string>
<string name="emulation_toggle_all">گۆڕینی سەرجەم</string>
<string name="emulation_control_adjust">ڕێکخستنی داپۆشەر</string>
<string name="emulation_control_scale">پێوەر</string>
<string name="emulation_control_opacity">ڕوونی</string>
<string name="emulation_touch_overlay_reset">دووبارە ڕێکخستنەوەی داپۆشەر</string>
<string name="emulation_touch_overlay_edit">دەستکاریکردنی داپۆشەر</string>
<string name="emulation_pause">وەستاندنی ئیمولەیشن</string>
<string name="emulation_unpause">لادانی وەستاندنی ئیمولەیشن</string>
<string name="emulation_input_overlay">هەڵبژاردەکانی داپۆشەر</string>
<string name="load_settings">بارکردنی ڕێکخستنەکان...</string>
<!-- Software keyboard -->
<string name="software_keyboard">کیبۆردی نەرمەکاڵا</string>
<!-- Errors and warnings -->
<string name="abort_button">دەربارە</string>
<string name="continue_button">بەردەوام بوون</string>
<string name="system_archive_not_found">ئەرشیفی سیستەم نەدۆزراوە</string>
<string name="system_archive_not_found_message">%s دیار نییە. تکایە ئەرشیفی سیستەمەکەت فڕێ بدە.\nبەردەوامی ئیمولەیشن لەوانەیە ببێتە هۆی تێکچوون و فڕێدانەدەرەوە.</string>
<string name="system_archive_general">ئەرشیفێکی سیستەم</string>
<string name="save_load_error">هەڵەی پاشەکەوتکردن/بارکردن</string>
<string name="fatal_error">هەڵەی کوشندە</string>
<string name="fatal_error_message">هەڵەیەکی کوشندە ڕوویدا. بۆ وردەکارییەکان لۆگەکە بپشکنە.\nبەردەوامی ئیمولەیشن لەوانەیە ببێتە هۆی تێکچوون و فڕێدانەدەرەوە.</string>
<string name="performance_warning">کوژاندنەوەی ئەم ڕێکخستنە دەبێتە هۆی کەمکردنەوەی کارایی ئیمولەیشن! بۆ باشترین ئەزموون، باشترە ئەم ڕێکخستنە چالاک بهێڵیتەوە.</string>
<!-- Region Names -->
<string name="region_japan">ژاپۆن</string>
<string name="region_usa">ئەمریکا</string>
<string name="region_europe">ئەورووپا</string>
<string name="region_australia">ئوسترالیا</string>
<string name="region_china">چین</string>
<string name="region_korea">کۆریا</string>
<string name="region_taiwan">تایوان</string>
<string name="memory_gigabyte">GB</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">ڤوڵکان</string>
<string name="renderer_none">هیچ</string>
<!-- Renderer Accuracy -->
<string name="renderer_accuracy_normal">ئاسایی</string>
<string name="renderer_accuracy_high">بەرز</string>
<string name="renderer_accuracy_extreme">ئەوپەڕ (خاو)</string>
<!-- Resolutions -->
<string name="resolution_half">0.5X (360p/540p)</string>
<string name="resolution_three_quarter">0.75X (540p/810p)</string>
<string name="resolution_one">1X (720p/1080p)</string>
<string name="resolution_two">2X (1440p/2160p) (خاو)</string>
<string name="resolution_three">3X (2160p/3240p) (خاو)</string>
<string name="resolution_four">4X (2880p/4320p) (خاو)</string>
<!-- Renderer VSync -->
<string name="renderer_vsync_immediate">دەستبەجێ (کوژاوە)</string>
<string name="renderer_vsync_mailbox">سندوقی پۆستە</string>
<string name="renderer_vsync_fifo">FIFO (پێکراو)</string>
<string name="renderer_vsync_fifo_relaxed">FIFO ئارام</string>
<!-- Scaling Filters -->
<string name="scaling_filter_nearest_neighbor">نزیکترین دراوسێ</string>
<string name="scaling_filter_bilinear">دوو هێڵی</string>
<string name="scaling_filter_bicubic">دووخشتەکی</string>
<string name="scaling_filter_gaussian">گاوسی</string>
<string name="scaling_filter_scale_force">پێوەرهێز</string>
<string name="scaling_filter_fsr">AMD FidelityFX™ سوپەر ووردبینی</string>
<!-- Anti-Aliasing -->
<string name="anti_aliasing_none">هیچ</string>
<string name="anti_aliasing_fxaa">FXAA</string>
<string name="anti_aliasing_smaa">SMAA</string>
<string name="screen_layout_auto">خودکار</string>
<!-- Aspect Ratios -->
<string name="ratio_default">بنەڕەت (16:9)</string>
<string name="ratio_force_four_three">ڕووبەری 4:3</string>
<string name="ratio_force_twenty_one_nine">ڕووبەری 21:9</string>
<string name="ratio_force_sixteen_ten">ڕووبەری 16:10</string>
<string name="ratio_stretch">کشانی پڕ بەشاشە</string>
<!-- CPU Accuracy -->
<string name="cpu_accuracy_accurate">وورد</string>
<string name="cpu_accuracy_unsafe">ناسەقامگیر</string>
<string name="cpu_accuracy_paranoid">بەگومان (خاو)</string>
<!-- Gamepad Buttons -->
<string name="gamepad_d_pad">4 دوگمەکە</string>
<string name="gamepad_left_stick">گێڕی چەپ</string>
<string name="gamepad_right_stick">گێڕی ڕاست</string>
<string name="gamepad_home">ماڵەوە</string>
<string name="gamepad_screenshot">وێنەگرتنی شاشە</string>
<!-- Disk shader cache -->
<string name="preparing_shaders">ئامادەکردنی سێبەرەکان</string>
<string name="building_shaders">دروستکردنی سێبەرەکان</string>
<!-- Theme options -->
<string name="change_app_theme">گۆڕینی ڕووکاری ئەپەکە</string>
<string name="theme_default">بنەڕەت</string>
<string name="theme_material_you">کەرەستەی تۆ</string>
<!-- Theme Modes -->
<string name="change_theme_mode">گۆڕینی دۆخی ڕووکار</string>
<string name="theme_mode_follow_system">پەیڕەوی کردنی سیستەم</string>
<string name="theme_mode_light">ڕوناکی</string>
<string name="theme_mode_dark">تاریک</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">پاشبنەمای ڕەش</string>
<string name="use_black_backgrounds_description">لە کاتی بەکارهێنانی ڕووکاری تاریکدا، پاشبنەمای ڕەش دادەنێ.</string>
<!-- Licenses screen strings -->
<string name="licenses">مۆڵەتەکان</string>
<string name="license_fidelityfx_fsr_description">بەرزکردنەوەی کوالێتی بەرز لە کۆمپانیای AMD</string>
</resources>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Diese Software kann Spiele für die Nintendo Switch abspielen. Keine Spiele oder Spielekeys sind enthalten.&lt;br /&gt;&lt;br /&gt;Bevor du beginnst, bitte halte deine <![CDATA[<b> prod.keys </b>]]> auf deinem Gerät bereit. .&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Mehr Infos</a>]]></string> <string name="app_disclaimer">Diese Software kann Spiele für die Nintendo Switch abspielen. Keine Spiele oder Spielekeys sind enthalten.&lt;br /&gt;&lt;br /&gt;Bevor du beginnst, bitte halte deine <![CDATA[<b> prod.keys </b>]]> auf deinem Gerät bereit. .&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Mehr Infos</a>]]></string>
<string name="emulation_notification_channel_name">Emulation ist aktiv</string> <string name="emulation_notification_channel_name">Emulation ist aktiv</string>
@ -25,6 +25,7 @@
<string name="back">Zurück</string> <string name="back">Zurück</string>
<string name="add_games">Spiele hinzufügen</string> <string name="add_games">Spiele hinzufügen</string>
<string name="add_games_description">Spieleverzeichnis auswählen</string> <string name="add_games_description">Spieleverzeichnis auswählen</string>
<string name="step_complete">Fertig!</string>
<!-- Home strings --> <!-- Home strings -->
<string name="home_games">Spiele</string> <string name="home_games">Spiele</string>
@ -38,6 +39,7 @@
<string name="add_games_warning_description">Spiele werden in der Spieleliste nicht angezeigt, wenn kein Ordner ausgewählt ist.</string> <string name="add_games_warning_description">Spiele werden in der Spieleliste nicht angezeigt, wenn kein Ordner ausgewählt ist.</string>
<string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string> <string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string>
<string name="home_search_games">Spiele suchen</string> <string name="home_search_games">Spiele suchen</string>
<string name="search_settings">Einstellungen suchen</string>
<string name="games_dir_selected">Spieleverzeichnis ausgewählt</string> <string name="games_dir_selected">Spieleverzeichnis ausgewählt</string>
<string name="install_prod_keys">prod.keys installieren</string> <string name="install_prod_keys">prod.keys installieren</string>
<string name="install_prod_keys_description">Zum Entschlüsseln von Spielen benötigt</string> <string name="install_prod_keys_description">Zum Entschlüsseln von Spielen benötigt</string>
@ -60,8 +62,11 @@
<string name="invalid_keys_file">Ungültige Schlüsseldatei ausgewählt</string> <string name="invalid_keys_file">Ungültige Schlüsseldatei ausgewählt</string>
<string name="install_keys_success">Schlüssel erfolgreich installiert</string> <string name="install_keys_success">Schlüssel erfolgreich installiert</string>
<string name="reading_keys_failure">Fehler beim Lesen der Schlüssel</string> <string name="reading_keys_failure">Fehler beim Lesen der Schlüssel</string>
<string name="install_prod_keys_failure_extension_description">Überprüfen Sie, ob Ihre Schlüsseldatei die Erweiterung \".keys\" hat, und versuchen Sie es erneut.</string>
<string name="install_amiibo_keys_failure_extension_description">Überprüfen Sie, ob Ihre Schlüsseldatei die Erweiterung \".bin\" hat, und versuchen Sie es erneut.</string>
<string name="invalid_keys_error">Ungültige Schlüssel</string> <string name="invalid_keys_error">Ungültige Schlüssel</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string> <string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">Die ausgewählte Datei ist falsch oder beschädigt. Bitte kopieren Sie Ihre Schlüssel erneut.</string>
<string name="install_gpu_driver">GPU-Treiber installieren</string> <string name="install_gpu_driver">GPU-Treiber installieren</string>
<string name="install_gpu_driver_description">Alternative Treiber für eventuell bessere Leistung oder Genauigkeit installieren</string> <string name="install_gpu_driver_description">Alternative Treiber für eventuell bessere Leistung oder Genauigkeit installieren</string>
<string name="advanced_settings">Erweiterte Einstellungen</string> <string name="advanced_settings">Erweiterte Einstellungen</string>
@ -84,7 +89,17 @@
<string name="save_file_invalid_zip_structure_description">Der erste Unterordnername muss die Titel-ID des Spiels sein.</string> <string name="save_file_invalid_zip_structure_description">Der erste Unterordnername muss die Titel-ID des Spiels sein.</string>
<string name="import_saves">Importieren</string> <string name="import_saves">Importieren</string>
<string name="export_saves">Exportieren</string> <string name="export_saves">Exportieren</string>
<string name="install_firmware">Firmware installieren</string>
<string name="install_firmware_description">Die Firmware muss in einem ZIP-Archiv vorliegen und wird zum Booten einiger Spiele benötigt</string>
<string name="firmware_installing">Firmware wird installiert</string>
<string name="firmware_installed_success">Die Firmware wurde erfolgreich installiert!</string>
<string name="firmware_installed_failure">Bei der Firmware installation ist etwas fehlgeschlagen.</string>
<string name="share_log">Debug-Logs teilen</string>
<string name="share_log_description">Debug-Logs an yuzu zur Untersuchung absenden</string>
<string name="share_log_missing">Keine Log-Datei gefunden</string>
<string name="install_game_content">Spiel installieren</string>
<string name="install_game_content_description">Spiel Update oder DLC installieren</string>
<string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string>
<!-- About screen strings --> <!-- About screen strings -->
<string name="gaia_is_not_real">Gaia ist nicht real</string> <string name="gaia_is_not_real">Gaia ist nicht real</string>
<string name="copied_to_clipboard">In die Zwischenablage kopiert</string> <string name="copied_to_clipboard">In die Zwischenablage kopiert</string>
@ -92,7 +107,10 @@
<string name="contributors">Beitragende</string> <string name="contributors">Beitragende</string>
<string name="contributors_description">Gemacht mit \u2764 vom yuzu Team</string> <string name="contributors_description">Gemacht mit \u2764 vom yuzu Team</string>
<string name="contributors_link">https://github.com/yuzu-emu/yuzu/graphs/contributors</string> <string name="contributors_link">https://github.com/yuzu-emu/yuzu/graphs/contributors</string>
<string name="licenses_description">Projekte, die yuzu für Android möglich machen </string>
<string name="build">Build</string> <string name="build">Build</string>
<string name="user_data">Nutzerdaten</string>
<string name="user_data_export_cancelled">Export abgebrochen</string>
<string name="support_link">https://discord.gg/u77vRWY</string> <string name="support_link">https://discord.gg/u77vRWY</string>
<string name="website_link">https://yuzu-emu.org/</string> <string name="website_link">https://yuzu-emu.org/</string>
<string name="github_link">https://github.com/yuzu-emu</string> <string name="github_link">https://github.com/yuzu-emu</string>
@ -107,45 +125,39 @@
<string name="early_access_updates">Früherer Zugriff auf Updates</string> <string name="early_access_updates">Früherer Zugriff auf Updates</string>
<string name="no_manual_installation">Keine manuelle Installation</string> <string name="no_manual_installation">Keine manuelle Installation</string>
<string name="prioritized_support">Priorisierte Unterstützung</string> <string name="prioritized_support">Priorisierte Unterstützung</string>
<string name="helping_game_preservation">Beitrag zur Erhaltung der Spiele</string>
<string name="our_eternal_gratitude">Unsere ewige Dankbarkeit</string> <string name="our_eternal_gratitude">Unsere ewige Dankbarkeit</string>
<string name="are_you_interested">Bist du interessiert?</string> <string name="are_you_interested">Bist du interessiert?</string>
<!-- General settings strings --> <!-- General settings strings -->
<string name="frame_limit_enable">Geschwindigkeitsbegrenzung aktivieren</string> <string name="frame_limit_enable">Limitierte Geschwindigkeit</string>
<string name="frame_limit_enable_description">Wenn aktiviert, wird die Emulationsgeschwindigkeit auf einen Prozentsatz der normalen Geschwindigkeit begrenzt.</string> <string name="frame_limit_enable_description">Limitiert die Geschwindigkeit auf einen von dir festgelegten Prozentsatz.</string>
<string name="frame_limit_slider">Geschwindkeitsbegrenzung in Prozent</string> <string name="frame_limit_slider">Geschwindkeitsbegrenzung in Prozent</string>
<string name="frame_limit_slider_description">Legt den Prozentsatz der Bergrenzung der Emulationsgeschwindigkeit fest. Mit dem Standardwert von 100% wird die Emulation auf die normale Geschwindigkeit begrenzt. Höhere oder niedrigere Werte erhöhen oder verringern die Geschwindigkeitsbegrenzung.</string> <string name="frame_limit_slider_description">Gibt die prozentuale Geschwindigkeit der Emulation an. 100% sind normal. Werte darüber oder drunter werden die Geschwindigkeit entsprechend verändern.</string>
<string name="cpu_accuracy">CPU-Genauigkeit</string> <string name="cpu_accuracy">CPU-Genauigkeit</string>
<!-- System settings strings --> <!-- System settings strings -->
<string name="use_docked_mode">Dock-Modus</string> <string name="use_docked_mode">Gedockter Modus</string>
<string name="use_docked_mode_description">Emuliert im Dock-Modus, was die Auflösung verbessert, aber die Leistung senkt.</string> <string name="use_docked_mode_description">Der Docked Modus erhöht die Auflösung, verringert die aber die Leistung. Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die Leistung.</string>
<string name="emulated_region">Emulierte Region</string> <string name="emulated_region">Emulierte Region</string>
<string name="emulated_language">Emulierte Sprache</string> <string name="emulated_language">Emulierte Sprache</string>
<string name="select_rtc_date">RTC-Datum auswählen</string> <string name="select_rtc_date">RTC-Datum auswählen</string>
<string name="select_rtc_time">RTC-Zeit auswählen</string> <string name="select_rtc_time">RTC-Zeit auswählen</string>
<string name="use_custom_rtc">Benutzerdefinierte RTC aktivieren</string> <string name="use_custom_rtc">Benutzerdefinierte Echtzeituhr</string>
<string name="use_custom_rtc_description">Mit dieser Einstellung kann eine benutzerdefinierte Echtzeituhr unabhängig von der aktuellen Systemzeit verwendet werden.</string>
<string name="set_custom_rtc">Benutzerdefinierte RTC einstellen</string>
<!-- Graphics settings strings --> <!-- Graphics settings strings -->
<string name="renderer_api">API</string>
<string name="renderer_accuracy">Genauigkeitsstufe</string> <string name="renderer_accuracy">Genauigkeitsstufe</string>
<string name="renderer_resolution">Auflösung</string>
<string name="renderer_vsync">VSync-Modus</string> <string name="renderer_vsync">VSync-Modus</string>
<string name="renderer_screen_layout">Orientierung</string>
<string name="renderer_aspect_ratio">Seitenverhältnis</string> <string name="renderer_aspect_ratio">Seitenverhältnis</string>
<string name="renderer_scaling_filter">Fensteranpassungsfilter</string> <string name="renderer_scaling_filter">Fensteranpassungsfilter</string>
<string name="renderer_anti_aliasing">Kantenglättungs-Methode</string>
<string name="renderer_force_max_clock">Maximale Taktfrequenz erzwingen (nur Adreno)</string> <string name="renderer_force_max_clock">Maximale Taktfrequenz erzwingen (nur Adreno)</string>
<string name="renderer_force_max_clock_description">Erzwingt den Betrieb der GPU mit der maximal möglichen Taktfrequenz (Temperaturbeschränkungen werden weiterhin angewendet).</string> <string name="renderer_force_max_clock_description">Erzwingt den Betrieb der GPU mit der maximal möglichen Taktfrequenz (Temperaturbeschränkungen werden weiterhin angewendet).</string>
<string name="renderer_asynchronous_shaders">Asynchrone Shader nutzen</string> <string name="renderer_asynchronous_shaders">Asynchrone Shader nutzen</string>
<string name="renderer_asynchronous_shaders_description">Kompiliert Shader asynchron, was Ruckler reduziert, aber zu Glitches führen kann.</string> <!-- Debug settings strings -->
<string name="renderer_debug">Grafik-Debugging aktivieren</string> <string name="cpu">CPU</string>
<string name="renderer_debug_description">Wenn aktiviert, schaltet die Grafik-API in einen langsameren Debugging-Modus.</string> <string name="cpu_debug_mode">CPU Debugging</string>
<string name="use_disk_shader_cache">Nutze Festplatten-Shader-Cache</string> <string name="gpu">GPU</string>
<string name="use_disk_shader_cache_description">Ruckeln wird durch das Speichern und Laden von generierten Shadern auf der Festplatte reduziert.</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Graphik-Debugging</string>
<!-- Audio settings strings -->
<string name="audio_volume">Lautstärke</string> <string name="audio_volume">Lautstärke</string>
<string name="audio_volume_description">Legt die Lautstärke der Audioausgabe fest.</string> <string name="audio_volume_description">Legt die Lautstärke der Audioausgabe fest.</string>
@ -154,14 +166,22 @@
<string name="ini_saved">Einstellungen gespeichert</string> <string name="ini_saved">Einstellungen gespeichert</string>
<string name="gameid_saved">Einstellungen für %1$s gespeichert</string> <string name="gameid_saved">Einstellungen für %1$s gespeichert</string>
<string name="error_saving">Fehler beim Speichern von %1$s.ini: %2$s</string> <string name="error_saving">Fehler beim Speichern von %1$s.ini: %2$s</string>
<string name="unimplemented_menu">Unimplementiertes Menü</string>
<string name="loading">Lädt...</string> <string name="loading">Lädt...</string>
<string name="reset_setting_confirmation">Möchtest du diese Einstellung auf den Standardwert zurücksetzen?</string> <string name="reset_setting_confirmation">Möchtest du diese Einstellung auf den Standardwert zurücksetzen?</string>
<string name="reset_to_default">Auf Standard zurücksetzen</string> <string name="reset_to_default">Auf Standard zurücksetzen</string>
<string name="reset_all_settings">Alle Einstellungen zurücksetzen?</string> <string name="reset_all_settings">Alle Einstellungen zurücksetzen?</string>
<string name="reset_all_settings_description">Alle erweiterten Einstellungen werden auf ihren Standardwert zurückgesetzt. Dies kann nicht rückgängig gemacht werden.</string>
<string name="settings_reset">Einstellungen zurückgesetzt</string> <string name="settings_reset">Einstellungen zurückgesetzt</string>
<string name="close">Schließen</string> <string name="close">Schließen</string>
<string name="learn_more">Mehr erfahren</string> <string name="learn_more">Mehr erfahren</string>
<string name="auto">Auto</string>
<string name="submit">Absenden</string>
<string name="string_null">Null</string>
<string name="string_import">Importieren</string>
<string name="export">Exportieren</string>
<string name="export_failed">Export fehlgeschlagen</string>
<string name="import_failed">Import fehlgeschlagen</string>
<string name="cancelling">Abbrechen</string>
<!-- GPU driver installation --> <!-- GPU driver installation -->
<string name="select_gpu_driver">GPU-Treiber auswählen</string> <string name="select_gpu_driver">GPU-Treiber auswählen</string>
@ -169,6 +189,7 @@
<string name="select_gpu_driver_install">Installieren</string> <string name="select_gpu_driver_install">Installieren</string>
<string name="select_gpu_driver_default">Standard</string> <string name="select_gpu_driver_default">Standard</string>
<string name="select_gpu_driver_use_default">Standard GPU-Treiber wird verwendet</string> <string name="select_gpu_driver_use_default">Standard GPU-Treiber wird verwendet</string>
<string name="select_gpu_driver_error">Ungültiger Treiber ausgewählt, Standard-Treiber wird verwendet!</string>
<string name="system_gpu_driver">System GPU-Treiber</string> <string name="system_gpu_driver">System GPU-Treiber</string>
<string name="installing_driver">Treiber wird installiert...</string> <string name="installing_driver">Treiber wird installiert...</string>
@ -179,6 +200,7 @@
<string name="preferences_graphics">Grafik</string> <string name="preferences_graphics">Grafik</string>
<string name="preferences_audio">Audio</string> <string name="preferences_audio">Audio</string>
<string name="preferences_theme">Theme und Farbe</string> <string name="preferences_theme">Theme und Farbe</string>
<string name="preferences_debug">Debug</string>
<!-- ROM loading errors --> <!-- ROM loading errors -->
<string name="loader_error_encrypted">Das ROM ist verschlüsselt</string> <string name="loader_error_encrypted">Das ROM ist verschlüsselt</string>
@ -192,22 +214,15 @@
<string name="emulation_exit">Emulation beenden</string> <string name="emulation_exit">Emulation beenden</string>
<string name="emulation_done">Fertig</string> <string name="emulation_done">Fertig</string>
<string name="emulation_fps_counter">FPS Zähler</string> <string name="emulation_fps_counter">FPS Zähler</string>
<string name="emulation_toggle_controls">Steuerung umschalten</string>
<string name="emulation_rel_stick_center">Relative Stick-Mitte</string>
<string name="emulation_dpad_slide">DPad Slide</string>
<string name="emulation_haptics">Haptik</string>
<string name="emulation_show_overlay">Overlay anzeigen</string>
<string name="emulation_toggle_all">Alle umschalten</string> <string name="emulation_toggle_all">Alle umschalten</string>
<string name="emulation_control_adjust">Overlay anpassen</string> <string name="emulation_control_adjust">Overlay anpassen</string>
<string name="emulation_control_scale">Größe</string> <string name="emulation_control_scale">Größe</string>
<string name="emulation_control_opacity">Transparenz</string> <string name="emulation_control_opacity">Transparenz</string>
<string name="emulation_touch_overlay_reset">Overlay zurücksetzen</string> <string name="emulation_touch_overlay_reset">Overlay zurücksetzen</string>
<string name="emulation_touch_overlay_edit">Overlay bearbeiten</string> <string name="emulation_touch_overlay_edit">Overlay bearbeiten</string>
<string name="emulation_pause">Emulation pausieren</string>
<string name="emulation_unpause">Emulation fortsetzen</string>
<string name="emulation_input_overlay">Overlay-Optionen</string> <string name="emulation_input_overlay">Overlay-Optionen</string>
<string name="load_settings">Lädt Einstellungen...</string> <string name="load_settings">Lade Einstellungen...</string>
<!-- Software keyboard --> <!-- Software keyboard -->
<string name="software_keyboard">Software-Tastatur</string> <string name="software_keyboard">Software-Tastatur</string>
@ -221,7 +236,7 @@
<string name="fatal_error">Schwerwiegender Fehler</string> <string name="fatal_error">Schwerwiegender Fehler</string>
<string name="fatal_error_message">Ein schwerwiegender Fehler ist aufgetreten. Einzelheiten wurden im Log protokolliert.\nDas Fortsetzen der Emulation kann zu Abstürzen und Bugs führen.</string> <string name="fatal_error_message">Ein schwerwiegender Fehler ist aufgetreten. Einzelheiten wurden im Log protokolliert.\nDas Fortsetzen der Emulation kann zu Abstürzen und Bugs führen.</string>
<string name="performance_warning">Das Deaktivieren dieser Einstellung führt zu erheblichen Leistungsverlusten! Für ein optimales Erlebnis wird empfohlen, sie aktiviert zu lassen.</string> <string name="performance_warning">Das Deaktivieren dieser Einstellung führt zu erheblichen Leistungsverlusten! Für ein optimales Erlebnis wird empfohlen, sie aktiviert zu lassen.</string>
<string name="memory_formatted">%1$s %2$s</string>
<!-- Region Names --> <!-- Region Names -->
<string name="region_japan">Japan</string> <string name="region_japan">Japan</string>
<string name="region_usa">USA</string> <string name="region_usa">USA</string>
@ -231,6 +246,15 @@
<string name="region_korea">Korea</string> <string name="region_korea">Korea</string>
<string name="region_taiwan">Taiwan</string> <string name="region_taiwan">Taiwan</string>
<!-- Memory Sizes -->
<string name="memory_byte">Byte</string>
<string name="memory_kilobyte">KB</string>
<string name="memory_megabyte">MB</string>
<string name="memory_gigabyte">GB</string>
<string name="memory_terabyte">TB</string>
<string name="memory_petabyte">PB</string>
<string name="memory_exabyte">EB</string>
<!-- Renderer APIs --> <!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string> <string name="renderer_vulkan">Vulkan</string>
<string name="renderer_none">Keiner</string> <string name="renderer_none">Keiner</string>
@ -267,12 +291,15 @@
<string name="anti_aliasing_fxaa">FXAA</string> <string name="anti_aliasing_fxaa">FXAA</string>
<string name="anti_aliasing_smaa">SMAA</string> <string name="anti_aliasing_smaa">SMAA</string>
<string name="screen_layout_portrait">Portrait</string>
<string name="screen_layout_auto">Auto</string>
<!-- Aspect Ratios --> <!-- Aspect Ratios -->
<string name="ratio_default">Standard (16:9)</string> <string name="ratio_default">Standard (16:9)</string>
<string name="ratio_force_four_three">4:3 erzwingen</string> <string name="ratio_force_four_three">4:3 erzwingen</string>
<string name="ratio_force_twenty_one_nine">21:9 erzwingen</string> <string name="ratio_force_twenty_one_nine">21:9 erzwingen</string>
<string name="ratio_force_sixteen_ten">Erzwinge 16:10</string> <string name="ratio_force_sixteen_ten">Erzwinge 16:10</string>
<string name="ratio_stretch">Auf Fenster anpassen</string> <string name="ratio_stretch">Auf Bildschirmgröße anpsassen</string>
<!-- CPU Accuracy --> <!-- CPU Accuracy -->
<string name="cpu_accuracy_accurate">Akkurat</string> <string name="cpu_accuracy_accurate">Akkurat</string>
@ -280,9 +307,9 @@
<string name="cpu_accuracy_paranoid">Paranoid (Langsam)</string> <string name="cpu_accuracy_paranoid">Paranoid (Langsam)</string>
<!-- Gamepad Buttons --> <!-- Gamepad Buttons -->
<string name="gamepad_d_pad">Steuerkreuz</string> <string name="gamepad_d_pad">D-Pad</string>
<string name="gamepad_left_stick">Linker Analogstick</string> <string name="gamepad_left_stick">Linker Stick</string>
<string name="gamepad_right_stick">Rechter Analogstick</string> <string name="gamepad_right_stick">Rechter Stick</string>
<string name="gamepad_home">Home</string> <string name="gamepad_home">Home</string>
<string name="gamepad_screenshot">Screenshot</string> <string name="gamepad_screenshot">Screenshot</string>
@ -291,18 +318,30 @@
<string name="building_shaders">Shader werden erstellt</string> <string name="building_shaders">Shader werden erstellt</string>
<!-- Theme options --> <!-- Theme options -->
<string name="change_app_theme">App-Theme ändern</string> <string name="change_app_theme">App-Thema ändern</string>
<string name="theme_default">Standard</string> <string name="theme_default">Standard</string>
<string name="theme_material_you">Material You</string> <string name="theme_material_you">Material You</string>
<!-- Theme Modes --> <!-- Theme Modes -->
<string name="change_theme_mode">Theme-Modus ändern</string> <string name="change_theme_mode">Themen-Modus ändern</string>
<string name="theme_mode_follow_system">System folgen</string> <string name="theme_mode_follow_system">System folgen</string>
<string name="theme_mode_light">Hell</string> <string name="theme_mode_light">Hell</string>
<string name="theme_mode_dark">Dunkel</string> <string name="theme_mode_dark">Dunkel</string>
<!-- Audio output engines -->
<string name="cubeb">cubeb</string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Schwarze Hintergünde verwenden</string> <string name="use_black_backgrounds">Schwarze Hintergründe</string>
<string name="use_black_backgrounds_description">Bei Verwendung des dunklen Themes, schwarze Hintergründe verwenden.</string> <string name="use_black_backgrounds_description">Bei Verwendung des dunklen Themes, schwarze Hintergründe verwenden.</string>
<!-- Picture-In-Picture -->
<string name="picture_in_picture">Bild im Bild</string>
<string name="pause">Pause</string>
<string name="mute">Stummschalten</string>
<string name="unmute">Ton aktivieren</string>
<!-- Licenses screen strings -->
<string name="licenses">Lizenzen</string>
<string name="license_fidelityfx_fsr_description">Hochwertiges Upscaling von AMD</string>
</resources> </resources>

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Este software ejecuta juegos para la videoconsola Nintendo Switch. Los videojuegos o keys no vienen incluidos.&lt;br /&gt;&lt;br /&gt;Antes de empezar, por favor, localice el archivo <![CDATA[<b> prod.keys </b>]]>en el almacenamiento de su dispositivo..&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Saber más</a>]]></string> <string name="app_disclaimer">Este software ejecuta juegos para la videoconsola Nintendo Switch. Los videojuegos o claves no vienen incluidos.&lt;br /&gt;&lt;br /&gt;Antes de empezar, por favor, localice el archivo <![CDATA[<b> prod.keys </b>]]>en el almacenamiento de su dispositivo..&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Saber más</a>]]></string>
<string name="emulation_notification_channel_name">Emulación activa</string> <string name="emulation_notification_channel_name">Emulación activa</string>
<string name="emulation_notification_channel_description">Muestra una notificación persistente cuando la emulación está activa.</string> <string name="emulation_notification_channel_description">Muestra una notificación persistente cuando la emulación está activa.</string>
<string name="emulation_notification_running">yuzu esta ejecutándose</string> <string name="emulation_notification_running">yuzu esta ejecutándose</string>
@ -25,6 +25,7 @@
<string name="back">Atrás</string> <string name="back">Atrás</string>
<string name="add_games">Añadir Juegos</string> <string name="add_games">Añadir Juegos</string>
<string name="add_games_description">Selecciona la carpeta de juegos</string> <string name="add_games_description">Selecciona la carpeta de juegos</string>
<string name="step_complete">¡Completado!</string>
<!-- Home strings --> <!-- Home strings -->
<string name="home_games">Juegos</string> <string name="home_games">Juegos</string>
@ -37,7 +38,8 @@
<string name="add_games_warning">¿Omitir la selección de la carpeta de juegos?</string> <string name="add_games_warning">¿Omitir la selección de la carpeta de juegos?</string>
<string name="add_games_warning_description">No se mostrará ningún juego si no se ha seleccionado una carpeta de juegos.</string> <string name="add_games_warning_description">No se mostrará ningún juego si no se ha seleccionado una carpeta de juegos.</string>
<string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string> <string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string>
<string name="home_search_games">Buscar Juegos</string> <string name="home_search_games">Buscar juegos</string>
<string name="search_settings">Buscar configuración</string>
<string name="games_dir_selected">Directorio de juegos seleccionado</string> <string name="games_dir_selected">Directorio de juegos seleccionado</string>
<string name="install_prod_keys">Instalar prod.keys</string> <string name="install_prod_keys">Instalar prod.keys</string>
<string name="install_prod_keys_description">Requerido para descifrar juegos</string> <string name="install_prod_keys_description">Requerido para descifrar juegos</string>
@ -58,15 +60,18 @@
<string name="warning_cancel">Cancelar</string> <string name="warning_cancel">Cancelar</string>
<string name="install_amiibo_keys">Instalar clave de Amiiboo</string> <string name="install_amiibo_keys">Instalar clave de Amiiboo</string>
<string name="install_amiibo_keys_description">Necesario para usar Amiibo en el juego</string> <string name="install_amiibo_keys_description">Necesario para usar Amiibo en el juego</string>
<string name="invalid_keys_file">Archivo de claves inválido seleccionado</string> <string name="invalid_keys_file">Archivo de claves seleccionado inválido</string>
<string name="install_keys_success">Claves instaladas correctamente</string> <string name="install_keys_success">Claves instaladas correctamente</string>
<string name="reading_keys_failure">Error al leer las claves de cifrado</string> <string name="reading_keys_failure">Error al leer las claves de cifrado</string>
<string name="install_prod_keys_failure_extension_description">Compruebe que el archivo de claves tenga una extensión .keys y pruebe otra vez.</string>
<string name="install_amiibo_keys_failure_extension_description">Compruebe que el archivo de claves tenga una extensión .bin y pruebe otra vez.</string>
<string name="invalid_keys_error">Claves de cifrado no válidas</string> <string name="invalid_keys_error">Claves de cifrado no válidas</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string> <string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">El archivo seleccionado es incorrecto o está corrupto. Vuelva a redumpear sus claves.</string> <string name="install_keys_failure_description">El archivo seleccionado es incorrecto o está corrupto. Vuelva a redumpear sus claves.</string>
<string name="install_gpu_driver">Instalar driver de GPU</string> <string name="install_gpu_driver">Instalar driver de GPU</string>
<string name="install_gpu_driver_description">Instale drivers alternativos para obtener un rendimiento o una precisión potencialmente mejores</string> <string name="install_gpu_driver_description">Instale drivers alternativos para obtener un rendimiento o una precisión potencialmente mejores</string>
<string name="advanced_settings">Opciones avanzadas</string> <string name="advanced_settings">Opciones avanzadas</string>
<string name="advanced_settings_game">Configuración avanzada: %1$s</string>
<string name="settings_description">Configurar las opciones del emulador</string> <string name="settings_description">Configurar las opciones del emulador</string>
<string name="search_recently_played">Jugado recientemente</string> <string name="search_recently_played">Jugado recientemente</string>
<string name="search_recently_added">Añadido recientemente</string> <string name="search_recently_added">Añadido recientemente</string>
@ -86,6 +91,33 @@
<string name="save_file_invalid_zip_structure_description">El nombre de la primera subcarpeta debe ser el Title ID del juego.</string> <string name="save_file_invalid_zip_structure_description">El nombre de la primera subcarpeta debe ser el Title ID del juego.</string>
<string name="import_saves">Importar</string> <string name="import_saves">Importar</string>
<string name="export_saves">Exportar</string> <string name="export_saves">Exportar</string>
<string name="install_firmware">Instalar firmware</string>
<string name="install_firmware_description">El firmware debe estar en un archivo ZIP y es necesario para ejecutar algunos juegos</string>
<string name="firmware_installing">Instalando firmware</string>
<string name="firmware_installed_success">Firmware instalado con éxito</string>
<string name="firmware_installed_failure">Falló la instalación de firmware</string>
<string name="firmware_installed_failure_description">Asegúrese de que los archivos nca del firmware estén en la raíz del zip e inténtelo de nuevo.</string>
<string name="share_log">Compartir registros de depuración</string>
<string name="share_log_description">Comparta el archivo de registro de yuzu para depurar problemas</string>
<string name="share_log_missing">No se encontró ningún archivo de registro</string>
<string name="install_game_content">Instalar contenido de juego</string>
<string name="install_game_content_description">Instalar actualizaciones o DLC</string>
<string name="installing_game_content">Instalando contenido...</string>
<string name="install_game_content_failure">Error instalando archivo(s) a la NAND</string>
<string name="install_game_content_failure_description">Asegúrese de que el/los contenido(s) son válidos y que el archivo prod.keys esté instalado.</string>
<string name="install_game_content_failure_base">La instalación de los juegos base no está permitida para así evitar posibles conflictos.</string>
<string name="install_game_content_failure_file_extension">Sólo hay soporte para el contenido en NSP y XCI. Asegúrese de que el/los contenido(s) son válidos.</string>
<string name="install_game_content_failed_count">%1$d error(es) de instalación</string>
<string name="install_game_content_success">Contenido(s) de juego instalado/s con éxito</string>
<string name="install_game_content_success_install">%1$d instalado con éxito</string>
<string name="install_game_content_success_overwrite">%1$d sobreescrito con éxito</string>
<string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string>
<string name="custom_driver_not_supported">Drivers personalizados no soportados</string>
<string name="custom_driver_not_supported_description">En estos momentos, la carga de drivers personalizados no está disponible para este dispositivo..\n¡Comprueba esta opción en el futuro para ver si ya está añadido el soporte a ese dispositivo!</string>
<string name="manage_yuzu_data">Administrar datos de yuzu</string>
<string name="manage_yuzu_data_description">Importa/exporta el firmware, las keys, los datos de usuario, ¡y más!</string>
<string name="share_save_file">Compartir archivo de guardado</string>
<string name="export_save_failed">La exportación del guardado falló</string>
<!-- About screen strings --> <!-- About screen strings -->
<string name="gaia_is_not_real">Gaia no es real</string> <string name="gaia_is_not_real">Gaia no es real</string>
@ -94,7 +126,18 @@
<string name="contributors">Contribuidores</string> <string name="contributors">Contribuidores</string>
<string name="contributors_description">Hecho con \u2764 del equipo yuzu</string> <string name="contributors_description">Hecho con \u2764 del equipo yuzu</string>
<string name="contributors_link">https://github.com/yuzu-emu/yuzu/graphs/contributors</string> <string name="contributors_link">https://github.com/yuzu-emu/yuzu/graphs/contributors</string>
<string name="licenses_description">Proyectos que hacen que yuzu para Android sea una realidad</string>
<string name="build">Versión</string> <string name="build">Versión</string>
<string name="user_data">Datos de usuario</string>
<string name="user_data_description">Importa/exporta todos los datos de usuario.\n\nCuando se importen los datos de usuario, ¡los demás datos de usuario existentes serán borrados!</string>
<string name="exporting_user_data">Exportando datos de usuario...</string>
<string name="importing_user_data">Importando datos de usuario...</string>
<string name="import_user_data">Importar datos de usuario</string>
<string name="invalid_yuzu_backup">Backup de válido</string>
<string name="user_data_export_success">Datos de usuario exportados con éxito</string>
<string name="user_data_import_success">Datos de usuario importados con éxito</string>
<string name="user_data_export_cancelled">Exportación cancelada</string>
<string name="user_data_import_failed_description">Asegúrese de que las carpetas de datos de usuario estén en la raíz de la carpeta del zip y contengan un archivo config en config/config.ini e inténtelo de nuevo.</string>
<string name="support_link">https://discord.gg/u77vRWY</string> <string name="support_link">https://discord.gg/u77vRWY</string>
<string name="website_link">https://yuzu-emu.org/</string> <string name="website_link">https://yuzu-emu.org/</string>
<string name="github_link">https://github.com/yuzu-emu</string> <string name="github_link">https://github.com/yuzu-emu</string>
@ -114,41 +157,53 @@
<string name="are_you_interested">¿Estás interesado?</string> <string name="are_you_interested">¿Estás interesado?</string>
<!-- General settings strings --> <!-- General settings strings -->
<string name="frame_limit_enable">Activar limite de velocidad</string> <string name="frame_limit_enable">Limitar velocidad</string>
<string name="frame_limit_enable_description">Cuando está habilitado, la velocidad de emulación se limitará a un porcentaje específico de la velocidad normal.</string> <string name="frame_limit_enable_description">Limita la velocidad de emulación a un porcentaje específico de la velocidad normal.</string>
<string name="frame_limit_slider">Limitar porcentaje de velocidad</string> <string name="frame_limit_slider">Limitar porcentaje de velocidad</string>
<string name="frame_limit_slider_description">Especifica el porcentaje para limitar la velocidad de emulación. Con el valor predeterminado del 100 %, la emulación se limitará a la velocidad normal. Valores más altos o más bajos aumentarán o disminuirán el límite de velocidad.</string> <string name="frame_limit_slider_description">Especifica el porcentaje para limitar la velocidad de emulación. 100% es la velocidad normal. Valores más altos o bajos incrementarán o disminuirán el límite de velocidad.</string>
<string name="cpu_accuracy">Precisión de CPU</string> <string name="cpu_accuracy">Precisión de CPU</string>
<string name="value_with_units">%1$s%2$s</string>
<!-- System settings strings --> <!-- System settings strings -->
<string name="use_docked_mode">Modo sobremesa</string> <string name="use_docked_mode">Modo Sobremesa</string>
<string name="use_docked_mode_description">Emula en modo sobremesa, lo que aumenta la resolución perjudicando el rendimiento.</string> <string name="use_docked_mode_description">Incrementa la resolución al coste de reducir el rendimiento. El Modo Portátil es usado cuando está desactivado, reduciendo la resolución y mejorando así el rendimiento.</string>
<string name="emulated_region">Región emulada</string> <string name="emulated_region">Región emulada</string>
<string name="emulated_language">Idioma emulado</string> <string name="emulated_language">Idioma emulado</string>
<string name="select_rtc_date">Seleccionar Fecha RTC</string> <string name="select_rtc_date">Seleccionar fecha RTC</string>
<string name="select_rtc_time">Seleccionar Tiempo RTC</string> <string name="select_rtc_time">Seleccionar tiempo RTC</string>
<string name="use_custom_rtc">Habilitar RTC Personalizado</string> <string name="use_custom_rtc">RTC personalizado</string>
<string name="use_custom_rtc_description">Esta configuración le permite configurar un reloj de tiempo real personalizado diferente a la hora actual de su sistema</string> <string name="use_custom_rtc_description">Te permite tener un reloj personalizado en tiempo real diferente del tiempo del propio sistema.</string>
<string name="set_custom_rtc">Establecer RTC Personalizado</string> <string name="set_custom_rtc">Configurar RTC personalizado</string>
<!-- Graphics settings strings --> <!-- Graphics settings strings -->
<string name="renderer_api">API</string>
<string name="renderer_accuracy">Nivel de precisión</string> <string name="renderer_accuracy">Nivel de precisión</string>
<string name="renderer_resolution">Resolución</string> <string name="renderer_resolution">Resolución (Portátil/Sobremesa)</string>
<string name="renderer_vsync">Modo VSync</string> <string name="renderer_vsync">Modo VSync</string>
<string name="renderer_screen_layout">Orientación</string>
<string name="renderer_aspect_ratio">Relación de aspecto</string> <string name="renderer_aspect_ratio">Relación de aspecto</string>
<string name="renderer_scaling_filter">Filtro de adaptación de ventana</string> <string name="renderer_scaling_filter">Filtro de adaptación de ventana</string>
<string name="renderer_anti_aliasing">Metodo Anti Aliasing</string> <string name="renderer_anti_aliasing">Método anti-aliasing</string>
<string name="renderer_force_max_clock">Forzar velocidad al máximo (solo Adreno)</string> <string name="renderer_force_max_clock">Forzar velocidad al máximo (solo Adreno)</string>
<string name="renderer_force_max_clock_description">Fuerza a la GPU a ejecutarse a la velocidad máxima de reloj posible (se seguirán aplicando restricciones térmicas).</string> <string name="renderer_force_max_clock_description">Fuerza a la GPU a ejecutarse a la velocidad máxima de reloj posible (se seguirán aplicando restricciones térmicas).</string>
<string name="renderer_asynchronous_shaders">Usar shaders asíncronos</string> <string name="renderer_asynchronous_shaders">Usar shaders asíncronos</string>
<string name="renderer_asynchronous_shaders_description">Compila shaders de forma asincrónica, lo que reducirá los parones pero puede introducir fallos.</string> <string name="renderer_asynchronous_shaders_description">Compila shaders de manera asíncrona, reduciendo los parones, pero puede introducir fallos.</string>
<string name="renderer_debug">Habilitar la depuración de gráficos</string> <string name="renderer_reactive_flushing">Usar limpieza reactiva</string>
<string name="renderer_debug_description">Cuando esté marcado, la API de gráficos entra en un modo de depuración más lento.</string> <string name="renderer_reactive_flushing_description">Mejora la precisión de renderizado en algunos juegos, pero reduce el rendimiento.</string>
<string name="use_disk_shader_cache">Usar caché de shaders en disco</string> <string name="use_disk_shader_cache">Caché de shaders en disco</string>
<string name="use_disk_shader_cache_description">Reduzca los parones almacenando y cargando shaders generados en el disco.</string> <string name="use_disk_shader_cache_description">Reduce los parones almacenando y cargando shaders generados.</string>
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
<string name="cpu_debug_mode">Depuración de CPU</string>
<string name="cpu_debug_mode_description">Pone la CPU en un modo de depuración lento.</string>
<string name="gpu">GPU</string>
<string name="renderer_api">API</string>
<string name="renderer_debug">Depuración de gráficos</string>
<string name="renderer_debug_description">Configura la API gráfica a un modo de depuración lento.</string>
<string name="fastmem">Fastmem</string>
<!-- Audio settings strings --> <!-- Audio settings strings -->
<string name="audio_output_engine">Motor de salida</string>
<string name="audio_volume">Volumen</string> <string name="audio_volume">Volumen</string>
<string name="audio_volume_description">Especifica el volumen de la salida de audio.</string> <string name="audio_volume_description">Especifica el volumen de la salida de audio.</string>
@ -157,14 +212,24 @@
<string name="ini_saved">Configuración guardada</string> <string name="ini_saved">Configuración guardada</string>
<string name="gameid_saved">Configuración guardada para %1$s</string> <string name="gameid_saved">Configuración guardada para %1$s</string>
<string name="error_saving">Error guardando %1$s.ini: %2$s</string> <string name="error_saving">Error guardando %1$s.ini: %2$s</string>
<string name="unimplemented_menu">Menú sin implementar</string>
<string name="loading">Cargando...</string> <string name="loading">Cargando...</string>
<string name="shutting_down">Saliendo...</string>
<string name="reset_setting_confirmation">¿Desea restablecer esta configuración a su valor predeterminado?</string> <string name="reset_setting_confirmation">¿Desea restablecer esta configuración a su valor predeterminado?</string>
<string name="reset_to_default">Restablecer a predeterminado</string> <string name="reset_to_default">Restablecer a predeterminado</string>
<string name="reset_all_settings">¿Restablecer todas las configuraciones?</string> <string name="reset_all_settings">¿Restablecer todas las configuraciones?</string>
<string name="reset_all_settings_description">Todas las configuraciones avanzadas se restablecerán a su configuración predeterminada. Esto no se puede deshacer.</string> <string name="reset_all_settings_description">Todas las opciones avanzadas se restablecerán a su configuración predeterminada. Esta acción no se puede deshacer.</string>
<string name="settings_reset">Reiniciar la configuracion</string> <string name="settings_reset">Reiniciar la configuracion</string>
<string name="close">Cerrar</string> <string name="close">Cerrar</string>
<string name="learn_more">Más información</string> <string name="learn_more">Saber más</string>
<string name="auto">Auto</string>
<string name="submit">Enviar</string>
<string name="string_null">Null</string>
<string name="string_import">Importar</string>
<string name="export">Exportar</string>
<string name="export_failed">La exportación falló</string>
<string name="import_failed">La importación falló</string>
<string name="cancelling">Cancelando</string>
<!-- GPU driver installation --> <!-- GPU driver installation -->
<string name="select_gpu_driver">Seleccionar driver GPU</string> <string name="select_gpu_driver">Seleccionar driver GPU</string>
@ -172,6 +237,7 @@
<string name="select_gpu_driver_install">Instalar</string> <string name="select_gpu_driver_install">Instalar</string>
<string name="select_gpu_driver_default">Predeterminado</string> <string name="select_gpu_driver_default">Predeterminado</string>
<string name="select_gpu_driver_use_default">Usando el driver de GPU por defecto </string> <string name="select_gpu_driver_use_default">Usando el driver de GPU por defecto </string>
<string name="select_gpu_driver_error">¡Driver no válido, utilizando el predeterminado del sistema!</string>
<string name="system_gpu_driver">Driver GPU del sistema</string> <string name="system_gpu_driver">Driver GPU del sistema</string>
<string name="installing_driver">Instalando driver...</string> <string name="installing_driver">Instalando driver...</string>
@ -182,10 +248,11 @@
<string name="preferences_graphics">Gráficos</string> <string name="preferences_graphics">Gráficos</string>
<string name="preferences_audio">Audio</string> <string name="preferences_audio">Audio</string>
<string name="preferences_theme">Tema y color</string> <string name="preferences_theme">Tema y color</string>
<string name="preferences_debug">Depuración</string>
<!-- ROM loading errors --> <!-- ROM loading errors -->
<string name="loader_error_encrypted">Su ROM está encriptada</string> <string name="loader_error_encrypted">Su ROM está encriptada</string>
<string name="loader_error_encrypted_roms_description"><![CDATA[Por favor, siga las guías para redumpear <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-cartridge-games\">cartuchos de juegos</a> o <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-installed-titles-eshop\">titulos instalados</a>.]]></string> <string name="loader_error_encrypted_roms_description"><![CDATA[Por favor, siga las guías para redumpear<a href=\"https://yuzu-emu.org/help/quickstart/#dumping-physical-titles-game-cards\">cartuchos de juegos</a> o <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-digital-titles-eshop\">títulos instalados</a>.]]></string>
<string name="loader_error_encrypted_keys_description"><![CDATA[Por favor, compruebe que su archivo <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> está instalado, para que los juegos sean descifrados.]]></string> <string name="loader_error_encrypted_keys_description"><![CDATA[Por favor, compruebe que su archivo <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> está instalado, para que los juegos sean descifrados.]]></string>
<string name="loader_error_video_core">Ocurrió un error al inicializar el núcleo de video, posiblemente debido a una incompatibilidad con el driver seleccionado</string> <string name="loader_error_video_core">Ocurrió un error al inicializar el núcleo de video, posiblemente debido a una incompatibilidad con el driver seleccionado</string>
<string name="loader_error_video_core_description">Esto suele deberse a un driver de GPU incompatible. La instalación de un controlador de GPU personalizado puede resolver este problema.</string> <string name="loader_error_video_core_description">Esto suele deberse a un driver de GPU incompatible. La instalación de un controlador de GPU personalizado puede resolver este problema.</string>
@ -196,25 +263,25 @@
<string name="emulation_exit">Salir de la emulación</string> <string name="emulation_exit">Salir de la emulación</string>
<string name="emulation_done">Hecho</string> <string name="emulation_done">Hecho</string>
<string name="emulation_fps_counter">Contador de FPS</string> <string name="emulation_fps_counter">Contador de FPS</string>
<string name="emulation_toggle_controls">Alternar Controles</string> <string name="emulation_toggle_controls">Alternar controles</string>
<string name="emulation_rel_stick_center">Centro Relativo del Stick</string> <string name="emulation_rel_stick_center">Centro relativo del stick</string>
<string name="emulation_dpad_slide">Deslizamiento de la Cruceta</string> <string name="emulation_dpad_slide">Deslizamiento de la cruceta</string>
<string name="emulation_haptics">Hápticos</string> <string name="emulation_haptics">Toques hápticos</string>
<string name="emulation_show_overlay">Mostrar pantalla</string> <string name="emulation_show_overlay">Mostrar overlay</string>
<string name="emulation_toggle_all">Alternar Todo</string> <string name="emulation_toggle_all">Alternar todo</string>
<string name="emulation_control_adjust">Ajustar pantalla</string> <string name="emulation_control_adjust">Ajustar overlay</string>
<string name="emulation_control_scale">Escala</string> <string name="emulation_control_scale">Escala</string>
<string name="emulation_control_opacity">Opacidad</string> <string name="emulation_control_opacity">Opacidad</string>
<string name="emulation_touch_overlay_reset">Reiniciar pantalla</string> <string name="emulation_touch_overlay_reset">Reiniciar overlay</string>
<string name="emulation_touch_overlay_edit">Editar pantalla</string> <string name="emulation_touch_overlay_edit">Editar overlay</string>
<string name="emulation_pause">Pausar Emulación</string> <string name="emulation_pause">Pausar emulación</string>
<string name="emulation_unpause">Reanudar Emulación</string> <string name="emulation_unpause">Despausar emulación</string>
<string name="emulation_input_overlay">Opciones de pantalla </string> <string name="emulation_input_overlay">Opciones de overlay</string>
<string name="load_settings">Cargando configuración...</string> <string name="load_settings">Cargando configuración...</string>
<!-- Software keyboard --> <!-- Software keyboard -->
<string name="software_keyboard">Software del teclado</string> <string name="software_keyboard">Teclado de software</string>
<!-- Errors and warnings --> <!-- Errors and warnings -->
<string name="abort_button">Abortar</string> <string name="abort_button">Abortar</string>
@ -226,6 +293,9 @@
<string name="fatal_error">Error fatal</string> <string name="fatal_error">Error fatal</string>
<string name="fatal_error_message">Ocurrió un error fatal. Consulte el registro para obtener más detalles.\nContinuar con la emulación puede provocar bloqueos y errores.</string> <string name="fatal_error_message">Ocurrió un error fatal. Consulte el registro para obtener más detalles.\nContinuar con la emulación puede provocar bloqueos y errores.</string>
<string name="performance_warning">¡Desactivar esta configuración reducirá significativamente el rendimiento de la emulación! Para obtener la mejor experiencia, se recomienda dejar esta configuración habilitada.</string> <string name="performance_warning">¡Desactivar esta configuración reducirá significativamente el rendimiento de la emulación! Para obtener la mejor experiencia, se recomienda dejar esta configuración habilitada.</string>
<string name="device_memory_inadequate">RAM de dispositivo: %1$s\nRecomendado: %2$s</string>
<string name="memory_formatted">%1$s %2$s</string>
<string name="no_game_present">¡No hay ningún juego ejecutable presente!</string>
<!-- Region Names --> <!-- Region Names -->
<string name="region_japan">Japón</string> <string name="region_japan">Japón</string>
@ -236,7 +306,14 @@
<string name="region_korea">Corea</string> <string name="region_korea">Corea</string>
<string name="region_taiwan">Taiwán</string> <string name="region_taiwan">Taiwán</string>
<!-- Language Names --> <!-- Memory Sizes -->
<string name="memory_byte">Byte</string>
<string name="memory_kilobyte">KB</string>
<string name="memory_megabyte">MB</string>
<string name="memory_gigabyte">GB</string>
<string name="memory_terabyte">TB</string>
<string name="memory_petabyte">PB</string>
<string name="memory_exabyte">EB</string>
<!-- Renderer APIs --> <!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string> <string name="renderer_vulkan">Vulkan</string>
@ -274,6 +351,11 @@
<string name="anti_aliasing_fxaa">FXAA</string> <string name="anti_aliasing_fxaa">FXAA</string>
<string name="anti_aliasing_smaa">SMAA</string> <string name="anti_aliasing_smaa">SMAA</string>
<!-- Screen Layouts -->
<string name="screen_layout_landscape">Paisaje</string>
<string name="screen_layout_portrait">Retrato</string>
<string name="screen_layout_auto">Auto</string>
<!-- Aspect Ratios --> <!-- Aspect Ratios -->
<string name="ratio_default">Predeterminado (16:9)</string> <string name="ratio_default">Predeterminado (16:9)</string>
<string name="ratio_force_four_three">Forzar 4:3</string> <string name="ratio_force_four_three">Forzar 4:3</string>
@ -298,7 +380,7 @@
<string name="building_shaders">Construyendo shaders</string> <string name="building_shaders">Construyendo shaders</string>
<!-- Theme options --> <!-- Theme options -->
<string name="change_app_theme">Cambiar Tema</string> <string name="change_app_theme">Cambiar tema</string>
<string name="theme_default">Predeterminado</string> <string name="theme_default">Predeterminado</string>
<string name="theme_material_you">Material You</string> <string name="theme_material_you">Material You</string>
@ -308,8 +390,22 @@
<string name="theme_mode_light">Claro</string> <string name="theme_mode_light">Claro</string>
<string name="theme_mode_dark">Oscuro</string> <string name="theme_mode_dark">Oscuro</string>
<!-- Audio output engines -->
<string name="cubeb">cubeb</string>
<!-- Black backgrounds theme --> <!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Usar Fondos Negros</string> <string name="use_black_backgrounds">Fondos oscuros</string>
<string name="use_black_backgrounds_description">Cuando utilice el modo oscuro, aplique fondos negros.</string> <string name="use_black_backgrounds_description">Cuando utilice el modo oscuro, aplique fondos negros.</string>
<!-- Picture-In-Picture -->
<string name="picture_in_picture">Picture in Picture</string>
<string name="picture_in_picture_description">Minimizar ventana cuando esté en segundo plano</string>
<string name="pause">Pausar</string>
<string name="play">Jugar</string>
<string name="mute">Mutear</string>
<string name="unmute">Desmutear</string>
<!-- Licenses screen strings -->
<string name="licenses">Licencias</string>
<string name="license_fidelityfx_fsr_description">Upscaling de alta calidad de AMD</string>
</resources> </resources>

Some files were not shown because too many files have changed in this diff Show More