diff --git a/.ci/linux.sh b/.ci/linux.sh
index 0603a0d7a..5b3521681 100755
--- a/.ci/linux.sh
+++ b/.ci/linux.sh
@@ -2,7 +2,10 @@
if [ "$TARGET" = "appimage" ]; then
# Compile the AppImage we distribute with Clang.
- export EXTRA_CMAKE_FLAGS=(-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_LINKER=/etc/bin/ld.lld)
+ export EXTRA_CMAKE_FLAGS=(-DCMAKE_CXX_COMPILER=clang++
+ -DCMAKE_C_COMPILER=clang
+ -DCMAKE_LINKER=/etc/bin/ld.lld
+ -DENABLE_ROOM_STANDALONE=OFF)
# Bundle required QT wayland libraries
export EXTRA_QT_PLUGINS="waylandcompositor"
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
@@ -12,7 +15,7 @@ else
fi
if [ "$GITHUB_REF_TYPE" == "tag" ]; then
- export EXTRA_CMAKE_FLAGS=($EXTRA_CMAKE_FLAGS -DENABLE_QT_UPDATE_CHECKER=ON)
+ export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" -DENABLE_QT_UPDATE_CHECKER=ON)
fi
mkdir build && cd build
@@ -21,8 +24,9 @@ cmake .. -G Ninja \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DENABLE_QT_TRANSLATION=ON \
+ -DENABLE_ROOM_STANDALONE=OFF \
-DUSE_DISCORD_PRESENCE=ON \
- "${EXTRA_CMAKE_FLAGS[@]}"
+ "${EXTRA_CMAKE_FLAGS[@]}"
ninja
strip -s bin/Release/*
diff --git a/.ci/macos-universal.sh b/.ci/macos-universal.sh
index 4ffde0794..54541a1c5 100755
--- a/.ci/macos-universal.sh
+++ b/.ci/macos-universal.sh
@@ -11,7 +11,7 @@ BASE_ARTIFACT_ARCH="${BASE_ARTIFACT##*-}"
mv $BASE_ARTIFACT $BUNDLE_DIR
# Executable binary paths that need to be combined.
-BIN_PATHS=(azahar-room Azahar.app/Contents/MacOS/azahar)
+BIN_PATHS=(Azahar.app/Contents/MacOS/azahar)
# Dylib paths that need to be combined.
IFS=$'\n'
@@ -36,8 +36,11 @@ for OTHER_ARTIFACT in "${ARTIFACTS_LIST[@]:1}"; do
done
done
+# Remove leftover libs so that they aren't distributed
+rm -rf "${BUNDLE_DIR}/libs"
+
# Re-sign executables and bundles after combining.
-APP_PATHS=(azahar-room Azahar.app)
+APP_PATHS=(Azahar.app)
for APP_PATH in "${APP_PATHS[@]}"; do
codesign --deep -fs - $BUNDLE_DIR/$APP_PATH
done
diff --git a/.ci/macos.sh b/.ci/macos.sh
index 94824f45b..4c353d1c3 100755
--- a/.ci/macos.sh
+++ b/.ci/macos.sh
@@ -11,6 +11,7 @@ cmake .. -GNinja \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DENABLE_QT_TRANSLATION=ON \
+ -DENABLE_ROOM_STANDALONE=OFF \
-DUSE_DISCORD_PRESENCE=ON \
"${EXTRA_CMAKE_FLAGS[@]}"
ninja
diff --git a/.ci/pack.sh b/.ci/pack.sh
index caa4a7feb..30a2d9546 100755
--- a/.ci/pack.sh
+++ b/.ci/pack.sh
@@ -14,7 +14,7 @@ else
fi
# Archive and upload the artifacts.
-mkdir artifacts
+mkdir -p artifacts
function pack_artifacts() {
ARTIFACTS_PATH="$1"
@@ -50,11 +50,6 @@ function pack_artifacts() {
rm -rf "$REV_NAME"
}
-if [ "$OS" = "windows" ] && [ "$GITHUB_REF_TYPE" = "tag" ]; then
- # Move the installer to the artifacts directory
- mv src/installer/bin/*.exe artifacts/
-fi
-
if [ -n "$UNPACKED" ]; then
# Copy the artifacts to be uploaded unpacked.
for ARTIFACT in build/bundle/*; do
diff --git a/.ci/source.sh b/.ci/source.sh
index 6298d408c..338ccf4c8 100755
--- a/.ci/source.sh
+++ b/.ci/source.sh
@@ -4,6 +4,10 @@ GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`"
GITREV="`git show -s --format='%h'`"
REV_NAME="azahar-unified-source-${GITDATE}-${GITREV}"
+if [ "$GITHUB_REF_TYPE" = "tag" ]; then
+ REV_NAME="azahar-unified-source-$GITHUB_REF_NAME"
+fi
+
COMPAT_LIST='dist/compatibility_list/compatibility_list.json'
mkdir artifacts
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a3b1b98d5..f4a53eb00 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -49,12 +49,14 @@ jobs:
${{ runner.os }}-${{ matrix.target }}-
- name: Build
run: ./.ci/linux.sh
- - name: Pack
- run: ./.ci/pack.sh
+ - name: Move AppImage to artifacts directory
if: ${{ matrix.target == 'appimage' }}
+ run: |
+ mkdir -p artifacts
+ mv build/bundle/*.AppImage artifacts/
- name: Upload
- uses: actions/upload-artifact@v4
if: ${{ matrix.target == 'appimage' }}
+ uses: actions/upload-artifact@v4
with:
name: ${{ env.OS }}-${{ env.TARGET }}
path: artifacts/
@@ -148,19 +150,19 @@ jobs:
restore-keys: |
${{ runner.os }}-${{ matrix.target }}-
- name: Set up MSVC
+ if: ${{ matrix.target == 'msvc' }}
uses: ilammy/msvc-dev-cmd@v1
- if: ${{ matrix.target == 'msvc' }}
- name: Install extra tools (MSVC)
- run: choco install ccache ninja wget
if: ${{ matrix.target == 'msvc' }}
+ run: choco install ccache ninja ptime wget
- name: Install vulkan-sdk (MSVC)
+ if: ${{ matrix.target == 'msvc' }}
run: |
wget https://sdk.lunarg.com/sdk/download/1.3.296.0/windows/VulkanSDK-1.3.296.0-Installer.exe -O D:/a/_temp/vulkan.exe
D:/a/_temp/vulkan.exe --accept-licenses --default-answer --confirm-command install
- if: ${{ matrix.target == 'msvc' }}
- name: Set up MSYS2
- uses: msys2/setup-msys2@v2
if: ${{ matrix.target == 'msys2' }}
+ uses: msys2/setup-msys2@v2
with:
msystem: clang64
update: true
@@ -168,10 +170,16 @@ jobs:
pacboy: >-
toolchain:p ccache:p cmake:p ninja:p spirv-tools:p
qt6-base:p qt6-multimedia:p qt6-multimedia-wmf:p qt6-tools:p qt6-translations:p
+ - name: Install extra tools (MSYS2)
+ if: ${{ matrix.target == 'msys2' }}
+ uses: crazy-max/ghaction-chocolatey@v3
+ with:
+ args: install ptime wget
- name: Install NSIS
+ if: ${{ github.ref_type == 'tag' }}
run: |
- Invoke-WebRequest https://deac-riga.dl.sourceforge.net/project/nsis/NSIS%203/3.10/nsis-3.10-setup.exe?viasf=1 -OutFile C:\WINDOWS\Temp\nsis-3.10-setup.exe
- Invoke-Expression "& C:\WINDOWS\Temp\nsis-3.10-setup.exe \S"
+ wget https://download.sourceforge.net/project/nsis/NSIS%203/3.11/nsis-3.11-setup.exe -O D:/a/_temp/nsis-setup.exe
+ ptime D:/a/_temp/nsis-setup.exe /S
shell: pwsh
- name: Disable line ending translation
run: git config --global core.autocrlf input
@@ -182,8 +190,8 @@ jobs:
run: |
cd src\installer
"C:\Program Files (x86)\NSIS\makensis.exe" /DPRODUCT_VARIANT=${{ matrix.target }} /DPRODUCT_VERSION=${{ github.ref_name }} citra.nsi
- mkdir bin
- move /y *.exe bin\
+ mkdir ..\..\artifacts 2> NUL
+ move /y *.exe ..\..\artifacts\
shell: cmd
- name: Pack
run: ./.ci/pack.sh
@@ -241,8 +249,8 @@ jobs:
name: ${{ env.OS }}-${{ env.TARGET }}
path: src/android/app/artifacts/
ios:
- runs-on: macos-14
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
+ runs-on: macos-14
env:
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_COMPILERCHECK: content
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 000000000..45d138adc
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -0,0 +1,23 @@
+name: azahar-stale
+
+on:
+ schedule:
+ - cron: "0 0 * * *"
+
+jobs:
+ stale-issues:
+ runs-on: ubuntu-latest
+ permissions:
+ issues: write
+ steps:
+ - uses: actions/stale@v9.1.0
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ days-before-issue-stale: 90
+ days-before-issue-close: 10
+ stale-issue-message: "This issue has been marked as stale. If there is no activity within the next 10 days, this issue will be closed."
+ close-issue-message: "This issue has been closed as stale."
+ days-before-pr-stale: -1
+ days-before-pr-close: -1
+ remove-issue-stale-when-updated: true
+ exempt-issue-labels: "priority - low,priority - medium,priority - high,priority - urgent,documentation,enhancement,miscellaneous,task,refactor"
diff --git a/.gitmodules b/.gitmodules
index 1a99568df..5b100db0f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -6,7 +6,7 @@
url = https://github.com/neobrain/nihstro.git
[submodule "soundtouch"]
path = externals/soundtouch
- url = https://codeberg.org/soundtouch/soundtouch.git
+ url = https://github.com/azahar-emu/soundtouch.git
[submodule "catch2"]
path = externals/catch2
url = https://github.com/catchorg/Catch2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a9dc14f62..e5de1ddec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,8 +41,8 @@ if (APPLE)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
else()
- # Minimum macOS 11
- set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0")
+ # Minimum macOS 13
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "13.4")
endif()
endif()
@@ -54,6 +54,13 @@ else()
set(IS_RELEASE_BUILD ON)
endif()
+if (MSVC)
+ add_compile_options(
+ /wd4711 # Suppresses `function 'xxxxx' selected for automatic inline expansion` messages
+ /wd5045 # Suppresses `Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified` messages
+ )
+endif()
+
# LTO takes too much memory and time using MSVC.
if (NOT MSVC AND IS_RELEASE_BUILD)
set(DEFAULT_ENABLE_LTO ON)
@@ -79,7 +86,8 @@ option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
option(ENABLE_QT_UPDATE_CHECKER "Enable built-in update checker for the Qt frontend" OFF)
CMAKE_DEPENDENT_OPTION(ENABLE_TESTS "Enable generating tests executable" ON "NOT IOS" OFF)
-CMAKE_DEPENDENT_OPTION(ENABLE_ROOM "Enable generating dedicated room executable" ON "NOT ANDROID AND NOT IOS" OFF)
+CMAKE_DEPENDENT_OPTION(ENABLE_ROOM "Enable dedicated room functionality" ON "NOT ANDROID AND NOT IOS" OFF)
+CMAKE_DEPENDENT_OPTION(ENABLE_ROOM_STANDALONE "Enable generating a standalone dedicated room executable" ON "ENABLE_ROOM" OFF)
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
option(ENABLE_SCRIPTING "Enable RPC server for scripting" ON)
@@ -111,6 +119,9 @@ endif()
if (ENABLE_QT_TRANSLATION)
add_definitions(-DENABLE_QT_TRANSLATION)
endif()
+if (ENABLE_ROOM)
+ add_definitions(-DENABLE_ROOM)
+endif()
if (ENABLE_SDL2_FRONTEND)
add_definitions(-DENABLE_SDL2_FRONTEND)
endif()
@@ -477,9 +488,8 @@ if (NOT ANDROID AND NOT IOS)
elseif (ENABLE_SDL2_FRONTEND)
bundle_target(citra_meta)
endif()
-
- if (ENABLE_ROOM)
- bundle_target(citra_room)
+ if (ENABLE_ROOM_STANDALONE)
+ bundle_target(citra_room_standalone)
endif()
endif()
@@ -492,11 +502,14 @@ endif()
# http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
if(ENABLE_QT AND UNIX AND NOT APPLE)
install(FILES "${PROJECT_SOURCE_DIR}/dist/azahar.desktop"
- DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications")
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications"
+ RENAME "org.azahar_emu.Azahar.desktop")
install(FILES "${PROJECT_SOURCE_DIR}/dist/azahar.svg"
- DESTINATION "${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps")
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps"
+ RENAME "org.azahar_emu.Azahar.svg")
install(FILES "${PROJECT_SOURCE_DIR}/dist/azahar.png"
- DESTINATION "${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/512x512/apps")
- install(FILES "${PROJECT_SOURCE_DIR}/dist/azahar.xml"
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/512x512/apps"
+ RENAME "org.azahar_emu.Azahar.png")
+ install(FILES "${PROJECT_SOURCE_DIR}/dist/org.azahar_emu.Azahar.xml"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/mime/packages")
endif()
diff --git a/CMakeModules/BundleTarget.cmake b/CMakeModules/BundleTarget.cmake
index 592f271a4..bd30faf91 100644
--- a/CMakeModules/BundleTarget.cmake
+++ b/CMakeModules/BundleTarget.cmake
@@ -117,6 +117,9 @@ if (BUNDLE_TARGET_EXECUTE)
set(extra_linuxdeploy_args --plugin qt)
endif()
+ # Set up app icon
+ file(COPY_FILE "${source_path}/dist/azahar.svg" "${CMAKE_BINARY_DIR}/dist/org.azahar_emu.Azahar.svg")
+
message(STATUS "Creating AppDir for executable ${executable_path}")
execute_process(COMMAND ${CMAKE_COMMAND} -E env
${extra_linuxdeploy_env}
@@ -124,7 +127,7 @@ if (BUNDLE_TARGET_EXECUTE)
${extra_linuxdeploy_args}
--plugin checkrt
--executable "${executable_path}"
- --icon-file "${source_path}/dist/azahar.svg"
+ --icon-file "${CMAKE_BINARY_DIR}/dist/org.azahar_emu.Azahar.svg"
--desktop-file "${source_path}/dist/${executable_name}.desktop"
--appdir "${appdir_path}"
RESULT_VARIABLE linuxdeploy_appdir_result)
@@ -276,22 +279,12 @@ else()
add_custom_target(bundle)
add_custom_command(
TARGET bundle
- COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bundle/")
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bundle/"
+ POST_BUILD)
add_custom_command(
TARGET bundle
- COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bundle/dist/")
- add_custom_command(
- TARGET bundle
- COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/dist/azahar.png" "${CMAKE_BINARY_DIR}/bundle/dist/azahar.png")
- add_custom_command(
- TARGET bundle
- COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/license.txt" "${CMAKE_BINARY_DIR}/bundle/")
- add_custom_command(
- TARGET bundle
- COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/README.md" "${CMAKE_BINARY_DIR}/bundle/")
- add_custom_command(
- TARGET bundle
- COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/dist/scripting" "${CMAKE_BINARY_DIR}/bundle/scripting")
+ COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/dist/scripting" "${CMAKE_BINARY_DIR}/bundle/scripting"
+ POST_BUILD)
# On Linux, add a command to prepare linuxdeploy and any required plugins before any bundling occurs.
if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
@@ -302,7 +295,8 @@ else()
"-DLINUXDEPLOY_PATH=${CMAKE_BINARY_DIR}/externals/linuxdeploy"
"-DLINUXDEPLOY_ARCH=${CMAKE_HOST_SYSTEM_PROCESSOR}"
-P "${CMAKE_SOURCE_DIR}/CMakeModules/BundleTarget.cmake"
- WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ POST_BUILD)
endif()
endfunction()
diff --git a/README.md b/README.md
index 93dda949a..5c4cccbd2 100644
--- a/README.md
+++ b/README.md
@@ -10,20 +10,20 @@ It was created from the merging of PabloMK7's Citra fork and the Lime3DS project
The goal of this project is to be the de-facto platform for future development.
-> [!NOTE]
-> Azahar has not fully released yet. For this reason, there are no compiled binaries available for download.
->
-> It is recommended that only developers and early adopters should use the emulator until our first stable release.
->
-> Here be dragons.
-
-
Configuració
@@ -83,9 +79,13 @@
Cancel·lar
Seleccionar carpeta d\'usuari.
dades d\'usuari amb el següent botó.]]>
+ Sembla que tens directoris d\'usuari configurats tant per a Lime3DS com per a Azahar. Probablement es deu al fet que vas actualitzar a Azahar i, quan se\'t va demanar, vas triar un directori d\'usuari diferent del qual usaves per a Lime3DS.\n\nAixó pot haver-te fet pensar que vas perdre partides guardades o altres configuracions; et demanem disculpes si això va ocórrer.\n\nPreferixes tornar a usar el teu directori d\'usuari original de Lime3DS, restaurant la configuració i les partides guardades de Lime3DS, o conservar el teu directori d\'usuari actual d\'Azahar?\n\nCap dels directoris s\'eliminarà, independentment de la teua elecció, i pots canviar lliurement entre ells usant l\'opció \"Seleccionar carpeta d\'usuari\".
+ Mantindre el directori Azahar actual
+ Usar el directori de Lime3DS anterior
Seleccionar
No pots saltar aquest pas
Aquest pas és necessari perquè Azahar funcione. Selecciona un directori i després podràs continuar.
+ Has perdut els permisos d\'escriptura en el teu directori de dades d\'usuari, on es guarden les partides guardades i altra informació. Això pot ocórrer després d\'algunes actualitzacions d\'aplicacions o d\'Android. Torna a seleccionar el directori per a recuperar els permisos i poder continuar.
Configuració de tema
Configura les teues preferències de temes per a Azahar.
Establir tema
@@ -122,15 +122,21 @@
Mou el joystick a esquerra o dreta.
HOME
Intercanviar Pantalles
+ Turbo
Aquest control s\'ha d\'assignar a un estic analògic del comandament o a un eix del Pad de Control!
Aquest control s\'ha d\'assignar a un botó del comandament!
+ Velocitat Turbo
+ Velocitat Turbo Activada
+ Velocitat Turbo Desactivada
Fitxers del sistema
Realitzar operacions de fitxers del sistema, com instal·lar fitxers del sistema o obrir el menú HOME
Connectar amb la ferramenta de configuració Artic
- ferramenta de configuració Azahar.
Notes:- Aquesta operació instal·larà fitxers únics de la consola a Azahar, no compartisques les teues carpetes d\'usuari o nand
després de completar el procés de configuració! - La configuració de Old 3DS és necessària perquè funcione la configuració de New 3DS.
- Els dos modes de configuració funcionaran independentment del model de la consola que execute la ferramenta de configuració.
]]>
+ ferramenta de configuració Azahar.
Notes:- Aquesta operació instal·larà fitxers únics de la consola a Azahar, no compartisques les teues carpetes d\'usuari o nand després de completar el procés de configuració!
- Després de la configuració, Azahar s\'enllaçarà a la consola que ha executat la ferramenta de configuració. Pots desvincular la consola més tard des de la pestanya \"Fitxers de sistema\" del menú d\'opcions de l\'emulador.
- No et connectes en línia amb Azahar i la consola 3DS al mateix temps després de configurar els arxius del sistema, ja que això podria causar problemes.
- La configuració de Old 3DS és necessària perquè funcione la configuració de New 3DS (configurar els dos modes és recomanat).
- Els dos modes de configuració funcionaran independentment del model de la consola que execute la ferramenta de configuració.
]]>
S\'està obtenint l\'estat actual dels fitxers del sistema, per favor espera...
+ Desvincular Dades Úniques de Consola
+ - OTP, SecureInfo i LocalFriendCodeSeed seran eliminats de Azahar.
- La teua llista d\'amics es restablirà i es tancarà la sessió del teu compte NNID/PNID.
- Els fitxers del sistema i els títols de la eshop obtinguts a través d\'Azahar es tornaran inaccessibles fins que la mateixa consola es vincule novament mitjançant la ferramenta de configuració (les dades guardades no es perdran).
Continuar?]]>
Configuració Old 3DS
Configuració New 3DS
La configuració és possible
@@ -147,20 +153,20 @@
Botons
Botó
-
- CPU JIT
- Usa el compilador Just-In-Time (JIT) per a l\'emulació de la CPU. Quan s\'active, el rendiment millorarà notablement.
- Rellotge
- Configura el rellotge emulat de la 3DS perquè tinga la mateixa data i hora del teu dispositiu o per a configurar una data i hora distinta.
- Velocitat de rellotge de la CPU
-
+ Configuració d\'emulació
Nom d\'usuari/a
Mode New 3DS
Usar Applets LLE (si están instal·lades)
+ Habilite els mòduls LLE necessaris per a les funcions en línia (si estan instal·lats)
+ Habilita els mòduls LLE necessaris per al mode multijugador en línia, accés a la eShop, etc.
Rellotge
- Temps de compensació
- Si el rellotge està en \"Rellotge emulat\", es canvia la data i l\'hora d\'inici.
+ Rellotge
+ Configura el rellotge emulat de la 3DS perquè tinga la mateixa data i hora del teu dispositiu o per a configurar una data i hora distinta.
+ Rellotge del Sistema
+ Rellotge Simulat
+ Si el rellotge està en \"Rellotge emulat\", es canvia la data i l\'hora d\'inici.
+ Configuració de perfil
Regió
Idioma
Aniversari
@@ -173,10 +179,16 @@
ID de Consola
Regenerar ID de Consola
Substituirà la teua ID de consola 3DS actual per una nova. La teua ID actual no es podrà recuperar. Pot tenir efectes inesperats dins de les aplicacions. Podria fallar si utilitzes un fitxer de configuració obsolet. Continuar?
+ Adreça MAC
+ Regenerar adreça MAC
+ Això reemplaçarà la teua adreça MAC actual per una nova. No es recomana fer-ho si vas obtindre la direcció MAC de la teua consola real amb la ferramenta de configuració. Continuar?
Carregador de complements 3GX
Carrega els plugins 3GX de la SD emulada si estan disponibles.
Permetre que les aplicacions canvien l\'estat del carregador de plugins
Permet que les apps homebrew activen el carregador de plugins fins i tot quan està desactivat.
+ Advertiment Regió No Vàlida
+ La configuració del país no és vàlida per a la regió emulada seleccionada.
+ La configuració del país no és vàlida per a la consola vinculada actual.
Càmera interior
@@ -199,26 +211,30 @@
Activar compilació de ombrejadors asíncrona
Compila els ombrejats en segón pla per a reduir les aturades durant la partida.
S\'esperen errors gràfics temporals quan estigue activat.
- Renderitzador de depuració
- Arxiva informació addicional gràfica relacionada amb la depuració. Quan està activada, el rendiment dels jocs serà reduït considerablement
- Activar Sincronització Vertical
- Sincronitza els quadres per segon del joc amb la taxa de refresc del teu dispositiu.
Filtre Linear
Activa el filtre linear, que fa que els gràfics del joc es vegen més suaus.
Filtre de Textures
Millora l\'aspecte visual de les aplicacions aplicant un filtre a les textures. Els filtres compatibles són Anime4K, Ultrafast, Bicubic, ScaleForce, xBRZ Freescale i MMPX.
- Activar Ombrejador de Hardware
- Usa el hardware per a emular els ombrejadors de 3DS. Quan s\'active, el rendiment millorarà notablement.
+ Endarrerir fil de renderitzat del joc
+ Retarda el fil de renderitzat del joc en enviar dades a la GPU. Ajuda a solucionar problemes de rendiment en les (poques) aplicacions amb velocitats de fotogrames dinàmiques.
+ Avançat
+ Mostreig de Textures
+ Sobreescriu el filtre de mostreig usat en jocs. Pot ser útil en uns certs casos de jocs amb baix rendiment en pujar la resolució. Si no estàs segur, possa\'l en Controlat per Joc.
Multiplicació Precisa
Usa multiplicacions més precises en els ombrejos de Hardware, que podrien arreglar uns certs problemes gràfics. Quan s\'active, el rendiment es reduirà.
Activar Emulació Asíncrona de la GPU
Usa un fil separat per a emular la GPU de manera asíncrona. Quan s\'active, el rendiment millorarà.
Límit de velocitat
- Quan s\'active, la velocitat d\'emulació estarà limitada a un percentatge determinat de la velocitat normal.
+ Quan s\'active, la velocitat d\'emulació estarà limitada a un percentatge determinat de la velocitat normal. Quan es desactive, la velocitat d\'emulació no tindrà límit i la tecla d\'accés ràpid de velocitat turbo no funcionarà.
Limitar percentatge de velocitat
Especifica el valor al qual es limita la velocitat d\'emulació. Amb el valor per defecte del 100%, l\'emulació es limitarà a la velocitat normal. Els valors alts o baixos incrementaran o reduiran el límit de velocitat.
+ Límit de Velocitat Turbo
+ Límit de velocitat d\'emulació utilitzat mentres la tecla d\'accés ràpid turbo està activa.
+ Expandir a l\'àrea de retallada
+ Amplia l\'àrea de visualització per a incloure l\'àrea de retallada (o osca).
Resolució interna
Especifica la resolució utilitzada per a renderitzar. Una resolució alta millora considerablement la qualitat visual, però també afecta bastant al rendiment i pot causar problemes en unes certes aplicacions.
+ Auto (Grandària Pantalla)
Nativa (400x240)
2x Nativa (800x480)
3x Nativa (1200x720)
@@ -234,7 +250,9 @@ S\'esperen errors gràfics temporals quan estigue activat.
Estereoscopia
Mode 3D Estereoscòpic
Profunditat
- Especifica el valor del regulador 3D. Hauria d\'estar posat a més enllà del 0% quan el Mode 3D Estereoscòpic està activat.
+ Especifica el valor del regulador 3D. Hauria d\'estar posat a més enllà del 0% quan el Mode 3D Estereoscòpic està activat.\nNota: Els valors de profunditat superiors al 100% no són possibles en hardware real i poden causar problemes gràfics.
+ Desactivar Renderitzat d\'Ull Dret
+ Millora enormement el rendiment en algunes aplicacions, però pot provocar parpellejos en unes altres.
Cardboard VR
Grandària de la pantalla Cardboard
Escala la pantalla a un percentatge de la seua grandària original.
@@ -264,6 +282,23 @@ S\'esperen errors gràfics temporals quan estigue activat.
Dispositiu d\'entrada d\'àudio
Mode d\'eixida de l\'àudio
+
+ CPU JIT
+ Usa el compilador Just-In-Time (JIT) per a l\'emulació de la CPU. Quan s\'active, el rendiment millorarà notablement.
+ Activar Ombrejador de Hardware
+ Usa el hardware per a emular els ombrejadors de 3DS. Quan s\'active, el rendiment millorarà notablement.
+ Velocitat de rellotge de la CPU
+ Activar Sincronització Vertical
+ Sincronitza els quadres per segon del joc amb la taxa de refresc del teu dispositiu.
+ Renderitzador de depuració
+ Arxiva informació addicional gràfica relacionada amb la depuració. Quan està activada, el rendiment dels jocs serà reduït considerablement
+ Guardar l\'eixida del registre en cada missatge
+ Envia immediatament el registre de depuració a un arxiu. Usa-ho si Azahar falla i es talla l\'eixida del registre.
+ Inici diferit amb mòduls LLE
+ Retarda l\'inici de l\'aplicació quan els mòduls LLE estan habilitats.
+ Operacions asíncrones deterministes
+ Fa que les operacions asíncrones siguen deterministes per a la depuració. Habilitar esta opció pot causar bloquejos.
+
Orientació de pantalla
Automàtica
@@ -278,6 +313,7 @@ S\'esperen errors gràfics temporals quan estigue activat.
Configuració guardada
Configuració guardada per a %1$s
Error guardant %1$s.ini: %2$s
+ Guardant...
Carregant...
Següent
Arrere
@@ -298,8 +334,14 @@ S\'esperen errors gràfics temporals quan estigue activat.
Seleccionar hora RTC
Vols reiniciar esta configuració al seu valor per defecte?
No pots editar-ho ara
+ Configuració deshabilitada
+ Esta configuració està actualment deshabilitada perquè una altra configuració no té el valor apropiat.
Esta opció no pot canviar-se mentres s\'està executant un joc.
Auto-elegir
+ Iniciar
+ Cancel·lant
+ Important
+ No tornar a mostrar
Seleccionar Directori de Joc
@@ -367,6 +409,8 @@ S\'esperen errors gràfics temporals quan estigue activat.
Abaix a l\'esquerra
Damunt
Davall
+ Separació de Pantalla
+ Espai entre pantalles en tots els modes de dos pantalles. Mesurat en píxels respecte a l\'altura de 240 píxels de la pantalla més gran.
Proporció de Pantalla Gran
Quantes vegades més gran és la pantalla gran que la pantalla xicoteta en Proporció de Pantalla Gran?
Ajusta l\'estil personalitzat en Configuració
@@ -384,6 +428,9 @@ S\'esperen errors gràfics temporals quan estigue activat.
Mostrar Estil
Tancar Joc
Activar pausa
+ Miscel·lanis
+ Usar Artic Controller en estar connectat al servidor de Artic Base
+ Utilitza els controls proporcionats per Artic Base Server quan estiga connectat a ell en lloc del dispositiu d\'entrada configurat.
Estàs segur que vols tancar el joc?
Amiibo
Carregar
@@ -455,6 +502,17 @@ S\'esperen errors gràfics temporals quan estigue activat.
Jugar
Drecera
+ Desinstal·lar Aplicació
+ Desinstal·lant...
+ Obrir Carpeta de Guardat
+ Obrir Carpeta d\'Aplicació
+ Obrir Carpeta de Mods
+ Obrir Carpeta de Textures
+ Obrir Carpeta de DLC
+ Obrir Carpeta d\'Actualitzacions
+ Obrir Carpeta Extra
+ Desinstal·lar DLC
+ Desinstal·lar Actualitzacions
Trucs
@@ -514,10 +572,6 @@ S\'esperen errors gràfics temporals quan estigue activat.
Fons foscos
Quan uses el tema fosc, s\'aplicaran fons foscos.
-
- Rellotge del Sistema
- Rellotge Simulat
-
JPN
USA
@@ -574,11 +628,15 @@ S\'esperen errors gràfics temporals quan estigue activat.
Anime4K
Bicubic
- Nearest Neighbor
ScaleForce
xBRZ
MMPX
+
+ Controlat per Joc
+ Nearest Neighbor
+ Liniar
+
Mono
Estéreo
@@ -739,33 +797,12 @@ S\'esperen errors gràfics temporals quan estigue activat.
Connectar amb una consola real que estiga executant un servidor Artic Base
Connectar amb Artic Base
Introduïx la direcció del servidor Artic Base
- Endarrerir fil de renderitzat del joc
- Retarda el fil de renderitzat del joc en enviar dades a la GPU. Ajuda a solucionar problemes de rendiment en les (poques) aplicacions amb velocitats de fotogrames dinàmiques.
Guardat ràpid
Guardat ràpid
Carregament ràpid
Guardat ràpid - %1$tF %1$tR
- Guardant...
- Carregant...
Guardat ràpid no disponible.
- Miscel·lanis
- Usar Artic Controller en estar connectat al servidor de Artic Base
- Utilitza els controls proporcionats per Artic Base Server quan estiga connectat a ell en lloc del dispositiu d\'entrada configurat.
- Guardar l\'eixida del registre en cada missatge
- Envia immediatament el registre de depuració a un arxiu. Usa-ho si Azahar falla i es talla l\'eixida del registre.
- Desactivar Renderitzat d\'Ull Dret
- Millora enormement el rendiment en algunes aplicacions, però pot provocar parpellejos en unes altres.
- Inici diferit amb mòduls LLE
- Retarda l\'inici de l\'aplicació quan els mòduls LLE estan habilitats.
- Operacions asíncrones deterministes
- Fa que les operacions asíncrones siguen deterministes per a la depuració. Habilitar esta opció pot causar bloquejos.
- Habilite els mòduls LLE necessaris per a les funcions en línia (si estan instal·lats)
- Habilita els mòduls LLE necessaris per al mode multijugador en línia, accés a la eShop, etc.
- Configuració d\'emulació
- Configuració de perfil
- Adreça MAC
- Regenerar adreça MAC
- Això reemplaçarà la teua adreça MAC actual per una nova. No es recomana fer-ho si vas obtindre la direcció MAC de la teua consola real amb la ferramenta de configuració. Continuar?
+
diff --git a/src/android/app/src/main/res/values-b+da+DK/strings.xml b/src/android/app/src/main/res/values-b+da+DK/strings.xml
index 1521af884..928b812c5 100644
--- a/src/android/app/src/main/res/values-b+da+DK/strings.xml
+++ b/src/android/app/src/main/res/values-b+da+DK/strings.xml
@@ -1,14 +1,10 @@
- Denne software kører applikationer til den håndholdte spillekonsol Nintendo 3DS. Ingen spiltitler er inkluderet.\n\nInden du kan begynde med at emulere, skal du vælge en mappe til at gemme Azahars brugerdata i.\n\nHvad er dette:\nWiki - Citra Android-brugerdata og lagring
+ Denne software kører applikationer til den håndholdte spillekonsol Nintendo 3DS. Ingen spiltitler er inkluderet.\n\nInden du kan begynde med at emulere, skal du vælge en mappe til at gemme Azahars brugerdata i.\n\nHvad er dette:\nWiki - Citra Android-brugerdata og lagring
Azahar 3DS emulator meddelelser
Azahar kører
Dernæst skal du vælge en applikationsmappe. Azahar vil vise alle 3DS ROM\'erne inde i den valgte mappe i appen.\n\nCIA ROM\'er, opdateringer og DLC skal installeres separat ved at klikke på mappeikonet og vælge installer CIA.
- Start
- Annullerer...
- Vigtig
- Vis ikke igen
Indstillinger
@@ -31,4 +27,775 @@
Tillad at Azahar udfylder applikationslisten
Om
En open source 3DS-emulator
-
+ Version, krediteringer og mere
+ Applikationsmappen er valgt
+ Ændrer de filer, som Azahar bruger til at indlæse applikationer
+ Rediger appens udseende
+ Installer CIA
+ Lær mere.]]>
+
+
+ Vælg GPU-driver
+ Vil du udskifte din nuværende GPU-driver?
+ Installere
+ Standardindstilling
+ Installerede %s
+ Bruger standard GPU-driver
+ Ugyldig driver valgt, bruger systemstandard!
+ System GPU driver
+ Installerer driver...
+
+
+ Kopieret til udklipsholder
+ Bidragsydere
+ Bidragsydere, der gjorde Azahar mulig
+ Projekter brugt af Azahar til Android
+ Byg
+ Licenser
+
+ Velkommen!
+ Lær hvordan du konfigurerer <b>Azahar</b> og kommer i gang med emulering.
+ Kom i gang
+ Afsluttet!
+ Applikationer
+ Vælg mappen <b>Applikationer</b> med knappen nedenfor.
+ Færdig
+ Du er klar.\nGod fornøjelse med emulatoren!
+ Fortsætte
+ Meddelelser
+ Giv tilladelse til meddelelser med knappen nedenfor.
+ Giv tilladelse
+ Vil du droppe at give tilladelse til meddelelser?
+ Azahar vil ikke være i stand til at give dig meddelelse om vigtige oplysninger.
+ Kamera
+ Giv kameraet tilladelse nedenfor til at efterligne 3DS-kameraet.
+ Mikrofon
+ Giv mikrofonen tilladelse nedenfor til at efterligne 3DS-mikrofonen.
+ Tilladelse nægtet
+ Vil du droppe at vælge applikationsmappen?
+ Software vil ikke blive vist på applikationslisten, hvis en mappe ikke er valgt.
+ Hjælp
+ Spring over
+ Annuller
+ Vælg brugermappe
+ brugerdata mappe med knappen nedenfor.]]>
+ Du ser ud til at have indstillet brugermapper til både Lime3DS og Azahar. Dette skyldes sandsynligvis, at du har opgraderet til Azahar, og da du bliver bedt om det, valgte du en anden brugermappe end den, der blev brugt til Lime3DS.\n\nDette kan have resulteret i, at du troede, at du havde mistet gemte tilstande eller andre indstillinger - vi beklager, hvis det skete.\n\nVil du gå tilbage til at bruge din oprindelige Lime3DS-brugermappe, gendanne indstillinger og gemte Lime3DS-spiltilstande, eller beholde dine nuværende Azahar brugermappe?\n\nIngen af mapperne slettes, uanset dit valg, og du kan frit skifte mellem dem ved at bruge valgmuligheden Vælg brugermappe.
+ Behold den aktuelle Azahar-mappe
+ Brug tidligere Lime3DS mappe
+ Vælg
+ Du kan ikke springe dette trin over
+ Dette trin er påkrævet for at Azahar kan fungere. Vælg en mappe og så kan du fortsætte.
+ Du har mistet skrivetilladelse i din brugerdata mappe, hvor gemte tilstande og anden information er gemt. Dette kan ske efter en app- eller Android-opdatering. Vælg venligst mappen for at give tilladelse igen, så du kan fortsætte.
+ Temaindstillinger
+ Konfigurer dine temaindstillinger for Azahar.
+ Indstil tema
+
+
+ Søg og filtrer applikationer
+ Søg applikationer
+ For nylig spillet
+ For nyligt tilføjet
+ Installeret
+
+
+ Circle Pad
+ C-Stick
+ Genvejstaster
+ Triggers
+ Trigger
+ D-Pad
+ D-Pad (akser)
+ Nogle kontrollere er muligvis ikke i stand til at tilknytte deres D-Pad som en akse. Hvis det er tilfældet, skal du bruge afsnittet D-Pad (knapper).
+ D-Pad (knapper)
+ Udfyld kun disse D-Pad, hvis du har problemer med opsætningen af D-Pad (akser).
+ Op/ned akse
+ Venstre/højre akse
+ Op
+ Ned
+ Venstre
+ Højre
+ Bind %1$s %2$s
+ Tryk på eller flyt et input.
+ Inputbinding
+ Tryk på eller flyt et input for at binde det til %1$s.
+ Bevæg joysticket op eller ned.
+ Bevæg joysticket til venstre eller højre
+ HOME
+ Byt skærme
+ Turbo
+ Denne kontrol skal være bundet til et gamepad analogt greb eller akse D-Pad!
+ Denne kontrol skal være bundet til en gamepad knap!
+
+ Systemfiler
+ Udfør handlinger som installation af systemfiler eller opstart af startmenu
+ Opret forbindelse til Artic opsætningsværktøj
+ Azahar Artic Setup Tool.
Bemærk:- Denne handling vil installere unikke konsoldata til Azahar, del ikke dine bruger- eller nand-mapper efter at have udført opsætningsprocessen!
- Mens du udfører opsætningsprocessen, vil Azahar forbinde til konsollen, der kører opsætningsværktøjet. Du kan fjerne forbindelsen til konsollen senere fra fanen Systemfiler i emulatorindstillingsmenuen.
- Gå ikke online med både Azahar og din 3DS-konsol på samme tid efter opsætning af systemfiler, da dette kan medføre problemer.
- Gammel 3DS-opsætning er nødvendig for at den nye 3DS-opsætning kan fungere (det anbefales at opsætte begge dele).
- Begge opsætningstilstande fungerer uanset hvilken model af konsollen, der kører opsætningsværktøjet.
]]>
+ Henter den aktuelle status for systemfiler, vent venligst...
+ Fjern linket til de unikke konsoldata
+ - Din OTP, SecureInfo og LocalFriendCodeSeed vil blive fjernet fra Azahar.
- Din venneliste nulstilles, og du bliver logget ud af din NNID/PNID-konto.
- Systemfiler og eshop-titler opnået gennem Azahar bliver utilgængelige, indtil den samme konsol er linket igen ved hjælp af opsætningsværktøjet (gemte data går ikke tabt).
Fortsætte?]]>
+ Gammel 3DS opsætning
+ Ny 3DS-opsætning
+ Opsætning er mulig.
+ Gammel 3DS-opsætning kræves først.
+ Opsætningen er allerede fuldført.
+ Indtast adressen til Artic opsætningsværktøj
+ Forbereder opsætning, vent venligst...
+ Start HOME-menuen
+ Vi apps i HOME menu i applikationslisten
+ Kør systemopsætning, når HOME-menuen startes.
+ HOME menu
+
+
+ Knapper
+ Knap
+
+
+ Emuleringsindstillinger
+ Brugernavn
+ Ny 3DS tilstand
+ Brug LLE Applets (hvis installeret)
+ Aktiver nødvendige LLE moduler til onlinefunktioner (hvis installeret)
+ Aktiverer de LLE moduler, der kræves til online multiplayer, eShop-adgang osv.
+ Ur
+ Ur
+ Indstil det emulerede 3DS ur til enten at afspejle det på din enhed eller anvende en simuleret dato og klokkeslæt.
+ Enhedens ur
+ Simuleret ur
+ Hvis uret er indstillet til \"Simuleret ur\", ændrer dette den faste startdato og klokkeslæt.
+ Profilindstillinger
+ Region
+ Sprog
+ Fødselsdag
+ Måned
+ Dag
+ Land
+ Spil mønter
+ Skridttæller skridt i timen
+ Antal skridt i timen som rapporteres af skridttælleren. Interval fra 0 til 65.535.
+ Konsol ID
+ Udtag nyt konsol ID
+ Dette vil erstatte dit nuværende virtuelle 3DS konsol ID med et nyt. Dit nuværende virtuelle 3DS konsol ID vil ikke kunne gendannes. Dette kan have uventede virkninger inde i applikationer. Dette kan mislykkes, hvis du bruger en forældet gemt konfiguration. Fortsætte?
+ MAC-adresse
+ Udtag ny MAC-adresse
+ Dette vil erstatte din nuværende MAC-adresse med en ny. Det anbefales ikke at gøre dette, hvis du har fået MAC-adressen fra din rigtige konsol ved hjælp af opsætningsværktøjet. Fortsætte?
+ Indlæsning af 3GX Plugins
+ Indlæser 3GX plugins fra det emulerede SD-kort, hvis de er tilgængelige.
+ Tillad applikationer at ændre plugin-indlæserens tilstand
+ Tillader at homebrew applikationer kan aktivere plugin-indlæseren, selv når den er deaktiveret.
+ Advarsel om uoverensstemmelse i region
+ Landeindstillingen er ikke gyldig for det valgte emulerede område.
+ Landeindstillingen er ikke gyldig for den aktuelle forbundne konsol.
+
+
+ Indre kamera
+ Ydre venstre kamera
+ Ydre højre kamera
+ Kameraets billedkilde
+ Indstiller billedkilden for det virtuelle kamera. Du kan bruge en billedfil eller et enhedskamera, hvis dette understøttes.
+ Kamera
+ Hvis indstillingen \"Billedkilde\" er sat til \"Enhedens kamera\", bruges det fysiske kamera.
+ Front
+ Bagside
+ Ekstern
+ Vend
+
+
+ Rendering
+ Grafik API
+ Aktiver generering af SPIR-V shader
+ Udsender den fragment shader, der bruges til at emulere PICA med SPIR-V i stedet for GLSL
+ Aktiver asynkron shader kompilering
+ Kompilerer shaders i baggrunden for at reducere hakken under spilet. Når det er aktiveret, skal du forvente tilfældige grafiske fejl
+ Lineær filtrering
+ Aktiverer lineær filtrering, hvilket får spillets grafik til at se mere jævnt ud.
+ Teksturfilter
+ Forbedrer det visuelle i applikationer ved at anvende et filter på teksturer. De understøttede filtre er Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale og MMPX.
+ Forsinket spillets renderingstråd
+ Forsink spillets remderingstråd, når den sender data til GPU\'en. Hjælper med ydeevneproblemer i de (meget få) applikationer med dynamiske framerates.
+ Avanceret\"
+ Tekstur sampling
+ Tilsidesætter det samplingsfilter, der bruges af spillene. Dette kan i nogle tilfælde være nyttigt for spil, der ikke håndterer opskalering godt. Hvis du er usikker, skal du indstille dette til Styret af spillene.
+ Nøjagtig multiplikation
+ Bruger mere nøjagtig multiplikation i hardware shaders, som kan rette nogle grafiske fejl. Når den er aktiveret, reduceres ydeevnen.
+ Aktiver asynkron GPU-emulering
+ Bruger en separat tråd til at emulere GPU\'en asynkront. Når den er aktiveret, vil ydeevnen blive forbedret.
+ Begræns hastighed
+ Når aktiveret, vil emuleringshastigheden være begrænset til en specificeret procentdel af normal hastighed. Hvis deaktiveret, vil emuleringshastigheden være ubegrænset, og genvejstasten for turbohastighed vil ikke fungere.
+ Begræns hastighedsprocent
+ Angiver procentdelen emuleringshastigheden skal begrænses til. Med standardværdien på 100% vil emulering være begrænset til normal hastighed. Værdier højere eller lavere vil øge eller mindske hastighedsgrænsen.
+ Anvend området ved frontkamera
+ Udvider visningsområdet til at omfatte området ved frontkameraet (eller indhakket).
+ Intern opløsning
+ Angiver den opløsning, der bruges til renderingen. En høj opløsning vil forbedre den visuelle kvalitet meget, men kræver også stor ydelse og kan forårsage fejl i visse applikationer.
+ Auto (skærmstørrelse)
+ Indbygget (400x240)
+ 2x indbygget (800 x 480)
+ 3x indbygget (1200 x 720)
+ 4x indbygget (1600 x 960)
+ 5x indbygget (2000x1200)
+ 6x indbygget (2400x1440)
+ 7x indbygget (2800x1680)
+ 8x indbygget (3200 x 1920)
+ 9x indbygget (3600x2160)
+ 10x indbygget (4000x2400)
+ Hvis du slår denne indstilling fra vil emuleringsydelsen reduceres betydeligt! For den bedste oplevelse anbefales det, at du lader denne indstilling være aktiveret.
+ Advarsel: Ændringer i disse indstillinger vil gøre emuleringen langsommere
+ Stereoskopi
+ Stereoskopisk 3D-tilstand
+ Dybde
+ Angiver værdien af 3D-skyderen. Denne bør sættes højere end 0 %, når stereoskopisk 3D-tilstand er aktiveret.\nBemærk: Dybdeværdier over 100 % er ikke muligt på rigtig hardware og kan forårsage grafiske problemer
+ Deaktiver rendering af højre øje
+ Forbedrer ydeevnen betydeligt i nogle applikationer, men kan forårsage flimren i andre.
+ Cardboard VR
+ Cardboard skærmstørrelse
+ Skalerer skærmen til en procentdel af dens oprindelige størrelse.
+ Horisontal forskydning
+ Angiver procentdelen af tom plads for at flytte skærmbillederne vandret. Positive værdier flytter de to øjne tættere på midten, mens negative værdier flytter dem væk.
+ Lodret forskydning
+ Angiver procentdelen af tom plads for at flytte skærmbillederne lodret. Positive værdier flytter de to øjne mod bunden, mens negative værdier flytter dem mod toppen.
+ Shader JIT
+ Disk shader cache
+ Reducer hakken ved at gemme og indlæse genererede shaders til disken. Det kan ikke bruges uden at aktivere hardware shader.
+ Værktøj
+ Dump teksturer
+ Teksturer dumpes til dump/textures/[Titel ID]/.
+ Brugerdefinerede teksturer
+ Teksturer indlæses fra load/textures/[Titel ID]/.
+ Indlæs brugerdefinerede teksturer på forhånd
+ Indlæser alle brugerdefinerede teksturer i hukommelsen. Denne funktion kan bruge meget hukommelse.
+ Brugerdefinerede teksturer indlæses asynkront
+ Indlæs brugerdefinerede teksturer asynkront med baggrundstråde for at reducere hakken under indlæsning.
+
+
+ Lydstyrke
+ Stræk lyden ud
+ Strækker lyden for at reducere hakken. Når det er aktiveret, øges lydforsinkelsen og ydeevnen reduceres lidt.
+ Aktiver lyd i realtid
+ Skalerer lydafspilningshastigheden for at tage højde for fald i emuleringens billedhastighed. Dette betyder, at lyden afspilles med fuld hastighed, selvom spillets billedhastighed er lav. Kan give problemer med synkroniseringen af lyd.
+ Lydindgangsenhed
+ Lydudgangstilstand
+
+
+ CPU JIT
+ Bruger JIT-kompileren (Just-in-Time) til CPU-emulering. Når den er aktiveret, vil spillets ydeevne blive væsentligt forbedret.
+ Aktiver hardware shader
+ Bruger hardware til at efterligne 3DS shaders. Når det er aktiveret, vil spillets ydeevne blive væsentligt forbedret.
+ CPU Clock hastighed
+ Aktiver V-Sync
+ Synkroniserer spillets frame rate med opdateringshastigheden på din enhed.
+ Fejlsøg renderingen
+ Log yderligere grafikrelaterede fejlfindingsoplysninger. Når det er aktiveret, vil spillets ydeevne blive væsentligt reduceret.
+ Tøm loggen for alle beskeder
+ Overfør øjeblikkeligt fejlretningsloggen til fil. Brug dette, hvis Azahar går ned, og logoutputtet afbrydes.
+ Forsinket start med LLE moduler
+ Forsinker starten af appen, når LLE moduler er aktiveret.
+ Deterministiske asynkrone operationer
+ Gør asynkrone operationer deterministiske for fejlretning. Aktivering af dette kan forårsage at programmet fryser fast.
+
+
+ Skærmorientering
+ Automatisk
+ Landskab
+ Omvendt landskab
+ Portræt
+ Omvendt portræt
+
+
+ Ryd
+ Standard
+ Gemte indstillinger
+ Gemte indstillinger for %1$s
+ Fejl ved lagring af %1$s.ini: %2$s
+ Gemmer...
+ Indlæser...
+ Næste
+ Tilbage
+ Lær mere
+ Luk
+ Nulstil til standard
+ spilkassetter eller installerede titler.]]>
+ Standard
+ Ingen
+ Auto
+ Slukket
+ Installere
+ Slet
+ Nulstil alle indstillinger?
+ Alle avancerede indstillinger vil blive nulstillet til deres standardkonfiguration. Dette kan ikke fortrydes.
+ Indstillinger nulstillet
+ Vælg RTC dato
+ Vælg RTC tid
+ Vil du nulstille denne indstilling til standardværdien?
+ Du kan ikke redigere dette nu
+ Indstillinger deaktiveret
+ Indstillingen er i øjeblikket deaktiveret, fordi en anden indstilling ikke har en passende værdi.
+ Denne indstilling kan ikke ændres, mens et spil kører.
+ Automatisk valg
+ Start
+ Annullerer...
+ Vigtig
+ Vis ikke igen
+
+
+ Vælg spilmappe
+
+
+ Egenskaber
+ Spilegenskaberne kunne ikke indlæses.
+
+
+ Indstillinger
+ Generelt
+ System
+ Kamera
+ Gamepad
+ Grafik
+ Lyd
+ Fejlfinding
+ Tema og farve
+ Layout
+
+
+ Din ROM er krypteret
+ Ugyldigt ROM-format
+ ROM-fil eksisterer ikke
+ Intet startbart spil til stede!
+
+
+ Tryk på Tilbage for at få adgang til menuen.
+ Gem tilstand
+ Hent tilstand
+ Slot %1$d
+ Slot %1$d - %2$tF %2$tR
+ Vis FPS
+ Haptisk feedback
+ Overlejringsindstillinger
+ Konfigurer kontroller
+ Rediger layout
+ Færdig
+ Skift kontrol
+ Juster skala
+ Global skala
+ Nulstil alle
+ Juster opacitet
+ Relativt stick centrum
+ D-Pad glidning
+ Åbn Indstillinger
+ Åbn snydekoder
+ Landskab skærmlayout
+ Portræt skærmlayout
+ Stor skærm
+ Portræt
+ Enkelt skærm
+ Side om side skærme
+ Hybrid skærme
+ Original
+ Standard
+ Brugerdefineret layout
+ Position for lille skærm
+ Hvor skal den lille skærm vises i forhold til den store i storskærmslayout?
+ Øverst til højre
+ Midt til højre
+ Nederst til højre (standard)
+ Øverst til venstre
+ Midt til venstre
+ Nederst til venstre
+ Over
+ Under
+ Mellemrum imellem skærme
+ Mellemrum imellem skærme i alle to-skærmstilstande. Målt i px i forhold til 240 px højden på den større skærm.
+ Forhold for stor skærm
+ Hvor mange gange større er den store skærm end den lille skærm i storskærmslayout?
+ Juster brugerdefineret layout i indstillinger
+ Landskab brugerdefineret layout
+ Portræt brugerdefineret layout
+ Øverste skærm
+ Nederste skærm
+ X-position
+ Y-position
+ Bredde
+ Højde
+ Skift layout
+ Byt skærme
+ Nulstil overlejring
+ Vis overlejring
+ Luk spil
+ Slå Pause til/fra
+ Diverse
+ Brug Artic kontroller, når du er tilsluttet Artic base server
+ Brug kontrollerne fra Artic base server, når forbundet til den i stedet for den konfigurerede inputenhed.
+ Er du sikker på, at du vil lukke det aktuelle spil?
+ Amiibo
+ Indlæs
+ Fjern
+ Vælg Amiibo fil
+ Fejl under indlæsning af Amiibo
+ Der opstod en fejl under indlæsning af den angivne Amiibo fil. Kontroller venligst, at filen er korrekt.
+ Sæt emulering på pause
+ Genoptag emulering
+ Lås skuffe
+ Lås skuffe op
+
+ Du skal tillade skriveadgang til eksternt lager, for at emulatoren kan fungere
+ Indlæser indstillinger...
+
+ Det eksterne lager skal være tilgængeligt for at Azahar kan anvendes
+
+ Vælg denne mappe
+ Ingen filer blev fundet, eller der er ikke valgt nogen spilmappe endnu.
+
+ Vis ikke dette igen
+ Søger mappe: %s
+ Flyt data
+ Flytter data...
+ Kopiér fil: %s
+ Kopi fuldført
+ Gem tilstande
+ Advarsel: Gemte tilstande er IKKE en erstatning for tilstande gemt i spillet og er ikke tilsigtet at være pålidelige.\n\nBruges på egen risiko!
+
+
+ Software tastatur
+ Jeg glemte
+ Tekstlængden er ikke korrekt (skal være %d tegn)
+ Teksten er for lang (må ikke være mere end %d tegn)
+ Blank indtastning er ikke tilladt
+ Tom indtastning er ikke tilladt
+ Ugyldig indtastning
+
+
+ Mii vælger
+ Standard Mii
+
+
+ Vælg billede
+ Kamera
+ Azahar skal have adgang til dit kamera for at efterligne 3DS\'ens kameraer.\n\nAlternativt kan du også indstille \"Billedkilde\" til \"Stillbillede\" i kameraindstillinger.
+
+
+ Mikrofon
+ Azahar skal have adgang til din mikrofon for at efterligne 3DS\'ens mikrofon.\n\nAlternativt kan du også ændre \"Lydindgangsenhed\" i lydindstillinger.
+
+
+ Afbryd
+ Fortsæt
+ Systemarkiv blev ikke fundet
+ %s mangler. Du skal dumpe dine systemarkiver.\nFortsat emulering kan resultere i nedbrud og fejl.
+ Installation mislykkedes. CIA-fil blev ikke fundet.
+ Et systemarkiv
+ Gem/indlæs fejl
+ Fatal fejl
+ Der opstod en fatal fejl. Kontroller loggen for detaljer.\nFortsat emulering kan resultere i nedbrud og fejl.
+ Ugyldig region
+ Ikke understøttet krypteret applikation
+
+
+ Forberedelse af shaders
+ Bygning af shaders
+
+
+ Spil
+ Genvej
+ Afinstaller applikation
+ Afinstallerer...
+ Åbn mappen med gemt data
+ Åbn applikationsmappe
+ Åbn mappen med Mods
+ Åbn mappen med teksturer
+ Åbn mappen med DLC
+ Åbn mappen med opdateringer
+ Åbn mappen med ekstra
+ Afinstaller DLC
+ Afinstaller opdateringer
+
+
+ Snyd
+ Tilføj snyd
+ Navn
+ Noter
+ Kode
+ Redigere
+ Slet
+ Er du sikker på, at du vil slette \"%1$s\"?
+ Navnet må ikke være tomt
+ Koden må ikke være tom
+ Fejl i linje %1$d
+
+
+
+ - Installerer %d filer. Se underretning for flere detaljer.
+ - Installerer %d filer. Se meddelelser for flere detaljer.
+
+ Azahar meddelelser under CIA installation
+ Installerer CIA
+ Installerer %1$s (%2$d/%3$d)
+ CIA er installeret med succes
+ Kunne ikke installere CIA
+ \"%s\" er blevet installeret korrekt
+ Installationen af \"%s\" blev afbrudt.\n Se venligst loggen for flere detaljer
+ \"%s\" er ikke en gyldig CIA
+ \"%s\" skal dekrypteres inden det kan anvendes med Azahar.\n En rigtig 3DS er påkrævet
+ Der opstod en ukendt fejl under installationen af \"%s\".\n Se venligst loggen for flere detaljer
+
+
+ %1$s %2$s
+ Byte
+ B
+ KB
+ MB
+ GB
+ TB
+ PB
+ EB
+
+
+ Tematilstand
+ Følg system
+ Lyst
+ Mørkt
+
+
+ Systemfarve
+ Brug operativsystemets farvetema i hele appen (tilsidesætter indstillingen \"Temafarve\")
+
+
+ Tema farve
+ Skift farvetemaet for appens menuer
+
+
+ Sorte baggrunde
+ Når du bruger det mørke tema, skal du anvende sorte baggrunde.
+
+
+ JPN
+ USA
+ EUR
+ AUS
+ CHN
+ KOR
+ TWN
+
+
+ Japansk (日本語)
+ Engelsk
+ Fransk (Français)
+ Tysk (Deutsch)
+ Italiensk (Italiano)
+ Spansk (Español)
+ Forenklet kinesisk (简体中文)
+ Koreansk (한국어)
+ Hollandsk (Nederlands)
+ Portugisisk (Português)
+ Russisk (Русский)
+ Traditionel kinesisk (正體中文)
+
+
+ Blank
+ Stillbillede
+ Enhedens kamera
+
+
+ Vilkårligt frontkamera
+ Vilkårligt bagkamera
+
+
+ Horisontal
+ Lodret
+ Omvendt
+
+
+ Statisk støj
+ Rigtig enhed (cubeb)
+ Rigtig enhed (OpenAL)
+
+
+ Side om Side
+ Omvendt side om side
+ Anaglyph
+ Interlaced
+ Omvendt interlaced
+
+
+ OpenGLES
+ Vulkan
+
+
+ Anime4K
+ Bikubisk
+ ScaleForce
+ xBRZ
+ MMPX
+
+
+ Styret af spillene
+ Nærmeste nabo
+ Lineær
+
+
+ Mono
+ Stereo
+ Surround
+
+
+ Japan
+ Anguilla
+ Antigua og Barbuda
+ Argentina
+ Aruba
+ Bahamas
+ Barbados
+ Belize
+ Bolivia
+ Brasilien
+ Britiske Jomfruøer
+ Canada
+ Caymanøerne
+ Chile
+ Colombia
+ Costa Rica
+ Dominica
+ Dominikanske Republik
+ Ecuador
+ El Salvador
+ Fransk Guyana
+ Grenada
+ Guadeloupe
+ Guatemala
+ Guyana
+ Haiti
+ Honduras
+ Jamaica
+ Martinique
+ Mexico
+ Montserrat
+ Hollandske Antiller
+ Nicaragua
+ Panama
+ Paraguay
+ Peru
+ Saint Kitts og Nevis
+ Sankt Lucia
+ Saint Vincent og Grenadinerne
+ Surinam
+ Trinidad og Tobago
+ Turks- og Caicosøerne
+ USA
+ Uruguay
+ Amerikanske Jomfruøer
+ Venezuela
+ Albanien
+ Australien
+ Østrig
+ Belgien
+ Bosnien-Hercegovina
+ Botswana
+ Bulgarien
+ Kroatien
+ Cypern
+ Tjekkiet
+ Danmark
+ Estland
+ Finland
+ Frankrig
+ Tyskland
+ Grækenland
+ Ungarn
+ Island
+ Irland
+ Italien
+ Letland
+ Lesotho
+ Liechtenstein
+ Litauen
+ Luxembourg
+ Makedonien
+ Malta
+ Montenegro
+ Mozambique
+ Namibia
+ Holland
+ New Zealand
+ Norge
+ Polen
+ Portugal
+ Rumænien
+ Rusland
+ Serbien
+ Slovakiet
+ Slovenien
+ Sydafrika
+ Spanien
+ Swaziland
+ Sverige
+ Schweiz
+ Tyrkiet
+ Storbritannien
+ Zambia
+ Zimbabwe
+ Aserbajdsjan
+ Mauretanien
+ Mali
+ Niger
+ Tchad
+ Sudan
+ Eritrea
+ Djibouti
+ Somalia
+ Andorra
+ Gibraltar
+ Guernsey
+ Isle of Man
+ Jersey
+ Monaco
+ Taiwan
+ Sydkorea
+ Hong Kong
+ Macau
+ Indonesien
+ Singapore
+ Thailand
+ Filippinerne
+ Malaysia
+ Kina
+ Forenede Arabiske Emirater
+ Indien
+ Egypten
+ Oman
+ Qatar
+ Kuwait
+ Saudi-Arabien
+ Syrien
+ Bahrain
+ Jordan
+ San Marino
+ Vatikanstaten
+ Bermuda
+
+
+ Januar
+ Februar
+ Marts
+ April
+ Maj
+ Juni
+ Juli
+ August
+ September
+ Oktober
+ November
+ December
+
+
+ Kunne ikke kommunikere med Artic base serveren. Emulering stopper.
+ Artic base
+ Opret forbindelse til en rigtig konsol, der kører en Artic base server
+ Opret forbindelse til Artic base
+ Indtast Artic base serveradressen
+
+
+ Hurtig lagring
+ Hurtig lagring
+ Hurtig indlæsning
+ Hurtig lagring - %1$tF %1$tR
+ Ingen hurtig lagring tilgængelig.
+
+
diff --git a/src/android/app/src/main/res/values-b+es+ES/strings.xml b/src/android/app/src/main/res/values-b+es+ES/strings.xml
index ca3e838c7..7abbbab3c 100644
--- a/src/android/app/src/main/res/values-b+es+ES/strings.xml
+++ b/src/android/app/src/main/res/values-b+es+ES/strings.xml
@@ -5,10 +5,6 @@
Notificaciones del emulador 3DS Azahar
Azahar está ejecutándose
A continuación, deberá seleccionar una Carpeta de Aplicaciones. Azahar mostrará todas las ROM de 3DS de la carpeta seleccionada en la aplicación.\n\nLas ROM CIA, actualizaciones y los DLC deberán instalarse por separado haciendo clic en el icono de la carpeta y seleccionando Instalar CIA.
- Iniciar
- Cancelando...
- Importante
- No volver a mostrar
Configuración
@@ -83,9 +79,13 @@
Cancelar
Seleccionar Carpeta de Usuario
datos de usuario con el botón de abajo.]]>
+ Parece que tienes directorios de usuario configurados tanto para Lime3DS como para Azahar. Probablemente se deba a que actualizaste a Azahar y, cuando se te pidió, elegiste un directorio de usuario diferente al que usabas para Lime3DS.\n\nEsto puede haberte hecho pensar que perdiste partidas guardadas u otras configuraciones; te pedimos disculpas si eso ocurrió.\n\n¿Prefieres volver a usar tu directorio de usuario original de Lime3DS, restaurando la configuración y las partidas guardadas de Lime3DS, o conservar tu directorio de usuario actual de Azahar?\n\nNinguno de los directorios se eliminará, independientemente de tu elección, y puedes cambiar libremente entre ellos usando la opción \"Seleccionar carpeta de usuario\".
+ Mantener el directorio Azahar actual
+ Usar el directorio de Lime3DS anterior
Seleccionar
No puedes saltarte este paso
Este paso es necesario para permitir que Azahar funcione. Por favor, seleccione un directorio y luego puede continuar.
+ Has perdido los permisos de escritura en tu directorio de datos de usuario, donde se guardan las partidas guardadas y otra información. Esto puede ocurrir después de algunas actualizaciones de aplicaciones o de Android. Vuelve a seleccionar el directorio para recuperar los permisos y poder continuar.
Configuración de tema
Configura tus preferencias de tema de Azahar.
Establecer tema
@@ -122,15 +122,21 @@
Mueve el joystick a izquierda o derecha.
HOME
Intercambiar Pantallas
+ Turbo
¡Este control debe asignarse a un stick analógico del mando o a un eje del Pad de Control!
¡Este control debe asignarse a un botón del mando!
+ Velocidad Turbo
+ Velocidad Turbo Activada
+ Velocidad Turbo Desactivada
Archivos de Sistema
Realizar operaciones de archivos del sistema, como instalar archivos del sistema o iniciar el Menú Home
Conectar con la herramienta de configuración Artic
- herramienta de configuración Artic.
Notas:- Esta operación instalará archivos únicos de la consola en Azahar, ¡no compartas las carpetas de usuario ni nand
después de realizar el proceso de configuración! - Se necesita la configuración de Old 3DS para que funcione la configuración de New 3DS.
- Ambos modos de configuración funcionarán independientemente del modelo de la consola que ejecute la herramienta de configuración.
]]>
+ herramienta de configuración Artic.
Notas:- Esta operación instalará archivos únicos de la consola en Azahar, ¡no compartas las carpetas de usuario ni nand después de realizar el proceso de configuración!
- Tras la configuración, Azahar se enlazará a la consola que ha ejecutado la herramienta de configuración. Puedes desvincular la consola más tarde desde la pestaña \"Archivos de sistema\" del menú de opciones del emulador.
- No te conectes en línea con Azahar y la consola 3DS al mismo tiempo después de configurar los archivos del sistema, ya que esto podría causar problemas.
- Se necesita la configuración de Old 3DS para que funcione la configuración de New 3DS (configurar ambos modos es recomendado).
- Ambos modos de configuración funcionarán independientemente del modelo de la consola que ejecute la herramienta de configuración.
]]>
Obteniendo el estado actual de los archivos del sistema, por favor espere...
+ Desvincular Datos Únicos de Consola
+ - OTP, SecureInfo y LocalFriendCodeSeed serán eliminados de Azahar.
- Tu lista de amigos se restablecerá y se cerrará la sesión de tu cuenta NNID/PNID.
- Los archivos del sistema y los títulos de la eshop obtenidos a través de Azahar se volverán inaccesibles hasta que la misma consola se vincule nuevamente mediante la herramienta de configuración (los datos guardados no se perderán).
¿Continuar?]]>
Configuración Old 3DS
Configuración New 3DS
La configuración es posible.
@@ -147,20 +153,20 @@
Botones
Botón
-
- CPU JIT
- Usa el compilador Just-In-Time (JIT) para la emulación de la CPU. Cuando se active, el rendimiento mejorará notablemente.
- Reloj
- Configura el reloj emulado de la 3DS para que tenga la misma fecha y hora de tu dispositivo o para configurar una fecha y hora distinta en éste.
- Velocidad de reloj de la CPU
-
+ Opciones de Emulación
Nombre de usuario/a
Modo New 3DS
Usar Applets LLE (si están instaladas)
+ Habilitar los módulos LLE necesarios para las funciones en línea (si están instalados)
+ Habilita los módulos LLE necesarios para el modo multijugador en línea, acceso a la eShop, etc.
Reloj
- Tiempo de compensación
- Si el reloj está en \"Reloj emulado\", ésto cambia la fecha y hora de inicio.
+ Reloj
+ Configura el reloj emulado de la 3DS para que tenga la misma fecha y hora de tu dispositivo o para configurar una fecha y hora distinta en éste.
+ Reloj del Sistema
+ Reloj Simulado
+ Si el reloj está en \"Reloj emulado\", ésto cambia la fecha y hora de inicio.
+ Opciones de Perfil
Región
Idioma
Cumpleaños
@@ -173,10 +179,16 @@
ID de Consola
Regenerar ID de Consola
Esto reemplazará tu ID de consola de 3DS virtual por una nueva. Tu ID actual será irrecuperable. Esto puede tener efectos inesperados en determinadas aplicaciones. Si usas un archivo de configuración obsoleto, esto podría fallar. ¿Desea continuar?
+ Dirección MAC
+ Regenerar Dirección MAC
+ Esto reemplazará tu dirección MAC actual por una nueva. No se recomienda hacerlo si obtuviste la dirección MAC de tu consola real con la herramienta de configuración. ¿Continuar?
Cargador de complementos 3GX
Carga los plugins 3GX de la SD emulada si están disponibles.
Permitir que las aplicaciones cambien el estado del cargador de plugins.
Permite que las apps de homebrew activen el cargador de complementos incluso cuando está desactivado.
+ Advertencia Región No Válida
+ La configuración del país no es válida para la región emulada seleccionada.
+ La configuración del país no es válida para la consola vinculada actual.
Cámara interior
@@ -199,26 +211,30 @@
Activar compilación de sombreados asíncrona
Compila los sombreados en el fondo para reducir los parones durante la partida.
Se esperan fallos gráficos temporales cuando ésta esté activado.
- Renderizador de depuración
- Archiva información adicional gráfica relacionada con la depuración. Cuando está activada, el rendimiento de los juegos será reducido considerablemente
- Activar Sincronización Vertical
- Sincroniza los cuadros por segundo del juego con la tasa de refresco de tu dispositivo.
Filtro Linear
Activa el filtro linear, que hace que los gráficos del juego se vean más suaves.
Filtro de Texturas
Mejora los gráficos visuales de las aplicaciones aplicando un filtro a las texturas. Los filtros soportados son Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale, y MMPX.
- Activar Sombreador de Hardware
- Usa el hardware para emular los sombreadores de 3DS. Cuando se active, el rendimiento mejorará notablemente.
+ Atrasar hilo de renderizado del juego
+ Retrasa el hilo de renderización del juego cuando envía datos a la GPU. Ayuda con los problemas de rendimiento en las (muy pocas) aplicaciones de fps dinámicos.
+ Avanzado
+ Muestreo de Texturas
+ Sobreescribe el filtro de muestreo usado en juegos. Puede ser útil en ciertos casos con juegos con bajo rendimiento al subir la resolución. Si no estás seguro, pónlo en Controlado por Juego
Multiplicación Precisa
Usa multiplicaciones más precisas en los sombreados de hardware, que podrían arreglar ciertos bugs gráficos. Cuando se active, el rendimiento se reducirá.
Activar Emulación Asíncrona de la GPU
Usa un hilo separado para emular la GPU de manera asíncrona. Cuando se active, el rendimiento mejorará.
Límite de velocidad
- Cuando se active, la velocidad de emulación estará limitada a un porcentaje determinado de la velocidad normal.
+ Cuando se active, la velocidad de emulación estará limitada a un porcentaje determinado de la velocidad normal. Cuando se desactive, la velocidad de emulación no tendrá límite y la tecla de acceso rápido de velocidad turbo no funcionará.
Limitar porcentaje de velocidad
Especifica el valor al que se limita la velocidad de emulación. Con el valor por defecto del 100%, la emulación se limitará a la velocidad normal. Los valores altos o altos incrementarán o reducirán el límite de velocidad.
+ Límite de Velocidad Turbo
+ Límite de velocidad de emulación utilizado mientras la tecla de acceso rápido turbo está activa.
+ Expandir al área de recorte
+ Amplía el área de visualización para incluir el área de recorte (o muesca).
Resolución interna
Especifica la resolución a la que se quiera renderizar. Una alta resolución mejorará la calidad visual un montón, pero también causará un gran impacto en el rendimiento y puede causar fallos en ciertas aplicaciones.
+ Auto (Tamaño Pantalla)
Nativa (400x240)
2x Nativa (800x480)
3x Nativa (1200x720)
@@ -234,7 +250,9 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.
Estereoscopía
Modo 3D Estereoscópico
Profundidad
- Especifica el valor del regulador 3D. Debería estar puesto a más allá del 0% cuando el Modo 3D Estereoscópico está activado.
+ Especifica el valor del regulador 3D. Debería estar puesto a más allá del 0% cuando el Modo 3D Estereoscópico está activado.\nNota: Los valores de profundidad superiores al 100 % no son posibles en hardware real y pueden causar problemas gráficos.
+ Desactivar Renderizado de Ojo Derecho
+ Mejora significativamente el rendimiento en algunas aplicaciones, pero puede causar parpadeo en otros.
Cardboard VR
Tamaño de la pantalla Cardboard
Escala la pantalla a un porcentaje de su tamaño original.
@@ -264,6 +282,23 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.
Dispositivo de entrada de audio
Modo de salida del audio
+
+ CPU JIT
+ Usa el compilador Just-In-Time (JIT) para la emulación de la CPU. Cuando se active, el rendimiento mejorará notablemente.
+ Activar Sombreador de Hardware
+ Usa el hardware para emular los sombreadores de 3DS. Cuando se active, el rendimiento mejorará notablemente.
+ Velocidad de reloj de la CPU
+ Activar Sincronización Vertical
+ Sincroniza los cuadros por segundo del juego con la tasa de refresco de tu dispositivo.
+ Renderizador de depuración
+ Archiva información adicional gráfica relacionada con la depuración. Cuando está activada, el rendimiento de los juegos será reducido considerablemente
+ Limpiar la salida del registro en cada mensaje
+ Inmediatamente guarda el registro de depuración en el archivo. Utilice ésto si Azahar se bloquea y la salida del registro se está cortando.
+ Retrasar el comienzo con módulos LLE
+ Retrasa el inicio de la aplicación cuando los módulos LLE están habilitados.
+ Operaciones asíncronas deterministas
+ Hace que las operaciones asíncronas sean deterministas para la depuración. Habilitar esta opción puede causar bloqueos.
+
Orientación de pantalla
Automática
@@ -278,6 +313,7 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.
Configuración guardada
Configuración guardada para %1$s
Error guardando %1$s.ini: %2$s
+ Guardando...
Cargando...
Siguiente
Atrás
@@ -298,8 +334,14 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.
Seleccionar hora RTC
¿Quiere reiniciar esta configuración a su valor por defecto?
No puedes editarlo ahora
+ Configuración deshabilitada
+ Esta configuración está actualmente deshabilitada debido a que otra configuración no tiene el valor apropiado.
Esta opción no puede cambiarse mientras se está ejecutando un juego.
Auto-elegir
+ Iniciar
+ Cancelando...
+ Importante
+ No volver a mostrar
Seleccionar Directorio de Juego
@@ -367,6 +409,8 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.
Abajo a la Izquierda
Encima
Debajo
+ Separación de Pantalla
+ Espacio entre pantallas en todos los modos de dos pantallas. Medido en píxeles con respecto a la altura de 240 píxeles de la pantalla más grande.
Proporción de Pantalla Grande
¿Cuántas veces más grande es la pantalla grande que la pantalla pequeña en Disposicion de Pantalla Grande?
Ajusta el estilo personalizado en Configuración
@@ -384,6 +428,9 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.
Mostrar Estilo
Cerrar Juego
Activar pausa
+ Misceláneos
+ Usar Artic Controller al estar conectado al servidor de Artic Base
+ Usa los controles dados por el Servidor de Artic Base al estar conectado a éste en vez de los controles del dispositivo configurado.
¿Estás seguro de querer cerrar el juego?
Amiibo
Cargar
@@ -455,6 +502,17 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.
Jugar
Atajo
+ Desinstalar Aplicación
+ Desinstalando...
+ Abrir Carpeta de Guardado
+ Abrir Carpeta de Aplicación
+ Abrir Carpeta de Mods
+ Abrir Carpeta de Texturas
+ Abrir Carpeta de DLC
+ Abrir Carpeta de Actualizaciones
+ Abrir Carpeta Extra
+ Desinstalar DLC
+ Desinstalar Actualizaciones
Trucos
@@ -515,10 +573,6 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.
Fondos Oscuros
Cuando uses el tema oscuro, se aplicarán fondos oscuros.
-
- Reloj del Sistema
- Reloj Simulado
-
JPN
USA
@@ -575,11 +629,15 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.
Anime4K
Bicubic
- Nearest Neighbor
ScaleForce
xBRZ
MMPX
+
+ Controlado por Juego
+ Nearest Neighbor
+ Linear
+
Mono
Estéreo
@@ -740,33 +798,12 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.
Conectar con una consola real que esté ejecutando un servidor Artic Base
Conectar con Artic Base
Introduce la dirección del servidor Artic Base
- Atrasar hilo de renderizado del juego
- Retrasa el hilo de renderización del juego cuando envía datos a la GPU. Ayuda con los problemas de rendimiento en las (muy pocas) aplicaciones de fps dinámicos.
Guardado rápido
Guardado rápido
Carga rápida
Guardado rápido - %1$tF %1$tR
- Guardando...
- Cargando...
Guardado rápido no disponible.
- Misceláneos
- Usar Artic Controller al estar conectado al servidor de Artic Base
- Usa los controles dados por el Servidor de Artic Base al estar conectado a éste en vez de los controles del dispositivo configurado.
- Limpiar la salida del registro en cada mensaje
- Inmediatamente guarda el registro de depuración en el archivo. Utilice ésto si Azahar se bloquea y la salida del registro se está cortando.
- Desactivar Renderizado de Ojo Derecho
- Mejora significativamente el rendimiento en algunas aplicaciones, pero puede causar parpadeo en otros.
- Retrasar el comienzo con módulos LLE
- Retrasa el inicio de la aplicación cuando los módulos LLE están habilitados.
- Operaciones asíncronas deterministas
- Hace que las operaciones asíncronas sean deterministas para la depuración. Habilitar esta opción puede causar bloqueos.
- Habilitar los módulos LLE necesarios para las funciones en línea (si están instalados)
- Habilita los módulos LLE necesarios para el modo multijugador en línea, acceso a la eShop, etc.
- Opciones de Emulación
- Opciones de Perfil
- Dirección MAC
- Regenerar Dirección MAC
- Esto reemplazará tu dirección MAC actual por una nueva. No se recomienda hacerlo si obtuviste la dirección MAC de tu consola real con la herramienta de configuración. ¿Continuar?
+
diff --git a/src/android/app/src/main/res/values-b+ja+JP/strings.xml b/src/android/app/src/main/res/values-b+ja+JP/strings.xml
index 4dedbd9ee..879f96568 100644
--- a/src/android/app/src/main/res/values-b+ja+JP/strings.xml
+++ b/src/android/app/src/main/res/values-b+ja+JP/strings.xml
@@ -1,4 +1,150 @@
+
+ エミュレーション設定
+ オンラインに必要なLLEモジュールを有効にする(インストール済みの場合)
+ eShopやオンラインマルチプレイヤーなどに必要なLLEモジュールを有効にします。
+ プロファイル設定
+ MACアドレス
+ MACアドレスを再生成
+ これを行うと、今のMACアドレスを新しいもので置き換えます。セットアップツールで実機からMACアドレスを吸い出した場合、これをするのは推奨しません。続行しますか?
+ 描写スレッドを遅延する
+ GPUにデータを送信する間、ゲームの描写スレッドを遅延します。動的フレームレートである(ほんの一部の)アプリケーションでのパフォーマンスが向上します。
+ デバッグログを即座にファイルに書き込みます。Azaharがクラッシュしてログが途切れるときに有効にしてください。
+ その他
+
+ 日本
+ アンゴラ
+ アンティグア・バーブーダ
+ アルゼンチン
+ アルバ
+ バハマ
+ バルバドス
+ ベリーズ
+ ボリビア
+ ブラジル
+ 英領ヴァージン諸島
+ カナダ
+ ケイマン諸島
+ チリ
+ コロンビア
+ コスタリカ
+ ドミニカ国
+ ドミニカ共和国
+ エクアドル
+ エルサルバドル
+ 仏領ギアナ
+ グレナダ
+ グアドループ
+ グアテマラ
+ ガイアナ
+ ハイチ
+ ホンジュラス
+ ジャマイカ
+ マルティニーク
+ メキシコ
+ モントセラト
+ オランダ領アンティル
+ ニカラグア
+ パナマ
+ パラグアイ
+ ペルー
+ セントクリストファー・ネーヴィス
+ セントルシア
+ セントビンセント及びグレナディーン諸島
+ スリナム
+ トリニダード・トバゴ
+ タークス・カイコス諸島
+ アメリカ合衆国
+ ウルグアイ
+ 米領ヴァージン諸島
+ ベネズエラ
+ アルバニア
+ Australia
+ オーストリア
+ ベルギー
+ ボスニア・ヘルツェゴビナ
+ ボツワナ
+ ブルガリア
+ クロアチア
+ キプロス
+ チェコ共和国
+ デンマーク
+ エストニア
+ フィンランド
+ フランス
+ ドイツ
+ ギリシャ
+ ハンガリー
+ アイスランド
+ アイルランド
+ イタリア
+ ラトビア
+ レソト
+ リヒテンシュタイン
+ リトアニア
+ ルクセンブルク
+ マケドニア
+ マルタ
+ モンテネグロ
+ モザンビーク
+ ナミビア
+ オランダ
+ ニュージーランド
+ ノルウェー
+ ポーランド
+ ポルトガル
+ ルーマニア
+ ロシア
+ セルビア
+ スロバキア
+ スロベニア
+ 南アフリカ
+ スペイン
+ スワジランド
+ スウェーデン
+ スイス
+ トルコ
+ イギリス
+ ザンビア
+ ジンバブエ
+ アゼルバイジャン
+ モーリタニア
+ マリ
+ ニジェール
+ チャド
+ スーダン
+ エリトリア
+ ジブチ
+ ソマリア
+ アンドラ
+ ジブラルタル
+ ガーンジー
+ マン島
+ ジャージー
+
+ 1月
+ 2月
+ 3月
+ 4月
+ 5月
+ 6月
+ 7月
+ 8月
+ 9月
+ 10月
+ 11月
+ 12月
+
+ Artic Base
+ Artic Baseのサーバーを実行している実機に接続
+ Artic Baseに接続
+ Artic Baseのサーバーアドレスを入力してください
+
+
+ クイックセーブ
+ クイックセーブ
+ クイックロード
+ クイックセーブ-%1$tF%1$tR
diff --git a/src/android/app/src/main/res/values-b+lt+LT/strings.xml b/src/android/app/src/main/res/values-b+lt+LT/strings.xml
index 4dedbd9ee..d9484cbb3 100644
--- a/src/android/app/src/main/res/values-b+lt+LT/strings.xml
+++ b/src/android/app/src/main/res/values-b+lt+LT/strings.xml
@@ -1,4 +1,219 @@
+ Azahar 3DS emulatorius
+ Azahar veikia
+
+ Nustatymai
+ Pasirinkimai
+ Paieška
+ Aplikacijos
+ Dalintis žurnalu
+ Žurnalas nerastas
+ Apie
+ Atviro kodo 3DS emulatorius
+ Instaliuoti
+ Licencijos
+
+ Sveiki!
+ Pradėti
+ Baigta!
+ Baigta
+ Tęsti
+ Pranešimai
+ Priimti leidimą
+ Kamera
+ Mikrofonas
+ Leidimas atmestas
+ Pagalba
+ Praleisti
+ Atšaukti
+ Pasirinkti vartotojo aplanką
+ Pasirinkti
+ Tu negali praleisti šio žingsnio
+ Nesenai žaista
+ Nesenai pridėta
+ Apkeisti ekranus
+
+ Sistemos failai
+ Vartotojo vardas
+ Laikrodis
+ Laikrodis
+ Įrenginio laikas
+ Netikras laikas
+ Regionas
+ Kalba
+ Gimtadienis
+ Mėnesis
+ Diena
+ Šalis
+ Konsolės ID
+ Kamera
+ Priekio
+ Galo
+ Išorinė
+ Apversti
+
+ Grafikos API
+ Tikslus atkūrimas
+ Riboti greitį
+ Vidinė rezoliucija
+ Gylis
+
+ Garsumas
+ Garso ištempimas
+ Įjungti realaus laiko garsą
+ Automatinis
+ Sužinoti daugiau
+ Uždaryti
+ Atstatyti visus nustatymus?
+ Pradėti
+ Atšaukiama...
+ Svarbu
+ Daugiau niekada nerodyti
+
+
+ Nustatymai
+ Sistema
+ Kamera
+ Grafika
+ Garsas
+ Tema ir Spalva
+ Išdėstymas
+
+ Rodyti FPS
+ Redaguoti išdėstymą
+ Baigta
+ Uždaryti žaidimą
+ Pašalinti
+ Pristabdyti Emuliaciją
+ Atstabdyti Emuliaciją
+ Aš pamiršau
+ Kamera
+
+ Mikrofonas
+ Tęsti
+
+ Žaisti
+ Pavadinimas
+ Kodas
+ Redaguoti
+ Ištrinti
+
+ Juodas fonas
+ Anglų
+
+ OpenGLES
+ Vulkan
+
+
+ Mono
+ Stereo
+ Erdvinis
+
+
+ Japonija
+ Angilija
+ Antigva ir Barbuda
+ Argentina
+ Aruba
+ Bahamos
+ Barbadosas
+ Belizas
+ Bolivija
+ Brazilija
+ Kanada
+ Čilė
+ Kolumbija
+ Kosta Rika
+ Dominika
+ Dominikos respublika
+ Ekvadoras
+ El Salvadoras
+ Prancūzų Gviana
+ Grenada
+ Gvadelupa
+ Jamaika
+ Meksika
+ Peru
+ Jungtinės Amerikos Valstijos
+ Venesuela
+ Albanija
+ Australija
+ Austrija
+ Belgija
+ Bosnija ir Hercegovina
+ Botsvana
+ Bulgarija
+ Kroatija
+ Kipras
+ Čekija
+ Danija
+ Estija
+ Suomija
+ Prancūzija
+ Vokietija
+ Graikija
+ Vengrija
+ Islandija
+ Airija
+ Italija
+ Latvija
+ Lesotas
+ Lichtenšteinas
+ Lietuva
+ Liuksemburgas
+ Makedonija
+ Malta
+ Juodkalnija
+ Mozambikas
+ Namibija
+ Nyderlandai
+ Naujoji Zelandija
+ Norvegija
+ Lenkija
+ Portugalija
+ Rumunija
+ Rusija
+ Serbija
+ Slovakija
+ Slovėnija
+ Pietų Afrika
+ Ispanija
+ Svazilandas
+ Švedija
+ Šveicarija
+ Turkija
+ Jungtinė Karalystė
+ Zambija
+ Zimbabvė
+ Azerbaidžanas
+ Mauritanija
+ Malis
+ Nigeris
+ Čadas
+ Sudanas
+ Andora
+ Taivanas
+ Pietų Korėja
+ Hong Kongas
+ Makao
+ Indonezija
+ Singapūras
+ Tailandas
+ Filipinai
+ Malaizija
+ Kinija
+ Jungtiniai Arabų Emyratai
+ Indija
+ Egiptas
+ Omanas
+ San Marinas
+ Vatikanas
+
+ Sausis
+ Vasaris
+ Kovas
+ Balandis
+ Gegužė
diff --git a/src/android/app/src/main/res/values-b+pl+PL/strings.xml b/src/android/app/src/main/res/values-b+pl+PL/strings.xml
index d65011fc2..06d97d91a 100644
--- a/src/android/app/src/main/res/values-b+pl+PL/strings.xml
+++ b/src/android/app/src/main/res/values-b+pl+PL/strings.xml
@@ -5,10 +5,6 @@
Powiadomienia o emulatorze Azahar
Azahar jest uruchomiony
Następnie należy wybrać folder z aplikacjami. Azahar wyświetli wszystkie ROM-y 3DS w wybranym folderze w aplikacji.\n\nROMy CIA, aktualizacje i DLC będą musiały zostać zainstalowane oddzielnie, klikając ikonę folderu i wybierając opcję Zainstaluj CIA.
- Rozpocznij
- Anulowanie...
- Ważne
- Nie pokazuj tego ponownie
Ustawienia
@@ -36,6 +32,8 @@
Zmienia pliki, których Azahar używa do ładowania aplikacji
Zmodyfikuj wygląd aplikacji
Instaluj CIA
+ Więcej informacji.]]>
+
Wybierz sterownik GPU
Czy chcesz wymienić swój obecny sterownik GPU?
@@ -81,9 +79,13 @@
Anuluj
Wybierz folder użytkownika
danych użytkownikakorzystając z przycisku poniżej.]]>
+ Wygląda na to, że masz ustawione katalogi użytkownika zarówno dla Lime3DS, jak i Azahar. Dzieje się tak prawdopodobnie dlatego, że zaktualizowałeś Azahar i po wyświetleniu monitu wybrałeś inny katalog użytkownika niż ten, który był używany w Lime3DS.\n\nMogło to spowodować utratę zapisów lub innych ustawień - przepraszamy, jeśli tak się stało.\n\nCzy chcesz powrócić do używania oryginalnego katalogu użytkownika Lime3DS, przywracając ustawienia i zapisując gry z Lime3DS, czy zachować obecny katalog użytkownika Azahar?\n\nŻaden z katalogów nie zostanie usunięty, niezależnie od dokonanego wyboru, a ty możesz swobodnie przełączać się między nimi za pomocą opcji Wybierz folder użytkownika.
+ Zachowaj aktualny katalog Azahar
+ Użyj wcześniejszego katalogu Lime3DS
Wybierz
Nie możesz pominąć tego kroku
Ten krok jest wymagany, aby umożliwić działanie Azahar. Wybierz katalog, a następnie możesz kontynuować.
+ Utraciłeś uprawnienia do zapisu w katalogu danych użytkownika, w którym przechowywane są zapisy i inne informacje. Może się to zdarzyć po niektórych aktualizacjach aplikacji lub systemu Android. Wybierz ponownie katalog, aby odzyskać uprawnienia i móc kontynuować.
Ustawienia motywu
Skonfiguruj ustawienia motywu dla Azahar.
Ustaw motyw
@@ -120,15 +122,21 @@
Przesuń analog w lewo lub w prawo.
HOME
Zamień ekrany
+ Turbo
Ten kontroler musi być powiązany z drążkiem analogowym gamepada lub z krzyżakiem!
Ten kontroler musi być powiązany z przyciskiem gamepada!
+ Prędkość Turbo
+ Prędkość Turbo włączona
+ Prędkość Turbo wyłączona
Pliki systemowe
Wykonywanie operacji na plikach systemowych, takich jak instalowanie plików systemowych lub uruchamianie Home Menu
Podłącz do narzędzia Artic Setup Tool
- Azahar Artic Setup Tool.
Uwaga:- Ta operacja zainstaluje unikalne pliki konsoli do Azahar, nie udostępniaj swoich folderów użytkownika lub nand
po wykonaniu procesu konfiguracji! - Konfiguracja Old 3DS jest wymagana, aby konfiguracja New 3DS działała.
- Oba tryby konfiguracji będą działać niezależnie od modelu konsoli, na której uruchomiono narzędzie konfiguracji.
]]>
+ Azahar Artic Setup Tool.
Uwaga:- Ta operacja zainstaluje unikalne pliki konsoli do Azahar, nie udostępniaj swoich folderów użytkownika lub nand po wykonaniu procesu konfiguracji!
- Podczas procesu konfiguracji Azahar połączy się z konsolą, na której uruchomione jest narzędzie instalacyjne. Konsolę można później odłączyć w zakładce System w menu konfiguracji emulatora.
- Nie korzystaj jednocześnie z Azahar i konsoli 3DS po skonfigurowaniu plików systemowych, bo może to spowodować błędy.
- Old 3DS jest wymagany do działania konfiguracji New 3DS (zalecane jest wykonanie obu tych konfiguracji).
- Oba tryby konfiguracji będą działać niezależnie od modelu konsoli, na której uruchomiono narzędzie konfiguracyjne.
]]>
Pobieranie bieżącego stanu plików systemowych, proszę zaczekać...
+ Odłącz unikalne dane konsoli
+ - Twój OTP, SecureInfo i LocalFriendCodeSeed zostaną usunięte z Azahar.
- Lista znajomych zostanie zresetowana, a użytkownik zostanie wylogowany z konta NNID/PNID.
- Pliki systemowe i tytuły z eshopu uzyskane za pośrednictwem Azahar staną się niedostępne do czasu ponownego połączenia z tą samą konsolą (dane zapisu nie zostaną utracone).
Kontynuować?]]>
Konfiguracja Old 3DS
Konfiguracja New 3DS
Konfiguracja jest możliwa.
@@ -145,20 +153,20 @@
Przyciski
Przycisk
-
- CPU JIT
- Używa wbudowanego kompilatora JIT (Just-in-Time) do emulacji procesora. Po włączeniu tej funkcji wydajność gry zostanie znacznie poprawiona.
- Zegar
- Ustaw emulowany zegar 3DS tak, aby odzwierciedlał zegar urządzenia lub rozpoczynał się od symulowanej daty i godziny.
- Prędkość taktowania procesora
-
+ Ustawienia emulacji
Nazwa użytkownika
Tryb New 3DS
Użyj apletów LLE (jeśli są zainstalowane)
+ Włącz wymagane moduły LLE dla funkcji online (jeśli są zainstalowane)
+ łącza moduły LLE potrzebne do gry wieloosobowej online, dostępu do eShopu itp.
Zegar
- Czas przesunięcia
- Jeśli zegar jest ustawiony na „Symulowany zegar”, zmienia to ustaloną datę i godzinę rozpoczęcia.
+ Zegar
+ Ustaw emulowany zegar 3DS tak, aby odzwierciedlał zegar urządzenia lub rozpoczynał się od symulowanej daty i godziny.
+ Zegar urządzenia
+ Symuluj zegar
+ Jeśli zegar jest ustawiony na „Symulowany zegar”, zmienia to ustaloną datę i godzinę rozpoczęcia.
+ Ustawienia profilu
Region
Język
Urodziny
@@ -171,10 +179,16 @@
ID Konsoli
Wygeneruj ID konsoli
To zastąpi twojego obecnego wirtualnego 3DS. Odzyskanie twojego obecnego 3DS będzie niemożliwe. To może spowodować niespodziewane efekty w aplikacjach. Operacja może się nie powieść jeżeli korzystasz z przestarzałej konfiguracji zapisów aplikacji. Kontynuować?
+ Adres MAC
+ Wygeneruj adres MAC
+ Spowoduje to zastąpienie bieżącego adresu MAC nowym. Nie zaleca się wykonywania tej czynności, jeśli adres MAC został uzyskany z rzeczywistej konsoli za pomocą narzędzia konfiguracyjnego. Kontynuować?
Wtyczka 3GX Loader
Ładuje wtyczki 3GX z emulowanej karty SD, jeśli są dostępne.
Zezwól aplikacjom na zmianę stanu programu ładującego wtyczki
Umożliwia aplikacjom homebrew włączenie programu ładującego wtyczki, nawet jeśli jest on wyłączony.
+ Ostrzeżenie o niedopasowaniu regionów
+ Ustawienie kraju nie jest prawidłowe dla wybranego emulowanego regionu.
+ Ustawienie kraju nie jest prawidłowe dla aktualnie podłączonej konsoli.
Kamera wewnętrzna
@@ -196,26 +210,30 @@
Emituje fragment shaderów używany do emulacji PICA przy użyciu SPIR-V zamiast GLSL.
Włącz asynchroniczną kompilację shaderów
Kompiluje shadery w tle, aby zmniejszyć zacinanie się podczas rozgrywki. Po włączeniu należy spodziewać się tymczasowych błędów graficznych
- Render debugowania
- Rejestruje dodatkowe informacje debugowania związane z grafiką. Po włączeniu, wydajność gry zostanie znacznie zmniejszona.
- Włącz V-Sync
- Synchronizuje liczbę klatek na sekundę gry z częstotliwością odświeżania urządzenia.
Filtrowanie Linear
Włącza filtrowanie liniowe, które sprawia, że grafika w grach jest płynniejsza.
Filtr tekstur
Ulepsza oprawę wizualną aplikacji poprzez zastosowanie filtrów do tekstur. Obsługiwane filtry to Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale i MMPX.
- Włącz shader sprzętu
- Używa sprzętu do emulacji shaderów 3DS. Po włączeniu, wydajność gry zostanie znacznie poprawiona.
+ Opóźnienie renderowania wątku gry
+ Opóźnia wątek renderowania aplikacji podczas przesyłania danych do GPU. Pomaga w kwestiach wydajności w (bardzo niewielu) aplikacjach z dynamiczną liczbą klatek na sekundę.
+ Zaawansowane\"
+ Próbkowanie tekstur
+ Zastępuje filtr próbkowania używany przez gry. Może to być przydatne w niektórych przypadkach, gdy gry źle zachowują się podczas skalowania w górę. Jeśli nie masz pewności, ustaw tę opcję na Kontrolowane przez grę.
Dokładne mnożenie
Używa dokładniejszego mnożenia w shaderach sprzętu, dzięki czemu może naprawić niektóre błędy graficzne. Po włączeniu tej funkcji wydajność zostanie zmniejszona.
Włącz asynchroniczną emulację GPU
Używa oddzielnego wątku do asynchronicznej emulacji GPU. Po włączeniu, wydajność zostanie poprawiona.
Ogranicz prędkość
- Po włączeniu prędkość emulacji zostanie ograniczona do określonego procentu normalnej prędkości.
+ Po włączeniu prędkość emulacji zostanie ograniczona do określonego procentu normalnej prędkości. Jeśli opcja ta jest wyłączona, prędkość emulacji nie zostanie ograniczona, a klawisz skrótu prędkości turbo nie będzie działał.
Ogranicz procent prędkości
Określa wartość procentową ograniczenia prędkości emulacji. Przy domyślnej wartości 100% emulacja będzie ograniczona do normalnej prędkości. Wyższe lub niższe wartości zwiększają lub zmniejszają ograniczenie prędkości.
+ Limit prędkości Turbo
+ Limit prędkości emulacji wykorzystywany, gdy aktywny jest klawisz skrótu turbo.
+ Rozszerz do obszaru wycięcia
+ Rozszerza obszar wyświetlania o obszar wycięcia.
Rozdzielczość Wewnętrzna
Określa rozdzielczość używaną do renderowania. Wysoka rozdzielczość znacznie poprawi jakość wizualną, ale jest również dość obciążająca dla wydajności i może powodować błędy w niektórych aplikacjach.
+ Automatyczne (Rozmiar ekranu)
Natywna (400x240)
2x Natywna (800x480)
3x Natywna (1200x720)
@@ -231,7 +249,9 @@
Sterowanie stereoskopowe
Tryb stereoskopowy 3D
Zasięg
- Określa wartość suwaka 3D. Powinien być ustawiony na wartość wyższą niż 0%, gdy włączony jest tryb stereoskopowy 3D.
+ Określa wartość suwaka 3D. Powinien być ustawiony na wartość wyższą niż 0%, gdy włączony jest tryb stereoskopowy 3D.\nUwaga: Wartość przekraczająca 100% nie jest możliwa na rzeczywistym sprzęcie i może powodować problemy graficzne.
+ Wyłącz renderowanie prawego oka
+ Znacznie poprawia wydajność w niektórych aplikacjach, ale może powodować migotanie w innych.
Cardboard VR
Rozmiar ekranu Cardboarda
Skaluje ekran do wartości procentowej jego oryginalnego rozmiaru.
@@ -261,13 +281,30 @@
Urządzenie wejściowe dźwięku
Tryb wyjścia dźwięku
+
+ CPU JIT
+ Używa wbudowanego kompilatora JIT (Just-in-Time) do emulacji procesora. Po włączeniu tej funkcji wydajność gry zostanie znacznie poprawiona.
+ Włącz shader sprzętu
+ Używa sprzętu do emulacji shaderów 3DS. Po włączeniu, wydajność gry zostanie znacznie poprawiona.
+ Prędkość taktowania procesora
+ Włącz V-Sync
+ Synchronizuje liczbę klatek na sekundę gry z częstotliwością odświeżania urządzenia.
+ Render debugowania
+ Rejestruje dodatkowe informacje debugowania związane z grafiką. Po włączeniu, wydajność gry zostanie znacznie zmniejszona.
+ Opróżnia log przy każdej wiadomości
+ Natychmiast zapisuje log debugowania do pliku. Użyj tego, jeśli azahar ulegnie awarii, a dane wyjściowe logu zostaną przerwane.
+ Opóźnione uruchamianie z modułami LLE
+ Opóźnia uruchomienie aplikacji, gdy włączone są moduły LLE.
+ Deterministyczne operacje asynchroniczne
+ Sprawia, że operacje asynchroniczne są deterministyczne dla debugowania. Włączenie tej opcji może powodować zawieszanie się gry.
+
Orientacja Ekranu
Automatycznie
Widok
Odwrócony widok
- Portret
- Odwrócony portret
+ Ekran
+ Odwrócony Ekran
Wyczyść
@@ -275,6 +312,7 @@
Zapisz ustawienia
Zapisane ustawienia dla %1$s
Błąd podczas zapisywania %1$s.ini: %2$s
+ Zapisywanie...
Wczytywanie...
Dalej
Wstecz
@@ -295,8 +333,14 @@
Wybierz czas RTC
Czy chcesz przywrócić to ustawienie do domyślnej wartości?
Nie możesz teraz tego edytować
+ Ustawienie wyłączone
+ To ustawienie jest obecnie wyłączone, ponieważ inne ustawienie nie jest odpowiednią wartością.
Tej opcji nie można zmienić podczas gry.
Wybór automatyczny
+ Rozpocznij
+ Anulowanie...
+ Ważne
+ Nie pokazuj tego ponownie
Wybierz folder gry
@@ -347,7 +391,7 @@
Geometryczny Układ Ekranu
Pionowy Układ Ekranu
Duży Ekran
- Obraz
+ Ekran
Pojedynczy ekran
Ekrany Obok Siebie
Hybrydowy Ekran
@@ -364,6 +408,8 @@
Lewy dolny róg
Powyżej
Poniżej
+ Odstęp ekranu
+ Odstęp między ekranami we wszystkich trybach dwuekranowych. Mierzona w px względem 240px wysokości większego ekranu.
Proporcja dużego ekranu
Ile razy większy jest duży ekran od małego w układzie dużego ekranu?
Dostosuj niestandardowy układ w Ustawieniach
@@ -381,6 +427,9 @@
Pokaż Nakładkę
Zamknij Grę
Włącz Pauzę
+ Różne
+ Użyj kontrolera Artic po podłączeniu do serwera Artic Base
+ W przypadku połączenia z serwerem Artic Base zamiast skonfigurowanego urządzenia wejściowego należy używać elementów sterujących udostępnianych przez ten serwer.
Czy na pewno chcesz zamknąć obecną grę?
Amiibo
Wczytaj
@@ -442,6 +491,9 @@
Błąd zapisywania/wczytywania
Krytyczny Błąd
Wystąpił błąd krytyczny. Kontynuowanie emulacji może spowodować awarie i błędy.
+ Nieprawidłowy region
+ Nieobsługiwana zaszyfrowana aplikacja
+
Przygotowanie shaderów
Tworzenie shaderów
@@ -449,6 +501,17 @@
Odtwórz
Skrót
+ Odinstaluj aktualizacje
+ Odinstalowywanie...
+ Otwórz folder zapisanych danych
+ Otwórz folder aplikacji
+ Otwórz folder modów
+ Otwórz folder tekstur
+ Otwórz folder z plikami DLC
+ Otwórz folder aktualizacji
+ Otwórz folder Extra
+ Odinstaluj DLC
+ Odinstaluj aktualizacje
Cheaty
@@ -472,6 +535,7 @@
Powiadomienia Azahar podczas instalacji CIA
Instalacja CIA
+ Instalacja %1$s (%2$d/%3$d)
Pomyślnie zainstalowano CIA
Instalacja CIA nie powiodła się
\"%s\" został pomyślnie zainstalowany
@@ -509,10 +573,6 @@
Czarne tło
W przypadku korzystania z ciemnego motywu należy stosować czarne tło.
-
- Zegar urządzenia
- Symuluj zegar
-
JPN
USA
@@ -569,11 +629,15 @@
Anime4K
Bicubic
- Nearest Neighbor
ScaleForce
xBRZ
MMPX
+
+ Kontrolowane przez grę
+ Nearest Neighbor
+ Linear
+
Mono
Stereo
@@ -734,33 +798,12 @@
Połącz się z prawdziwą konsolą, na której działa serwer Artic Base
Połącz z Artic Base
Wprowadź adres serwera Artic Base
- Opóźnienie renderowania wątku gry
- Opóźnia wątek renderowania aplikacji podczas przesyłania danych do GPU. Pomaga w kwestiach wydajności w (bardzo niewielu) aplikacjach z dynamiczną liczbą klatek na sekundę.
Szybkie zapisywanie
Szybkie zapisywanie
Szybkie zapisywanie
Szybkie zapisywanie - %1$tF %1$tR
- Zapisywanie...
- Wczytywanie...
Funkcja szybkiego zapisu nie jest dostępna.
- Różne
- Użyj kontrolera Artic po podłączeniu do serwera Artic Base
- W przypadku połączenia z serwerem Artic Base zamiast skonfigurowanego urządzenia wejściowego należy używać elementów sterujących udostępnianych przez ten serwer.
- Opróżnia log przy każdej wiadomości
- Natychmiast zapisuje log debugowania do pliku. Użyj tego, jeśli azahar ulegnie awarii, a dane wyjściowe logu zostaną przerwane.
- Wyłącz renderowanie prawego oka
- Znacznie poprawia wydajność w niektórych aplikacjach, ale może powodować migotanie w innych.
- Opóźnione uruchamianie z modułami LLE
- Opóźnia uruchomienie aplikacji, gdy włączone są moduły LLE.
- Deterministyczne operacje asynchroniczne
- Sprawia, że operacje asynchroniczne są deterministyczne dla debugowania. Włączenie tej opcji może powodować zawieszanie się gry.
- Włącz wymagane moduły LLE dla funkcji online (jeśli są zainstalowane)
- łącza moduły LLE potrzebne do gry wieloosobowej online, dostępu do eShopu itp.
- Ustawienia emulacji
- Ustawienia profilu
- Adres MAC
- Wygeneruj adres MAC
- Spowoduje to zastąpienie bieżącego adresu MAC nowym. Nie zaleca się wykonywania tej czynności, jeśli adres MAC został uzyskany z rzeczywistej konsoli za pomocą narzędzia konfiguracyjnego. Kontynuować?
+
diff --git a/src/android/app/src/main/res/values-b+pt+BR/strings.xml b/src/android/app/src/main/res/values-b+pt+BR/strings.xml
index 616673403..03cc09a89 100644
--- a/src/android/app/src/main/res/values-b+pt+BR/strings.xml
+++ b/src/android/app/src/main/res/values-b+pt+BR/strings.xml
@@ -5,10 +5,6 @@
Notificações do emulador Azahar 3DS
Azahar está Executando
Em seguida, você precisará selecionar uma pasta de Aplicativos. O Azahar exibirá todas as ROMs de 3DS dentro da pasta selecionada no aplicativo.\n\nROMs, atualizações e DLC no formato CIA precisarão ser instaladas separadamente clicando no ícone da pasta e selecionando Instalar CIA.
- Iniciar
- Cancelando...
- Importante
- Não mostrar novamente
Configurações
@@ -83,9 +79,13 @@
Cancelar
Selecione a Pasta do Usuário
dados de usuáriocom o botão abaixo.]]>
+ Parece que você tem diretórios de usuários configurados para ambos o Lime3DS e o Azahar. Isso ocorreu devido a você ter atualizado para o Azahar, e quando solicitado, escolha um diretório de usuário diferente daquele que foi usado pelo Lime3DS.\n\nIsso pode ter resultado em você pensar que tenha perdidos dados salvos ou outras configurações - pedimos desculpas caso isso tenha acontecido.\n\nGostaria de voltar a usar sua pasta de usuário original do Lime3DS, restaurar configurações e salvar os jogos do Lime3DS, ou manter o diretório de usuário do Azahar atual?\n\nNenhum dos diretórios serão excluídos, independente de sua escolha, sinta-se livre para trocar entre elas usando a opção Selecionar Pasta de Usuário.
+ Manter diretório atual do Azahar
+ Usar o diretório antigo do Lime3DS
Selecionar
Você não pode pular esta etapa
Este passo é necessário para permitir que o Azahar funcione. Selecione um diretório para continuar.
+ Você perdeu suas permissões de escrita no seu diretório de dados de usuário, onde dados salvos e outras informações são guardadas. Isso pode acontecer depois que algum app ou Android atualiza. Re-selecione o diretório para reobter as permissões para que você possa continuar.
Configurações de Tema
Configure suas preferências de tema para o Azahar.
Definir Tema
@@ -122,15 +122,17 @@
Mova o seu joystick para esquerda ou para direita.
Menu Principal
Trocar telas
+ Turbo
Este controle tem de ser mapeado a um eixo analógico do gamepad ou um eixo de D-pad!
Este controle tem de ser mapeado a um botão do gamepad!
-
Arquivos do Sistema
Executar operações de arquivos do sistema, como instalar arquivos do sistema ou iniciar o Menu Principal.
Conectar à Ferramenta de Configuração do Artic
- Azahar Artic Setup Tool.
Notas:- Esta operação instalará arquivos exclusivos do console no Azahar, não compartilhe suas pastas de usuário ou nand
após executar o processo de configuração! - A configuração Antiga do 3DS é necessária para que a configuração do Novo 3DS funcione
- Ambos os modos de configuração funcionarão independentemente do modelo do console que estiver executando a ferramenta de configuração.
]]>
+ Ferramenta de Configuração Artic do Azahar.
Notas:- Esta operação instalará os dados exclusivos do console para o Azahar, não compartilhe sua pasta de usuário ou nand depois de realizar este processo!
- Enquanto estiver realizando o processo de configuração, o Azahar irá vincular-se ao console executando a ferramenta de configuração. Você poderá desvincular o console mais tarde na aba Sistema no menu de configuração do emulador.
- Não entre no online com ambos Azahar e seu console 3DS ao mesmo tempo depois de configurar os arquivos de sistema, já que isso poderá causar problemas.
- A configuração do Antigo 3DS é necessária para a configuração do Novo 3DS funcionar (realizar ambas as configurações é recomendado).
- Ambos os modos de configuração irão funcionar independente do modelo do console executando a ferramenta de configuração.
]]>
Buscando o status atual dos arquivos do sistema, por favor, aguarde...
+ Desvincular dados exclusivos do console
+ - Seu OTP, SecureInfo e LocalFriendCodeSeed serão removidos do Azahar.
- Sua lista de amigos será redefinida e sua sessão será finalizada em sua conta NNID/PNID.
- Arquivos do sistema e títulos da eshop obtidos pelo Azahar se tornarão inacessíveis até que o mesmo console seja vinculado de novo usando a ferramenta de configuração (dados salvos não serão perdidos).
Deseja continuar?]]>
Configuração do Antigo 3DS
Configuração do Novo 3DS
É possível configurar.
@@ -147,20 +149,19 @@
Botões
Botão
-
- CPU JIT
- Utiliza um compilador Just-in-Time (JIT) para emulação da CPU. Quando ativado, o desempenho do jogo será consideravelmente melhorado.
- Relógio
- Configura o relógio emulado do 3DS para refletir o do seu dispositivo ou para começar numa data e hora simulados.
- Velocidade do Clock da CPU
-
+ Configurações de Emulação
Nome de usuário
Modo do Novo 3DS
Usar miniaplicativos LLE (se instalados)
+ Ativa os módulos LLE necessários para os recursos online (se instalado)
+ Ativa os módulos LLE necessários para o multijogador online, acesso à eShop, etc.
Relógio
- Tempo de deslocamento
- Se o relógio estiver definido como \"Relógio simulado\", isso altera a data e a hora fixas de início.
+ Relógio
+ Configura o relógio emulado do 3DS para refletir o do seu dispositivo ou para começar numa data e hora simulados.
+ Clock do Dispositivo
+ Clock Simulado
+ Configurações de Perfil
Região
Linguagem
Aniversário
@@ -172,11 +173,17 @@
Número de passos por hora relatados pelo pedômetro. Na faixa de 0 a 65.535.
ID do console
Gerar Novamente o ID do Console
- Isso substituirá seu ID do console 3DS virtual atual por um novo. Seu ID do console 3DS virtual atual não poderá ser recuperado. Isso pode ter efeitos inesperados dentro dos aplicativos. Poderão ocorrer falhas ao usar um arquivo salvo de configuração desatualizado. Continuar?
+ Isso substituirá seu ID do console 3DS virtual atual por um novo. Seu ID do console 3DS virtual atual não poderá ser recuperado. Isso pode ter efeitos inesperados dentro dos aplicativos. Poderão ocorrer falhas ao usar um arquivo salvo de configuração desatualizado. Deseja continuar?
+ Endereço MAC
+ Gerar Novamente o Endereço MAC
+ Isto substituirá seu endereço MAC atual por um novo. Não é recomendado fazer isso se você possuir o endereço MAC do seu console real usando esta ferramenta de configuração. Deseja continuar?
Carregador de Plug-ins 3GX
Carregar plug-ins 3GX do cartão SD emulado, se estiverem disponíveis.
Permitir que os Aplicativos Alterem o Estado do Carregador de Plug-ins
Permitir que aplicativos homebrew habilitem o carregador de plugins mesmo quando ele estiver desabilitado.
+ Aviso de inconsistência de região
+ O país configurado não é válido para a região emulada selecionada.
+ O país configurado não é válido para o console vinculado atual.
Câmera frontal
@@ -198,26 +205,28 @@
Emite o fragment shader usado para emular PICA usando SPIR-V em vez de GLSL
Ativar a compilação assíncrona de shaders
Compila shaders em segundo plano para reduzir travamentos durante o jogo. Quando ativado, espere falhas gráficas temporárias
- Renderizador de Depuração
- Registre informações adicionais de depuração relacionadas a gráficos. Quando ativado, o desempenho do jogo será significativamente reduzido.
- Ativar sincronização vertical
- Sincroniza a taxa de quadros do jogo com a taxa de atualização da tela do seu dispositivo.
Filtragem Linear
Ativa a filtragem linear, que suaviza o visual do jogo.
Filtro de texturas
Aprimora o visual dos aplicativos ao aplicar filtros às texturas. Os filtros compatíveis são: Anime4K Ultrafast, Bicúbico, ScaleForce, xBRZ Freescale e MMPX.
- Ativar Shaders via Hardware
- Utiliza o hardware para emular os shaders do 3DS. Quando ativado, o desempenho do jogo será consideravelmente melhorado.
+ Atrasar thread de renderização do aplicativo
+ Atrasar thread de renderização do aplicativo quando for enviado dados para a GPU. Ajuda com problemas de desempenho em (muito poucos) aplicativos com taxa de quadros dinâmica.
+ Avançado\"
+ Amostragem de Texturas
+ Substitui o filtro de amostragem usado pelos jogos. Isso pode ser útil em certos casos com jogos que se comportem mal durante o upscaling. Em caso de dúvidas, defina como Controlado pelo Jogo.
Multiplicação precisa
Utiliza uma multiplicação mais precisa de shaders no hardware, o que pode corrigir problemas visuais. Quando ativada, pode haver redução no desempenho.
Ativar emulação de GPU assíncrona
Usa uma thread separada para emular a GPU de forma assíncrona. Esta opção aprimora o desempenho quando ativada.
Limite de velocidade
- Quando ativado, a velocidade da emulação será limitada a uma porcentagem da velocidade normal.
+ Quando ativo, a velocidade de emulação será limitada à uma porcentagem especificada da velocidade normal. Se desativado, a velocidade de emulação será destravada e a tecla de atalho do turbo não irá funcionar.
Limite de velocidade percentual
Especifica a porcentagem para limitar a velocidade. Com o padrão de 100% a emulação será limitada a velocidade normal. Valores maiores ou menores vão aumentar ou reduzir o limite de velocidade.
+ Expandir para a área recortada
+ Expande a área da tela para incluir a área recortada (ou notch).
Resolução Interna
Especifica a resolução utilizada para renderização. Uma resolução alta melhorará muito a qualidade visual, mas poderá também impactar muito no desempenho e causar defeitos em certos aplicativos.
+ Automático (tamanho da tela)
Nativo (400x240)
2x Nativo (800x480)
3x Nativo (1200x720)
@@ -233,7 +242,9 @@
Estereoscopia
Modo 3D Estereoscópico
Profundidade
- Especifica o valor do controle deslizante 3D. Deve ser definido como superior a 0% quando o 3D Estereoscópico estiver ativado.
+ Especifica o valor do controle deslizante 3D. Deve ser definido como superior a 0% quando o 3D Estereoscópico estiver ativado.\nNota: Valores de profundidade acima de 100% não são possíveis no hardware real e podem causar problemas gráficos
+ Desativar a renderização do olho direito
+ Melhora muito o desempenho em alguns aplicativos, mas pode causar piscadas em outros.
VR Cardboard
Tamanho da Tela do Cardboard
Dimensiona a tela para uma porcentagem de seu tamanho original.
@@ -263,6 +274,23 @@
Dispositivo de entrada de áudio
Modo de Saída de Som
+
+ CPU JIT
+ Utiliza um compilador Just-in-Time (JIT) para emulação da CPU. Quando ativado, o desempenho do jogo será consideravelmente melhorado.
+ Ativar Shaders via Hardware
+ Utiliza o hardware para emular os shaders do 3DS. Quando ativado, o desempenho do jogo será consideravelmente melhorado.
+ Velocidade do Clock da CPU
+ Ativar sincronização vertical
+ Sincroniza a taxa de quadros do jogo com a taxa de atualização da tela do seu dispositivo.
+ Renderizador de Depuração
+ Registre informações adicionais de depuração relacionadas a gráficos. Quando ativado, o desempenho do jogo será significativamente reduzido.
+ Limpar a saída do log a cada mensagem
+ Grava imediatamente o log de depuração no arquivo. Use isto se o Azahar travar e a saída do log estiver sendo cortada.
+ Atraso na inicialização com módulos LLE
+ Atrasa a inicialização do aplicativo quando os módulos LLE estão ativados.
+ Operações Assíncronas Determinísticas
+ Torna as operações assíncronas determinísticas para depuração. Ativar essa opção pode causar congelamentos.
+
Orientação da Tela
Automático
@@ -297,8 +325,14 @@
Selecione o horário RTC
Você quer redefinir essa configuração para o valor padrão?
Você não pode editar isso agora
+ Configuração desativada
+ Esta configuração está atualmente desativada porque outra configuração não está com o valor correto.
Esta opção não pode ser alterada enquanto o jogo estiver em execução.
Seleção Automática
+ Iniciar
+ Cancelando...
+ Importante
+ Não mostrar novamente
Escolher pasta de jogos
@@ -383,6 +417,9 @@
Mostrar sobreposição
Fechar jogo
Alternar Pausa
+ Diversos
+ Use o Controle Artic quando conectado ao Servidor Artic Base
+ Use os controles fornecidos pelo Artic Base Server ao se conectar a ele, em vez do dispositivo de entrada configurado.
Deseja mesmo fechar o jogo atual?
Amiibo
Carregar
@@ -444,6 +481,9 @@
Erro ao Salvar/Carregar
Erro Fatal
Ocorreu um erro fatal. Verifique o registro para obter detalhes.\nContinuar a emulação pode resultar em falhas e bugs.
+ Região inválida
+ Aplicativo criptografado não suportado
+
Preparando Shaders
Construindo Shaders
@@ -451,6 +491,17 @@
Jogar
Atalho
+ Desinstalar Aplicativo
+ Desinstalando...
+ Abrir pasta de dados salvos
+ Abrir pasta do aplicativo
+ Abrir pasta de mods
+ Abrir pasta de texturas
+ Abrir pasta de DLC
+ Abrir pasta de atualizações
+ Abrir pasta extra
+ Desinstalar DLC
+ Desinstalar atualizações
Truques
@@ -473,6 +524,7 @@
Notificações do Azahar durante a instalação do CIA
Instalando CIA
+ Instalando %1$s (%2$d/%3$d)
CIA Instalado com sucesso
Erro ao instalar o CIA
\"%s\" foi instalado com sucesso
@@ -510,10 +562,6 @@
Fundos Pretos
Ao usar o tema escuro, aplique fundos pretos.
-
- Clock do Dispositivo
- Clock Simulado
-
JPN
USA
@@ -570,11 +618,15 @@
Anime4K
Bicúbico
- Ponto Vizinho Mais Próximo
ScaleForce
xBRZ
MMPX
+
+ Controlado pelo Jogo
+ Ponto Vizinho Mais Próximo
+ Linear
+
Mono
Estéreo
@@ -735,33 +787,12 @@
Conecte-se a um console real que esteja executando um servidor Artic Base
Conectar-se ao Artic Base
Digite o endereço do servidor Artic Base
- Atrasar thread de renderização do aplicativo
- Atrasar thread de renderização do aplicativo quando for enviado dados para a GPU. Ajuda com problemas de desempenho em (muito poucos) aplicativos com taxa de quadros dinâmica.
Salvar rápido
Salvar rápido
Carregar rápido
Salvar rápido - %1$tF %1$tR
- Salvando...
- Carregando...
Nenhum Salvamento Rápido disponível.
- Diversos
- Use o Controle Artic quando conectado ao Servidor Artic Base
- Use os controles fornecidos pelo Artic Base Server ao se conectar a ele, em vez do dispositivo de entrada configurado.
- Limpar a saída do log a cada mensagem
- Grava imediatamente o log de depuração no arquivo. Use isto se o Azahar travar e a saída do log estiver sendo cortada.
- Desativar a renderização do olho direito
- Melhora muito o desempenho em alguns aplicativos, mas pode causar piscadas em outros.
- Atraso na inicialização com módulos LLE
- Atrasa a inicialização do aplicativo quando os módulos LLE estão ativados.
- Operações Assíncronas Determinísticas
- Torna as operações assíncronas determinísticas para depuração. Ativar essa opção pode causar congelamentos.
- Ativa os módulos LLE necessários para os recursos online (se instalado)
- Ativa os módulos LLE necessários para o multijogador online, acesso à eShop, etc.
- Configurações de Emulação
- Configurações de Perfil
- Endereço MAC
- Gerar Novamente o Endereço MAC
- Isto substituirá seu endereço MAC atual por um novo. Não é recomendado fazer isso se você possuir o endereço MAC do seu console real usando esta ferramenta de configuração. Continuar?
+
diff --git a/src/android/app/src/main/res/values-b+ru+RU/strings.xml b/src/android/app/src/main/res/values-b+ru+RU/strings.xml
index 2f7d01ec1..71c29df00 100644
--- a/src/android/app/src/main/res/values-b+ru+RU/strings.xml
+++ b/src/android/app/src/main/res/values-b+ru+RU/strings.xml
@@ -1,8 +1,6 @@
- Запустить
- Отмена...
Настройки
Опции
@@ -78,7 +76,6 @@
HOME
Данный элемент управления должен быть привязан к аналоговому стику или крестовине геймпада!
Данный элемент управления должен быть привязан к кнопке геймпада!
-
Запуск меню HOME
Запускать настройку системы при загрузке меню HOME
Меню HOME
@@ -87,19 +84,13 @@
Кнопки
Кнопка
-
- JIT для CPU
- Использовать Just-in-Time (JIT) компилятор для эмуляции CPU. При включении существенно повышает производительность в играх.
- Часы
- Установить для эмулируемых часов 3DS текущее время устройства или запускать с фиксированной датой и временем.
- Скорость процессора
-
-
Имя пользователя
Режим новой 3DS
Часы
- Смещение времени
- Установка фиксированных начальных значений даты и времени для часов в режиме \"Симуляция\".
+ Часы
+ Установить для эмулируемых часов 3DS текущее время устройства или запускать с фиксированной датой и временем.
+ Часы устройства
+ Виртуальные часы
Регион
Язык
День рождения
@@ -112,7 +103,6 @@
Загрузчик плагина 3GX
При наличии плагинов 3GX они будут загружаться с эмулируемой SD-карты.
Позволять homebrew-приложениям включать загрузчик плагина даже когда он выключен.
-
Внутренняя камера
Внешняя камера слева
@@ -133,21 +123,14 @@
Запускать фрагментный шейдер, используемый для эмуляции PICA на SPIR-V вместо GLSL.
Вкл. асинхронную компиляцию шейдеров
Компилировать шейдеры в фоновом потоке для уменьшения лагов во время игры. При включении возможны временные сбои графики.
- Отладка рендера
- Логировать расширенную отладочную информацию по графике. При включении существенно снижает производительность.
- Вкл. V-Sync
- Синхронизирует кадровую частоту в играх с частотой обновления устройства.
Линейное сглаживание
Вкл. линейное сглаживание для смягчения графики в играх.
Сглаживание текстур
- Вкл. аппаратные шейдеры
- Эмулировать шейдеры 3DS аппаратными средствами. При включении существенно повышает производительность в играх.
Точное умножение
Исп. более точное умножение для аппаратных шейдеров. Может исправлять некоторые графические баги, но при включении снижает производительность.
Вкл. асинхронную эмуляцию GPU
Использовать отдельный поток для асинхронной эмуляции GPU. При включении повышает производительность.
Ограничивать скорость
- При включении устанавливает скорость эмуляции на указанный процент от нормальной скорости.
Процент ограничения скорости
Устанавливает процентное значение для ограничения скорости эмуляции. Стандартное значение 100% соответствует нормальной скорости. Более высокие или низкие значения повышают или понижают лимит скорости.
Внутреннее разрешение
@@ -156,7 +139,6 @@
Стереоизображение
Стереоскопический режим 3D
Глубина
- Установка значения уровня 3D. При включении стереоскопического 3D должно быть больше 0%.
Cardboard VR
Размер экрана Cardboard
Масштабирует экран к процентному значению от оригинального размера.
@@ -184,6 +166,16 @@
Устройство ввода звука
Режим вывода звука
+
+ JIT для CPU
+ Использовать Just-in-Time (JIT) компилятор для эмуляции CPU. При включении существенно повышает производительность в играх.
+ Вкл. аппаратные шейдеры
+ Эмулировать шейдеры 3DS аппаратными средствами. При включении существенно повышает производительность в играх.
+ Скорость процессора
+ Вкл. V-Sync
+ Синхронизирует кадровую частоту в играх с частотой обновления устройства.
+ Отладка рендера
+ Логировать расширенную отладочную информацию по графике. При включении существенно снижает производительность.
Удалить
По умолчанию
@@ -211,7 +203,8 @@
В данный момент редактирование недоступно
Опцию нельзя изменить во время игры.
Автовыбор
-
+ Запустить
+ Отмена...
Выбор папки с играми
@@ -359,10 +352,6 @@
Чёрный фон
Применять чёрный фон для тёмной темы.
-
- Часы устройства
- Виртуальные часы
-
Япония
США
@@ -418,11 +407,11 @@
Anime4K
Бикубический
- Ближайший сосед
ScaleForce
xBRZ
MMPX
+ Ближайший сосед
Моно
Стерео
diff --git a/src/android/app/src/main/res/values-b+tr+TR/strings.xml b/src/android/app/src/main/res/values-b+tr+TR/strings.xml
index 6cf9ad269..f76ec3c75 100644
--- a/src/android/app/src/main/res/values-b+tr+TR/strings.xml
+++ b/src/android/app/src/main/res/values-b+tr+TR/strings.xml
@@ -1,42 +1,228 @@
- İptal ediliyor...
+ Bu yazılım Nintendo 3DS el konsolu uygulamalarını çalıştırmak içindir. Hiçbir oyun dosyası içermez. \n\nEmülasyon yapmaya başlamadan önce lütfen Azahar kullanıcı verilerinin depolanması için bir dosya seçin. \n\nBu nedir?:\nWiki - Citra Android Kullanıcı verileri ve depolama
+ Azahar 3DS emülatörü bildirimleri
+ Azahar çalışıyor
+ Sırada, bir Uygulama Dosyası seçmelisiniz. Azahar seçili dosyadaki bütün 3DS ROM\'larını uygulamada gösterecektir.\n\nCİA ROM\'larının, güncellemelerin ve DLC\'lerin; dosya ikonuna tıklanıp \"CIA İndir\"i seçerek ayrı olarak indirilmesi gerekir.
+
Ayarlar
Seçenekler
+ Ara
+ Uygulamalar
+ Emülatör ayarlarını yapılandır
+ CIA Dosyası Yükle
+ Uygulamalar, güncellemeler veya DLC yükle
+ Log\'u Paylaş
+ Sorunları gidermek için Azahar\'ın log dosyasını paylaş
+ GPU Sürücü Yöneticisi
+ GPU Sürücüsü Yükle
+ Daha iyi performans veya doğruluk olasılığı için alternatif sürücü yükle
+ Sürücü zaten yüklü
+ Özel sürücüler desteklenmiyor
+ Bu cihaz için özel sürücü yükleme henüz desteklenmiyor. \nLütfen gelecekte destek eklenmiş mi diye tekrar kontrol edin!
+ Log dosyası bulunamadı
+ Uygulamalar Dosyasını Seç
+ Azahar\'ın uygulama listesini doldurmasına izin verir
Hakkında
+ Açık kaynaklı bir 3DS emülatörü
+ Yapı sürümü, katkıda bulunanlar ve daha fazlası
+ Uygulama dizini seçildi
+ Azahar\'ın uygulama yüklemek için kullandığı dosyaları değiştirir
+ Uygulamanın görünüşünü değiştir
+ CIA Yükle
+ Daha fazla öğren.]]>
+
+
+ GPU Sürücüsü seç
+ Halihazırda var olan GPU sürücüsünü değiştirmek ister misiniz?
+ Yükle
Varsayılan
+ %syüklendi
+ Varsayılan GPU sürücüsü kullanılıyor
+ Geçersiz sürücü seçildi, varsayılan sistem sürücüsü kullanılıyor!
+ Sistem GPU sürücüsü
+ Sürücü yükleniyor...
+
+
+ Panoya kopyalandı
Katkıda Bulunanlar
Azahar\'ı mümkün kılan kişiler
+ Android için Azahar tarafından kullanılan projeler
+ Yapı
+ Lisanslar
+
+ Hoş geldiniz!
+ <b>Azahar</b>\'ı nasıl kuracağını öğren ve emülasyona başla.
+ Başlayın
+ Tamamlandı!
+ Uygulamalar
+ Aşağıdaki buton ile <b>Applications</b> dosyasını seçin.
+ Bitti
+ Her şey hazır! \nEmülatörü güle güle kullanın!
+ Devam et
+ Bildirimler
+ Aşağıdaki buton ile bildirim izni verin.
İzin ver
+ Bildirim izni vermeyi geçmek istediğinizden emin misiniz?
+ Azahar sizi önemli bilgiler hakkında bilgilendiremeyecek.
Kamera
+ 3DS kamera emülasyonu için aşağıdaki izni verin.
Mikrofon
+ 3DS mikrofon emülasyonu için aşağıdaki izni verin.
+ İzin reddedildi
+ Uygulama dosyasını seçmeyi atla?
+ Eğer bir dosya seçili değilse yazılımlar uygulama listesinde görünmeyecektir.
Yardım
+ Atla
+ İptal et
+ Kullanıcı Dosyası Seç
+ kullanıcı verileridizinini seçin.]]>
+ Hem Lime3DS hem de Azahar için ayarlanmış kullanıcı dizinleriniz var gibi görünüyor. Bunun nedeni muhtemelen Azahar\'a geçmiş olmanız ve sorulduğunda Lime3DS için kullanılandan farklı bir kullanıcı dizini seçmiş olmanızdır.\n\nBu, kayıtları veya diğer ayarları kaybettiğinizi düşünmenize neden olmuş olabilir - böyle bir şey olduysa özür dileriz. \n\nOrijinal Lime3DS kullanıcı dizininizi kullanmaya geri dönmek, Lime3DS\'deki ayarları ve oyun kayıtlarını geri yüklemek mi istersiniz; yoksa mevcut Azahar kullanıcı dizininizi korumak mı? \n\nSeçiminiz ne olursa olsun her iki dizin de silinmeyecektir ve Kullanıcı Klasörü Seç seçeneğini kullanarak aralarında serbestçe geçiş yapabilirsiniz.
+ Şimdiki Azahar Dizinini Koru
+ Eski Lime3DS Dizinini Kullan
Seç
+ Bu adımı geçemezsiniz
+ Bu adım Azahar\'ın çalışması için gereklidir. Lütfen devam etmek için bir dizin seçin.
+ Kayıtların ve diğer bilgilerin depolandığı kullanıcı verileridizininizdeki yazma izinlerini kaybettiniz. Bu durum bazı uygulama veya Android güncellemelerinden sonra meydana gelebilir. Devam edebilmeniz için lütfen izinleri yeniden kazanmak üzere dizini yeniden seçin.
Tema Ayarları
+ Azahar için tema tercihlerinizi yapılandırın.
Tema Ayarla
+
+ Uygulamaları Ara ve Filtrele
+ Uygulamaları Ara
+ Son oynanan
+ Son eklenen
+ Yüklü
+
+
+ Circle Pad
+ C-Stick
+ Kısayol tuşları
+ Tetik tuşları
+ Tetik tuşu
+ D-Pad
+ D-Pad (Eksen)
+ Bazı oyun kolları D-pad\'lerini bir eksen olarak atayamayabilir. Durum buysa D-Pad (butonlar) bölümünü kullanın.
+ D-pad (Buton)
+ Sadece D-Pad (Eksen) atamasında sorun yaşıyorsanız D-Pad\'inizi bunlara atayın.
Yukarı/Aşağı Eksen
Sol/Sağ Eksen
Yukarı
Aşağı
Sol
Sağ
-
- CPU JIT
+ Ata %1$s%2$s
+ Bir girdiye basın veya hareket ettirin.
+ Girdi Ataması
+ Bir girdiyi %1$s e atamak için basın veya hareket ettirin.
+ Joystick\'inizi yukarı veya aşağı kaydırın.
+ Joystick\'inizi sağa veya sola kaydırın.
+ HOME
+ Ekranları değiştir
+ Turbo
+ Bu kontrol bir oyun kolu analog çubuğuna veya D-pad eksenine bağlanmalıdır!
+ Bu kontrol bir oyun kolu düğmesine bağlı olmalıdır!
+ Turbo Hız
+ Turbo Hız Aktif
+ Turbo Hız Devre Dışı
+
+
+ Sistem Dosyaları
+ Sistem dosyaları yüklemek veya Home menüsünü başlatmak gibi sistem dosyası işlemlerini gerçekleştirin
+ Artic Kurulum Aracına Bağlan
+ Mevcut sistem dosyaları durumu toplanıyor, lütfen bekleyin...
+ Eski 3DS Kurulumu
+ Yeni 3DS Kurulumu
+ Kurulum mümkün.
+ Önce eski 3DS kurulumu gereklidir.
+ Kurulum zaten tamamlandı.
+ Kurulum hazırlanıyor, lütfen bekleyin...
+ HOME Menüsünü Aç
+ HOME menü uygulamalarını Uygulamalar listesinde göster
+ HOME menüsü açıldığında sistem kurulumunu başlat
+ HOME Menüsü
+
+
+ Butonlar
+ Buton
+
+
+ Emülasyon Ayarları
+ Kullanıcı adı
Yeni 3DS Modu
+ LLE Applet\'lerini kullan (eğer yüklüyse)
+ Çevrimiçi özellikler için gerekli LLE modüllerini etkinleştirin (yüklüyse)
+ Çevrimiçi çok oyunculu oyun, eShop erişimi vb. için gereken LLE modüllerini etkinleştirir.
+ Saat
+ Saat
+ Taklit edilen 3DS saatini cihazınızın saatini yansıtacak veya simüle edilmiş bir tarih ve saatte başlayacak şekilde ayarlayın.
+ Cihaz Saati
+ Simüle Edilmiş Saat
+ Saat “Simüle edilmiş saat” olarak ayarlanmışsa, bu başlanılan sabit tarih ve saati değiştirir.
+ Profil Ayarları
Bölge
Dil
+ Doğum günü
Ay
Gün
Ülke
+ Play Coin\'leri
+ Saat Başına Adımsayar Adımları
+ Adımsayar tarafından bildirilen saat başına adım sayısı. 0 ile 65,535 arasında değişir.
+ Konsol İD\'si
+ Konsol İD\'sini Yeniden Oluştur
+ Bu, mevcut sanal 3DS konsol kimliğinizi yenisiyle değiştirecektir. Mevcut sanal 3DS konsol kimliğiniz kurtarılamayacaktır. Bu, uygulamaların içinde beklenmedik etkilere neden olabilir. Eski bir konfigürasyon kaydı kullanıyorsanız bu işlem başarısız olabilir. Devam etmek istiyor musunuz?
+ MAC Adresi
+ MAC Adresini Yeniden Oluştur
+ Bu, mevcut MAC adresinizi yenisiyle değiştirecektir. MAC adresini kurulum aracını kullanarak gerçek konsolunuzdan aldıysanız bunu yapmanız önerilmez. Yine de devam mı?
+ 3GX Eklenti Yükleyici
+ 3GX eklentilerini eğer mevcutsa emüle edilmiş SD karttan yükler.
+ Uygulamaların Eklenti Yükleyici Durumunu Değiştirmesine İzin Verin
+ Homebrew uygulamalarının devre dışı olsa bile eklenti yükleyiciyi etkinleştirmesine izin verir.
+ Bölge Uyuşmazlık Uyarısı
+ Ülke ayarı emülasyon bölgesi için geçerli değil.
+ Ülke ayarı bağlı olan konsol için geçerli değil.
+
İç Kamera
+ Dış Sol Kamera
+ Dış Sağ Kamera
+ Kamera Resim Kaynağı
Kamera
Ön
- V-Sync\'i Etkinleştir
+ Geri
+
+ İşleyici
+ Grafik API\'ı
+ SPIR-V gölgelendirici oluşturmayı etkinleştir
+ Asenkron gölgeleme derlemesini etkinleştir
+ Oyun sırasında takılmayı azaltmak için gölgelendiricileri arka planda derler. Etkinleştirildiğinde geçici grafik hataları meydana gelebilir.
+ Doğrusal filtreleme
+ Oyun görsellerinin daha pürüzsüz görünmesini sağlayan doğrusal filtrelemeyi etkinleştirir.
+ Doku Filtresi
+ Dokulara bir filtre uygulayarak uygulamaların görsellerini geliştirir. Desteklenen filtreler Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale ve MMPX\'tir.
+ Oyun işleme iş parçacığını geciktir
+ GPU\'ya veri gönderirken oyun işleme iş parçacığını geciktirin. Dinamik kare hızlarına sahip (çok az sayıda) uygulamada performans sorunlarına yardımcı olur.
+ Gelişmiş\"
+ Doku Örnekleme
+ Oyunlar tarafından kullanılan örnekleme filtresini geçersiz kılar. Bu, yükseltme sırasında kötü davranan oyunlarla ilgili bazı durumlarda yararlı olabilir. Emin değilseniz, bunu Oyun Kontrollü olarak ayarlayın.
+ İsabetli Çoğaltma
+ Donanım gölgelendiricilerinde daha doğru çarpım kullanır, bu da bazı grafik hatalarını düzeltebilir. Etkinleştirildiğinde performans düşecektir.
+ Asenkron GPU emülasyonunu etkinleştir
+ GPU emülasyonunu asenkron olarak yapmak için ayrı bir iş parçacığı kullanır. Etkinleştirildiğinde performans artacaktır.
+ Hızı Sınırlandır
+ Etkinleştirildiğinde, emülasyon hızı normal hızın belirli bir yüzdesiyle sınırlandırılır. Devre dışı bırakılırsa, emülasyon hızı sınırlandırılmaz ve turbo hız kısayol tuşu çalışmaz.
+ Hız Sınırlandırma Yüzdesi
+ Emülasyon hızını sınırlamak için yüzdeyi belirtir. Varsayılan değer olan %100 ile emülasyon normal hız ile sınırlandırılacaktır. Daha yüksek veya daha düşük değerler hız sınırını artıracak veya azaltacaktır Etkinleştirildiğinde, emülasyon hızı normal hızın belirli bir yüzdesiyle sınırlandırılacaktır. Devre dışı bırakılırsa, emülasyon hızı sınırlandırılmaz ve turbo hız kısayol tuşu çalışmaz.
+ Turbo Hız Limiti
+ Turbo kısayolu aktfiken kullanılan emülasyon hız limiti.
+ İç Çözünürlük
+ Render için kullanılan çözünürlüğü belirtir. Yüksek çözünürlük görsel kaliteyi çok artıracaktır ancak performans açısından da oldukça ağırdır ve bazı uygulamalarda aksaklıklara neden olabilir.
+ Otomatik (Ekran Boyutu)
Doğal (400x240)
2x Doğal (800x480)
3x Doğal (1200x720)
@@ -47,15 +233,87 @@
8x Doğal (3200x1920)
9x Doğal (3600x2160)
10x Doğal (4000x2400)
+ Bu ayarın kapatılması emülasyon performansını önemli ölçüde düşürecektir! En iyi deneyim için bu ayarı etkin bırakmanız önerilir.
+ Uyarı: Bu ayarları değiştirmek emülasyonu yavaşlatacaktır
+ Stereoskopi
Stereoskopik 3B Modu
Derinlik
+ 3D kaydıracının değerini belirtir. Stereoskopik 3D etkinleştirildiğinde bu değer %0\'dan daha yüksek bir değere ayarlanmalıdır.\nNot: %100\'ün üzerindeki derinlik değerleri gerçek donanımda mümkün değildir ve grafik sorunlarına neden olabilir
+ Sağ Göz Render\'ını Devre Dışı Bırak
+ Bazı uygulamalarda performansı büyük ölçüde artırır, ancak diğerlerinde titremeye neden olabilir.
+ Karton VR
+ Karton Ekran Boyutu
+ Ekranı orijinal boyutunun belirli bir yüzdesine ölçeklendirir.
+ Yatay kaydırma
+ Ekranları yatay olarak kaydırmak için boş alanın yüzdesini belirtir. Pozitif değerler iki gözü ortaya yaklaştırırken, negatif değerler uzaklaştırır.
+ Dikey kaydırma
+ Ekranları dikey olarak kaydırmak için boş alanın yüzdesini belirtir. Pozitif değerler iki gözü aşağıya doğru hareket ettirirken, negatif değerler yukarıya doğru hareket ettirir.
+ Shader JIT
+ Disk Gölgelendirici Önbelleği
+ Oluşturulan gölgelendiricileri diske depolayarak ve yükleyerek takılmayı azaltın. Donanım Gölgelendiricisi Etkinleştirilmeden kullanılamaz.
+ Özel Dokular
+ Özel Dokuları Önceden Yükle
+ Tüm özel dokuları belleğe yükler. Bu özellik çok fazla bellek kullanabilir.
+ Asenkron Özel Doku Yükleme
+
+ Ses düzeyi
+ Ses Gerdirme
+ Gerçek zamanlı sesi etkinleştir
+ Emülasyon kare hızındaki düşüşleri hesaba katmak için ses çalma hızını ölçeklendirir. Bu, oyun kare hızı düşük olsa bile sesin tam hızda çalınacağı anlamına gelir. Ses senkronizasyon sorunlarına neden olabilir.
+ Ses Giriş Cihazı
+ Ses Çıkış Modu
+
+
+ CPU JIT
+ CPU emülasyonu için Just-in-Time (JIT) derleyicisini kullanır. Etkinleştirildiğinde, oyun performansı önemli ölçüde artacaktır.
+ Donanımsal Shader\'ı Etkinleştir
+ 3DS shader\'larının emülasyonu için donanımı kullanır. Etkinleştirildiğinde oyun performansı önemli ölçüde artacaktır.
+ CPU Saat Hızı
+ V-Sync\'i Etkinleştir
+ Oyun kare hızını cihazınızın yenileme hızına senkronize eder.
+ LLE modülleriyle başlamayı geciktir
+ LLE modülleri etkinken uygulamanın başlamasını geciktirir
+
+ Ekran Yönelimi
Otomatik
+ Portre
+ Ters Portre
+
+
+ Temizle
Varsayılan
+ Ayarlar kaydedildi
+ %1$siçin ayarlar kaydedildi
+ %1$s.ini\'yi kaydederken hata oluştu%2$s
+ Kaydediliyor...
Yükleniyor...
+ Sonraki
Geri
+ Daha Fazla Öğren
+ Kapat
+ Varsayılanlara Sıfırla
Varsayılan
+ Kapalı
+ Yükle
Sil
+ Tüm Ayarlar Sıfırlansın Mı?
+ Tüm gelişmiş ayarlar varsayılanlara sıfırlanacaktır. Bu işlem geri alınamaz.
+ Ayarları sıfırla
+ Gerçek Zamanlı Saat tarihini seç
+ Gerçek Zamanlı Saat zamanını seç
+ Bu ayarı varsayılan değerlerine döndürmek ister misiniz?
+ Bunu şu an düzenleyemezsin
+ Ayar devre dışı bırakıldı
+ Bu ayar, başka bir ayarın uygun değer olmaması nedeniyle şu anda devre dışı bırakılmıştır.
+ Bu seçenek oyun devam ederken değiştirilemez.
Otomatik Seç
+ Başlat
+ İptal ediliyor...
+ Önemli
+ Tekrar gösterme
+
+
+ Oyun Dosyası Seç
Özellikler
@@ -66,46 +324,181 @@
Genel
Sistem
Kamera
+ Oyun Kolu
+ Grafikler
Ses
+ Hata Ayıklama
Tema ve Renk
+ Düzen
+
+
+ ROM\'unuz Şifreli
+ Geçersiz ROM formatı
+ ROM dosyası mevcut değil
+ Başlatılabilir oyun yok!
+
+
+ Menüye erişmek için Geri\'ye basın
+ Durumu Kaydet
+ Durumu Yükle
+ FPS\'i Göster
+ Dokunsal Geri Bildirim
+ Kontrolleri Yapılandır
+ Düzeni Değiştir
+ Bitti
+ Ölçeği Ayarla
Tümünü Sıfırla
Görünürlüğü Ayarla
+ D-Pad kayması
Ayarları Aç
Hileleri Aç
+ Yatay Ekran Düzeni
+ Dikey Ekran Düzeni
+ Büyük Ekran
Portre
Tek Ekran
+ Yan Yana Ekranlar
+ Hibrit Ekranlar
Orijinal
Varsayılan
+ Özel Düzen
+ Küçük Ekran Konumu
+ Büyük Ekran Düzeninde küçük ekran büyük ekrana kıyasla nerede olmalı?
Sağ Üst
+ Orta Sağ
+ Sağ Alt (varsayılan)
Sol Üst
+ Orta Sol
Sol Alt
+ Yukarı
+ Aşağı
+ Büyük Ekran Oranı
+ Büyük Ekran düzeninde büyük ekran küçük ekrandan kaç kat daha büyük olsun?
+ Ayarlarda Özel Düzeni Değiştirin
+ Özel Yatay Düzen
+ Özel Dikey Düzen
+ Üst Ekran
+ Alt Ekran
+ X-Konumu
+ Y-Konumu
Genişlik
Yükseklik
+ Ekranları Değiştir
+ Oyunu Kapat
+ Çeşitli
+ Artic Base Sunucusundayken Artic Oyun Kolunu kullan
+ Mevcut oyunu kapatmak istediğinizden emin misiniz?
+ Amiibo
Yükle
Kaldır
Amiibo Dosyası Seç
+ Amiibo Yüklenirken Hata Oluştu
+ Belirtilen Amiibo dosyası yüklenirken bir hata oluştu. Lütfen dosyanın doğru olup olmadığını kontrol edin.
Emülasyonu Duraklat
Emülasyonu Devam Ettir
+ Emülatörün çalışması için harici depolama alanına yazma erişimine izin vermeniz gerekir
+ Ayarlar Yükleniyor...
+
+ Azahar\'ı kullanmak için harici depolama alanının kullanılabilir olması gerekir
+
Bu Dizini Seç
+ Hiçbir dosya bulunamadı veya henüz hiçbir oyun dizini seçilmedi.
+
+ Bunu tekrar gösterme
Dizin aranıyor: %s
+ Verileri Taşı
+ Veriler Taşınıyor...
+ Dosya kopyalanıyor: %s
+ Kopyalama Tamamlandı
+ Kayıt Durumları
+ Uyarı: Kayıt durumları uygulama içi kayıtları için bir vekil değildir ve güvenilir olmaları için tasarlanmamıştır. \n\nKullanım riski size aittir!
+
+
+ Sanal Klavye
Unuttum
+ Metin uzunluğu uygun değil (%d karakter olmalı)
+ Metin fazla uzun (%d karakterden daha uzun olmamalı)
+ Boş girdiye izin verilmiyor.
+ Boş girdiye izin verilmiyor.
+ Geçersiz girdi
+
Mii Seçici
Standart Mii
+
+ Resim Seçin
Kamera
+ Azahar\'ın 3DS\'in kameralarını taklit etmek için kameranıza erişmesi gerekir.\n\nAlternatif olarak, Kamera Ayarlarında “Görüntü Kaynağı ”nı “Hareketsiz Görüntü” olarak da ayarlayabilirsiniz.
+
Mikrofon
+ Azahar\'ın 3DS\'in mikrofonunu taklit etmek için mikrofonunuza erişmesi gerekir.\n\nAlternatif olarak, Ses Ayarları\'nda “Ses Giriş Aygıtı ”nı da değiştirebilirsiniz.
+
+
+ İptal et
+ Devam et
Sistem Arşivi Bulunamadı
+ %seksik. Lütfen sistem arşivlerinizi indirin.\nEmülasyona devam etmek çökmelere ve hatalara neden olabilir.
+ Kurulum Başarısız. CIA dosyası bulunamadı.
Bir sistem arşivi
+ Kaydetme/yükleme Hatası
+ Ölümcül Hata
+ Ölümcül bir hata oluştu. Ayrıntılar için log\'u kontrol edin.\nEmülasyona devam etmek çökmelere ve hatalara neden olabilir.
+ Geçersiz bölge
+ Desteklenmeyen şifreli uygulama
+
+
+ Gölgelendiriciler Hazırlanıyor
+ Gölgelendiriciler Oluşturuluyor
+
+
+ Oyna
+ Kısayol
+ Uygulamayı Sil
+ Siliniyor...
+ Kayıt Verileri Klasörünü Aç
+ Uygulama Dosyasını Aç
+ Mod Dosyasını Aç
+ Dokular Klasörünü Aç
+ DLC Klasörünü Aç
+ Güncellemeler Dosyasını Aç
+ Ekstra Klasörünü Aç
+ DLC\'leri Sil
+ Güncellemeleri Sil
+
Hileler
Hile Ekle
+ İsim
Notlar
+ Kod
Düzenle
Sil
+ \"%1$s\"i silmek istediğinizden emin misiniz?
+ İsim boş olamaz
Kod boş olamaz
+ %1$d. satırda hata
+
+
+
+ - %ddosyası indiriliyor. Daha fazla detay için bildirime bakın.
+ - %ddosyaları indiriliyor. Daha fazla detay için bildirime bakın.
+
+ CIA Kurulumu sırasında Azahar bildirimleri
+ CİA Yükleniyor
+ Yükleniyor %1$s(%2$d/%3$d)
+ CİA başarıyla yüklendi
+ CİA yüklemesi başarısız oldu
\"%s\" başarıyla yüklendi
+ \"%s\" yüklemesi durduruldu.\nDaha fazla detay için lütfen log a bakın.
+ \"%s\" geçerli bir CİA değil
+ \"%s\" Azahar\'la kullanılmadan önce şifresi çözülmelidir. \n Gerçek bir 3DS gereklidir.
+ \"%s\" yüklenirken bilinmeyen bir hata meydana geldi.\n Daha fazla detay için lütfen log a bakın
+
+
+ %1$s%2$s
+ Bit
B
KB
MB
@@ -116,46 +509,112 @@
Tema Modu
+ Sistemle Aynı
Açık
Koyu
+ Uygulama genelinde işletim sisteminin renk temasını kullanın (Etkinleştirildiğinde “Tema Rengi” ayarını geçersiz kılar)
+
Tema Rengi
-
- Cihaz Saati
+ Uygulama menülerinin renk temasını değiştirin
+
+
+ Siyah Arkaplanlar
+ Koyu temayı kullanırken siyah arka plan uygulayın.
+
+
+ JPN
+ ABD
+ AVR
+ AUS
+ CHN
+ KOR
+ TWN
+
+
+ Japonca (日本語)
İngilizce
+ Fransızca (Français)
Almanca (Deutsch)
İtalyanca (Italiano)
İspanyolca (Español)
+ Basitleştirilmiş Çince (简体中文)
+ Korece (한국어)
+ Felemenkçe (Hollanda)
+ Portekizce (Português)
+ Rusça (Русский)
+ Geleneksel Çince (正體中文)
+
Boş
+ Sabit Görüntü
Cihaz Kamerası
+
+ Herhangi Bir Ön Kamera
+ Herhangi Bir Arka Kamera
+
Yatay
Dikey
Ters
+
+ Statik Ses
+ Gerçek Cihaz (cubeb)
+ Gerçek Cihaz (OpenAL)
+
+
+ Yan Yana
+ Ters Yan Yana
+ Anaglif
+
+ OpenGLES
Vulkan
+
+ Anime4K
Bikübik
+ ScaleForce
xBRZ
MMPX
+
+ Oyun Kontrollü
+ Lineer
+
+
+ Mono
+ Stereo
+ Üç boyutlu
+
Japonya
Anguilla
+ Antigua ve Barbuda
Arjantin
+ Aruba
Bahamalar
+ Barbados
+ Belize
Bolivya
Brezilya
+ Britanya Virjin Adaları
Kanada
+ Cayman Adaları
Şili
Kolombiya
Kosta Rika
+ Dominika
+ Dominik Cumhuriyeti
Ekvador
El Salvador
Fransız Guyanası
+ Grenada
+ Guadelup
+ Guatemala
+ Guyana
Haiti
Honduras
Jamaika
@@ -167,10 +626,14 @@
Paraguay
Peru
Saint Kitts ve Nevis
+ Saint Lucia
+ Saint Vincent ve Grenadinler
Surinam
+ Trinidad ve Tobago
Turks ve Caicos Adaları
Amerika Birleşik Devletleri
Uruguay
+ ABD Virgin Adaları
Venezuela
Arnavutluk
Avustralya
@@ -193,6 +656,7 @@
İrlanda
İtalya
Letonya
+ Lesotho
Lihtenştayn
Litvanya
Lüksemburg
@@ -223,12 +687,17 @@
Azerbaycan
Moritanya
Mali
+ Nijerya
+ Çad
Sudan
Eritre
Cibuti
+ Somali
Andorra
Cebelitarık
+ Guernsey
Man Adası
+ Jersey
Monako
Tayvan
Güney Kore
@@ -251,6 +720,7 @@
Bahreyn
Ürdün
San Marino
+ Vatikan
Bermuda
@@ -267,6 +737,18 @@
Kasım
Aralık
- Kaydediliyor...
- Yükleniyor...
-
+
+ Artic Base sunucusu ile iletişim kurulamadı. Emülasyon durdurulacaktır.
+ Artic Base
+ Artic Base sunucusu kullanan gerçek bir konsola bağlan
+ Artic Base\'e Bağlan
+ Artic Base sunucu adresi gir
+
+
+ Hızlı Kayıt
+ Hızlı Kayıt
+ Hızlı Yükle
+ Hızlı Kayıt - %1$tF %1$tR
+ Hiçbir Hızlı Kayıt mevcut değil.
+
+
diff --git a/src/android/app/src/main/res/values-b+zh+CN/strings.xml b/src/android/app/src/main/res/values-b+zh+CN/strings.xml
index a0430515a..a3e85a3b8 100644
--- a/src/android/app/src/main/res/values-b+zh+CN/strings.xml
+++ b/src/android/app/src/main/res/values-b+zh+CN/strings.xml
@@ -5,10 +5,6 @@
Azahar 3DS 模拟器通知
Azahar 正在运行
接下来,您需要选择一个应用文件夹。Azahar 将显示所选文件夹中的所有 3DS ROM。\n\nCIA ROM、更新和 DLC 需要分别进行安装,具体为点击文件夹图标并选择“安装 CIA”。
- 开始
- 取消中…
- 重要提示
- 不再显示
设置
@@ -83,9 +79,13 @@
取消
选择用户文件夹
用户数据目录。]]>
+ 您似乎同时为 Lime3DS 和 Azahar 设置了用户目录。这可能是因为您升级到了 Azahar,并在系统提示时选择了与 Lime3DS 不同的用户目录。\n\n这可能导致您误以为丢失了存档或其他设置 - 如果发生这种情况,我们深表歉意。\n\n您想恢复原来的 Lime3DS 用户目录、Lime3DS 设置和游戏存档,还是保持当前的 Azahar 用户目录?\n\n无论您选择哪种方式,这两个目录都不会被删除,您可以使用“选择用户文件夹”选项在它们之间自由切换。
+ 保持当前的 Azahar 目录
+ 使用先前的 Lime3DS 目录
选择
此步骤不可跳过
此步骤是 Azahar 正常运行所必需的。请选择一个目录,然后才可继续。
+ 您已失去对用户数据目录的写入权限,该目录用于存储存档和其他信息数据。某些应用或 Android 更新后可能会出现这种情况。请重新选择该目录以重新获得权限,才能继续操作。
主题设置
配置您的 Azahar 主题偏好。
设置主题
@@ -122,15 +122,21 @@
向左或向右轻推您的摇杆。
HOME
交换屏幕
+ 加速
此操作只能绑定到游戏手柄的摇杆或十字方向键上!
此操作只能绑定到游戏手柄的按键上!
+ 加速
+ 加速已启用
+ 加速已禁用
系统文件
执行系统文件操作,如安装系统文件或启动 HOME 菜单
连接到 Artic 设置工具
- Azahar Artic 设置工具获取此类文件。
注意:- 此操作会将掌机独有文件安装到 Azahar,
执行安装过程后请勿共享您的用户或 nand 文件夹! - 新 3DS 设置需要先进行老 3DS 设置后才能运作。
- 无论运行设置工具的掌机型号如何,这两种设置模式均可运作。
]]>
+ Azahar Artic 设置工具进行设置。
注意:- 此操作会将掌机独有数据安装到 Azahar,执行设置过程后请勿共享您的用户或 nand 文件夹!
- 在执行设置过程时,Azahar 将关联到运行设置工具的掌机。您可以随时从模拟器配置菜单的“系统”选项卡中取消关联掌机。
- 设置系统文件后,请勿同时使用 Azahar 和 3DS 掌机联网,因为这可能会导致问题。
- 新 3DS 设置需要先进行老 3DS 设置才能运作(建议两种设置模式都执行)。
- 无论运行设置工具的掌机型号如何,两种设置模式均可运作。
]]>
正在获取当前系统文件状态,请稍候...
+ 取消关联掌机独有数据
+ - 您的 OTP、SecureInfo 和 LocalFriendCodeSeed 文件将从 Azahar 中删除。
- 您的好友列表将被重置,并且注销 NNID/PNID 帐户。
- 通过 Azahar 获得的系统文件和 eshop 数字版应用将变得无法访问,直到再次关联同一掌机(保存的数据不会丢失)。
是否继续?]]>
老 3DS 设置
新 3DS 设置
可以进行设置。
@@ -147,20 +153,20 @@
按键
按键
-
- CPU JIT
- 使用即时编译 (JIT) 进行 CPU 仿真。启用后,游戏性能将显著提高。
- 系统时钟类型
- 将模拟 3DS 时钟设为映射设备的实际时钟或是使用自定义的时间和日期。
- CPU 时钟频率
-
+ 模拟设置
用户名
New 3DS 模式
使用 LLE 小程序 (如果已安装)
+ 启用在线功能所需的 LLE 模块(如果已安装)
+ 启用在线多人游戏、eShop 访问等所需的 LLE 模块。
设备时钟
- 模拟时钟
- 如果将“系统时钟类型”设置为“模拟时钟”,可以修改时钟的日期和时间。
+ 系统时钟类型
+ 将模拟 3DS 时钟设为映射设备的实际时钟或是使用自定义的时间和日期。
+ 设备时钟
+ 模拟时钟
+ 如果将“系统时钟类型”设置为“模拟时钟”,可以修改时钟的日期和时间。
+ 资料设置
区域
语言
生日
@@ -173,10 +179,16 @@
设备 ID
重新生成设备 ID
这将使用一个新的虚拟 3DS 掌机 ID 取代您当前的虚拟 3DS 掌机 ID。您当前的虚拟 3DS 掌机 ID 将无法恢复。对应用内部可能会产生意外影响。如果您使用一个过时的配置存档则可能会失败。是否继续?
+ MAC 地址
+ 重新生成 MAC 地址
+ 这将用新 MAC 地址替换您当前的 MAC 地址。如果您使用设置工具从真实掌机获取 MAC 地址,则不建议执行此操作。是否继续?
3GX 插件加载器
当插件可用时,从模拟 SD 卡加载 3GX 插件。
允许应用更改插件加载器状态
允许自制程序启用插件加载器。
+ 区域不匹配警告
+ 此国家/地区设置对于所选择的模拟区域无效。
+ 此国家/地区设置对于当前关联的掌机无效。
内置摄像头
@@ -198,26 +210,30 @@
使用 SPIR-V 而不是 GLSL 来模拟 PICA 的着色器
启用异步着色器编译
在后台编译着色器以减少卡顿。可能出现短暂的图形故障
- 调试渲染器
- 记录更多与图形相关的调试信息。启用后,游戏性能将显著降低。
- 启用垂直同步
- 将游戏帧率与设备的屏幕刷新率同步。
线性过滤
开启后,游戏视觉效果会更加平滑。
纹理滤镜
通过对纹理使用滤镜来增强应用的视觉效果。支持的滤镜包括 Anime4K Ultrafast、Bicubic、ScaleForce、xBRZ freescale 和 MMPX。
- 启用硬件着色器
- 使用硬件模拟 3DS 着色器。启用后,游戏性能将显著提高。
+ 延迟游戏渲染线程
+ 在游戏渲染线程向 GPU 提交数据时延迟线程。有助于解决(极少数)具有动态帧率应用的性能问题。
+ 高级选项\"
+ 纹理采样
+ 覆盖游戏所使用的采样过滤器。这在某些情况下提升表现不佳的游戏画质时可能很有用。如果不确定,请将其设置为“由游戏控制”
精确乘法运算
在硬件着色器中使用更加精确的乘法运算,这可能会修复一些图形错误。启用后,性能将有所降低。
启用异步 GPU 模拟
使用一个单独线程异步模拟 GPU 。启用后,游戏性能将有所提高。
运行速度限制
- 启用时,运行速度将被限制为正常速度的指定百分比。
+ 启用后,模拟速度将被限制为正常速度的指定百分比。如果禁用,模拟速度则不受限制,并且加速热键将不起作用。
限制运行速度百分比
指定限制运行速度的百分比。默认情况下,100% 将限制为正常运行速度。较高或较低的值将增加或降低运行速度。
+ 加速限制
+ 加速热键激活时使用的模拟速度限制。
+ 扩展到裁剪区域
+ 扩大显示区域以包含裁剪(或切口)区域。
内部分辨率
指定渲染使用的分辨率。高分辨率将大大提高视觉质量,但也会对性能造成很大影响,并可能导致某些应用出现故障。
+ 自动(屏幕大小)
原生(400x240)
2 倍(800x480)
3 倍(1200x720)
@@ -233,7 +249,9 @@
画面立体
立体 3D 模式
画面深度
- 指定 3D 画面深度的值。启用立体 3D 模式时,应将其设置为高于 0% 的值。
+ 指定 3D 滑块按钮的值。启用立体 3D 模式时,应将其设置为高于 0% 的值。\n注意:实机硬件上不可能出现超过 100% 的深度值,并且可能会导致图形问题
+ 禁用右眼渲染
+ 极大地提高某些应用的性能,但可能会导致其他应用出现闪烁。
Cardboard VR
Cardboard 屏幕尺寸
将屏幕缩放至其原始大小的指定百分比。
@@ -263,6 +281,23 @@
音频输入设备
声音输出模式
+
+ CPU JIT
+ 使用即时编译 (JIT) 进行 CPU 仿真。启用后,游戏性能将显著提高。
+ 启用硬件着色器
+ 使用硬件模拟 3DS 着色器。启用后,游戏性能将显著提高。
+ CPU 时钟频率
+ 启用垂直同步
+ 将游戏帧率与设备的屏幕刷新率同步。
+ 调试渲染器
+ 记录更多与图形相关的调试信息。启用后,游戏性能将显著降低。
+ 刷新每条消息的日志输出
+ 立即将调试日志提交到文件。如果 Azahar 崩溃并且日志输出被切断,请使用此选项。
+ 使用 LLE 模块延迟启动
+ 当 LLE 模块启用时延迟应用的启动。
+ 确定性异步操作
+ 使异步操作在调试时具有确定性。启用此功能可能会导致停滞。
+
屏幕方向
自动
@@ -277,13 +312,14 @@
已保存的设置
已将设置保存于 %1$s 中
保存 %1$s.ini 失败:%2$s
+ 正在保存...
加载中…
下一步
上一步
了解更多
关闭
恢复默认
- 请按照指南以转储您的<a href=https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/>游戏卡带</a>或<a href=https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/>已安装的游戏</a>。
+ 游戏卡带或已安装的应用。]]>
默认
无
自动
@@ -297,8 +333,14 @@
选择时间
您要将此设置项重置为默认值吗?
您现在不能编辑此项
+ 设置已禁用
+ 由于另一个设置不是合适的值,此设置当前已被禁用。
在游戏运行时此项不能更改。
自动选择
+ 开始
+ 取消中…
+ 重要提示
+ 不再显示
选择游戏目录
@@ -366,6 +408,8 @@
左下
上面
下面
+ 屏幕间隔
+ 所有双屏模式下屏幕之间的间隔。以像素为单位,相对于上屏的 240 像素高度进行测量。
大屏幕占比
“大屏幕”布局中大屏幕比小屏幕大多少倍?
在设置中调整自定义布局
@@ -383,6 +427,9 @@
显示虚拟按键
关闭游戏
暂停/继续
+ 杂项
+ 连接到 Artic Base 服务器时使用 Artic 控制器
+ 连接到 Artic Base 服务器时使用其提供的控制器,而不是配置的输入设备。
您确定要关闭当前的游戏吗?
Amiibo
加载
@@ -446,6 +493,9 @@
保存/读取出现错误
致命错误
发生致命错误。请查阅日志获取相关信息。\n继续模拟可能会导致错误和崩溃。
+ 无效的地区
+ 不支持的加密应用
+
正在准备着色器
正在构建着色器
@@ -453,6 +503,17 @@
开始游戏
快捷方式
+ 卸载应用
+ 正在卸载...
+ 打开存档数据文件夹
+ 打开应用文件夹
+ 打开模组文件夹
+ 打开纹理文件夹
+ 打开 DLC 文件夹
+ 打开更新文件夹
+ 打开额外数据文件夹
+ 卸载 DLC
+ 卸载更新
金手指
@@ -473,6 +534,7 @@
CIA 安装期间的 Azahar 通知
正在安装 CIA 文件
+ 正在安装 %1$s (%2$d/%3$d)
CIA 文件安装成功
CIA 文件安装失败
“%s”已安装成功
@@ -512,10 +574,6 @@
黑色背景
使用深色主题时,套用黑色背景。
-
- 设备时钟
- 模拟时钟
-
日本(JPN)
北美(USA)
@@ -572,11 +630,15 @@
Anime4K
双三线过滤
- 最近邻
强制缩放
xBRZ
MMPX
+
+ 由游戏控制
+ 最近邻
+ 线性过滤
+
单声道
立体声
@@ -737,33 +799,12 @@
连接到运行 Artic Base 服务器的真实主机
连接到 Artic Base
输入 Arctic Base 服务器地址
- 延迟游戏渲染线程
- 在游戏渲染线程向 GPU 提交数据时延迟线程。有助于解决(极少数)具有动态帧率应用的性能问题。
快速保存
快速保存
快速加载
快速保存 - %1$tF %1$tR
- 正在保存...
- 正在加载...
没有可用的快速保存。
- 杂项
- 连接到 Artic Base 服务器时使用 Artic 控制器
- 连接到 Artic Base 服务器时使用其提供的控制器,而不是配置的输入设备。
- 刷新每条消息的日志输出
- 立即将调试日志提交到文件。如果 Azahar 崩溃并且日志输出被切断,请使用此选项。
- 禁用右眼渲染
- 极大地提高某些应用的性能,但可能会导致其他应用出现闪烁。
- 使用 LLE 模块延迟启动
- 当 LLE 模块启用时延迟应用的启动。
- 确定性异步操作
- 使异步操作在调试时具有确定性。启用此功能可能会导致停滞。
- 启用在线功能所需的 LLE 模块(如果已安装)
- 启用在线多人游戏、eShop 访问等所需的 LLE 模块。
- 模拟设置
- 资料设置
- MAC 地址
- 重新生成 MAC 地址
- 这将用新 MAC 地址替换您当前的 MAC 地址。如果您使用设置工具从真实掌机获取 MAC 地址,则不建议执行此操作。是否继续?
+
diff --git a/src/android/app/src/main/res/values-de/strings.xml b/src/android/app/src/main/res/values-de/strings.xml
index 445ded7bd..0ed3b0daa 100644
--- a/src/android/app/src/main/res/values-de/strings.xml
+++ b/src/android/app/src/main/res/values-de/strings.xml
@@ -5,8 +5,7 @@
Azahar 3DS-Emulator-Benachrichtigungen
Azahar läuft
Als Nächstes müssen Sie einen Anwendungsordner auswählen. Azahar zeigt alle 3DS-ROMs im ausgewählten Ordner in der App an.\n\nCIA-ROMs, Updates und DLC müssen separat installiert werden, indem Sie auf das Ordnersymbol klicken und CIA installieren auswählen
- Start
- Wird abgebrochen...
+
Einstellungen
Optionen
@@ -119,7 +118,6 @@
Bildschirme tauschen
Diese Eingabe muss an einen Analogstick oder eine Steuerkreuz-Achse gebunden sein!
Diese Eingabe muss an einen Gamepad-Knopf gebunden sein!
-
HOME-Menü starten
Zeige Home Menü Apps in der Anwendungs Liste
System-Setup ausführen, wenn das HOME-Menü aufgerufen wird
@@ -129,20 +127,14 @@
Knöpfe
Knopf
-
- CPU JIT
- Benutzt den Just-in-Time (JIT) Compiler für die CPU-Emulation. Wenn aktiviert wird die Spielleistung stark verbessert.
- Uhr
- Du kannst die 3DS-Uhr so einstellen, dass sie entweder die Systemzeit deines Gerätes widerspiegelt, oder dir eine eigene Zeit aussuchen.
- CPU-Takt-Rate
-
-
Nutzername
New 3DS-Modus
Nutze LLE-Applets (sofern installiert)
Uhr
- Zeitverschiebung
- Falls die Systemuhr auf „Simulierte Uhr“ gesetzt ist, verschiebt dies die Ursprungszeit und das Ursprungsdatum, auf die die Uhr eingestellt war dementsprechend.
+ Uhr
+ Du kannst die 3DS-Uhr so einstellen, dass sie entweder die Systemzeit deines Gerätes widerspiegelt, oder dir eine eigene Zeit aussuchen.
+ Systemuhr
+ Simulierte Uhr
Region
Sprache
Geburtstag
@@ -158,7 +150,6 @@
Lade 3GX Plugins von der emulierten SD-Karte, wenn sie verfügbar sind.
Erlaubt Anwendungen den Plugin-Lader-Zustand zu ändern
Erlaubt es Homebrew-Anwendungen den Plugin-Lader zu aktivieren, auch wenn es sonst deaktiviert ist.
-
Innenkamera
Außenkamera Links
@@ -179,22 +170,17 @@
Gibt den Fragment-Shader aus, der zur Emulation von PICA unter Verwendung von SPIR-V statt GLSL verwendet wird.
Asynchrone GPU-Emulation aktivieren
Kompiliere Shader im Hintergrund, um das Stottern des Spiels zu reduzieren. Dadurch kann es zu temporären grafischen Fehlern während des Spielens kommen.
- Debug-Renderer
- Zusätzliche grafisch spezifische Debuginformationen werden protokolliert. Wenn dies aktiviert ist, ist die Leistung des Spiels minimal reduziert.
- V-Sync aktivieren
- Synchronisiert die Bildrate des Spiels mit der Bildwiederholrate des Geräts.
Lineare Filterung
Aktiviert lineare Filterung, welche die Spieltexturen glättet.
Texturfilter
Verbessert die Optik von Anwendungen durch Anwenden eines Filters auf Texturen. Die unterstützten Filter sind Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale und MMPX.
- Hardware Shader aktivieren
- Benutzt Hardware, um die 3DS-Shader zu emulieren. Wenn aktiviert, wird die Spielleistung stark verbessert.
+ Game-Render-Thread verzögern
+ Verzögert den Render-Thread des Spiels, wenn er Daten an die GPU sendet. Hilft bei Leistungsproblemen in den (sehr wenigen) Anwendungen mit dynamischen Frameraten.
Genaue Multiplikation
Benutzt genauere Multiplikation in Hardware-Shadern, welche einige Grafikbugs fixen kann. Wenn aktiviert, ist die Leistung reduziert.
Asynchrone GPU-Emulation aktivieren
Verwendet einen separaten Thread, um die GPU asynchron zu emulieren. Wenn aktiviert, wird die Leistung verbessert.
Höchstgeschwindigkeit
- Wenn aktiviert, wird die Emulationsgeschwindigkeit auf einen angegebenen Prozentsatz der normalen Geschwindigkeit begrenzt.
Höchstgeschwindigkeit in Prozent
Gibt den Prozentsatz zur Begrenzung der Emulationsgeschwindigkeit an. Mit der Voreinstellung von 100% wird die Emulation auf normale Geschwindigkeit begrenzt. Höhere oder niedrigere Werte erhöhen oder verringern die Geschwindigkeitsbeschränkung.
Interne Auflösung
@@ -214,7 +200,8 @@
Stereoskopie
Stereoskopischer 3D-Modus
Tiefe
- Gibt den Wert des 3D-Schiebereglers an. Dieser Wert sollte auf mehr als 0 % eingestellt werden, wenn Stereoskopisches 3D aktiviert ist.
+ Rendering für das rechte Auge deaktivieren
+ Verbessert die Leistung in einigen Anwendungen erheblich, kann in anderen jedoch zu Flackern führen.
Karton-VR
Karton-Bildschirmgröße
Skaliert den Bildschirm auf einen Prozentsatz seiner Originalgröße.
@@ -244,6 +231,17 @@
Audioeingabegerät
Tonausgabemodus
+
+ CPU JIT
+ Benutzt den Just-in-Time (JIT) Compiler für die CPU-Emulation. Wenn aktiviert wird die Spielleistung stark verbessert.
+ Hardware Shader aktivieren
+ Benutzt Hardware, um die 3DS-Shader zu emulieren. Wenn aktiviert, wird die Spielleistung stark verbessert.
+ CPU-Takt-Rate
+ V-Sync aktivieren
+ Synchronisiert die Bildrate des Spiels mit der Bildwiederholrate des Geräts.
+ Debug-Renderer
+ Zusätzliche grafisch spezifische Debuginformationen werden protokolliert. Wenn dies aktiviert ist, ist die Leistung des Spiels minimal reduziert.
+ Protokollausgabe bei jeder Nachricht
Bildschirmausrichtung
Automatisch
@@ -280,7 +278,8 @@
Du kannst das nicht bearbeiten
Diese Einstellung kann nicht geändert werden, solange ein Spiel läuft.
Automatisch auswählen
-
+ Start
+ Wird abgebrochen...
Spieleordner auswählen
@@ -364,6 +363,8 @@
Overlay anzeigen
Spiel schließen
Pause umschalten
+ Weiteres
+ Verwende den Artic Controller, wenn eine Verbindung zum Artic Base Server besteht
Möchtest du das Spiel wirklich schließen?
Amiibo
Laden
@@ -432,7 +433,6 @@
Spielen
Verknüpfung
-
Cheats
Cheat hinzufügen
@@ -490,10 +490,6 @@
Schwarzer Hintergrund
Wenn das dunkle Design aktiviert ist, wird der Hintergrund tiefschwarz dargestellt.
-
- Systemuhr
- Simulierte Uhr
-
JPN
USA
@@ -550,11 +546,11 @@
Anime4K
Bikubisch
- Nearest-Neighbor
ScaleForce
xBRZ
MMPX
+ Nearest-Neighbor
Mono
Stereo
@@ -715,20 +711,12 @@
Verbinde dich mit einer echten Konsole, die über Artic-Base läuft.
Verbinde dich mit Artic-Base
Gib die Artic-Base-Serveradresse ein
- Game-Render-Thread verzögern
- Verzögert den Render-Thread des Spiels, wenn er Daten an die GPU sendet. Hilft bei Leistungsproblemen in den (sehr wenigen) Anwendungen mit dynamischen Frameraten.
Schnellspeichern
Schnellspeichern
Schnellladen
Schnellspeichern - %1$tF %1$tR
- Speichervorgang...
- Ladevorgang...
Kein Schnellspeicher vorhanden.
- Weiteres
- Verwende den Artic Controller, wenn eine Verbindung zum Artic Base Server besteht
- Protokollausgabe bei jeder Nachricht
- Rendering für das rechte Auge deaktivieren
- Verbessert die Leistung in einigen Anwendungen erheblich, kann in anderen jedoch zu Flackern führen.
-
+
+
diff --git a/src/android/app/src/main/res/values-el/strings.xml b/src/android/app/src/main/res/values-el/strings.xml
index 4dedbd9ee..de2bd17a2 100644
--- a/src/android/app/src/main/res/values-el/strings.xml
+++ b/src/android/app/src/main/res/values-el/strings.xml
@@ -1,4 +1,9 @@
+ Εγκατάσταση αρχείου CIA
+ Σχετικά
+ Εγκατάσταση CIA
+ Εγκατάσταση
+ Εγκαταστάθηκε %s
diff --git a/src/android/app/src/main/res/values-fi/strings.xml b/src/android/app/src/main/res/values-fi/strings.xml
index 89a788441..a44d0d32a 100644
--- a/src/android/app/src/main/res/values-fi/strings.xml
+++ b/src/android/app/src/main/res/values-fi/strings.xml
@@ -12,12 +12,8 @@
Liikuta tattia vasemmalle tai oikealle.
Nappulat
-
- Aktivoi CPU JIT
- Käyttää Just-in-Time (JIT) kääntäjää prosessorin emulointiin. Kun tämä on päällä, pelien suorituskyky on huomattavasti parempi.
Järjestelmän kellotyyppi
Aseta emuloidun 3DS:n kello samaksi kuin laitteesi kello, tai aloita kello simuloidusta päivämäärästä ja ajasta.
- Järjestelmän kellon aloitusajan yliajo.
Emuloitu alue
Emuloitu kieli
@@ -33,14 +29,16 @@
Ulkoinen
Kuvan kääntö
- Aktivoi V-Sync
- Synkronoi pelin virkistystaajuus laitteesi virkistystaajuuteen.
- Aktivoi Laitteistovarjostin
- Käyttää laitteistoa emuloidakseen 3DS:n varjostimia. Kun tämä on päällä, pelien suorituskyky on huomattavasti parempi.
Aktivoi nopeuden rajoitus
- Kun aktivoitu, emulaation nopeus on rajoitettu asetettuun prosenttiin normaalista nopeudesta.
Rajoita nopeusprosenttia
Aktivoi äänen venytys
+
+ Aktivoi CPU JIT
+ Käyttää Just-in-Time (JIT) kääntäjää prosessorin emulointiin. Kun tämä on päällä, pelien suorituskyky on huomattavasti parempi.
+ Aktivoi Laitteistovarjostin
+ Käyttää laitteistoa emuloidakseen 3DS:n varjostimia. Kun tämä on päällä, pelien suorituskyky on huomattavasti parempi.
+ Aktivoi V-Sync
+ Synkronoi pelin virkistystaajuus laitteesi virkistystaajuuteen.
Tyhjennä
Oletus
diff --git a/src/android/app/src/main/res/values-fr/strings.xml b/src/android/app/src/main/res/values-fr/strings.xml
index cd9492cbc..982cf9d04 100644
--- a/src/android/app/src/main/res/values-fr/strings.xml
+++ b/src/android/app/src/main/res/values-fr/strings.xml
@@ -5,10 +5,6 @@
Notifications de l\'émulateur 3DS Azahar
Azahar est en cours d\'exécution
Ensuite, vous devrez sélectionner un dossier d\'applications. Azahar affichera toutes les ROMs 3DS à l\'intérieur du dossier sélectionné dans l\'application. Les ROMs CIA, les mises à jour et les DLCs devront être installés séparément en cliquant sur l\'icône du dossier et en sélectionnant Installer CIA.
- Démarrer
- Annulation...
- Important
- Ne pas montrer à nouveau
Paramètres
@@ -124,12 +120,10 @@
Permuter les écrans
Cette commande doit être rattachée à un stick analogique de manette ou à un axe de la manette + !
Cette commande doit être rattachée à un bouton de la manette !
-
Fichiers système
Effectuer des opérations sur les fichiers système, telles que l\'installation de fichiers système ou le démarrage du menu Home.
Connexion à Artic Setup Tool
- Azahar Artic Setup Tool.
Notes :- Cette opération va installer des fichiers uniques à la console dans Azahar, ne partagez pas vos dossiers utilisateur ou nand après avoir effectué le processus d\'installation !
- La configuration de la Old 3DS est nécessaire pour que la configuration de la New 3DS fonctionne.
- Les deux modes d\'installation fonctionneront quel que soit le modèle de la console qui exécute l\'outil d\'installation.
]]>
Récupération de l\'état actuel des fichiers du système, veuillez patienter...
Configuration Old 3DS
Configuration New 3DS
@@ -147,20 +141,19 @@
Boutons
Bouton
-
- CPU JIT
- Utilise le compilateur Just-in-Time (JIT) pour l\'émulation CPU. Lorsqu\'il est activé, la performance des jeux sera améliorée de manière significative.
- Horloge
- Définissez l\'horloge émulée de la 3DS pour qu\'elle corresponde à votre appareil ou démarre à une date et heure simulée.
- Fréquence d\'horloge du CPU
-
+ Paramètres d\'émulation
Nom d\'utilisateur
Mode New 3DS
Utilise les applets LLE (si installés)
+ Activer les modules LLE requis pour les fonctionnalités en ligne (si installés)
+ Active les modules LLE nécessaires pour le multijoueur en ligne, l\'accès à l\'eShop, etc.
Horloge
- Décalage temporel
- Si l\'horloge est réglée sur \"Horloge simulée\", cela modifie la date et l\'heure fixes de début.
+ Horloge
+ Définissez l\'horloge émulée de la 3DS pour qu\'elle corresponde à votre appareil ou démarre à une date et heure simulée.
+ Horloge de l\'appareil
+ Horloge simulée
+ Paramètres du profil
Région
Langue
Anniversaire
@@ -173,11 +166,13 @@
ID de la console
Régénérer l\'ID de la console
Cette opération remplacera l\'ID de votre console virtuelle 3DS par un nouvel ID. L\'ID actuel de votre console virtuelle 3DS ne pourra pas être récupéré. Cette opération peut avoir des effets inattendus dans les applications. Cette opération peut échouer si vous utilisez une sauvegarde de configuration obsolète. Continuer ?
+ Adresse MAC
+ Régénérer l\'adresse MAC
+ Cela remplacera votre adresse MAC actuelle par une nouvelle. Il n\'est pas recommandé d\'effectuer cette opération si vous avez obtenu l\'adresse MAC de votre console réelle à l\'aide de l\'outil de configuration. Continuer ?
3GX Plugin Loader
Charge les plugins 3GX à partir de la carte SD émulée s\'ils sont disponibles.
Autoriser les applications à modifier l\'état du Plugin Loader
Autoriser les applications homebrew à activer le Plugin Loader même lorsqu\'il est désactivé.
-
Caméra intérieure
Caméra extérieure de gauche
@@ -198,22 +193,17 @@
Émet le shader de fragment utilisé pour émuler PICA en utilisant SPIR-V plutôt que GLSL
Activer la compilation asynchrone des shaders
Compile les shaders en arrière-plan pour réduire les saccades pendant le jeu. Lorsqu\'il est activé, prévoyez des problèmes graphiques temporaires.
- Rendu de débogage
- Enregistre des informations de débogage supplémentaires liées aux graphiques. Lorsqu\'il est activé, les performances du jeu seront significativement réduites.
- Activer la synchronisation verticale (VSync)
- Synchronise la fréquence d\'images du jeu avec la fréquence de rafraîchissement de votre appareil.
Filtrage linéaire
Active le filtrage linéaire, qui améliorera le lissage graphique du jeu.
Filtrage des textures
Améliore l\'aspect visuel des applications en appliquant un filtre aux textures. Les filtres pris en charge sont Anime4K Ultrafast, Bicubique, ScaleForce, xBRZ freescale et MMPX.
- Activer le shader hardware
- Utilise le hardware pour émuler les shaders de la 3DS. Lorsqu\'il est activé, la performance des jeux sera améliorée de manière significative.
+ Retarde le rendu de thread du jeu
+ Délai le thread de rendu du jeu lorsqu\'il soumet des données au GPU. Cela permet de résoudre les problèmes de performance dans les (très rares) applications avec des fréquences d\'images dynamiques.
Multiplication précise
Utilise une multiplication plus précise dans les shaders hardware, ce qui peut corriger certains bugs graphiques. Lorsqu\'elle est activée, la performance sera réduite.
Active l\'émulation asynchone du GPU
Utilise une unité d’exécution séparée pour émuler le GPU de manière asynchrone. La performance sera améliorée.
Limite de vitesse
- Lorsqu\'elle est activée, la vitesse d\'émulation sera limitée par un pourcentage spécifique de la vitesse normale.
Limiter le pourcentage de vitesse
Définit le taux de limitation de la vitesse d\'émulation. À 100%, par défaut, l\'émulation sera limitée à la vitesse normale. Des valeurs supérieures ou inférieures augmenteront ou diminueront la limite de la vitesse.
Résolution interne
@@ -233,7 +223,8 @@
Stéréoscopie
Mode 3D stéréoscopique
Profondeur
- Spécifie la valeur du curseur 3D. Cette valeur doit être supérieure à 0% lorsque la 3D stéréoscopique est activée.
+ Désactiver le rendu de l\'œil droit
+ Améliore considérablement les performances dans certaines applications, mais peut provoquer des scintillements dans d\'autres.
Réalité virtuelle Cardboard
Taille de l\'écran Cardboard
Redimensionne l\'écran à un pourcentage de sa taille d\'origine.
@@ -263,6 +254,23 @@
Périphérique d\'entrée audio
Mode de sortie audio
+
+ CPU JIT
+ Utilise le compilateur Just-in-Time (JIT) pour l\'émulation CPU. Lorsqu\'il est activé, la performance des jeux sera améliorée de manière significative.
+ Activer le shader hardware
+ Utilise le hardware pour émuler les shaders de la 3DS. Lorsqu\'il est activé, la performance des jeux sera améliorée de manière significative.
+ Fréquence d\'horloge du CPU
+ Activer la synchronisation verticale (VSync)
+ Synchronise la fréquence d\'images du jeu avec la fréquence de rafraîchissement de votre appareil.
+ Rendu de débogage
+ Enregistre des informations de débogage supplémentaires liées aux graphiques. Lorsqu\'il est activé, les performances du jeu seront significativement réduites.
+ Vider la sortie des logs sur chaque message
+ Enregistre immédiatement le log de débogage dans un fichier. A utiliser si Azahar se plante et que la sortie du journal est coupée.
+ Démarrage différé avec les modules LLE
+ Retarde le démarrage de l\'application lorsque les modules LLE sont activés.
+ Opérations asynchrones déterministes
+ Rend les opérations asynchrones déterministes pour le débogage. L\'activation de cette fonction peut entraîner des blocages.
+
Orientation de l\'écran
Auto
@@ -299,6 +307,10 @@
Vous ne pouvez pas modifier cela maintenant
Cette option ne peut pas être modifiée pendant qu\'un jeu est lancé.
Sélection Automatique
+ Démarrer
+ Annulation...
+ Important
+ Ne pas montrer à nouveau
Choisir un répertoire de jeu
@@ -383,6 +395,9 @@
Afficher l\'overlay
Fermer le jeu
Pause
+ Divers
+ Utilise l\'Artic Controller quand connecté à un serveur Artic Base
+ Utilisez les commandes fournies par le serveur Artic Base lorsque vous y êtes connecté, au lieu du périphérique d\'entrée configuré.
Êtes-vous sûr de vouloir fermer le jeu en cours ?
Amiibo
Charger
@@ -454,7 +469,6 @@
Jouer
Raccourci
-
Codes de triche
Ajouter un code de triche
@@ -514,10 +528,6 @@
Arrière-plan noir
Lorsque vous utilisez le thème sombre, appliquer un arrière-plan noir.
-
- Horloge de l\'appareil
- Horloge simulée
-
JPN
USA
@@ -574,11 +584,11 @@
Anime4K
Bicubique
- Plus proche voisin
ScaleForce
xBRZ
MMPX
+ Plus proche voisin
Mono
Stéreo
@@ -739,33 +749,12 @@
Se connecter à une vraie console exécutant un serveur Artic Base
Se connecter à Artic Base
Entrez l\'adresse du serveur Artic Base
- Retarde le rendu de thread du jeu
- Délai le thread de rendu du jeu lorsqu\'il soumet des données au GPU. Cela permet de résoudre les problèmes de performance dans les (très rares) applications avec des fréquences d\'images dynamiques.
Sauvegarde rapide
Sauvegarde rapide
Recharge rapide
Sauvegarde rapide - %1$tF %1$tR
- Sauvegarde...
- Chargement...
Aucune sauvegarde rapide disponible.
- Divers
- Utilise l\'Artic Controller quand connecté à un serveur Artic Base
- Utilisez les commandes fournies par le serveur Artic Base lorsque vous y êtes connecté, au lieu du périphérique d\'entrée configuré.
- Vider la sortie des logs sur chaque message
- Enregistre immédiatement le log de débogage dans un fichier. A utiliser si Azahar se plante et que la sortie du journal est coupée.
- Désactiver le rendu de l\'œil droit
- Améliore considérablement les performances dans certaines applications, mais peut provoquer des scintillements dans d\'autres.
- Démarrage différé avec les modules LLE
- Retarde le démarrage de l\'application lorsque les modules LLE sont activés.
- Opérations asynchrones déterministes
- Rend les opérations asynchrones déterministes pour le débogage. L\'activation de cette fonction peut entraîner des blocages.
- Activer les modules LLE requis pour les fonctionnalités en ligne (si installés)
- Active les modules LLE nécessaires pour le multijoueur en ligne, l\'accès à l\'eShop, etc.
- Paramètres d\'émulation
- Paramètres du profil
- Adresse MAC
- Régénérer l\'adresse MAC
- Cela remplacera votre adresse MAC actuelle par une nouvelle. Il n\'est pas recommandé d\'effectuer cette opération si vous avez obtenu l\'adresse MAC de votre console réelle à l\'aide de l\'outil de configuration. Continuer ?
+
diff --git a/src/android/app/src/main/res/values-it/strings.xml b/src/android/app/src/main/res/values-it/strings.xml
index efead8a84..578c9c402 100644
--- a/src/android/app/src/main/res/values-it/strings.xml
+++ b/src/android/app/src/main/res/values-it/strings.xml
@@ -8,8 +8,7 @@ Cos\'è questo:
Notifiche emulatore Azahar 3DS
Azahar è in esecuzione
Ora è necessario selezionare una cartella Applicazioni. Azahar mostrerà tutte le ROM 3DS all\'interno della cartella selezionata nell\'app. Le ROM CIA, gli aggiornamenti e DLC dovranno essere installati separatamente cliccando sulla cartella e selezionando installa CIA.
- Avvia
- Cancellazione...
+
Impostazioni
Opzioni
@@ -37,6 +36,8 @@ Controlla ancora questa opzione in futuro per controllare se il supporto è stat
Cambia i file che Azahar usa per caricare le applicazioni
Modifica l\'aspetto dell\'app
Installa CIA
+ Scopri di più.]]>
+
Seleziona il driver GPU
Vuoi rimpiazzare il tuo driver GPU attuale?
@@ -124,12 +125,10 @@ Divertiti usando l\'emulatore!
Inverti Schermi
Questo controllo dev\'essere assegnato ad uno stick analogico di un gamepad o ad un asse del Pad Direzionale!
Questo controllo dev\'essere assegnato a un pulsante del gamepad!
-
File di Sistema
Esegui operazioni sui file di sistema come installare file di sistema o avviare il Menu Home
Connettiti a Artic Setup Tool
- Setup Artic Tool di Azahar.
Note: - Questa operazione installerà file unici della console all\'interno di Azahar, non condividere i le tue cartelle utente o nand
dopo aver completato il processo di setup! - Il setup di un Old 3DS è necessario per far sì che il setup di un New 3DS funzioni.
- Entrambe le modalità di setup funzioneranno indipendentemente dal modello della console che esegue il tool di setup.
]]>
Ottenendo lo stato attuale dei file di sistema, per favore attendi...
Setup Old 3DS
Setup New 3DS
@@ -147,20 +146,19 @@ Divertiti usando l\'emulatore!
Pulsanti
Pulsante
-
- CPU JIT
- Utilizza il compilatore Just-in-Time (JIT) per l\'emulazione della CPU. Se abilitato, le prestazioni di gioco miglioreranno significativamente.
- Orologio
- Scegli se l\'orologio di sistema del 3DS emulato dovrà rispecchiare l\'orario del tuo dispositivo o se dovrà indicare una data e ora in particolare.
- Velocità Clock CPU
-
+ Impostazioni Emulazione
Nome Utente
Modalità New 3DS
Usa Applet LLE (se installati)
+ Abilitare i moduli LLE richiesti per le funzionalità online (se installati)
+ Abilita i moduli LLE necessari per il multigiocatore online, l\'accesso all\'eShop, ecc.
Orologio
- Offset Orario
- Se l\'orologio è impostato su \"Orologio Simulato\", verranno cambiati le date e gli orari prefissati.
+ Orologio
+ Scegli se l\'orologio di sistema del 3DS emulato dovrà rispecchiare l\'orario del tuo dispositivo o se dovrà indicare una data e ora in particolare.
+ Orologio del dispositivo
+ Orologio simulato
+ Impostazioni profilo
Regione
Lingua
Compleanno
@@ -173,11 +171,13 @@ Divertiti usando l\'emulatore!
ID Console
Rigenera ID Console
Questo rimpiazzerà l\'ID virtuale della console 3DS con uno nuovo. L\'ID della console 3DS attuale non potrà essere recuperato. Questo potrebbe avere effetti inaspettati in alcue applicazioni. Questo processo potrebbe fallire se usi un salvataggio della configurazione obsoleto. Continuare?
+ Indirizzo MAC
+ Rigenera indirizzo MAC
+ Questo rimpiazzerà il tuo indirizzo MAC attuale con uno nuovo. È sconsigliato farlo se hai impostato l\'indirizzo MAC dalla tua console reale usando il Setup Tool. Continuare?
Loader Plugin 3GX
Carica i plugin 3GX dalla scheda SD emulata, se disponibili.
Consenti alle applicazioni di cambiare lo stato del Plugin Loader
Permetti alle app homebrew di abilitare il Plugin Loader anche quando è disabilitato.
-
Fotocamera Interna
Fotocamera Esterna di Sinistra
@@ -198,22 +198,17 @@ Divertiti usando l\'emulatore!
Crea le fragments shader usate per emulare PICA tramite SPIR-V, invece di GLSL
Abilita la compilazione asincrona delle shader
Compila le shader in background per ridurre lo stuttering durante il gameplay. Quando abilitato, potrebbero verificarsi dei glitch grafici.
- Renderer di Debug
- Logga informazioni di debug riguardante la grafica. Se abilitato, le performance del software emulato diminuiranno drasticamente
- Abilita V-Sync
- Sincronizza il frame rate dei giochi con il refresh rate del tuo dispositivo.
Filtering Lineare
Abilita il filtro lineare, che fa sembrare più smussata la grafica dei giochi.
Filtro Texture
Migliora la grafica delle applicazioni applicando un filtro alle texture. I filtri supportati sono Anime4k Ultrafast, Bicubic, ScaleForce, xBRZ freescale e MMPX.
- Abilita le Shader Hardware
- Utilizza l\'hardware per emulare gli shader del 3DS. Se abilitato, le prestazioni dei giochi miglioreranno significativamente.
+ Ritarda il thread di rendering del gioco
+ Ritarda il thread di rendering del gioco quando invia dati alla GPU. Aiuta con i problemi di prestazioni nelle (poche) applicazioni con frame rate dinamici.
Moltiplicazione Accurata
Utilizza una moltiplicazione più accurata degli shader hardware, che potrebbe correggere alcuni bug grafici. Se abilitato, le prestazioni saranno ridotte.
Abilita emulazione GPU asincrona
Utilizza un thread separato per emulare la GPU in differita. Se abilitato, le prestazioni miglioreranno.
Limita Velocità
- Se abilitato, la velocità d\'emulazione sarà limitata ad una percentuale specifica di velocità normale.
Limita Velocità tramite Percentuale
Specifica a quale percentuale limitare la velocità d\'emulazione. Utilizzando l\'impostazione predefinita di 100% l\'emulazione sarà limitata alla velocità normale. Valori superiori o inferiori aumenteranno o diminuiranno il limite di velocità.
Risoluzione Interna
@@ -233,7 +228,8 @@ Divertiti usando l\'emulatore!
Stereoscopia
Modalità Stereoscopia 3D
Profondità
- Specifica il valore del regolatore di profindità 3D. Dovrebbe avere valore maggiore di 0% quando il 3D stereoscopico è abilitato.
+ Disabilita il rendering dell\'occhio destro
+ Migliora notevolmente le prestazioni in alcune applicazioni, ma può causare flickering in altre.
Cardboard VR
Grandezza Cardboard
Scala lo schermo ad una percentuale fissata della sua grandezza originale
@@ -263,6 +259,23 @@ Divertiti usando l\'emulatore!
Dispositivo di input Audio
Modalità di output audio
+
+ CPU JIT
+ Utilizza il compilatore Just-in-Time (JIT) per l\'emulazione della CPU. Se abilitato, le prestazioni di gioco miglioreranno significativamente.
+ Abilita le Shader Hardware
+ Utilizza l\'hardware per emulare gli shader del 3DS. Se abilitato, le prestazioni dei giochi miglioreranno significativamente.
+ Velocità Clock CPU
+ Abilita V-Sync
+ Sincronizza il frame rate dei giochi con il refresh rate del tuo dispositivo.
+ Renderer di Debug
+ Logga informazioni di debug riguardante la grafica. Se abilitato, le performance del software emulato diminuiranno drasticamente
+ Svuota l\'output del log ad ogni messaggio
+ Invia immediatamente il log di debug al file. Usalo se Azahar si blocca e l\'output del log viene tagliato.
+ Ritarda l\'avvio con moduli LLE
+ Ritarda l\'avvio dell\'app quando i moduli LLE sono abilitati.
+ Operazioni Deterministiche desincronizzate
+ Rende le operazioni asincrone deterministiche per il debug. Abilitare questa opzione potrebbe causare blocchi.
+
Orientamento schermo
Automatico
@@ -299,6 +312,10 @@ Divertiti usando l\'emulatore!
Non puoi modificare questo ora
Questa opzione non può essere modificata mentre un gioco è in esecuzione.
Auto-seleziona.
+ Avvia
+ Cancellazione...
+ Importante
+ Non mostrare più
Seleziona cartella dei giochi
@@ -383,6 +400,9 @@ Divertiti usando l\'emulatore!
Mostra Controlli di gioco
Chiudi il Gioco
Abilita/disabilita Pausa
+ Miscellanea
+ Usa Artic Controller quando connesso a Artic Base Server
+ Usa i controlli forniti da Artic Base Server quando connesso ad esso al posto del dispositivo di input configurato.
Sei sicuro di voler chiudere il gioco corrente?
Amiibo
Carica
@@ -444,6 +464,9 @@ Divertiti usando l\'emulatore!
Errore nel Salvataggio/Caricamento
Errore Fatale
Consulta il log per i dettagli.\nContinuare con l\'emulazione potrebbe causare un crash.
+ Regione non valida
+ Applicazione criptata non supportata
+
Preparando le Shaders
Costruisco le Shaders
@@ -451,7 +474,6 @@ Divertiti usando l\'emulatore!
Riproduci
Scorciatoia
-
Trucchi
Aggiungi Trucco
@@ -473,6 +495,7 @@ Divertiti usando l\'emulatore!
Notifiche di Azahar durante l\'installazione dei CIA
Installando il CIA
+ Installazione %1$s (%2$d/%3$d)
CIA installato con successo
Errore nell\'installazione del file CIA.
\"%s\" è stato installato con successo
@@ -510,10 +533,6 @@ Divertiti usando l\'emulatore!
Sfondi neri
Quando il tema scuro è attivo, usa sfondi neri.
-
- Orologio del dispositivo
- Orologio simulato
-
JPN
USA
@@ -570,11 +589,11 @@ Divertiti usando l\'emulatore!
Anime4K
Bicubic
- Nearest Neighbor
ScaleForce
xBRZ
MMPX
+ Nearest Neighbor
Mono
Stereo
@@ -735,33 +754,12 @@ Divertiti usando l\'emulatore!
Connettiti a una console reale che sta eseguendo il server Artic Base
Connetti ad Artic Base
Inserisci l\'indirizzo del server Artic Base
- Ritarda il thread di rendering del gioco
- Ritarda il thread di rendering del gioco quando invia dati alla GPU. Aiuta con i problemi di prestazioni nelle (poche) applicazioni con frame rate dinamici.
Salvataggio Rapido
Salvataggio Rapido
Caricamento Rapido
Salvataggio Rapido - %1$tF %1$tR
- Salvataggio..
- Caricamento...
Nessun Salvataggio Rapido Disponibile
- Miscellanea
- Usa Artic Controller quando connesso a Artic Base Server
- Usa i controlli forniti da Artic Base Server quando connesso ad esso al posto del dispositivo di input configurato.
- Svuota l\'output del log ad ogni messaggio
- Invia immediatamente il log di debug al file. Usalo se Azahar si blocca e l\'output del log viene tagliato.
- Disabilita il rendering dell\'occhio destro
- Migliora notevolmente le prestazioni in alcune applicazioni, ma può causare flickering in altre.
- Ritarda l\'avvio con moduli LLE
- Ritarda l\'avvio dell\'app quando i moduli LLE sono abilitati.
- Operazioni Deterministiche desincronizzate
- Rende le operazioni asincrone deterministiche per il debug. Abilitare questa opzione potrebbe causare blocchi.
- Abilitare i moduli LLE richiesti per le funzionalità online (se installati)
- Abilita i moduli LLE necessari per il multigiocatore online, l\'accesso all\'eShop, ecc.
- Impostazioni Emulazione
- Impostazioni profilo
- Indirizzo MAC
- Rigenera indirizzo MAC
- Questo rimpiazzerà il tuo indirizzo MAC attuale con uno nuovo. È sconsigliato farlo se hai impostato l\'indirizzo MAC dalla tua console reale usando il Setup Tool. Continuare?
+
diff --git a/src/android/app/src/main/res/values-nb/strings.xml b/src/android/app/src/main/res/values-nb/strings.xml
index ff65e5f2a..cf9aa7f2e 100644
--- a/src/android/app/src/main/res/values-nb/strings.xml
+++ b/src/android/app/src/main/res/values-nb/strings.xml
@@ -16,16 +16,10 @@
Beveg Joystick venstre eller høyre
Denne kontrollen må være bundet til en håndkontroller\'s analog spak eller kontrollpluss akse!
Denne kontrollen må være bundet til en håndkontroller knapp!
-
Taster
-
- Aktiver CPU JIT
- Bruker Just-in-Time (JIT) kompilator til CPU emulering. Når dette er aktivert, vil spill ytelsen bli betydelig forbedret.
Systemklokketype
Sett den emulerte 3DS-klokken til enten å gjenspeile den på enheten din, eller start på en simulert dato og tid.
- Overstyring av starttid på systemklokken
- Hvis \"Systemklokketypen\" innstillingen er satt til \"Simulert Klokke\" Endrer dette startpunktet til den datoen og klokkeslettet.
Emulert region
Emulert Språk
@@ -41,19 +35,14 @@
Ekstern
Vend Bilde
- Aktiver V-Sync
- Synkroniserer spillrammefrekvensen med oppdateringsfrekvensen på enheten din.
Aktiver lineær filtrering
Aktiverer lineær filtrering, noe som får spillvisualer til å vises jevnere.
Tekstur Filter
- Aktiver maskinvare shader
- Bruker maskinvare for å etterligne 3DS shaders. Når dette er aktivert, vil spillytelsen bli betydelig forbedret.
Aktiver nøyaktig shader-multiplikasjon
Bruker mer nøyaktig multiplikasjon i maskinvare shaders, som kan fikse noen grafiske feil. Når dette er aktivert, reduseres ytelsen.
Aktiver asynkron GPU-emulering
Bruker en egen tråd for å emulere GPU asynkront. Når dette er aktivert, forbedres ytelsen.
Aktiver fartsbegrensning
- Når dette er aktivert, vil emuleringshastigheten være begrenset til en spesifisert prosentandel av normal hastighet.
Begrens fartsprosent
Angir prosentandelen som skal begrense emuleringshastighet. Med standard 100% emulering vil være begrenset til normal hastighet. Verdier høyere eller lavere vil øke eller redusere fartsgrensen.
Intern oppløsning
@@ -61,6 +50,13 @@
Advarsel: Endring av disse innstillingene reduserer emuleringen
Aktiver lydstrekking
Strekker lyd for å redusere stamming. Når dette er aktivert, øker lydforsinkelsen og reduserer ytelsen litt.
+
+ Aktiver CPU JIT
+ Bruker Just-in-Time (JIT) kompilator til CPU emulering. Når dette er aktivert, vil spill ytelsen bli betydelig forbedret.
+ Aktiver maskinvare shader
+ Bruker maskinvare for å etterligne 3DS shaders. Når dette er aktivert, vil spillytelsen bli betydelig forbedret.
+ Aktiver V-Sync
+ Synkroniserer spillrammefrekvensen med oppdateringsfrekvensen på enheten din.
Tøm
Standard
diff --git a/src/android/app/src/main/res/values-nl/strings.xml b/src/android/app/src/main/res/values-nl/strings.xml
index a0e3cce2c..0c13f6095 100644
--- a/src/android/app/src/main/res/values-nl/strings.xml
+++ b/src/android/app/src/main/res/values-nl/strings.xml
@@ -3,8 +3,6 @@
Azahar 3DS emulator notificaties
Azahar is Actief
- Start
- Annuleren…
Instellingen
Opties
@@ -102,7 +100,6 @@ Vink deze optie in de toekomst nogmaals aan om te zien of er ondersteuning is to
Verwissel Schermen
Deze besturing moet worden gekoppeld aan een analoge gamepad-stick of D-pad-as!
Deze besturing moet aan een gamepadknop zijn gekoppeld!
-
Start het HOME Menu
Start Systeem-Instellingen wanneer het HOME menu wordt opgestart
HOME Menu
@@ -111,20 +108,12 @@ Vink deze optie in de toekomst nogmaals aan om te zien of er ondersteuning is to
Knoppen
Knop
-
- CPU-JIT
- Maakt gebruik van de Just-in-Time (JIT)-compiler voor CPU-emulatie. Indien ingeschakeld, worden de spelprestaties aanzienlijk verbeterd.
- Klok
- Stel de geëmuleerde 3DS-klok zo in dat deze de klok van je apparaat weerspiegelt of start op een gesimuleerde datum en tijd.
- CPU Klok Snelheid
-
-
Gebruikersnaam
New 3DS Modus
Gebruik LLE-applets (indien geïnstalleerd)
Klok
- Offset-tijd
- Als de klok is ingesteld op \"Gesimuleerde klok\", verandert dit de vaste datum en tijd waarop moet worden gestart.
+ Klok
+ Stel de geëmuleerde 3DS-klok zo in dat deze de klok van je apparaat weerspiegelt of start op een gesimuleerde datum en tijd.
Regio
Taal
Geboortedatum
@@ -138,4 +127,10 @@ Vink deze optie in de toekomst nogmaals aan om te zien of er ondersteuning is to
Console-ID opnieuw genereren
3GX-pluginlader
Laadt 3GX-plug-ins van de geëmuleerde SD-kaart als deze beschikbaar zijn.
+
+ CPU-JIT
+ Maakt gebruik van de Just-in-Time (JIT)-compiler voor CPU-emulatie. Indien ingeschakeld, worden de spelprestaties aanzienlijk verbeterd.
+ CPU Klok Snelheid
+ Start
+ Annuleren…
diff --git a/src/android/app/src/main/res/values-sv/strings.xml b/src/android/app/src/main/res/values-sv/strings.xml
index 91d4a0ebc..37f336dd0 100644
--- a/src/android/app/src/main/res/values-sv/strings.xml
+++ b/src/android/app/src/main/res/values-sv/strings.xml
@@ -5,8 +5,7 @@
Aviseringar för Azahar 3DS-emulator
Azahar är igång
Näst måste du välja en applikationsmapp. Azahar kommer att visa alla 3DS ROM i den valda mappen i appen.\n\nCIA ROM, uppdateringar och DLC måste installeras separat genom att klicka på mappikonen och välja Installera CIA.
- Starta
- Avbryter...
+
Inställningar
Alternativ
@@ -119,12 +118,10 @@
Byt skärm
Den här kontrollen måste vara bunden till en gamepad-analog spak eller D-pad-axel!
Den här kontrollen måste vara bunden till en gamepad-knapp!
-
Systemfiler
Utför systemfilsoperationer som att installera systemfiler eller starta upp startmenyn
Anslut till Artic Setup Tool
- Azahar Artic Setup Tool.
Observera:- Den här åtgärden installerar konsolunika filer till Azahar, dela inte dina användar- eller nand-mappar
efter att du har utfört installationsprocessen! - Installation av gammal 3DS behövs för att installationen av ny 3DS ska fungera.
- Båda installationslägena fungerar oavsett vilken modell konsolen som kör installationsverktyget har.
]]>
Hämtar aktuell status för systemfiler, vänta...
Gammal 3DS-konfiguration
Ny 3DS-konfiguration
@@ -142,20 +139,19 @@
Knappar
Knapp
-
- CPU JIT
- Använder JIT-kompilatorn (Just-in-Time) för CPU-emulering. När den är aktiverad kommer spelprestanda att förbättras avsevärt.
- Klocka
- Ställ in den emulerade 3DS-klockan så att den antingen återspeglar den på din enhet eller startar vid ett simulerat datum och klockslag.
- CPU-klockhastighet
-
+ Emuleringsinställningar
Användarnamn
Nytt 3DS-läge
Använd LLE Applets (om installerat)
+ Aktivera nödvändiga LLE-moduler för onlinefunktioner (om de är installerade)
+ Aktiverar de LLE-moduler som krävs för multiplayer online, eShop-åtkomst etc.
Klocka
- Förskjut tid
- Om klockan är inställd på "Simulerad klocka" ändras det fasta datumet och tiden att starta vid.
+ Klocka
+ Ställ in den emulerade 3DS-klockan så att den antingen återspeglar den på din enhet eller startar vid ett simulerat datum och klockslag.
+ Enhetsklocka
+ Simulerad klocka
+ Profilinställningar
Region
Språk
Födelsedag
@@ -168,11 +164,13 @@
Konsol-id
Skapa nytt konsol-id
Detta kommer att ersätta ditt nuvarande virtuella 3DS-konsol-ID med ett nytt. Ditt nuvarande virtuella 3DS-konsol-ID kommer inte att kunna återställas. Detta kan få oväntade effekter i applikationer. Detta kan misslyckas om du använder en föråldrad konfigurationssparning. Fortsätta?
+ MAC-adress
+ Återgenerera MAC-adress
+ Detta kommer att ersätta din nuvarande MAC-adress med en ny. Det är inte rekommenderat att göra detta om du fick MAC-adressen från din riktiga konsol med hjälp av installationsverktyget. Fortsätta?
Inläsare för 3GX-insticksmoduler
Inlästa 3GX-insticksmoduler från det emulerade SD-kortet om de finns tillgängliga.
Tillåt applikationer att ändra insticksinläsarens tillstånd
Tillåter homebrew-appar att aktivera insticksinläsaren även när den är inaktiverad.
-
Innerkamera
Yttre vänstra kameran
@@ -193,22 +191,17 @@
Skickar ut den fragment shader som används för att emulera PICA med SPIR-V istället för GLSL
Aktivera asynkron shader-kompilering
Sammanställer shaders i bakgrunden för att minska stuttering under spelet. När det är aktiverat kan du förvänta dig tillfälliga grafiska glitches
- Felsök renderingsprogrammet
- Loggar ytterligare grafikrelaterad felsökningsinformation. När den är aktiverad kommer spelets prestanda att minska avsevärt.
- Aktivera V-Sync
- Synkroniserar spelets bildfrekvens till uppdateringsfrekvensen på din enhet.
Lineär filtrering
Aktiverar linjär filtrering, vilket gör att spelets grafik ser jämnare ut.
Texturfilter
Förbättrar det visuella i applikationer genom att tillämpa ett filter på texturer. De filter som stöds är Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale och MMPX.
- Aktivera hårdvaru-shader
- Använder hårdvara för att emulera 3DS-shaders. När detta är aktiverat kommer spelprestanda att förbättras avsevärt.
+ Fördröj spelets renderingstråd
+ Fördröj spelets renderingstråd när den skickar data till GPU:n. Hjälper till med prestandaproblem i de (mycket få) applikationer med dynamiska bildfrekvenser.
Accurate Multiplication
Använder mer exakt multiplikation i hårdvaru-shaders, vilket kan åtgärda vissa grafiska buggar. När detta är aktiverat kommer prestandan att minska.
Aktivera asynkron GPU-emulering
Använder en separat tråd för att emulera GPU:n asynkront. När detta är aktiverat kommer prestandan att förbättras.
Begränsa hastighet
- När den är aktiverad begränsas emuleringshastigheten till en angiven procentandel av normal hastighet.
Gränsa hastigheten i procent
Anger procentsatsen för att begränsa emuleringshastigheten. Med standardvärdet 100% kommer emuleringen att begränsas till normal hastighet. Värden som är högre eller lägre ökar eller minskar hastighetsgränsen.
Intern upplösning
@@ -228,7 +221,8 @@
Stereoskop
Stereoskopiskt 3D-läge
Djup
- Anger värdet för 3D-reglaget. Detta bör sättas högre än 0% när stereoskopisk 3D är aktiverad.
+ Inaktivera rendering av höger öga
+ Förbättrar prestandan avsevärt i vissa applikationer, men kan orsaka flimmer i andra.
Cardboard VR
Storlek på kartongskärm
Skalar skärmen till en procentandel av dess ursprungliga storlek.
@@ -258,6 +252,23 @@
Ljudinmatningsenhet
Ljudutmatningsläge
+
+ CPU JIT
+ Använder JIT-kompilatorn (Just-in-Time) för CPU-emulering. När den är aktiverad kommer spelprestanda att förbättras avsevärt.
+ Aktivera hårdvaru-shader
+ Använder hårdvara för att emulera 3DS-shaders. När detta är aktiverat kommer spelprestanda att förbättras avsevärt.
+ CPU-klockhastighet
+ Aktivera V-Sync
+ Synkroniserar spelets bildfrekvens till uppdateringsfrekvensen på din enhet.
+ Felsök renderingsprogrammet
+ Loggar ytterligare grafikrelaterad felsökningsinformation. När den är aktiverad kommer spelets prestanda att minska avsevärt.
+ Töm loggen för varje meddelande
+ Överför omedelbart felsökningsloggen till fil. Använd detta om Azahar kraschar och loggutmatningen skärs av.
+ Försenad start med LLE-moduler
+ Fördröjer starten av appen när LLE-moduler är aktiverade.
+ Deterministiska asynkrona operationer
+ Gör asynkrona operationer deterministiska för felsökning. Om du aktiverar detta kan det orsaka frysningar.
+
Skärmorientering
Automatisk
@@ -294,7 +305,8 @@
Du kan inte redigera detta nu
Det här alternativet kan inte ändras medan ett spel pågår.
Autovälj
-
+ Starta
+ Avbryter...
Välj spelmapp
@@ -378,6 +390,9 @@
Visa överlägg
Stäng spelet
Växla paus
+ Diverse
+ Använd Artic Controller när du är ansluten till Artic Base-servern
+ Använd de kontroller som tillhandahålls av Artic Base Server när du är ansluten till den istället för den konfigurerade inmatningsenheten.
Är du säker på att du vill stänga det aktuella spelet?
Amiibo
Läs in
@@ -446,7 +461,6 @@
Spela
Genväg
-
Fusk
Lägg till fusk
@@ -504,10 +518,6 @@
Svart bakgrund
När du använder det mörka temat ska du använda svarta bakgrunder.
-
- Enhetsklocka
- Simulerad klocka
-
JPN
USA
@@ -564,11 +574,11 @@
Anime4K
Bikubisk
- Närmaste granne
ScaleForce
xBRZ
MMPX
+ Närmaste granne
Mono
Stereo
@@ -729,33 +739,12 @@
Anslut till en riktig konsol som kör en Artic Base-server
Anslut till Artic Base
Ange Artic Base serveradress
- Fördröj spelets renderingstråd
- Fördröj spelets renderingstråd när den skickar data till GPU:n. Hjälper till med prestandaproblem i de (mycket få) applikationer med dynamiska bildfrekvenser.
Snabbspara
Snabbspara
Snabbinläsning
Snabbspara - %1$tF %1$tR
- Sparar...
- Läser in...
Ingen snabbsparning tillgänglig
- Diverse
- Använd Artic Controller när du är ansluten till Artic Base-servern
- Använd de kontroller som tillhandahålls av Artic Base Server när du är ansluten till den istället för den konfigurerade inmatningsenheten.
- Töm loggen för varje meddelande
- Överför omedelbart felsökningsloggen till fil. Använd detta om Azahar kraschar och loggutmatningen skärs av.
- Inaktivera rendering av höger öga
- Förbättrar prestandan avsevärt i vissa applikationer, men kan orsaka flimmer i andra.
- Försenad start med LLE-moduler
- Fördröjer starten av appen när LLE-moduler är aktiverade.
- Deterministiska asynkrona operationer
- Gör asynkrona operationer deterministiska för felsökning. Om du aktiverar detta kan det orsaka frysningar.
- Aktivera nödvändiga LLE-moduler för onlinefunktioner (om de är installerade)
- Aktiverar de LLE-moduler som krävs för multiplayer online, eShop-åtkomst etc.
- Emuleringsinställningar
- Profilinställningar
- MAC-adress
- Återgenerera MAC-adress
- Detta kommer att ersätta din nuvarande MAC-adress med en ny. Det är inte rekommenderat att göra detta om du fick MAC-adressen från din riktiga konsol med hjälp av installationsverktyget. Fortsätta?
+
diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml
index ecf58c60f..51b68bd60 100644
--- a/src/android/app/src/main/res/values/arrays.xml
+++ b/src/android/app/src/main/res/values/arrays.xml
@@ -31,11 +31,13 @@
- @string/emulation_portrait_layout_top_full
+ - @string/emulation_screen_layout_original
- @string/emulation_screen_layout_custom
- 0
+ - 2
- 1
@@ -129,6 +131,7 @@
- @string/controller_c
- @string/button_home
- @string/button_swap
+ - @string/button_turbo
@@ -233,6 +236,17 @@
- 5
+
+ - @string/game_controlled
+ - @string/nearest_neighbor
+ - @string/linear
+
+
+ - 0
+ - 1
+ - 2
+
+
- Blue (Default)
- Cyan
@@ -298,6 +312,7 @@
+ - @string/internal_resolution_setting_auto
- @string/internal_resolution_setting_1x
- @string/internal_resolution_setting_2x
- @string/internal_resolution_setting_3x
@@ -310,6 +325,7 @@
- @string/internal_resolution_setting_10x
+ - 0
- 1
- 2
- 3
diff --git a/src/android/app/src/main/res/values/integers.xml b/src/android/app/src/main/res/values/integers.xml
index 50cde75f8..1f19c2373 100644
--- a/src/android/app/src/main/res/values/integers.xml
+++ b/src/android/app/src/main/res/values/integers.xml
@@ -33,6 +33,8 @@
850
370
850
+ 630
+ 850
810
@@ -65,5 +67,7 @@
794
460
675
+ 453
+ 720
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 8afbc7d7e..16d84d1bc 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -9,10 +9,6 @@
Azahar 3DS emulator notifications
Azahar is Running
Next, you will need to select an Applications Folder. Azahar will display all of the 3DS ROMs inside of the selected folder in the app.\n\nCIA ROMs, updates and DLC will need to be installed separately by clicking on the folder icon and selecting Install CIA.
- Start
- Cancelling…
- Important
- Don\'t show again
Settings
@@ -93,9 +89,13 @@
Cancel
Select User Folder
user data directory with the button below.]]>
+ You appear to have user directories set for both Lime3DS and Azahar. This is likely because you upgraded to Azahar, and when prompted chose a different user directory than what was being used for Lime3DS.\n\nThis may have resulted in you thinking you lost saves or other settings - we apologize if that happened.\n\nWould you like to go back to using your original Lime3DS user directory, restoring settings and save games from Lime3DS, or keep your current Azahar user directory?\n\nNeither directory will be deleted, regardless of your choice, and you may freely switch between them using the Select User Folder option.
+ Keep Current Azahar Directory
+ Use Prior Lime3DS Directory
Select
You can\'t skip this step
This step is required to allow Azahar to work. Please select a directory and then you can continue.
+ You have lost write permissions on your user data directory, where saves and other information are stored. This can happen after some app or Android updates. Please re-select the directory to regain permissions so you can continue.
https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage
Theme Settings
Configure your theme preferences for Azahar.
@@ -137,6 +137,7 @@
START
HOME
Swap Screens
+ Turbo
X
Y
L
@@ -145,13 +146,18 @@
ZR
This control must be bound to a gamepad analog stick or D-pad axis!
This control must be bound to a gamepad button!
+ Turbo Speed
+ Turbo Speed Enabled
+ Turbo Speed Disabled
System Files
Perform system file operations such as installing system files or booting the Home Menu
Connect to Artic Setup Tool
- Azahar Artic Setup Tool.
Notes:- This operation will install console unique files to Azahar, do not share your user or nand folders
after performing the setup process! - Old 3DS setup is needed for the New 3DS setup to work.
- Both setup modes will work regardless of the model of the console running the setup tool.
]]>
+ Azahar Artic Setup Tool.
Notes:- This operation will install console unique data to Azahar, do not share your user or nand folders after performing the setup process!
- While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the console later from the System Files tab in the emulator options menu.
- Do not go online with both Azahar and your 3DS console at the same time after setting up system files, as this could cause issues.
- Old 3DS setup is needed for the New 3DS setup to work (setting up both is recommended).
- Both setup modes will work regardless of the model of the console running the setup tool.
]]>
Fetching current system files status, please wait...
+ Unlink Console Unique Data
+ - Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.
- Your friend list will reset and you will be logged out of your NNID/PNID account.
- System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again using the setup tool (save data will not be lost).
Continue?]]>
Old 3DS Setup
New 3DS Setup
Setup is possible.
@@ -168,20 +174,20 @@
Buttons
Button
-
- CPU JIT
- Uses the Just-in-Time (JIT) compiler for CPU emulation. When enabled, game performance will be significantly improved.
- Clock
- Set the emulated 3DS clock to either reflect that of your device or start at a simulated date and time.
- CPU Clock Speed
-
+ Emulation Settings
Username
New 3DS Mode
Use LLE Applets (if installed)
+ Enable required LLE modules for online features (if installed)
+ Enables the LLE modules required for online multiplayer, eShop access, etc.
Clock
- Offset Time
- If the clock is set to \"Simulated clock\", this changes the fixed date and time to start at.
+ Clock
+ Set the emulated 3DS clock to either reflect that of your device or start at a simulated date and time.
+ Device Clock
+ Simulated Clock
+ If the clock is set to \"Simulated clock\", this changes the fixed date and time to start at.
+ Profile Settings
Region
Language
Birthday
@@ -194,10 +200,16 @@
Console ID
Regenerate Console ID
This will replace your current virtual 3DS console ID with a new one. Your current virtual 3DS console ID will not be recoverable. This might have unexpected effects inside applications. This might fail if you use an outdated config save. Continue?
+ MAC Address
+ Regenerate MAC Address
+ This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue?
3GX Plugin Loader
Loads 3GX plugins from the emulated SD card if they are available.
Allow Applications to Change Plugin Loader State
Allows homebrew apps to enable the plugin loader even when it is disabled.
+ Region Mismatch Warning
+ The country setting is not valid for the selected emulated region.
+ The country setting is not valid for the current linked console.
Inner Camera
@@ -219,26 +231,30 @@
Emits the fragment shader used to emulate PICA using SPIR-V instead of GLSL
Enable asynchronous shader compilation
Compiles shaders in the background to reduce stuttering during gameplay. When enabled expect temporary graphical glitches
- Debug Renderer
- Log additional graphics related debug information. When enabled, game performance will be significantly reduced.
- Enable V-Sync
- Synchronizes the game frame rate to the refresh rate of your device.
Linear Filtering
Enables linear filtering, which causes game visuals to appear smoother.
Texture Filter
Enhances the visuals of applications by applying a filter to textures. The supported filters are Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale, and MMPX.
- Enable Hardware Shader
- Uses hardware to emulate 3DS shaders. When enabled, game performance will be significantly improved.
+ Delay game render thread
+ Delay the game render thread when it submits data to the GPU. Helps with performance issues in the (very few) applications with dynamic framerates.
+ Advanced"
+ Texture Sampling
+ Overrides the sampling filter used by games. This can be useful in certain cases with poorly behaved games when upscaling. If unsure, set this to Game Controlled.
Accurate Multiplication
Uses more accurate multiplication in hardware shaders, which may fix some graphical bugs. When enabled, performance will be reduced.
Enable asynchronous GPU emulation
Uses a separate thread to emulate the GPU asynchronously. When enabled, performance will be improved.
Limit Speed
- When enabled, emulation speed will be limited to a specified percentage of normal speed.
+ When enabled, emulation speed will be limited to a specified percentage of normal speed. If disabled, emulation speed will be uncapped and the turbo speed hotkey will not work.
Limit Speed Percent
Specifies the percentage to limit emulation speed. With the default of 100% emulation will be limited to normal speed. Values higher or lower will increase or decrease the speed limit.
+ Turbo Speed Limit
+ Emulation speed limit used while the turbo hotkey is active.
+ Expand to Cutout Area
+ Expands the display area to include the cutout (or notch) area.
Internal Resolution
Specifies the resolution used to render at. A high resolution will improve visual quality a lot but is also quite heavy on performance and might cause glitches in certain applications.
+ Auto (Screen Size)
Native (400x240)
2x Native (800x480)
3x Native (1200x720)
@@ -254,7 +270,9 @@
Stereoscopy
Stereoscopic 3D Mode
Depth
- Specifies the value of the 3D slider. This should be set to higher than 0% when Stereoscopic 3D is enabled.
+ Specifies the value of the 3D slider. This should be set to higher than 0% when Stereoscopic 3D is enabled.\nNote: Depth values over 100% are not possible on real hardware and may cause graphical issues
+ Disable Right Eye Render
+ Greatly improves performance in some applications, but can cause flickering in others.
Cardboard VR
Cardboard Screen Size
Scales the screen to a percentage of its original size.
@@ -284,6 +302,23 @@
Audio Input Device
Sound Output Mode
+
+ CPU JIT
+ Uses the Just-in-Time (JIT) compiler for CPU emulation. When enabled, game performance will be significantly improved.
+ Enable Hardware Shader
+ Uses hardware to emulate 3DS shaders. When enabled, game performance will be significantly improved.
+ CPU Clock Speed
+ Enable V-Sync
+ Synchronizes the game frame rate to the refresh rate of your device.
+ Debug Renderer
+ Log additional graphics related debug information. When enabled, game performance will be significantly reduced.
+ Flush log output on every message
+ Immediately commits the debug log to file. Use this if Azahar crashes and the log output is being cut.
+ Delay start with LLE modules
+ Delays the start of the app when LLE modules are enabled.
+ Deterministic Async Operations
+ Makes async operations deterministic for debugging. Enabling this may cause freezes.
+
Screen Orientation
Automatic
@@ -298,6 +333,7 @@
Saved settings
Saved settings for %1$s
Error saving %1$s.ini: %2$s
+ Saving…
Loading…
Next
Back
@@ -318,8 +354,14 @@
Select RTC time
Do you want to reset this setting back to its default value?
You can\'t edit this now
+ Setting disabled
+ This setting is currently disabled due to another setting not being the appropriate value.
This option can\'t be changed while a game is running.
Auto-Select
+ Start
+ Cancelling…
+ Important
+ Don\'t show again
Select Game Folder
@@ -387,6 +429,8 @@
Bottom Left
Above
Below
+ Screen Gap
+ Gap between screens in all two-screen modes. Measured in px relative to the 240px height of the larger screen.
Large Screen Proportion
How many times larger is the large screen than the small screen in Large Screen layout?
Adjust Custom Layout in Settings
@@ -404,6 +448,9 @@
Show Overlay
Close Game
Toggle Pause
+ Miscellaneous
+ Use Artic Controller when connected to Artic Base Server
+ Use the controls provided by Artic Base Server when connected to it instead of the configured input device.
Are you sure that you would like to close the current game?
Amiibo
Load
@@ -475,6 +522,17 @@
Play
Shortcut
+ Uninstall Application
+ Uninstalling...
+ Open Save Data Folder
+ Open Application Folder
+ Open Mods Folder
+ Open Textures Folder
+ Open DLC Folder
+ Open Updates Folder
+ Open Extra Folder
+ Uninstall DLC
+ Uninstall Updates
Cheats
@@ -536,10 +594,6 @@
Black Backgrounds
When using the dark theme, apply black backgrounds.
-
- Device Clock
- Simulated Clock
-
JPN
USA
@@ -596,11 +650,15 @@
Anime4K
Bicubic
- Nearest Neighbor
ScaleForce
xBRZ
MMPX
+
+ Game Controlled
+ Nearest Neighbor
+ Linear
+
Mono
Stereo
@@ -761,33 +819,12 @@
Connect to a real console that is running an Artic Base server
Connect to Artic Base
Enter Artic Base server address
- Delay game render thread
- Delay the game render thread when it submits data to the GPU. Helps with performance issues in the (very few) applications with dynamic framerates.
Quicksave
Quicksave
Quickload
Quicksave - %1$tF %1$tR
- Saving…
- Loading…
No Quicksave available.
- Miscellaneous
- Use Artic Controller when connected to Artic Base Server
- Use the controls provided by Artic Base Server when connected to it instead of the configured input device.
- Flush log output on every message
- Immediately commits the debug log to file. Use this if Azahar crashes and the log output is being cut.
- Disable Right Eye Render
- Greatly improves performance in some applications, but can cause flickering in others.
- Delay start with LLE modules
- Delays the start of the app when LLE modules are enabled.
- Deterministic Async Operations
- Makes async operations deterministic for debugging. Enabling this may cause freezes.
- Enable required LLE modules for online features (if installed)
- Enables the LLE modules required for online multiplayer, eShop access, etc.
- Emulation Settings
- Profile Settings
- MAC Address
- Regenerate MAC Address
- This will replace your current MAC address with a new one. It is not recommended to do this if you got the MAC address from your real console using the setup tool. Continue?
+
diff --git a/src/audio_core/cubeb_input.cpp b/src/audio_core/cubeb_input.cpp
index f182bd2c2..0cd650af6 100644
--- a/src/audio_core/cubeb_input.cpp
+++ b/src/audio_core/cubeb_input.cpp
@@ -1,4 +1,4 @@
-// Copyright 2018 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -144,6 +144,11 @@ Samples CubebInput::Read() {
while (impl->sample_queue.Pop(queue)) {
samples.insert(samples.end(), queue.begin(), queue.end());
}
+
+ if (samples.empty()) {
+ samples = GenerateSilentSamples(parameters);
+ }
+
return samples;
}
diff --git a/src/audio_core/input.h b/src/audio_core/input.h
index ba2621890..e47f5942c 100644
--- a/src/audio_core/input.h
+++ b/src/audio_core/input.h
@@ -1,4 +1,4 @@
-// Copyright 2023 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -53,6 +53,22 @@ public:
*/
virtual Samples Read() = 0;
+ /**
+ * Generates a buffer of silence.
+ * Takes into account the sample size and signedness of the input.
+ */
+ virtual Samples GenerateSilentSamples(const InputParameters& params) {
+ u8 silent_value = 0x00;
+
+ if (params.sample_size == 8) {
+ silent_value = params.sign == Signedness::Unsigned ? 0x80 : 0x00;
+ return std::vector(32, silent_value);
+ } else {
+ silent_value = params.sign == Signedness::Unsigned ? 0x80 : 0x00;
+ return std::vector(64, silent_value);
+ }
+ }
+
protected:
InputParameters parameters;
};
diff --git a/src/audio_core/null_input.h b/src/audio_core/null_input.h
index 00dacf5bd..1b0796ea7 100644
--- a/src/audio_core/null_input.h
+++ b/src/audio_core/null_input.h
@@ -1,4 +1,4 @@
-// Copyright 2019 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -30,10 +30,11 @@ public:
void AdjustSampleRate(u32 sample_rate) override {}
Samples Read() override {
- return {};
+ return GenerateSilentSamples(parameters);
}
private:
+ InputParameters parameters;
bool is_sampling = false;
};
diff --git a/src/audio_core/openal_input.cpp b/src/audio_core/openal_input.cpp
index 935b16454..3d4c55fb0 100644
--- a/src/audio_core/openal_input.cpp
+++ b/src/audio_core/openal_input.cpp
@@ -1,4 +1,4 @@
-// Copyright 2023 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -108,6 +108,10 @@ Samples OpenALInput::Read() {
return {};
}
+ if (samples.empty()) {
+ samples = GenerateSilentSamples(parameters);
+ }
+
return samples;
}
diff --git a/src/citra_meta/CMakeLists.txt b/src/citra_meta/CMakeLists.txt
index 8fe6459a9..68f35bbae 100644
--- a/src/citra_meta/CMakeLists.txt
+++ b/src/citra_meta/CMakeLists.txt
@@ -52,6 +52,10 @@ if (ENABLE_QT)
target_link_libraries(citra_meta PRIVATE Boost::boost Qt6::Widgets)
endif()
+if (ENABLE_ROOM)
+ target_link_libraries(citra_meta PRIVATE citra_room)
+endif()
+
if (ENABLE_QT AND UNIX AND NOT APPLE)
target_link_libraries(citra_meta PRIVATE Qt6::DBus gamemode)
endif()
diff --git a/src/citra_meta/common_strings.h b/src/citra_meta/common_strings.h
index a0f1ed31b..4d78f3a05 100644
--- a/src/citra_meta/common_strings.h
+++ b/src/citra_meta/common_strings.h
@@ -1,4 +1,4 @@
-// Copyright Citra Emulator Project / Lime3DS Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -25,6 +25,10 @@ constexpr char help_string[] =
// TODO: Move -m outside of this check when it is implemented in Qt frontend
"-m, --multiplayer [nick:password@address:port] Nickname, password, address and port for "
"multiplayer (currently only usable with SDL frontend)\n"
+#endif
+#ifdef ENABLE_ROOM
+ " --room Utilize dedicated multiplayer room functionality (equivalent to "
+ "the old citra-room executable)\n"
#endif
"-v, --version Output version information and exit\n"
"-w, --windowed Start in windowed mode";
diff --git a/src/citra_meta/main.cpp b/src/citra_meta/main.cpp
index cbe2774cc..5c8936f30 100644
--- a/src/citra_meta/main.cpp
+++ b/src/citra_meta/main.cpp
@@ -1,4 +1,4 @@
-// Copyright Citra Emulator Project / Lime3DS Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -7,6 +7,9 @@
#ifdef ENABLE_QT
#include "citra_qt/citra_qt.h"
#endif
+#ifdef ENABLE_ROOM
+#include "citra_room/citra_room.h"
+#endif
#ifdef ENABLE_SDL2_FRONTEND
#include "citra_sdl/citra_sdl.h"
#endif
@@ -19,6 +22,20 @@ __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
#endif
int main(int argc, char* argv[]) {
+#if ENABLE_ROOM
+ bool launch_room = false;
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--room") == 0) {
+ launch_room = true;
+ }
+ }
+
+ if (launch_room) {
+ LaunchRoom(argc, argv, true);
+ return 0;
+ }
+#endif
+
#if ENABLE_QT
bool no_gui = false;
for (int i = 1; i < argc; i++) {
@@ -42,4 +59,4 @@ int main(int argc, char* argv[]) {
#endif
return 0;
-}
\ No newline at end of file
+}
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index fcab2be0b..5b2842aa3 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -1,4 +1,4 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -10,6 +10,7 @@
#include
#include "citra_qt/bootmanager.h"
#include "citra_qt/citra_qt.h"
+#include "citra_qt/util/util.h"
#include "common/color.h"
#include "common/microprofile.h"
#include "common/scm_rev.h"
@@ -71,9 +72,14 @@ void EmuThread::run() {
std::size_t total) { emit LoadProgress(stage, value, total); });
}
+ system.GPU().Renderer().Rasterizer()->SetSwitchDiskResourcesCallback(
+ [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
+ emit SwitchDiskResources(stage, value, total);
+ });
+
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
- system.GPU().Renderer().Rasterizer()->LoadDiskResources(
+ system.GPU().Renderer().Rasterizer()->LoadDefaultDiskResources(
stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
emit LoadProgress(stage, value, total);
});
@@ -714,7 +720,7 @@ void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_p
screenshot_image.bits(),
[this, screenshot_path](bool invert_y) {
const std::string std_screenshot_path = screenshot_path.toStdString();
- if (screenshot_image.mirrored(false, invert_y).save(screenshot_path)) {
+ if (GetMirroredImage(screenshot_image, false, invert_y).save(screenshot_path)) {
LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path);
} else {
LOG_ERROR(Frontend, "Failed to save screenshot to \"{}\"", std_screenshot_path);
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index 24fdf45e3..8082b5590 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -1,4 +1,4 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -110,6 +110,9 @@ signals:
void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total);
+ void SwitchDiskResources(VideoCore::LoadCallbackStage stage, std::size_t value,
+ std::size_t total);
+
void HideLoadingScreen();
};
diff --git a/src/citra_qt/camera/camera_util.cpp b/src/citra_qt/camera/camera_util.cpp
index 878ac910c..d0031e6f2 100644
--- a/src/citra_qt/camera/camera_util.cpp
+++ b/src/citra_qt/camera/camera_util.cpp
@@ -1,4 +1,4 @@
-// Copyright 2018 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -7,6 +7,7 @@
#include
#include
#include "citra_qt/camera/camera_util.h"
+#include "citra_qt/util/util.h"
namespace CameraUtil {
@@ -213,9 +214,9 @@ std::vector ProcessImage(const QImage& image, int width, int height, bool o
}
QImage scaled =
image.scaled(width, height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
- QImage transformed =
- scaled.copy((scaled.width() - width) / 2, (scaled.height() - height) / 2, width, height)
- .mirrored(flip_horizontal, flip_vertical);
+ QImage transformed = GetMirroredImage(
+ scaled.copy((scaled.width() - width) / 2, (scaled.height() - height) / 2, width, height),
+ flip_horizontal, flip_vertical);
if (output_rgb) {
QImage converted = transformed.convertToFormat(QImage::Format_RGB16);
std::memcpy(buffer.data(), converted.bits(), width * height * sizeof(u16));
diff --git a/src/citra_qt/citra_qt.cpp b/src/citra_qt/citra_qt.cpp
index 9f0a0ea6b..5cb575b9e 100644
--- a/src/citra_qt/citra_qt.cpp
+++ b/src/citra_qt/citra_qt.cpp
@@ -329,6 +329,8 @@ GMainWindow::GMainWindow(Core::System& system_)
ui->setupUi(this);
statusBar()->hide();
+ setWindowIcon(QIcon(QString::fromStdString(":/icons/azahar.png")));
+
default_theme_paths = QIcon::themeSearchPaths();
UpdateUITheme();
@@ -387,14 +389,22 @@ GMainWindow::GMainWindow(Core::System& system_)
LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", mem_info.total_swap_memory / f64{1_GiB});
UpdateWindowTitle();
+#ifdef __APPLE__
+ // Workaround for https://github.com/azahar-emu/azahar/issues/933
+ ui->menubar->setNativeMenuBar(false);
+#endif
+
show();
#ifdef ENABLE_QT_UPDATE_CHECKER
if (UISettings::values.check_for_update_on_start) {
update_future = QtConcurrent::run([]() -> QString {
- const std::optional latest_release = UpdateChecker::CheckForUpdate();
- if (latest_release && latest_release.value() != Common::g_build_fullname) {
- return QString::fromStdString(latest_release.value());
+ const bool is_prerelease = // TODO: This can be done better -OS
+ (strstr(Common::g_build_fullname, "rc") != NULL);
+ const std::optional latest_release_tag =
+ UpdateChecker::GetLatestRelease(is_prerelease);
+ if (latest_release_tag && latest_release_tag.value() != Common::g_build_fullname) {
+ return QString::fromStdString(latest_release_tag.value());
}
return QString{};
});
@@ -498,6 +508,8 @@ void GMainWindow::InitializeWidgets() {
progress_bar->hide();
statusBar()->addPermanentWidget(progress_bar);
+ loading_shaders_label = new QLabel();
+
artic_traffic_label = new QLabel();
artic_traffic_label->setToolTip(
tr("Current Artic traffic speed. Higher values indicate bigger transfer loads."));
@@ -513,8 +525,8 @@ void GMainWindow::InitializeWidgets() {
tr("Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For "
"full-speed emulation this should be at most 16.67 ms."));
- for (auto& label :
- {artic_traffic_label, emu_speed_label, game_fps_label, emu_frametime_label}) {
+ for (auto& label : {loading_shaders_label, artic_traffic_label, emu_speed_label, game_fps_label,
+ emu_frametime_label}) {
label->setVisible(false);
label->setFrameStyle(QFrame::NoFrame);
label->setContentsMargins(4, 0, 4, 0);
@@ -696,25 +708,36 @@ void GMainWindow::InitializeRecentFileMenuActions() {
void GMainWindow::InitializeSaveStateMenuActions() {
for (u32 i = 0; i < Core::SaveStateSlotCount; ++i) {
actions_load_state[i] = new QAction(this);
- actions_load_state[i]->setData(i + 1);
+ actions_load_state[i]->setData(i);
connect(actions_load_state[i], &QAction::triggered, this, &GMainWindow::OnLoadState);
- ui->menu_Load_State->addAction(actions_load_state[i]);
-
+ if (i > 0)
+ ui->menu_Load_State->addAction(actions_load_state[i]);
actions_save_state[i] = new QAction(this);
- actions_save_state[i]->setData(i + 1);
+ actions_save_state[i]->setData(i);
connect(actions_save_state[i], &QAction::triggered, this, &GMainWindow::OnSaveState);
- ui->menu_Save_State->addAction(actions_save_state[i]);
+ if (i > 0)
+ ui->menu_Save_State->addAction(actions_save_state[i]);
}
connect(ui->action_Load_from_Newest_Slot, &QAction::triggered, this, [this] {
UpdateSaveStates();
if (newest_slot != 0) {
- actions_load_state[newest_slot - 1]->trigger();
+ actions_load_state[newest_slot]->trigger();
}
});
connect(ui->action_Save_to_Oldest_Slot, &QAction::triggered, this, [this] {
UpdateSaveStates();
- actions_save_state[oldest_slot - 1]->trigger();
+ actions_save_state[oldest_slot]->trigger();
+ });
+
+ // Quick save / load uses slot
+ connect(ui->action_Quick_Save, &QAction::triggered, this, [this] {
+ UpdateSaveStates();
+ actions_save_state[0]->trigger();
+ });
+ connect(ui->action_Quick_Load, &QAction::triggered, this, [this] {
+ UpdateSaveStates();
+ actions_load_state[0]->trigger();
});
connect(ui->menu_Load_State->menuAction(), &QAction::hovered, this,
@@ -757,8 +780,12 @@ void GMainWindow::InitializeHotkeys() {
link_action_shortcut(ui->action_Screen_Layout_Upright_Screens,
QStringLiteral("Rotate Screens Upright"));
link_action_shortcut(ui->action_Advance_Frame, QStringLiteral("Advance Frame"));
- link_action_shortcut(ui->action_Load_from_Newest_Slot, QStringLiteral("Load from Newest Slot"));
- link_action_shortcut(ui->action_Save_to_Oldest_Slot, QStringLiteral("Save to Oldest Slot"));
+ link_action_shortcut(ui->action_Load_from_Newest_Slot,
+ QStringLiteral("Load from Newest Non-Quicksave Slot"));
+ link_action_shortcut(ui->action_Save_to_Oldest_Slot,
+ QStringLiteral("Save to Oldest Non-Quicksave Slot"));
+ link_action_shortcut(ui->action_Quick_Save, QStringLiteral("Quick Save"));
+ link_action_shortcut(ui->action_Quick_Load, QStringLiteral("Quick Load"));
link_action_shortcut(ui->action_View_Lobby, QStringLiteral("Multiplayer Browse Public Rooms"));
link_action_shortcut(ui->action_Start_Room, QStringLiteral("Multiplayer Create Room"));
link_action_shortcut(ui->action_Connect_To_Room,
@@ -783,6 +810,11 @@ void GMainWindow::InitializeHotkeys() {
}
});
connect_shortcut(QStringLiteral("Toggle Per-Application Speed"), [&] {
+ if (!hotkey_registry
+ .GetKeySequence(QStringLiteral("Main Window"), QStringLiteral("Toggle Turbo Mode"))
+ .isEmpty()) {
+ return;
+ }
Settings::values.frame_limit.SetGlobal(!Settings::values.frame_limit.UsingGlobal());
UpdateStatusBar();
});
@@ -790,31 +822,12 @@ void GMainWindow::InitializeHotkeys() {
[&] { Settings::values.dump_textures = !Settings::values.dump_textures; });
connect_shortcut(QStringLiteral("Toggle Custom Textures"),
[&] { Settings::values.custom_textures = !Settings::values.custom_textures; });
- // We use "static" here in order to avoid capturing by lambda due to a MSVC bug, which makes
- // the variable hold a garbage value after this function exits
- static constexpr u16 SPEED_LIMIT_STEP = 5;
- connect_shortcut(QStringLiteral("Increase Speed Limit"), [&] {
- if (Settings::values.frame_limit.GetValue() == 0) {
- return;
- }
- if (Settings::values.frame_limit.GetValue() < 995 - SPEED_LIMIT_STEP) {
- Settings::values.frame_limit.SetValue(Settings::values.frame_limit.GetValue() +
- SPEED_LIMIT_STEP);
- } else {
- Settings::values.frame_limit = 0;
- }
- UpdateStatusBar();
- });
- connect_shortcut(QStringLiteral("Decrease Speed Limit"), [&] {
- if (Settings::values.frame_limit.GetValue() == 0) {
- Settings::values.frame_limit = 995;
- } else if (Settings::values.frame_limit.GetValue() > SPEED_LIMIT_STEP) {
- Settings::values.frame_limit.SetValue(Settings::values.frame_limit.GetValue() -
- SPEED_LIMIT_STEP);
- UpdateStatusBar();
- }
- UpdateStatusBar();
- });
+
+ connect_shortcut(QStringLiteral("Toggle Turbo Mode"),
+ [&] { GMainWindow::SetTurboEnabled(!GMainWindow::IsTurboEnabled()); });
+
+ connect_shortcut(QStringLiteral("Increase Speed Limit"), [&] { AdjustSpeedLimit(true); });
+ connect_shortcut(QStringLiteral("Decrease Speed Limit"), [&] { AdjustSpeedLimit(false); });
connect_shortcut(QStringLiteral("Audio Mute/Unmute"), &GMainWindow::OnMute);
connect_shortcut(QStringLiteral("Audio Volume Down"), &GMainWindow::OnDecreaseVolume);
@@ -836,7 +849,7 @@ void GMainWindow::InitializeHotkeys() {
});
connect_shortcut(QStringLiteral("Increase 3D Factor"), [this] {
const auto factor_3d = Settings::values.factor_3d.GetValue();
- if (factor_3d < 100) {
+ if (factor_3d < 255) {
if (factor_3d % FACTOR_3D_STEP != 0) {
Settings::values.factor_3d =
factor_3d + FACTOR_3D_STEP - (factor_3d % FACTOR_3D_STEP);
@@ -1427,6 +1440,8 @@ void GMainWindow::BootGame(const QString& filename) {
connect(emu_thread.get(), &EmuThread::LoadProgress, loading_screen,
&LoadingScreen::OnLoadProgress, Qt::QueuedConnection);
+ connect(emu_thread.get(), &EmuThread::SwitchDiskResources, this,
+ &GMainWindow::OnSwitchDiskResources, Qt::QueuedConnection);
connect(emu_thread.get(), &EmuThread::HideLoadingScreen, loading_screen,
&LoadingScreen::OnLoadComplete);
@@ -1526,6 +1541,7 @@ void GMainWindow::ShutdownGame() {
status_bar_update_timer.stop();
message_label_used_for_movie = false;
show_artic_label = false;
+ loading_shaders_label->setVisible(false);
artic_traffic_label->setVisible(false);
emu_speed_label->setVisible(false);
game_fps_label->setVisible(false);
@@ -1591,7 +1607,7 @@ void GMainWindow::UpdateSaveStates() {
ui->menu_Save_State->setEnabled(true);
ui->action_Load_from_Newest_Slot->setEnabled(false);
- oldest_slot = newest_slot = 0;
+ oldest_slot = newest_slot = 1;
oldest_slot_time = std::numeric_limits::max();
newest_slot_time = 0;
@@ -1602,13 +1618,33 @@ void GMainWindow::UpdateSaveStates() {
auto savestates = Core::ListSaveStates(title_id, movie.GetCurrentMovieID());
for (u32 i = 0; i < Core::SaveStateSlotCount; ++i) {
actions_load_state[i]->setEnabled(false);
- actions_load_state[i]->setText(tr("Slot %1").arg(i + 1));
- actions_save_state[i]->setText(tr("Slot %1").arg(i + 1));
+ if (i == 0) {
+ actions_load_state[i]->setText(tr("Quick Load"));
+ actions_save_state[i]->setText(tr("Quick Save"));
+ } else {
+ actions_load_state[i]->setText(tr("Slot %1").arg(i));
+ actions_save_state[i]->setText(tr("Slot %1").arg(i));
+ }
}
for (const auto& savestate : savestates) {
+ if (savestate.slot >= Core::SaveStateSlotCount) {
+ continue;
+ }
const bool display_name =
savestate.status == Core::SaveStateInfo::ValidationStatus::RevisionDismatch &&
!savestate.build_name.empty();
+ actions_load_state[savestate.slot]->setEnabled(true);
+ if (savestate.slot == 0) {
+ const auto text = tr("%2 %3")
+ .arg(QDateTime::fromSecsSinceEpoch(savestate.time)
+ .toString(QStringLiteral("yyyy-MM-dd hh:mm:ss")))
+ .arg(display_name ? QString::fromStdString(savestate.build_name)
+ : QLatin1String())
+ .trimmed();
+ ui->action_Quick_Save->setText(tr("Quick Save - %1").arg(text).trimmed());
+ ui->action_Quick_Load->setText(tr("Quick Load - %1").arg(text).trimmed());
+ continue;
+ }
const auto text =
tr("Slot %1 - %2 %3")
.arg(savestate.slot)
@@ -1617,12 +1653,10 @@ void GMainWindow::UpdateSaveStates() {
.arg(display_name ? QString::fromStdString(savestate.build_name) : QLatin1String())
.trimmed();
- actions_load_state[savestate.slot - 1]->setEnabled(true);
- actions_load_state[savestate.slot - 1]->setText(text);
- actions_save_state[savestate.slot - 1]->setText(text);
+ actions_load_state[savestate.slot]->setText(text);
+ actions_save_state[savestate.slot]->setText(text);
ui->action_Load_from_Newest_Slot->setEnabled(true);
-
if (savestate.time > newest_slot_time) {
newest_slot = savestate.slot;
newest_slot_time = savestate.time;
@@ -1632,10 +1666,11 @@ void GMainWindow::UpdateSaveStates() {
oldest_slot_time = savestate.time;
}
}
- for (u32 i = 0; i < Core::SaveStateSlotCount; ++i) {
+ // Value as 1 because quicksave slot is not used for this calculation
+ for (u32 i = 1; i < Core::SaveStateSlotCount; ++i) {
if (!actions_load_state[i]->isEnabled()) {
// Prefer empty slot
- oldest_slot = i + 1;
+ oldest_slot = i;
oldest_slot_time = 0;
break;
}
@@ -2112,15 +2147,18 @@ void GMainWindow::OnMenuSetUpSystemFiles() {
QVBoxLayout layout(&dialog);
QLabel label_description(
- tr("Azahar needs files from a real console to be able to use some of its features.
"
- "You can get such files with the Azahar needs console unique data and firmware files from a real console to be "
+ "able to use some of its features.
Such files and data can be set up with the Azahar "
- "Artic Setup Tool
Notes:
- This operation will install console unique "
- "files "
- "to Azahar, do not share your user or nand folders
after performing the setup "
- "process! - Old 3DS setup is needed for the New 3DS setup to "
- "work.
- Both setup modes will work regardless of the model of the console "
- "running the setup tool.
"),
+ "Artic Setup Tool
Notes:- This operation will install console unique "
+ "data to Azahar, do not share your user or nand folders
after performing the setup "
+ "process! - While doing the setup process, Azahar will link to the console "
+ "running the setup tool. You can unlink the
console later from the System tab in the "
+ "emulator configuration menu. - Do not go online with both Azahar and your 3DS "
+ "console at the same time after setting up system files,
as it could cause "
+ "issues. - Old 3DS setup is needed for the New 3DS setup to work (doing both "
+ "setup modes is recommended).
- Both setup modes will work regardless of the "
+ "model of the console running the setup tool.
"),
&dialog);
label_description.setOpenExternalLinks(true);
layout.addWidget(&label_description);
@@ -2417,6 +2455,8 @@ void GMainWindow::OnPauseContinueGame() {
}
void GMainWindow::OnStopGame() {
+ SetTurboEnabled(false);
+
play_time_manager->Stop();
// Update game list to show new play time
game_list->PopulateAsync(UISettings::values.game_dirs);
@@ -2568,6 +2608,50 @@ void GMainWindow::ChangeSmallScreenPosition() {
UpdateSecondaryWindowVisibility();
}
+bool GMainWindow::IsTurboEnabled() {
+ return turbo_mode_active;
+}
+
+void GMainWindow::SetTurboEnabled(bool state) {
+ turbo_mode_active = state;
+ GMainWindow::ReloadTurbo();
+}
+
+void GMainWindow::ReloadTurbo() {
+ if (IsTurboEnabled()) {
+ Settings::temporary_frame_limit = Settings::values.turbo_limit.GetValue();
+ Settings::is_temporary_frame_limit = true;
+ } else {
+ Settings::is_temporary_frame_limit = false;
+ }
+
+ UpdateStatusBar();
+}
+
+// TODO: This should probably take in something more descriptive than a bool. -OS
+void GMainWindow::AdjustSpeedLimit(bool increase) {
+ const int SPEED_LIMIT_STEP = 5;
+ auto active_limit =
+ IsTurboEnabled() ? &Settings::values.turbo_limit : &Settings::values.frame_limit;
+ const auto active_limit_value = active_limit->GetValue();
+
+ if (increase) {
+ if (active_limit_value < 995) {
+ active_limit->SetValue(active_limit_value + SPEED_LIMIT_STEP);
+ }
+ } else {
+ if (active_limit_value > SPEED_LIMIT_STEP) {
+ active_limit->SetValue(active_limit_value - SPEED_LIMIT_STEP);
+ }
+ }
+
+ if (IsTurboEnabled()) {
+ ReloadTurbo();
+ }
+
+ UpdateStatusBar();
+}
+
void GMainWindow::ToggleScreenLayout() {
const Settings::LayoutOption new_layout = []() {
switch (Settings::values.layout_option.GetValue()) {
@@ -2685,6 +2769,7 @@ void GMainWindow::OnConfigure() {
} else {
setMouseTracking(false);
}
+ ReloadTurbo();
UpdateSecondaryWindowVisibility();
UpdateBootHomeMenuState();
UpdateStatusButtons();
@@ -2908,7 +2993,7 @@ void GMainWindow::ShowFFmpegErrorMessage() {
message_box.setText(
tr("FFmpeg could not be loaded. Make sure you have a compatible version installed."
#ifdef _WIN32
- "\n\nTo install FFmpeg to Lime, press Open and select your FFmpeg directory."
+ "\n\nTo install FFmpeg to Azahar, press Open and select your FFmpeg directory."
#endif
"\n\nTo view a guide on how to install FFmpeg, press Help."));
message_box.setStandardButtons(QMessageBox::Ok | QMessageBox::Help
@@ -3642,6 +3727,18 @@ void GMainWindow::OnEmulatorUpdateAvailable() {
}
#endif
+void GMainWindow::OnSwitchDiskResources(VideoCore::LoadCallbackStage stage, std::size_t value,
+ std::size_t total) {
+ if (stage == VideoCore::LoadCallbackStage::Prepare) {
+ loading_shaders_label->setText(QString());
+ loading_shaders_label->setVisible(true);
+ } else if (stage == VideoCore::LoadCallbackStage::Complete) {
+ loading_shaders_label->setVisible(false);
+ } else {
+ loading_shaders_label->setText(loading_screen->GetStageTranslation(stage, value, total));
+ }
+}
+
void GMainWindow::UpdateWindowTitle() {
const QString full_name = QString::fromUtf8(Common::g_build_fullname);
@@ -3812,7 +3909,9 @@ void LaunchQtFrontend(int argc, char* argv[]) {
// Init settings params
QCoreApplication::setOrganizationName(QStringLiteral("Azahar Developers"));
+ QCoreApplication::setOrganizationDomain(QStringLiteral("azahar_emu.org"));
QCoreApplication::setApplicationName(QStringLiteral("Azahar"));
+ QGuiApplication::setDesktopFileName(QStringLiteral("org.azahar_emu.Azahar"));
auto rounding_policy = GetHighDpiRoundingPolicy();
QApplication::setHighDpiScaleFactorRoundingPolicy(rounding_policy);
diff --git a/src/citra_qt/citra_qt.h b/src/citra_qt/citra_qt.h
index 1c5184928..c8d74a131 100644
--- a/src/citra_qt/citra_qt.h
+++ b/src/citra_qt/citra_qt.h
@@ -24,6 +24,7 @@
#include "citra_qt/user_data_migration.h"
#include "core/core.h"
#include "core/savestate.h"
+#include "video_core/rasterizer_interface.h"
// Needs to be included at the end due to https://bugreports.qt.io/browse/QTBUG-73263
#include
@@ -260,6 +261,10 @@ private slots:
void ToggleSecondaryFullscreen();
void ChangeScreenLayout();
void ChangeSmallScreenPosition();
+ bool IsTurboEnabled();
+ void SetTurboEnabled(bool);
+ void ReloadTurbo();
+ void AdjustSpeedLimit(bool increase);
void UpdateSecondaryWindowVisibility();
void ToggleScreenLayout();
void OnSwapScreens();
@@ -295,6 +300,8 @@ private slots:
#ifdef ENABLE_QT_UPDATE_CHECKER
void OnEmulatorUpdateAvailable();
#endif
+ void OnSwitchDiskResources(VideoCore::LoadCallbackStage stage, std::size_t value,
+ std::size_t total);
private:
Q_INVOKABLE void OnMoviePlaybackCompleted();
@@ -330,6 +337,7 @@ private:
QProgressBar* progress_bar = nullptr;
QLabel* message_label = nullptr;
bool show_artic_label = false;
+ QLabel* loading_shaders_label = nullptr;
QLabel* artic_traffic_label = nullptr;
QLabel* emu_speed_label = nullptr;
QLabel* game_fps_label = nullptr;
@@ -348,6 +356,9 @@ private:
UserDataMigrator user_data_migrator;
std::unique_ptr config;
+ // Hotkeys
+ bool turbo_mode_active = false;
+
// Whether emulation is currently running in Citra.
bool emulation_running = false;
std::unique_ptr emu_thread;
diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp
index c72810b37..426600bdc 100644
--- a/src/citra_qt/configuration/config.cpp
+++ b/src/citra_qt/configuration/config.cpp
@@ -54,7 +54,7 @@ const std::array, Settings::NativeAnalog::NumAnalogs> QtConfi
// This must be in alphabetical order according to action name as it must have the same order as
// UISetting::values.shortcuts, which is alphabetically ordered.
// clang-format off
-const std::array QtConfig::default_hotkeys {{
+const std::array QtConfig::default_hotkeys {{
{QStringLiteral("Advance Frame"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::ApplicationShortcut}},
{QStringLiteral("Audio Mute/Unmute"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), Qt::WindowShortcut}},
{QStringLiteral("Audio Volume Down"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WindowShortcut}},
@@ -70,26 +70,29 @@ const std::array QtConfig::default_hotkeys {{
{QStringLiteral("Increase Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("+"), Qt::ApplicationShortcut}},
{QStringLiteral("Load Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), Qt::WidgetWithChildrenShortcut}},
{QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), Qt::WidgetWithChildrenShortcut}},
- {QStringLiteral("Load from Newest Slot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+V"), Qt::WindowShortcut}},
- {QStringLiteral("Multiplayer Browse Public Lobby"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+B"), Qt::ApplicationShortcut}},
+ {QStringLiteral("Load from Newest Non-Quicksave Slot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+V"), Qt::WindowShortcut}},
+ {QStringLiteral("Multiplayer Browse Public Rooms"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+B"), Qt::ApplicationShortcut}},
{QStringLiteral("Multiplayer Create Room"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+N"), Qt::ApplicationShortcut}},
{QStringLiteral("Multiplayer Direct Connect to Room"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Shift"), Qt::ApplicationShortcut}},
{QStringLiteral("Multiplayer Leave Room"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+L"), Qt::ApplicationShortcut}},
{QStringLiteral("Multiplayer Show Current Room"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+R"), Qt::ApplicationShortcut}},
+ {QStringLiteral("Quick Save"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WindowShortcut}},
+ {QStringLiteral("Quick Load"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WindowShortcut}},
{QStringLiteral("Remove Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F3"), Qt::ApplicationShortcut}},
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}},
{QStringLiteral("Rotate Screens Upright"), QStringLiteral("Main Window"), {QStringLiteral("F8"), Qt::WindowShortcut}},
- {QStringLiteral("Save to Oldest Slot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+C"), Qt::WindowShortcut}},
+ {QStringLiteral("Save to Oldest Non-Quicksave Slot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+C"), Qt::WindowShortcut}},
{QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}},
{QStringLiteral("Swap Screens"), QStringLiteral("Main Window"), {QStringLiteral("F9"), Qt::WindowShortcut}},
{QStringLiteral("Toggle 3D"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+3"), Qt::ApplicationShortcut}},
{QStringLiteral("Toggle Custom Textures"), QStringLiteral("Main Window"), {QStringLiteral("F7"), Qt::ApplicationShortcut}},
{QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}},
{QStringLiteral("Toggle Frame Advancing"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+A"), Qt::ApplicationShortcut}},
- {QStringLiteral("Toggle Per-Application Speed"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), Qt::ApplicationShortcut}},
+ {QStringLiteral("Toggle Per-Application Speed"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), Qt::ApplicationShortcut}},
{QStringLiteral("Toggle Screen Layout"), QStringLiteral("Main Window"), {QStringLiteral("F10"), Qt::WindowShortcut}},
{QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), Qt::WindowShortcut}},
{QStringLiteral("Toggle Texture Dumping"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::ApplicationShortcut}},
+ {QStringLiteral("Toggle Turbo Mode"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::ApplicationShortcut}},
}};
// clang-format on
@@ -519,6 +522,7 @@ void QtConfig::ReadLayoutValues() {
ReadGlobalSetting(Settings::values.swap_screen);
ReadGlobalSetting(Settings::values.upright_screen);
ReadGlobalSetting(Settings::values.large_screen_proportion);
+ ReadGlobalSetting(Settings::values.screen_gap);
ReadGlobalSetting(Settings::values.small_screen_position);
if (global) {
@@ -681,6 +685,7 @@ void QtConfig::ReadRendererValues() {
ReadGlobalSetting(Settings::values.use_vsync_new);
ReadGlobalSetting(Settings::values.resolution_factor);
ReadGlobalSetting(Settings::values.frame_limit);
+ ReadGlobalSetting(Settings::values.turbo_limit);
ReadGlobalSetting(Settings::values.bg_red);
ReadGlobalSetting(Settings::values.bg_green);
@@ -1078,6 +1083,7 @@ void QtConfig::SaveLayoutValues() {
WriteGlobalSetting(Settings::values.swap_screen);
WriteGlobalSetting(Settings::values.upright_screen);
WriteGlobalSetting(Settings::values.large_screen_proportion);
+ WriteGlobalSetting(Settings::values.screen_gap);
WriteGlobalSetting(Settings::values.small_screen_position);
if (global) {
WriteBasicSetting(Settings::values.mono_render_option);
@@ -1206,6 +1212,7 @@ void QtConfig::SaveRendererValues() {
WriteGlobalSetting(Settings::values.use_vsync_new);
WriteGlobalSetting(Settings::values.resolution_factor);
WriteGlobalSetting(Settings::values.frame_limit);
+ WriteGlobalSetting(Settings::values.turbo_limit);
WriteGlobalSetting(Settings::values.bg_red);
WriteGlobalSetting(Settings::values.bg_green);
diff --git a/src/citra_qt/configuration/config.h b/src/citra_qt/configuration/config.h
index d1a7abfcf..2c9039dde 100644
--- a/src/citra_qt/configuration/config.h
+++ b/src/citra_qt/configuration/config.h
@@ -26,7 +26,7 @@ public:
static const std::array default_buttons;
static const std::array, Settings::NativeAnalog::NumAnalogs> default_analogs;
- static const std::array default_hotkeys;
+ static const std::array default_hotkeys;
private:
void Initialize(const std::string& config_name);
diff --git a/src/citra_qt/configuration/configure_dialog.cpp b/src/citra_qt/configuration/configure_dialog.cpp
index 6c5a78e11..0f0fe2e71 100644
--- a/src/citra_qt/configuration/configure_dialog.cpp
+++ b/src/citra_qt/configuration/configure_dialog.cpp
@@ -1,4 +1,4 @@
-// Copyright 2016 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
diff --git a/src/citra_qt/configuration/configure_enhancements.ui b/src/citra_qt/configuration/configure_enhancements.ui
index a496d35f5..b69676d02 100644
--- a/src/citra_qt/configuration/configure_enhancements.ui
+++ b/src/citra_qt/configuration/configure_enhancements.ui
@@ -276,7 +276,7 @@
0
- 100
+ 255
0
@@ -285,6 +285,13 @@
+ -
+
+
+ Note: Depth values over 100% are not possible on real hardware and may cause graphical issues
+
+
+
-
-
diff --git a/src/citra_qt/configuration/configure_general.cpp b/src/citra_qt/configuration/configure_general.cpp
index cf091ec3c..9a2d58a68 100644
--- a/src/citra_qt/configuration/configure_general.cpp
+++ b/src/citra_qt/configuration/configure_general.cpp
@@ -26,9 +26,14 @@ static constexpr int SettingsToSlider(int value) {
ConfigureGeneral::ConfigureGeneral(QWidget* parent)
: QWidget(parent), ui(std::make_unique()) {
-
ui->setupUi(this);
+ connect(ui->turbo_limit, &QSlider::valueChanged, this, [&](double value) {
+ Settings::values.turbo_limit.SetValue(SliderToSettings(value));
+ ui->turbo_limit_display_label->setText(
+ QStringLiteral("%1%").arg(Settings::values.turbo_limit.GetValue()));
+ });
+
// Set a minimum width for the label to prevent the slider from changing size.
// This scales across DPIs, and is acceptable for uncapitalized strings.
const auto width = static_cast(tr("unthrottled").size() * 6);
@@ -60,12 +65,14 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
});
connect(ui->change_screenshot_dir, &QToolButton::clicked, this, [this] {
+ ui->change_screenshot_dir->setEnabled(false);
const QString dir_path = QFileDialog::getExistingDirectory(
this, tr("Select Screenshot Directory"), ui->screenshot_dir_path->text(),
QFileDialog::ShowDirsOnly);
if (!dir_path.isEmpty()) {
ui->screenshot_dir_path->setText(dir_path);
}
+ ui->change_screenshot_dir->setEnabled(true);
});
}
@@ -73,6 +80,10 @@ ConfigureGeneral::~ConfigureGeneral() = default;
void ConfigureGeneral::SetConfiguration() {
if (Settings::IsConfiguringGlobal()) {
+ ui->turbo_limit->setValue(SettingsToSlider(Settings::values.turbo_limit.GetValue()));
+ ui->turbo_limit_display_label->setText(
+ QStringLiteral("%1%").arg(Settings::values.turbo_limit.GetValue()));
+
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
ui->toggle_background_pause->setChecked(
UISettings::values.pause_when_in_background.GetValue());
@@ -121,16 +132,6 @@ void ConfigureGeneral::SetConfiguration() {
!UISettings::values.screenshot_path.UsingGlobal());
ConfigurationShared::SetHighlight(ui->emulation_speed_layout,
!Settings::values.frame_limit.UsingGlobal());
- ConfigurationShared::SetHighlight(ui->widget_region,
- !Settings::values.region_value.UsingGlobal());
- const bool is_region_global = Settings::values.region_value.UsingGlobal();
- ui->region_combobox->setCurrentIndex(
- is_region_global ? ConfigurationShared::USE_GLOBAL_INDEX
- : static_cast(Settings::values.region_value.GetValue()) +
- ConfigurationShared::USE_GLOBAL_OFFSET + 1);
- } else {
- // The first item is "auto-select" with actual value -1, so plus one here will do the trick
- ui->region_combobox->setCurrentIndex(Settings::values.region_value.GetValue() + 1);
}
UISettings::values.screenshot_path.SetGlobal(ui->screenshot_combo->currentIndex() ==
@@ -145,12 +146,14 @@ void ConfigureGeneral::SetConfiguration() {
}
void ConfigureGeneral::ResetDefaults() {
+ ui->button_reset_defaults->setEnabled(false);
QMessageBox::StandardButton answer = QMessageBox::question(
this, tr("Azahar"),
tr("Are you sure you want to reset your settings and close Azahar?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (answer == QMessageBox::No) {
+ ui->button_reset_defaults->setEnabled(true);
return;
}
@@ -160,9 +163,6 @@ void ConfigureGeneral::ResetDefaults() {
}
void ConfigureGeneral::ApplyConfiguration() {
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_value, ui->region_combobox,
- [](s32 index) { return index - 1; });
-
ConfigurationShared::ApplyPerGameSetting(
&Settings::values.frame_limit, ui->emulation_speed_combo, [this](s32) {
const bool is_maximum = ui->frame_limit->value() == ui->frame_limit->maximum();
@@ -191,7 +191,6 @@ void ConfigureGeneral::RetranslateUI() {
void ConfigureGeneral::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) {
- ui->region_combobox->setEnabled(Settings::values.region_value.UsingGlobal());
ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal());
return;
}
@@ -208,12 +207,9 @@ void ConfigureGeneral::SetupPerGameUI() {
ConfigurationShared::SetHighlight(ui->widget_screenshot, index == 1);
});
+ ui->turbo_limit->setVisible(false);
ui->general_group->setVisible(false);
ui->button_reset_defaults->setVisible(false);
ui->toggle_gamemode->setVisible(false);
ui->toggle_update_checker->setVisible(false);
-
- ConfigurationShared::SetColoredComboBox(
- ui->region_combobox, ui->widget_region,
- static_cast(Settings::values.region_value.GetValue(true) + 1));
}
diff --git a/src/citra_qt/configuration/configure_general.h b/src/citra_qt/configuration/configure_general.h
index 3c6cef219..93a855387 100644
--- a/src/citra_qt/configuration/configure_general.h
+++ b/src/citra_qt/configuration/configure_general.h
@@ -1,4 +1,4 @@
-// Copyright 2016 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
diff --git a/src/citra_qt/configuration/configure_general.ui b/src/citra_qt/configuration/configure_general.ui
index 4b6b0adf6..741b898c3 100644
--- a/src/citra_qt/configuration/configure_general.ui
+++ b/src/citra_qt/configuration/configure_general.ui
@@ -73,75 +73,6 @@
Emulation
- -
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- Region:
-
-
-
- -
-
-
-
-
- Auto-select
-
-
- -
-
- JPN
-
-
- -
-
- USA
-
-
- -
-
- EUR
-
-
- -
-
- AUS
-
-
- -
-
- CHN
-
-
- -
-
- KOR
-
-
- -
-
- TWN
-
-
-
-
-
-
-
-
@@ -216,6 +147,82 @@
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Turbo Speed Limit:
+
+
+
+ -
+
+
+ 0
+
+
+ 198
+
+
+ 5
+
+
+ 15
+
+
+ 19
+
+
+ Qt::Horizontal
+
+
+ QSlider::TicksBelow
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 32
+ 20
+
+
+
+
+ -
+
+
+
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
diff --git a/src/citra_qt/configuration/configure_graphics.ui b/src/citra_qt/configuration/configure_graphics.ui
index cb0a7323c..b2ee3c279 100644
--- a/src/citra_qt/configuration/configure_graphics.ui
+++ b/src/citra_qt/configuration/configure_graphics.ui
@@ -258,7 +258,7 @@
-
- <html><head/><body><p>Overrides the sampling filter used by applications. This can be useful in certain cases with poorly behaved applications when upscaling. If unsure set this to Application Controlled</p></body></html>
+ <html><head/><body><p>Overrides the sampling filter used by applications. This can be useful in certain cases with poorly behaved applications when upscaling. If unsure, set this to Application Controlled</p></body></html>
Texture Sampling
diff --git a/src/citra_qt/configuration/configure_hotkeys.cpp b/src/citra_qt/configuration/configure_hotkeys.cpp
index 6ac0dcd8a..ecaed462b 100644
--- a/src/citra_qt/configuration/configure_hotkeys.cpp
+++ b/src/citra_qt/configuration/configure_hotkeys.cpp
@@ -1,4 +1,4 @@
-// Copyright 2017 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -98,6 +98,38 @@ void ConfigureHotkeys::Configure(QModelIndex index) {
}
const auto [key_sequence_used, used_action] = IsUsedKey(key_sequence);
+ // Check for turbo/per-game speed conflict. Needed to prevent the user from binding both hotkeys
+ // to the same action. Which cuases problems resetting the frame limit.to the inititla value.
+ const QString current_action =
+ model->data(model->index(index.row(), 0, index.parent())).toString();
+ const bool is_turbo = current_action == tr("Toggle Turbo Mode");
+ const bool is_per_game = current_action == tr("Toggle Per-Application Speed");
+
+ if (is_turbo || is_per_game) {
+ QString other_action =
+ is_turbo ? tr("Toggle Per-Application Speed") : tr("Toggle Turbo Mode");
+ QKeySequence other_sequence;
+
+ for (int r = 0; r < model->rowCount(); ++r) {
+ const QStandardItem* const parent = model->item(r, 0);
+ for (int r2 = 0; r2 < parent->rowCount(); ++r2) {
+ if (parent->child(r2, 0)->text() == other_action) {
+ other_sequence = QKeySequence::fromString(
+ parent->child(r2, hotkey_column)->text(), QKeySequence::NativeText);
+ break;
+ }
+ }
+ }
+
+ // Show warning if either hotkey is already set
+ if (!key_sequence.isEmpty() && !other_sequence.isEmpty()) {
+ QMessageBox::warning(this, tr("Conflicting Key Sequence"),
+ tr("The per-application speed and turbo speed hotkeys cannot be "
+ "bound at the same time."));
+ return;
+ }
+ }
+
if (key_sequence_used && key_sequence != QKeySequence(previous_key.toString())) {
QMessageBox::warning(
this, tr("Conflicting Key Sequence"),
diff --git a/src/citra_qt/configuration/configure_input.cpp b/src/citra_qt/configuration/configure_input.cpp
index 502c5caba..2cc319968 100644
--- a/src/citra_qt/configuration/configure_input.cpp
+++ b/src/citra_qt/configuration/configure_input.cpp
@@ -1,4 +1,4 @@
-// Copyright Citra Emulator Project / Lime3DS Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -377,8 +377,10 @@ ConfigureInput::ConfigureInput(Core::System& _system, QWidget* parent)
});
connect(ui->buttonMotionTouch, &QPushButton::clicked, this, [this] {
+ ui->buttonMotionTouch->setEnabled(false);
QDialog* motion_touch_dialog = new ConfigureMotionTouch(this);
- return motion_touch_dialog->exec();
+ motion_touch_dialog->exec();
+ ui->buttonMotionTouch->setEnabled(true);
});
ui->buttonDelete->setEnabled(ui->profile->count() > 1);
@@ -580,9 +582,11 @@ void ConfigureInput::MapFromButton(const Common::ParamPackage& params) {
}
void ConfigureInput::AutoMap() {
+ ui->buttonAutoMap->setEnabled(false);
if (QMessageBox::information(this, tr("Information"),
tr("After pressing OK, press any button on your joystick"),
QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) {
+ ui->buttonAutoMap->setEnabled(true);
return;
}
input_setter = [this](const Common::ParamPackage& params) {
@@ -597,6 +601,7 @@ void ConfigureInput::AutoMap() {
}
timeout_timer->start(5000); // Cancel after 5 seconds
poll_timer->start(200); // Check for new inputs every 200ms
+ ui->buttonAutoMap->setEnabled(true);
}
void ConfigureInput::HandleClick(QPushButton* button,
@@ -671,13 +676,16 @@ void ConfigureInput::RetranslateUI() {
}
void ConfigureInput::NewProfile() {
+ ui->buttonNew->setEnabled(false);
const QString name =
QInputDialog::getText(this, tr("New Profile"), tr("Enter the name for the new profile."));
if (name.isEmpty()) {
+ ui->buttonNew->setEnabled(true);
return;
}
if (IsProfileNameDuplicate(name)) {
WarnProposedProfileNameIsDuplicate();
+ ui->buttonNew->setEnabled(true);
return;
}
@@ -688,12 +696,15 @@ void ConfigureInput::NewProfile() {
ui->profile->setCurrentIndex(Settings::values.current_input_profile_index);
LoadConfiguration();
ui->buttonDelete->setEnabled(ui->profile->count() > 1);
+ ui->buttonNew->setEnabled(true);
}
void ConfigureInput::DeleteProfile() {
+ ui->buttonDelete->setEnabled(false);
const auto answer = QMessageBox::question(
this, tr("Delete Profile"), tr("Delete profile %1?").arg(ui->profile->currentText()));
if (answer != QMessageBox::Yes) {
+ ui->buttonDelete->setEnabled(true);
return;
}
const int index = ui->profile->currentIndex();
@@ -705,18 +716,22 @@ void ConfigureInput::DeleteProfile() {
}
void ConfigureInput::RenameProfile() {
+ ui->buttonRename->setEnabled(false);
const QString new_name = QInputDialog::getText(this, tr("Rename Profile"), tr("New name:"));
if (new_name.isEmpty()) {
+ ui->buttonRename->setEnabled(true);
return;
}
if (IsProfileNameDuplicate(new_name)) {
WarnProposedProfileNameIsDuplicate();
+ ui->buttonRename->setEnabled(true);
return;
}
ui->profile->setItemText(ui->profile->currentIndex(), new_name);
Settings::RenameCurrentProfile(new_name.toStdString());
Settings::SaveProfile(ui->profile->currentIndex());
+ ui->buttonRename->setEnabled(true);
}
bool ConfigureInput::IsProfileNameDuplicate(const QString& name) const {
diff --git a/src/citra_qt/configuration/configure_layout.cpp b/src/citra_qt/configuration/configure_layout.cpp
index cc78d8948..58a0e66da 100644
--- a/src/citra_qt/configuration/configure_layout.cpp
+++ b/src/citra_qt/configuration/configure_layout.cpp
@@ -1,4 +1,4 @@
-// Copyright Citra Emulator Project / Lime3DS Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -98,8 +98,10 @@ ConfigureLayout::ConfigureLayout(QWidget* parent)
#endif
connect(ui->bg_button, &QPushButton::clicked, this, [this] {
+ ui->bg_button->setEnabled(false);
const QColor new_bg_color = QColorDialog::getColor(bg_color);
if (!new_bg_color.isValid()) {
+ ui->bg_button->setEnabled(true);
return;
}
bg_color = new_bg_color;
@@ -107,6 +109,7 @@ ConfigureLayout::ConfigureLayout(QWidget* parent)
pixmap.fill(bg_color);
const QIcon color_icon(pixmap);
ui->bg_button->setIcon(color_icon);
+ ui->bg_button->setEnabled(true);
});
}
@@ -124,6 +127,7 @@ void ConfigureLayout::SetConfiguration() {
ui->toggle_swap_screen->setChecked(Settings::values.swap_screen.GetValue());
ui->toggle_upright_screen->setChecked(Settings::values.upright_screen.GetValue());
+ ui->screen_gap->setValue(Settings::values.screen_gap.GetValue());
ui->large_screen_proportion->setValue(Settings::values.large_screen_proportion.GetValue());
ui->small_screen_position_combobox->setCurrentIndex(
static_cast(Settings::values.small_screen_position.GetValue()));
@@ -163,6 +167,7 @@ void ConfigureLayout::RetranslateUI() {
void ConfigureLayout::ApplyConfiguration() {
Settings::values.large_screen_proportion = ui->large_screen_proportion->value();
+ Settings::values.screen_gap = ui->screen_gap->value();
Settings::values.small_screen_position = static_cast(
ui->small_screen_position_combobox->currentIndex());
Settings::values.custom_top_x = ui->custom_top_x->value();
diff --git a/src/citra_qt/configuration/configure_layout.ui b/src/citra_qt/configuration/configure_layout.ui
index 3b564515b..33ef4fc68 100644
--- a/src/citra_qt/configuration/configure_layout.ui
+++ b/src/citra_qt/configuration/configure_layout.ui
@@ -107,6 +107,44 @@
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Screen Gap
+
+
+
+ -
+
+
+ 0.0
+
+
+ 720.0
+
+
+ 0.0
+
+
+
+
+
+
-
diff --git a/src/citra_qt/configuration/configure_per_game.cpp b/src/citra_qt/configuration/configure_per_game.cpp
index 88709df16..1a943d732 100644
--- a/src/citra_qt/configuration/configure_per_game.cpp
+++ b/src/citra_qt/configuration/configure_per_game.cpp
@@ -1,5 +1,10 @@
-// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright Citra Emulator Project / Azahar Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
#include
#include
diff --git a/src/citra_qt/configuration/configure_storage.cpp b/src/citra_qt/configuration/configure_storage.cpp
index d46cb0614..2346f06c2 100644
--- a/src/citra_qt/configuration/configure_storage.cpp
+++ b/src/citra_qt/configuration/configure_storage.cpp
@@ -1,4 +1,4 @@
-// Copyright 2021 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -21,6 +21,7 @@ ConfigureStorage::ConfigureStorage(bool is_powered_on_, QWidget* parent)
});
connect(ui->change_nand_dir, &QPushButton::clicked, this, [this]() {
+ ui->change_nand_dir->setEnabled(false);
const QString dir_path = QFileDialog::getExistingDirectory(
this, tr("Select NAND Directory"),
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)),
@@ -29,6 +30,7 @@ ConfigureStorage::ConfigureStorage(bool is_powered_on_, QWidget* parent)
FileUtil::UpdateUserPath(FileUtil::UserPath::NANDDir, dir_path.toStdString());
SetConfiguration();
}
+ ui->change_nand_dir->setEnabled(true);
});
connect(ui->open_sdmc_dir, &QPushButton::clicked, []() {
@@ -37,6 +39,7 @@ ConfigureStorage::ConfigureStorage(bool is_powered_on_, QWidget* parent)
});
connect(ui->change_sdmc_dir, &QPushButton::clicked, this, [this]() {
+ ui->change_sdmc_dir->setEnabled(false);
const QString dir_path = QFileDialog::getExistingDirectory(
this, tr("Select SDMC Directory"),
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)),
@@ -45,6 +48,7 @@ ConfigureStorage::ConfigureStorage(bool is_powered_on_, QWidget* parent)
FileUtil::UpdateUserPath(FileUtil::UserPath::SDMCDir, dir_path.toStdString());
SetConfiguration();
}
+ ui->change_sdmc_dir->setEnabled(true);
});
connect(ui->toggle_virtual_sd, &QCheckBox::clicked, this, [this]() {
diff --git a/src/citra_qt/configuration/configure_system.cpp b/src/citra_qt/configuration/configure_system.cpp
index 005ebe394..fb9f6d7bb 100644
--- a/src/citra_qt/configuration/configure_system.cpp
+++ b/src/citra_qt/configuration/configure_system.cpp
@@ -238,6 +238,16 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
&ConfigureSystem::RefreshConsoleID);
connect(ui->button_regenerate_mac, &QPushButton::clicked, this, &ConfigureSystem::RefreshMAC);
+ connect(ui->button_unlink_console, &QPushButton::clicked, this,
+ &ConfigureSystem::UnlinkConsole);
+ connect(ui->combo_country, qOverload(&QComboBox::currentIndexChanged), this,
+ [this](int index) {
+ CheckCountryValid(static_cast(ui->combo_country->itemData(index).toInt()));
+ });
+ connect(ui->region_combobox, qOverload(&QComboBox::currentIndexChanged), this,
+ [this]([[maybe_unused]] int index) {
+ CheckCountryValid(static_cast(ui->combo_country->currentData().toInt()));
+ });
connect(ui->button_secure_info, &QPushButton::clicked, this, [this] {
ui->button_secure_info->setEnabled(false);
@@ -278,6 +288,8 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
ui->combo_country->addItem(tr(country_names.at(i)), i);
}
}
+ ui->label_country_invalid->setVisible(false);
+ ui->label_country_invalid->setStyleSheet(QStringLiteral("QLabel { color: #ff3333; }"));
SetupPerGameUI();
ConfigureTime();
@@ -288,6 +300,19 @@ ConfigureSystem::~ConfigureSystem() = default;
void ConfigureSystem::SetConfiguration() {
enabled = !system.IsPoweredOn();
+ if (!Settings::IsConfiguringGlobal()) {
+ ConfigurationShared::SetHighlight(ui->region_label,
+ !Settings::values.region_value.UsingGlobal());
+ const bool is_region_global = Settings::values.region_value.UsingGlobal();
+ ui->region_combobox->setCurrentIndex(
+ is_region_global ? ConfigurationShared::USE_GLOBAL_INDEX
+ : static_cast(Settings::values.region_value.GetValue()) +
+ ConfigurationShared::USE_GLOBAL_OFFSET + 1);
+ } else {
+ // The first item is "auto-select" with actual value -1, so plus one here will do the trick
+ ui->region_combobox->setCurrentIndex(Settings::values.region_value.GetValue() + 1);
+ }
+
ui->combo_init_clock->setCurrentIndex(static_cast(Settings::values.init_clock.GetValue()));
QDateTime date_time;
date_time.setSecsSinceEpoch(Settings::values.init_time.GetValue());
@@ -349,6 +374,7 @@ void ConfigureSystem::ReadSystemSettings() {
// set the country code
country_code = cfg->GetCountryCode();
ui->combo_country->setCurrentIndex(ui->combo_country->findData(country_code));
+ CheckCountryValid(country_code);
// set whether system setup is needed
system_setup = cfg->IsSystemSetupNeeded();
@@ -371,6 +397,10 @@ void ConfigureSystem::ReadSystemSettings() {
void ConfigureSystem::ApplyConfiguration() {
if (enabled) {
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_value,
+ ui->region_combobox,
+ [](s32 index) { return index - 1; });
+
bool modified = false;
// apply username
@@ -527,15 +557,17 @@ void ConfigureSystem::UpdateInitTicks(int init_ticks_type) {
}
void ConfigureSystem::RefreshConsoleID() {
+ ui->button_regenerate_console_id->setEnabled(false);
QMessageBox::StandardButton reply;
QString warning_text =
tr("This will replace your current virtual 3DS console ID with a new one. "
"Your current virtual 3DS console ID will not be recoverable. "
"This might have unexpected effects in applications. This might fail "
"if you use an outdated config save. Continue?");
- reply = QMessageBox::critical(this, tr("Warning"), warning_text,
- QMessageBox::No | QMessageBox::Yes);
+ reply =
+ QMessageBox::warning(this, tr("Warning"), warning_text, QMessageBox::No | QMessageBox::Yes);
if (reply == QMessageBox::No) {
+ ui->button_regenerate_console_id->setEnabled(true);
return;
}
@@ -544,9 +576,11 @@ void ConfigureSystem::RefreshConsoleID() {
cfg->UpdateConfigNANDSavegame();
ui->label_console_id->setText(
tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper()));
+ ui->button_regenerate_console_id->setEnabled(true);
}
void ConfigureSystem::RefreshMAC() {
+ ui->button_regenerate_mac->setEnabled(false);
QMessageBox::StandardButton reply;
QString warning_text = tr("This will replace your current MAC address with a new one. "
"It is not recommended to do this if you got the MAC address from "
@@ -554,11 +588,61 @@ void ConfigureSystem::RefreshMAC() {
reply =
QMessageBox::warning(this, tr("Warning"), warning_text, QMessageBox::No | QMessageBox::Yes);
if (reply == QMessageBox::No) {
+ ui->button_regenerate_mac->setEnabled(true);
return;
}
mac_address = Service::CFG::GenerateRandomMAC();
ui->label_mac->setText(tr("MAC: %1").arg(QString::fromStdString(mac_address)));
+ ui->button_regenerate_mac->setEnabled(true);
+}
+
+void ConfigureSystem::UnlinkConsole() {
+ ui->button_unlink_console->setEnabled(false);
+ QMessageBox::StandardButton reply;
+ QString warning_text =
+ tr("This action will unlink your real console from Azahar, with the following "
+ "consequences:
- Your OTP, SecureInfo and LocalFriendCodeSeed will be removed "
+ "from Azahar.
- Your friend list will reset and you will be logged out of your "
+ "NNID/PNID account.
- System files and eshop titles obtained through Azahar will "
+ "become inaccessible until the same console is linked again (save data will not be "
+ "lost).
Continue?");
+ reply =
+ QMessageBox::warning(this, tr("Warning"), warning_text, QMessageBox::No | QMessageBox::Yes);
+ if (reply == QMessageBox::No) {
+ ui->button_unlink_console->setEnabled(true);
+ return;
+ }
+
+ HW::UniqueData::UnlinkConsole();
+ RefreshSecureDataStatus();
+ ui->button_unlink_console->setEnabled(true);
+}
+
+void ConfigureSystem::CheckCountryValid(u8 country) {
+ // TODO(PabloMK7): Make this per-game compatible
+ if (!Settings::IsConfiguringGlobal())
+ return;
+
+ s32 region = ui->region_combobox->currentIndex() - 1;
+ QString label_text;
+
+ if (region != Settings::REGION_VALUE_AUTO_SELECT &&
+ !cfg->IsValidRegionCountry(static_cast(region), country)) {
+ label_text = tr("Invalid country for configured region");
+ }
+ if (HW::UniqueData::GetSecureInfoA().IsValid()) {
+ region = static_cast(cfg->GetRegionValue(true));
+ if (!cfg->IsValidRegionCountry(static_cast(region), country)) {
+ if (!label_text.isEmpty()) {
+ label_text += QString::fromStdString("\n");
+ }
+ label_text += tr("Invalid country for console unique data");
+ }
+ }
+
+ ui->label_country_invalid->setText(label_text);
+ ui->label_country_invalid->setVisible(!label_text.isEmpty());
}
void ConfigureSystem::InstallSecureData(const std::string& from_path, const std::string& to_path) {
@@ -578,29 +662,36 @@ void ConfigureSystem::RefreshSecureDataStatus() {
auto status_to_str = [](HW::UniqueData::SecureDataLoadStatus status) {
switch (status) {
case HW::UniqueData::SecureDataLoadStatus::Loaded:
- return "Loaded";
+ return tr("Status: Loaded");
case HW::UniqueData::SecureDataLoadStatus::InvalidSignature:
- return "Loaded (Invalid Signature)";
+ return tr("Status: Loaded (Invalid Signature)");
+ case HW::UniqueData::SecureDataLoadStatus::RegionChanged:
+ return tr("Status: Loaded (Region Changed)");
case HW::UniqueData::SecureDataLoadStatus::NotFound:
- return "Not Found";
+ return tr("Status: Not Found");
case HW::UniqueData::SecureDataLoadStatus::Invalid:
- return "Invalid";
+ return tr("Status: Invalid");
case HW::UniqueData::SecureDataLoadStatus::IOError:
- return "IO Error";
+ return tr("Status: IO Error");
default:
- return "";
+ return QString();
}
};
- ui->label_secure_info_status->setText(
- tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadSecureInfoA())).c_str()));
+ ui->label_secure_info_status->setText(status_to_str(HW::UniqueData::LoadSecureInfoA()));
ui->label_friend_code_seed_status->setText(
- tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadLocalFriendCodeSeedB()))
- .c_str()));
- ui->label_otp_status->setText(
- tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadOTP())).c_str()));
- ui->label_movable_status->setText(
- tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadMovable())).c_str()));
+ status_to_str(HW::UniqueData::LoadLocalFriendCodeSeedB()));
+ ui->label_otp_status->setText(status_to_str(HW::UniqueData::LoadOTP()));
+ ui->label_movable_status->setText(status_to_str(HW::UniqueData::LoadMovable()));
+
+ if (HW::UniqueData::IsFullConsoleLinked()) {
+ ui->linked_console->setVisible(true);
+ ui->button_otp->setEnabled(false);
+ ui->button_secure_info->setEnabled(false);
+ ui->button_friend_code_seed->setEnabled(false);
+ } else {
+ ui->linked_console->setVisible(false);
+ }
}
void ConfigureSystem::RetranslateUI() {
@@ -614,6 +705,7 @@ void ConfigureSystem::SetupPerGameUI() {
ui->toggle_lle_applets->setEnabled(Settings::values.lle_applets.UsingGlobal());
ui->enable_required_online_lle_modules->setEnabled(
Settings::values.enable_required_online_lle_modules.UsingGlobal());
+ ui->region_combobox->setEnabled(Settings::values.region_value.UsingGlobal());
return;
}
@@ -625,6 +717,7 @@ void ConfigureSystem::SetupPerGameUI() {
ui->label_init_ticks_type->setVisible(false);
ui->label_init_ticks_value->setVisible(false);
ui->label_console_id->setVisible(false);
+ ui->label_mac->setVisible(false);
ui->label_sound->setVisible(false);
ui->label_language->setVisible(false);
ui->label_country->setVisible(false);
@@ -646,6 +739,7 @@ void ConfigureSystem::SetupPerGameUI() {
ui->edit_init_ticks_value->setVisible(false);
ui->toggle_system_setup->setVisible(false);
ui->button_regenerate_console_id->setVisible(false);
+ ui->button_regenerate_mac->setVisible(false);
// Apps can change the state of the plugin loader, so plugins load
// to a chainloaded app with specific parameters. Don't allow
// the plugin loader state to be configured per-game as it may
@@ -653,6 +747,7 @@ void ConfigureSystem::SetupPerGameUI() {
ui->label_plugin_loader->setVisible(false);
ui->plugin_loader->setVisible(false);
ui->allow_plugin_loader->setVisible(false);
+ ui->group_real_console_unique_data->setVisible(false);
ConfigurationShared::SetColoredTristate(ui->toggle_new_3ds, Settings::values.is_new_3ds,
is_new_3ds);
@@ -661,4 +756,7 @@ void ConfigureSystem::SetupPerGameUI() {
ConfigurationShared::SetColoredTristate(ui->enable_required_online_lle_modules,
Settings::values.enable_required_online_lle_modules,
required_online_lle_modules);
+ ConfigurationShared::SetColoredComboBox(
+ ui->region_combobox, ui->region_label,
+ static_cast(Settings::values.region_value.GetValue(true) + 1));
}
diff --git a/src/citra_qt/configuration/configure_system.h b/src/citra_qt/configuration/configure_system.h
index 086b84a22..af7c81200 100644
--- a/src/citra_qt/configuration/configure_system.h
+++ b/src/citra_qt/configuration/configure_system.h
@@ -52,6 +52,8 @@ private:
void UpdateInitTicks(int init_ticks_type);
void RefreshConsoleID();
void RefreshMAC();
+ void UnlinkConsole();
+ void CheckCountryValid(u8 country);
void InstallSecureData(const std::string& from_path, const std::string& to_path);
void RefreshSecureDataStatus();
diff --git a/src/citra_qt/configuration/configure_system.ui b/src/citra_qt/configuration/configure_system.ui
index 97e4b4654..244fb3c5f 100644
--- a/src/citra_qt/configuration/configure_system.ui
+++ b/src/citra_qt/configuration/configure_system.ui
@@ -64,30 +64,82 @@
System Settings
- -
+
-
Enable New 3DS mode
- -
+
-
Use LLE applets (if installed)
- -
+
-
- Enable required LLE modules for online features (if installed)
+ Enable required LLE modules for
+online features (if installed)
Enables the LLE modules needed for online multiplayer, eShop access, etc.
+ -
+
+
+ Region:
+
+
+
+ -
+
+
-
+
+ Auto-select
+
+
+ -
+
+ JPN
+
+
+ -
+
+ USA
+
+
+ -
+
+ EUR
+
+
+ -
+
+ AUS
+
+
+ -
+
+ CHN
+
+
+ -
+
+ KOR
+
+
+ -
+
+ TWN
+
+
+
+
-
@@ -296,14 +348,21 @@
-
- -
+
-
+
+
+
+
+
+
+ -
Clock
- -
+
-
-
@@ -317,28 +376,28 @@
- -
+
-
Startup time
- -
+
-
yyyy-MM-ddTHH:mm:ss
- -
+
-
Offset time
- -
+
-
-
@@ -362,14 +421,14 @@
- -
+
-
Initial System Ticks
- -
+
-
-
@@ -383,14 +442,14 @@
- -
+
-
Initial System Ticks Override
- -
+
-
@@ -403,21 +462,21 @@
- -
+
-
Play Coins
- -
+
-
300
- -
+
-
<html><head/><body><p>Number of steps per hour reported by the pedometer. Range from 0 to 65,535.</p></body></html>
@@ -427,28 +486,28 @@
- -
+
-
9999
- -
+
-
Run System Setup when Home Menu is launched
- -
+
-
Console ID:
- -
+
-
@@ -464,14 +523,14 @@
- -
+
-
MAC:
- -
+
-
@@ -487,21 +546,21 @@
- -
+
-
3GX Plugin Loader:
- -
+
-
Enable 3GX plugin loader
- -
+
-
Allow applications to change plugin loader state
@@ -517,122 +576,157 @@
Real Console Unique Data
+
-
+
+
+
-
+
+
+
-
+
+
+ Your real console is linked to Azahar.
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::RightToLeft
+
+
+ Unlink
+
+
+
+
+
+
+ -
+
+
+ OTP
+
+
+
+ -
+
+
+
-
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::RightToLeft
+
+
+ Choose
+
+
+
+
+
+
+ -
+
+
+ SecureInfo_A/B
+
+
+
+ -
+
+
+
-
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::RightToLeft
+
+
+ Choose
+
+
+
+
+
+
+ -
+
+
+ LocalFriendCodeSeed_A/B
+
+
+
+ -
+
+
+
-
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Qt::RightToLeft
+
+
+ Choose
+
+
+
+
+
+
+
+
+
-
-
-
- SecureInfo_A/B
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Qt::RightToLeft
-
-
- Choose
-
-
-
-
-
-
- -
-
-
- LocalFriendCodeSeed_A/B
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Qt::RightToLeft
-
-
- Choose
-
-
-
-
-
-
- -
-
-
- OTP
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Qt::RightToLeft
-
-
- Choose
-
-
-
-
-
-
- -
movable.sed
- -
+
-
-
diff --git a/src/citra_qt/loading_screen.cpp b/src/citra_qt/loading_screen.cpp
index 2135b7db1..ba2fdcaa6 100644
--- a/src/citra_qt/loading_screen.cpp
+++ b/src/citra_qt/loading_screen.cpp
@@ -1,4 +1,4 @@
-// Copyright 2020 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -184,14 +184,7 @@ void LoadingScreen::OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size
}
// update labels and progress bar
- const auto& stg = tr(stage_translations.at(stage));
- if (stage == VideoCore::LoadCallbackStage::Decompile ||
- stage == VideoCore::LoadCallbackStage::Build ||
- stage == VideoCore::LoadCallbackStage::Preload) {
- ui->stage->setText(stg.arg(value).arg(total));
- } else {
- ui->stage->setText(stg);
- }
+ ui->stage->setText(GetStageTranslation(stage, value, total));
ui->value->setText(estimate);
ui->progress_bar->setValue(static_cast(value));
previous_time = now;
@@ -205,4 +198,16 @@ void LoadingScreen::paintEvent(QPaintEvent* event) {
QWidget::paintEvent(event);
}
+QString LoadingScreen::GetStageTranslation(VideoCore::LoadCallbackStage stage, std::size_t value,
+ std::size_t total) {
+ const auto& stg = tr(stage_translations.at(stage));
+ if (stage == VideoCore::LoadCallbackStage::Decompile ||
+ stage == VideoCore::LoadCallbackStage::Build ||
+ stage == VideoCore::LoadCallbackStage::Preload) {
+ return stg.arg(value).arg(total);
+ } else {
+ return stg;
+ }
+}
+
void LoadingScreen::Clear() {}
diff --git a/src/citra_qt/loading_screen.h b/src/citra_qt/loading_screen.h
index 98d18e243..a6bfc7d09 100644
--- a/src/citra_qt/loading_screen.h
+++ b/src/citra_qt/loading_screen.h
@@ -1,4 +1,4 @@
-// Copyright 2020 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -49,6 +49,9 @@ public:
// See https://wiki.qt.io/How_to_Change_the_Background_Color_of_QWidget
void paintEvent(QPaintEvent* event) override;
+ QString GetStageTranslation(VideoCore::LoadCallbackStage stage, std::size_t value,
+ std::size_t total);
+
signals:
void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total);
/// Signals that this widget is completely hidden now and should be replaced with the other
diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui
index 7cd7fdc4e..70f1915b4 100644
--- a/src/citra_qt/main.ui
+++ b/src/citra_qt/main.ui
@@ -100,6 +100,7 @@
Save State
+
@@ -343,11 +345,21 @@
Save to Oldest Slot
+
+
+ Quick Save
+
+
Load from Newest Slot
+
+
+ Quick Load
+
+
Configure...
diff --git a/src/citra_qt/update_checker.cpp b/src/citra_qt/update_checker.cpp
index a8a3955d7..b4d34344c 100644
--- a/src/citra_qt/update_checker.cpp
+++ b/src/citra_qt/update_checker.cpp
@@ -9,47 +9,74 @@
#include "common/logging/log.h"
#include "update_checker.h"
-std::optional UpdateChecker::CheckForUpdate() {
- constexpr auto UPDATE_CHECK_URL = "http://api.github.com";
- constexpr auto UPDATE_CHECK_PATH = "/repos/azahar-emu/azahar/releases/latest";
- constexpr std::size_t UPDATE_CHECK_TIMEOUT_SECONDS = 15;
+std::optional GetResponse(std::string url, std::string path) {
+ constexpr std::size_t timeout_seconds = 15;
- std::unique_ptr client = std::make_unique(UPDATE_CHECK_URL);
- client->set_connection_timeout(UPDATE_CHECK_TIMEOUT_SECONDS);
- client->set_read_timeout(UPDATE_CHECK_TIMEOUT_SECONDS);
- client->set_write_timeout(UPDATE_CHECK_TIMEOUT_SECONDS);
+ std::unique_ptr client = std::make_unique(url);
+ client->set_connection_timeout(timeout_seconds);
+ client->set_read_timeout(timeout_seconds);
+ client->set_write_timeout(timeout_seconds);
if (client == nullptr) {
- LOG_ERROR(Frontend, "Invalid URL {}{}", UPDATE_CHECK_URL, UPDATE_CHECK_PATH);
+ LOG_ERROR(Frontend, "Invalid URL {}{}", url, path);
return {};
}
httplib::Request request{
.method = "GET",
- .path = UPDATE_CHECK_PATH,
+ .path = path,
};
client->set_follow_location(true);
const auto result = client->send(request);
if (!result) {
- LOG_ERROR(Frontend, "GET to {}{} returned null", UPDATE_CHECK_URL, UPDATE_CHECK_PATH);
+ LOG_ERROR(Frontend, "GET to {}{} returned null", url, path);
return {};
}
const auto& response = result.value();
if (response.status >= 400) {
- LOG_ERROR(Frontend, "GET to {}{} returned error status code: {}", UPDATE_CHECK_URL,
- UPDATE_CHECK_PATH, response.status);
+ LOG_ERROR(Frontend, "GET to {}{} returned error status code: {}", url, path,
+ response.status);
return {};
}
if (!response.headers.contains("content-type")) {
- LOG_ERROR(Frontend, "GET to {}{} returned no content", UPDATE_CHECK_URL, UPDATE_CHECK_PATH);
+ LOG_ERROR(Frontend, "GET to {}{} returned no content", url, path);
return {};
}
+ return response.body;
+}
+
+std::optional UpdateChecker::GetLatestRelease(bool include_prereleases) {
+ constexpr auto update_check_url = "http://api.github.com";
+ std::string update_check_path = "/repos/azahar-emu/azahar/releases";
try {
- return nlohmann::json::parse(response.body).at("tag_name");
+ if (include_prereleases) {
+ // This can return either a prerelease or a normal release, whichever is more recent
+ const auto response = GetResponse(update_check_url, update_check_path);
+ if (!response)
+ return {};
+ return nlohmann::json::parse(response.value()).at(0).at("tag_name");
+ } else {
+ update_check_path += "/latest";
+ const auto response = GetResponse(update_check_url, update_check_path);
+ if (!response)
+ return {};
+ return nlohmann::json::parse(response.value()).at("tag_name");
+ }
+
} catch (nlohmann::detail::out_of_range&) {
+ LOG_ERROR(Frontend,
+ "Parsing JSON response from {}{} failed during update check: "
+ "nlohmann::detail::out_of_range",
+ update_check_url, update_check_path);
+ return {};
+ } catch (nlohmann::detail::type_error&) {
+ LOG_ERROR(Frontend,
+ "Parsing JSON response from {}{} failed during update check: "
+ "nlohmann::detail::type_error",
+ update_check_url, update_check_path);
return {};
}
}
diff --git a/src/citra_qt/update_checker.h b/src/citra_qt/update_checker.h
index b416503e7..843b5a1cb 100644
--- a/src/citra_qt/update_checker.h
+++ b/src/citra_qt/update_checker.h
@@ -8,5 +8,5 @@
#include
namespace UpdateChecker {
-std::optional CheckForUpdate();
+std::optional GetLatestRelease(bool);
}
diff --git a/src/citra_qt/util/util.cpp b/src/citra_qt/util/util.cpp
index 413e94abc..9c234ec37 100644
--- a/src/citra_qt/util/util.cpp
+++ b/src/citra_qt/util/util.cpp
@@ -1,4 +1,4 @@
-// Copyright Citra Emulator Project / Lime3DS Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -174,4 +174,20 @@ const std::string GetApplicationsDirectory() {
#else
return QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString();
#endif
-}
\ No newline at end of file
+}
+
+QImage GetMirroredImage(QImage source_image, bool flip_horizontal, bool flip_vertical) {
+#if QT_VERSION < QT_VERSION_CHECK(6, 9, 0) // Fallback, uses deprecated method
+ return source_image.mirrored(flip_horizontal, flip_vertical);
+#else // New method
+ auto orientation_horizontal = static_cast(0x0);
+ auto orientation_vertical = static_cast(0x0);
+
+ if (flip_horizontal)
+ orientation_horizontal = Qt::Horizontal;
+ if (flip_vertical)
+ orientation_vertical = Qt::Vertical;
+
+ return source_image.flipped(orientation_horizontal | orientation_vertical);
+#endif
+}
diff --git a/src/citra_qt/util/util.h b/src/citra_qt/util/util.h
index 428d69ffd..fff56166f 100644
--- a/src/citra_qt/util/util.h
+++ b/src/citra_qt/util/util.h
@@ -1,4 +1,4 @@
-// Copyright Citra Emulator Project / Lime3DS Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -41,3 +41,11 @@ QPixmap GetQPixmapFromSMDH(const std::vector& smdh_data);
* @return The user’s applications directory
*/
[[nodiscard]] const std::string GetApplicationsDirectory();
+
+/**
+ * Imitates the deprecated `QImage::mirrored` function in a forwards-compatible manner
+ * @param flip_horizontal Whether the image should be flipped horizontally
+ * @param flip_vertical Whether the image should be flipped vertically
+ * @return QImage The mirrored image
+ */
+QImage GetMirroredImage(QImage source_image, bool flip_horizontal, bool flip_vertical);
diff --git a/src/citra_room/CMakeLists.txt b/src/citra_room/CMakeLists.txt
index 203dd7d69..28ac50748 100644
--- a/src/citra_room/CMakeLists.txt
+++ b/src/citra_room/CMakeLists.txt
@@ -1,13 +1,12 @@
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
-add_executable(citra_room
+add_library(citra_room STATIC EXCLUDE_FROM_ALL
precompiled_headers.h
citra_room.cpp
+ citra_room.h
citra_room.rc
)
-set_target_properties(citra_room PROPERTIES OUTPUT_NAME "azahar-room")
-
create_target_directory_groups(citra_room)
target_link_libraries(citra_room PRIVATE citra_common network)
diff --git a/src/citra_room/citra_room.cpp b/src/citra_room/citra_room.cpp
index defd4d956..b956003f9 100644
--- a/src/citra_room/citra_room.cpp
+++ b/src/citra_room/citra_room.cpp
@@ -1,4 +1,4 @@
-// Copyright 2017 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -161,11 +161,16 @@ static void InitializeLogging(const std::string& log_file) {
}
/// Application entry point
-int main(int argc, char** argv) {
+void LaunchRoom(int argc, char** argv, bool called_by_option) {
Common::DetachedTasks detached_tasks;
int option_index = 0;
char* endarg;
+ char* new_argv0 = argv[0];
+ if (called_by_option) {
+ strcat(new_argv0, " --room");
+ }
+
std::string room_name;
std::string room_description;
std::string password;
@@ -199,6 +204,8 @@ int main(int argc, char** argv) {
// Removed options
{"preferred-game", optional_argument, 0, 'g'},
{"preferred-game-id", optional_argument, 0, 0},
+ // Entry option
+ {"room", 0, 0, 0},
{0, 0, 0, 0},
};
@@ -248,17 +255,17 @@ int main(int argc, char** argv) {
break;
case 'h':
PrintHelp(argv[0]);
- return 0;
+ exit(0);
case 'v':
PrintVersion();
- return 0;
+ exit(0);
case 'g':
PrintRemovedOptionWarning(argv[0], "--preferred-game/-g");
- return 255;
+ exit(255);
case 0:
if (strcmp(long_options[option_index].name, "preferred-game-id") == 0) {
PrintRemovedOptionWarning(argv[0], "--preferred-game-id");
- return 255;
+ exit(255);
}
}
}
@@ -267,12 +274,12 @@ int main(int argc, char** argv) {
if (room_name.empty()) {
std::cout << "room name is empty!\n\n";
PrintHelp(argv[0]);
- return -1;
+ exit(-1);
}
if (preferred_game.empty()) {
std::cout << "preferred application is empty!\n\n";
PrintHelp(argv[0]);
- return -1;
+ exit(-1);
}
if (preferred_game_id == 0) {
std::cout
@@ -283,12 +290,12 @@ int main(int argc, char** argv) {
std::cout << "max_members needs to be in the range 2 - "
<< Network::MaxConcurrentConnections << "!\n\n";
PrintHelp(argv[0]);
- return -1;
+ exit(-1);
}
if (port > 65535) {
std::cout << "port needs to be in the range 0 - 65535!\n\n";
PrintHelp(argv[0]);
- return -1;
+ exit(-1);
}
if (ban_list_file.empty()) {
std::cout << "Ban list file not set!\nThis should get set to load and save room ban "
@@ -350,7 +357,7 @@ int main(int argc, char** argv) {
preferred_game, preferred_game_id, std::move(verify_backend), ban_list,
enable_citra_mods)) {
std::cout << "Failed to create room: \n\n";
- return -1;
+ exit(-1);
}
std::cout << "Room is open. Close with Q+Enter...\n\n";
auto announce_session = std::make_unique();
@@ -377,5 +384,4 @@ int main(int argc, char** argv) {
}
Network::Shutdown();
detached_tasks.WaitForAllTasks();
- return 0;
}
diff --git a/src/citra_room/citra_room.h b/src/citra_room/citra_room.h
new file mode 100644
index 000000000..3d9b8749c
--- /dev/null
+++ b/src/citra_room/citra_room.h
@@ -0,0 +1,7 @@
+// Copyright Citra Emulator Project / Azahar Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+void LaunchRoom(int argc, char** argv, bool called_by_option);
diff --git a/src/citra_room_standalone/CMakeLists.txt b/src/citra_room_standalone/CMakeLists.txt
new file mode 100644
index 000000000..e48051469
--- /dev/null
+++ b/src/citra_room_standalone/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_executable(citra_room_standalone
+ citra_room_standalone.cpp
+)
+
+set_target_properties(citra_room_standalone PROPERTIES OUTPUT_NAME "azahar-room")
+
+target_link_libraries(citra_room_standalone PRIVATE citra_room)
+
+if(UNIX AND NOT APPLE)
+ install(TARGETS citra_room_standalone RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
+endif()
diff --git a/src/citra_room_standalone/citra_room_standalone.cpp b/src/citra_room_standalone/citra_room_standalone.cpp
new file mode 100644
index 000000000..d06e53e0a
--- /dev/null
+++ b/src/citra_room_standalone/citra_room_standalone.cpp
@@ -0,0 +1,9 @@
+// Copyright Citra Emulator Project / Azahar Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "citra_room/citra_room.h"
+
+int main(int argc, char* argv[]) {
+ LaunchRoom(argc, argv, false);
+}
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 1ed74bd51..5d1b184fa 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -4,6 +4,7 @@
// Copyright Dolphin Emulator Project
// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
#include
#include
diff --git a/src/common/file_util.h b/src/common/file_util.h
index a4881b57b..ef36ce02f 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -4,6 +4,7 @@
// Copyright Dolphin Emulator Project
// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
#pragma once
diff --git a/src/common/hacks/hack_list.cpp b/src/common/hacks/hack_list.cpp
index eb88bccde..c5702df5e 100644
--- a/src/common/hacks/hack_list.cpp
+++ b/src/common/hacks/hack_list.cpp
@@ -108,5 +108,53 @@ HackManager hack_manager = {
},
}},
+ {HackType::REGION_FROM_SECURE,
+ HackEntry{
+ .mode = HackAllowMode::FORCE,
+ .affected_title_ids =
+ {
+ // eShop
+ 0x0004001000020900, // JPN
+ 0x0004001000021900, // USA
+ 0x0004001000022900, // EUR
+ 0x0004001000027900, // KOR
+ 0x0004001000028900, // TWN
+
+ // System Settings
+ 0x0004001000020000, // JPN
+ 0x0004001000021000, // USA
+ 0x0004001000022000, // EUR
+ 0x0004001000026000, // CHN
+ 0x0004001000027000, // KOR
+ 0x0004001000028000, // TWN
+
+ // Nintendo Network ID Settings
+ 0x000400100002BF00, // JPN
+ 0x000400100002C000, // USA
+ 0x000400100002C100, // EUR
+
+ // System Settings
+ 0x0004003000008202, // JPN
+ 0x0004003000008F02, // USA
+ 0x0004003000009802, // EUR
+ 0x000400300000A102, // CHN
+ 0x000400300000A902, // KOR
+ 0x000400300000B102, // TWN
+
+ // NIM
+ 0x0004013000002C02, // Normal
+ 0x0004013000002C03, // Safe mode
+ 0x0004013020002C03, // New 3DS safe mode
+
+ // ACT
+ 0x0004013000003802, // Normal
+
+ // FRD
+ 0x0004013000003202, // Normal
+ 0x0004013000003203, // Safe mode
+ 0x0004013020003203, // New 3DS safe mode
+ },
+ }},
+
}};
}
\ No newline at end of file
diff --git a/src/common/hacks/hack_list.h b/src/common/hacks/hack_list.h
index 1a21a0575..43d7ea409 100644
--- a/src/common/hacks/hack_list.h
+++ b/src/common/hacks/hack_list.h
@@ -13,6 +13,7 @@ enum class HackType : int {
ACCURATE_MULTIPLICATION,
DECRYPTION_AUTHORIZED,
ONLINE_LLE_REQUIRED,
+ REGION_FROM_SECURE,
};
class UserHackData {};
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index c26771018..08af05e88 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -115,6 +115,7 @@ void LogSettings() {
log_setting("Layout_PortraitLayoutOption", values.portrait_layout_option.GetValue());
log_setting("Layout_SwapScreen", values.swap_screen.GetValue());
log_setting("Layout_UprightScreen", values.upright_screen.GetValue());
+ log_setting("Layout_ScreenGap", values.screen_gap.GetValue());
log_setting("Layout_LargeScreenProportion", values.large_screen_proportion.GetValue());
log_setting("Layout_SmallScreenPosition", values.small_screen_position.GetValue());
log_setting("Utility_DumpTextures", values.dump_textures.GetValue());
@@ -208,6 +209,7 @@ void RestoreGlobalState(bool is_powered_on) {
values.swap_screen.SetGlobal(true);
values.upright_screen.SetGlobal(true);
values.large_screen_proportion.SetGlobal(true);
+ values.screen_gap.SetGlobal(true);
values.small_screen_position.SetGlobal(true);
values.bg_red.SetGlobal(true);
values.bg_green.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index c09021e60..d061add3c 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -51,6 +51,7 @@ enum class PortraitLayoutOption : u32 {
// formerly mobile portrait
PortraitTopFullWidth,
PortraitCustomLayout,
+ PortraitOriginal
};
/** Defines where the small screen will appear relative to the large screen
@@ -497,6 +498,7 @@ struct Values {
Setting use_shader_jit{true, "use_shader_jit"};
SwitchableSetting resolution_factor{1, 0, 10, "resolution_factor"};
SwitchableSetting frame_limit{100, 0, 1000, "frame_limit"};
+ SwitchableSetting turbo_limit{200, 0, 1000, "turbo_limit"};
SwitchableSetting texture_filter{TextureFilter::NoFilter, "texture_filter"};
SwitchableSetting texture_sampling{TextureSampling::GameControlled,
"texture_sampling"};
@@ -508,6 +510,7 @@ struct Values {
SwitchableSetting upright_screen{false, "upright_screen"};
SwitchableSetting large_screen_proportion{4.f, 1.f, 16.f,
"large_screen_proportion"};
+ SwitchableSetting screen_gap{0, "screen_gap"};
SwitchableSetting small_screen_position{SmallScreenPosition::BottomRight,
"small_screen_position"};
Setting custom_top_x{0, "custom_top_x"};
diff --git a/src/core/cheats/cheat_base.h b/src/core/cheats/cheat_base.h
index d8a5924cd..634b1643c 100644
--- a/src/core/cheats/cheat_base.h
+++ b/src/core/cheats/cheat_base.h
@@ -1,10 +1,11 @@
-// Copyright 2018 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include
+#include "common/common_types.h"
namespace Core {
class System;
@@ -14,7 +15,7 @@ namespace Cheats {
class CheatBase {
public:
virtual ~CheatBase();
- virtual void Execute(Core::System& system) const = 0;
+ virtual void Execute(Core::System& system, u32 process_id) const = 0;
virtual bool IsEnabled() const = 0;
virtual void SetEnabled(bool enabled) = 0;
diff --git a/src/core/cheats/cheats.cpp b/src/core/cheats/cheats.cpp
index 30b8e56cc..2cdb75ad1 100644
--- a/src/core/cheats/cheats.cpp
+++ b/src/core/cheats/cheats.cpp
@@ -1,4 +1,4 @@
-// Copyright 2018 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -25,7 +25,8 @@ CheatEngine::~CheatEngine() {
}
}
-void CheatEngine::Connect() {
+void CheatEngine::Connect(u32 process_id) {
+ this->process_id = process_id;
event = system.CoreTiming().RegisterEvent(
"CheatCore::run_event",
[this](u64 thread_id, s64 cycle_late) { RunCallback(thread_id, cycle_late); });
@@ -107,7 +108,7 @@ void CheatEngine::RunCallback([[maybe_unused]] std::uintptr_t user_data, s64 cyc
std::shared_lock lock{cheats_list_mutex};
for (const auto& cheat : cheats_list) {
if (cheat->IsEnabled()) {
- cheat->Execute(system);
+ cheat->Execute(system, process_id);
}
}
}
diff --git a/src/core/cheats/cheats.h b/src/core/cheats/cheats.h
index 8f8127d74..c3a9e840c 100644
--- a/src/core/cheats/cheats.h
+++ b/src/core/cheats/cheats.h
@@ -1,4 +1,4 @@
-// Copyright 2018 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -30,7 +30,7 @@ public:
~CheatEngine();
/// Registers the cheat execution callback.
- void Connect();
+ void Connect(u32 process_id);
/// Returns a span of the currently active cheats.
std::span> GetCheats() const;
@@ -50,6 +50,10 @@ public:
/// Saves currently active cheats to file for the specified title id.
void SaveCheatFile(u64 title_id) const;
+ u32 GetConnectedPID() const {
+ return process_id;
+ }
+
private:
/// The cheat execution callback.
void RunCallback(std::uintptr_t user_data, s64 cycles_late);
@@ -58,6 +62,7 @@ private:
Core::System& system;
Core::TimingEventType* event;
std::optional loaded_title_id;
+ u32 process_id = 0xFFFFFFFF;
std::vector> cheats_list;
mutable std::shared_mutex cheats_list_mutex;
};
diff --git a/src/core/cheats/gateway_cheat.cpp b/src/core/cheats/gateway_cheat.cpp
index b30fda542..176264b7d 100644
--- a/src/core/cheats/gateway_cheat.cpp
+++ b/src/core/cheats/gateway_cheat.cpp
@@ -56,10 +56,10 @@ static inline std::enable_if_t> CompOp(const GatewayCheat:
}
}
-static inline void LoadOffsetOp(Memory::MemorySystem& memory, const GatewayCheat::CheatLine& line,
- State& state) {
+static inline void LoadOffsetOp(Memory::MemorySystem& memory, const Kernel::Process& process,
+ const GatewayCheat::CheatLine& line, State& state) {
u32 addr = line.address + state.offset;
- state.offset = memory.Read32(addr);
+ state.offset = memory.Read32(process, addr);
}
static inline void LoopOp(const GatewayCheat::CheatLine& line, State& state) {
@@ -145,6 +145,7 @@ static inline void JokerOp(const GatewayCheat::CheatLine& line, State& state,
}
static inline void PatchOp(const GatewayCheat::CheatLine& line, State& state, Core::System& system,
+ const Kernel::Process& process,
std::span cheat_lines) {
if (state.if_flag > 0) {
// Skip over the additional patch lines
@@ -166,7 +167,7 @@ static inline void PatchOp(const GatewayCheat::CheatLine& line, State& state, Co
state.current_line_nr++;
}
first = !first;
- system.Memory().Write32(addr, tmp);
+ system.Memory().Write32(process, addr, tmp);
addr += 4;
num_bytes -= 4;
}
@@ -174,7 +175,7 @@ static inline void PatchOp(const GatewayCheat::CheatLine& line, State& state, Co
u32 tmp = (first ? cheat_lines[state.current_line_nr].first
: cheat_lines[state.current_line_nr].value) >>
bit_offset;
- system.Memory().Write8(addr, static_cast(tmp));
+ system.Memory().Write8(process, addr, static_cast(tmp));
addr += 1;
num_bytes -= 1;
bit_offset += 8;
@@ -229,16 +230,27 @@ GatewayCheat::GatewayCheat(std::string name_, std::string code, std::string comm
GatewayCheat::~GatewayCheat() = default;
-void GatewayCheat::Execute(Core::System& system) const {
+void GatewayCheat::Execute(Core::System& system, u32 process_id) const {
State state;
Memory::MemorySystem& memory = system.Memory();
- auto Read8 = [&memory](VAddr addr) { return memory.Read8(addr); };
- auto Read16 = [&memory](VAddr addr) { return memory.Read16(addr); };
- auto Read32 = [&memory](VAddr addr) { return memory.Read32(addr); };
- auto Write8 = [&memory](VAddr addr, u8 value) { memory.Write8(addr, value); };
- auto Write16 = [&memory](VAddr addr, u16 value) { memory.Write16(addr, value); };
- auto Write32 = [&memory](VAddr addr, u32 value) { memory.Write32(addr, value); };
+ std::shared_ptr process = system.Kernel().GetProcessById(process_id);
+ if (!process) {
+ return;
+ }
+
+ auto Read8 = [&memory, &process](VAddr addr) { return memory.Read8(*process, addr); };
+ auto Read16 = [&memory, &process](VAddr addr) { return memory.Read16(*process, addr); };
+ auto Read32 = [&memory, &process](VAddr addr) { return memory.Read32(*process, addr); };
+ auto Write8 = [&memory, &process](VAddr addr, u8 value) {
+ memory.Write8(*process, addr, value);
+ };
+ auto Write16 = [&memory, &process](VAddr addr, u16 value) {
+ memory.Write16(*process, addr, value);
+ };
+ auto Write32 = [&memory, &process](VAddr addr, u32 value) {
+ memory.Write32(*process, addr, value);
+ };
for (state.current_line_nr = 0; state.current_line_nr < cheat_lines.size();
state.current_line_nr++) {
@@ -261,7 +273,7 @@ void GatewayCheat::Execute(Core::System& system) const {
// EXXXXXXX YYYYYYYY
// Copies YYYYYYYY bytes from (current code location + 8) to [XXXXXXXX + offset].
// We need to call this here to skip the additional patch lines
- PatchOp(line, state, system, cheat_lines);
+ PatchOp(line, state, system, *process, cheat_lines);
break;
case CheatType::Terminator:
// D0000000 00000000 - ENDIF
@@ -336,7 +348,7 @@ void GatewayCheat::Execute(Core::System& system) const {
break;
case CheatType::LoadOffset:
// BXXXXXXX 00000000 - offset = word[XXXXXXX+offset]
- LoadOffsetOp(system.Memory(), line, state);
+ LoadOffsetOp(system.Memory(), *process, line, state);
break;
case CheatType::Loop: {
// C0000000 YYYYYYYY - LOOP next block YYYYYYYY times
@@ -417,7 +429,7 @@ void GatewayCheat::Execute(Core::System& system) const {
case CheatType::Patch: {
// EXXXXXXX YYYYYYYY
// Copies YYYYYYYY bytes from (current code location + 8) to [XXXXXXXX + offset].
- PatchOp(line, state, system, cheat_lines);
+ PatchOp(line, state, system, *process, cheat_lines);
break;
}
}
diff --git a/src/core/cheats/gateway_cheat.h b/src/core/cheats/gateway_cheat.h
index ff200af59..dadfd2042 100644
--- a/src/core/cheats/gateway_cheat.h
+++ b/src/core/cheats/gateway_cheat.h
@@ -1,4 +1,4 @@
-// Copyright 2018 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -59,7 +59,7 @@ public:
GatewayCheat(std::string name, std::string code, std::string comments);
~GatewayCheat();
- void Execute(Core::System& system) const override;
+ void Execute(Core::System& system, u32 process_id) const override;
bool IsEnabled() const override;
void SetEnabled(bool enabled) override;
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 321e72646..98ac85eba 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -394,7 +394,7 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
}
cheat_engine.LoadCheatFile(title_id);
- cheat_engine.Connect();
+ cheat_engine.Connect(process->process_id);
perf_stats = std::make_unique(title_id);
@@ -473,7 +473,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
#else
for (u32 i = 0; i < num_cores; ++i) {
cpu_cores.push_back(
- std::make_shared(this, *memory, USER32MODE, i, timing->GetTimer(i)));
+ std::make_shared(*this, *memory, USER32MODE, i, timing->GetTimer(i)));
}
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
@@ -814,9 +814,11 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
// This needs to be set from somewhere - might as well be here!
if (Archive::is_loading::value) {
+ u32 cheats_pid;
+ ar & cheats_pid;
timing->UnlockEventQueue();
memory->SetDSP(*dsp_core);
- cheat_engine.Connect();
+ cheat_engine.Connect(cheats_pid);
gpu->Sync();
// Re-register gpu callback, because gsp service changed after service_manager got
@@ -824,6 +826,9 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
auto gsp = service_manager->GetService("gsp::Gpu");
gpu->SetInterruptHandler(
[gsp](Service::GSP::InterruptId interrupt_id) { gsp->SignalInterrupt(interrupt_id); });
+ } else {
+ u32 cheats_pid = cheat_engine.GetConnectedPID();
+ ar & cheats_pid;
}
save_state_status = SaveStateStatus::NONE;
diff --git a/src/core/file_sys/archive_ncch.cpp b/src/core/file_sys/archive_ncch.cpp
index 54d4639c5..fb0be5640 100644
--- a/src/core/file_sys/archive_ncch.cpp
+++ b/src/core/file_sys/archive_ncch.cpp
@@ -1,4 +1,4 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -133,6 +133,9 @@ ResultVal> NCCHArchive::OpenFile(const Path& path,
constexpr u32 region_manifest = 0x00010402;
constexpr u32 ng_word_list = 0x00010302;
constexpr u32 shared_font = 0x00014002;
+ constexpr u32 shared_font_CHN = 0x00014102;
+ constexpr u32 shared_font_KOR = 0x00014202;
+ constexpr u32 shared_font_TWN = 0x00014302;
u32 high = static_cast(title_id >> 32);
u32 low = static_cast(title_id & 0xFFFFFFFF);
@@ -158,6 +161,11 @@ ResultVal> NCCHArchive::OpenFile(const Path& path,
"Shared Font file missing. Loading open source replacement from memory");
archive_data =
std::vector(std::begin(SHARED_FONT_DATA), std::end(SHARED_FONT_DATA));
+ } else if (low == shared_font_CHN || low == shared_font_KOR || low == shared_font_TWN) {
+ LOG_ERROR(Service_FS, "CHN/KOR/TWN shared font file missing. Loading open source "
+ "replacement, but text will not display properly");
+ archive_data =
+ std::vector(std::begin(SHARED_FONT_DATA), std::end(SHARED_FONT_DATA));
}
} else if (high == system_data_archive) {
if (low == ng_word_list) {
diff --git a/src/core/file_sys/cia_container.cpp b/src/core/file_sys/cia_container.cpp
index 3297b96b0..957c541b3 100644
--- a/src/core/file_sys/cia_container.cpp
+++ b/src/core/file_sys/cia_container.cpp
@@ -1,4 +1,4 @@
-// Copyright 2017 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -13,11 +13,11 @@
namespace FileSys {
Loader::ResultStatus CIAContainer::Load(const FileBackend& backend) {
- std::vector header_data(sizeof(Header));
+ std::vector header_data(sizeof(CIAHeader));
// Load the CIA Header
- ResultVal read_result = backend.Read(0, sizeof(Header), header_data.data());
- if (read_result.Failed() || *read_result != sizeof(Header))
+ ResultVal read_result = backend.Read(0, sizeof(CIAHeader), header_data.data());
+ if (read_result.Failed() || *read_result != sizeof(CIAHeader))
return Loader::ResultStatus::Error;
Loader::ResultStatus result = LoadHeader(header_data);
@@ -65,8 +65,8 @@ Loader::ResultStatus CIAContainer::Load(const std::string& filepath) {
return Loader::ResultStatus::Error;
// Load CIA Header
- std::vector header_data(sizeof(Header));
- if (file.ReadBytes(header_data.data(), sizeof(Header)) != sizeof(Header))
+ std::vector header_data(sizeof(CIAHeader));
+ if (file.ReadBytes(header_data.data(), sizeof(CIAHeader)) != sizeof(CIAHeader))
return Loader::ResultStatus::Error;
Loader::ResultStatus result = LoadHeader(header_data);
@@ -134,11 +134,12 @@ Loader::ResultStatus CIAContainer::Load(std::span file_data) {
}
Loader::ResultStatus CIAContainer::LoadHeader(std::span header_data, std::size_t offset) {
- if (header_data.size() - offset < sizeof(Header)) {
+ if (header_data.size() - offset < sizeof(CIAHeader)) {
return Loader::ResultStatus::Error;
}
- std::memcpy(&cia_header, header_data.data(), sizeof(Header));
+ std::memcpy(&cia_header, header_data.data(), sizeof(CIAHeader));
+ has_header = true;
return Loader::ResultStatus::Success;
}
@@ -157,6 +158,11 @@ Loader::ResultStatus CIAContainer::LoadTitleMetadata(std::span tmd_dat
return cia_tmd.Load(tmd_data, offset);
}
+Loader::ResultStatus CIAContainer::LoadTitleMetadata(const TitleMetadata& tmd) {
+ cia_tmd = tmd;
+ return Loader::ResultStatus::Success;
+}
+
Loader::ResultStatus CIAContainer::LoadMetadata(std::span meta_data, std::size_t offset) {
if (meta_data.size() - offset < sizeof(Metadata)) {
return Loader::ResultStatus::Error;
@@ -167,7 +173,7 @@ Loader::ResultStatus CIAContainer::LoadMetadata(std::span meta_data, s
return Loader::ResultStatus::Success;
}
-const Ticket& CIAContainer::GetTicket() const {
+Ticket& CIAContainer::GetTicket() {
return cia_ticket;
}
@@ -260,4 +266,7 @@ void CIAContainer::Print() const {
LOG_DEBUG(Service_FS, "Content {:x} Offset: 0x{:08x} bytes", i, GetContentOffset(i));
}
}
+const CIAHeader* CIAContainer::GetHeader() {
+ return has_header ? &cia_header : nullptr;
+}
} // namespace FileSys
diff --git a/src/core/file_sys/cia_container.h b/src/core/file_sys/cia_container.h
index d7fa46dad..e562dc9be 100644
--- a/src/core/file_sys/cia_container.h
+++ b/src/core/file_sys/cia_container.h
@@ -1,4 +1,4 @@
-// Copyright 2017 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -28,6 +28,30 @@ constexpr std::size_t CIA_DEPENDENCY_SIZE = 0x300;
constexpr std::size_t CIA_METADATA_SIZE = 0x400;
constexpr u32 CIA_SECTION_ALIGNMENT = 0x40;
+struct CIAHeader {
+ u32_le header_size;
+ u16_le type;
+ u16_le version;
+ u32_le cert_size;
+ u32_le tik_size;
+ u32_le tmd_size;
+ u32_le meta_size;
+ u64_le content_size;
+ std::array content_present;
+
+ bool IsContentPresent(std::size_t index) const {
+ // The content_present is a bit array which defines which content in the TMD
+ // is included in the CIA, so check the bit for this index and add if set.
+ // The bits in the content index are arranged w/ index 0 as the MSB, 7 as the LSB, etc.
+ return (content_present[index >> 3] & (0x80 >> (index & 7))) != 0;
+ }
+ void SetContentPresent(u16 index) {
+ content_present[index >> 3] |= (0x80 >> (index & 7));
+ }
+};
+
+static_assert(sizeof(CIAHeader) == CIA_HEADER_SIZE, "CIA Header structure size is wrong");
+
/**
* Helper which implements an interface to read and write CTR Installable Archive (CIA) files.
* Data can either be loaded from a FileBackend, a string path, or from a data array. Data can
@@ -46,9 +70,11 @@ public:
Loader::ResultStatus LoadTicket(std::span ticket_data, std::size_t offset = 0);
Loader::ResultStatus LoadTicket(const Ticket& ticket);
Loader::ResultStatus LoadTitleMetadata(std::span tmd_data, std::size_t offset = 0);
+ Loader::ResultStatus LoadTitleMetadata(const TitleMetadata& tmd);
Loader::ResultStatus LoadMetadata(std::span meta_data, std::size_t offset = 0);
- const Ticket& GetTicket() const;
+ const CIAHeader* GetHeader();
+ Ticket& GetTicket();
const TitleMetadata& GetTitleMetadata() const;
std::array& GetDependencies();
u32 GetCoreVersion() const;
@@ -68,30 +94,6 @@ public:
void Print() const;
- struct Header {
- u32_le header_size;
- u16_le type;
- u16_le version;
- u32_le cert_size;
- u32_le tik_size;
- u32_le tmd_size;
- u32_le meta_size;
- u64_le content_size;
- std::array content_present;
-
- bool IsContentPresent(std::size_t index) const {
- // The content_present is a bit array which defines which content in the TMD
- // is included in the CIA, so check the bit for this index and add if set.
- // The bits in the content index are arranged w/ index 0 as the MSB, 7 as the LSB, etc.
- return (content_present[index >> 3] & (0x80 >> (index & 7))) != 0;
- }
- void SetContentPresent(u16 index) {
- content_present[index >> 3] |= (0x80 >> (index & 7));
- }
- };
-
- static_assert(sizeof(Header) == CIA_HEADER_SIZE, "CIA Header structure size is wrong");
-
private:
struct Metadata {
std::array dependencies;
@@ -102,7 +104,8 @@ private:
static_assert(sizeof(Metadata) == CIA_METADATA_SIZE, "CIA Metadata structure size is wrong");
- Header cia_header;
+ bool has_header = false;
+ CIAHeader cia_header;
Metadata cia_metadata;
Ticket cia_ticket;
TitleMetadata cia_tmd;
diff --git a/src/core/file_sys/ticket.cpp b/src/core/file_sys/ticket.cpp
index 1979755a7..76c4cbae5 100644
--- a/src/core/file_sys/ticket.cpp
+++ b/src/core/file_sys/ticket.cpp
@@ -100,8 +100,11 @@ Loader::ResultStatus Ticket::Load(std::span file_data, std::size_t off
if (total_size < content_index_end)
return Loader::ResultStatus::Error;
- content_index.resize(content_index_size);
- std::memcpy(content_index.data(), &file_data[offset + content_index_start], content_index_size);
+ std::vector content_index_vec;
+ content_index_vec.resize(content_index_size);
+ std::memcpy(content_index_vec.data(), &file_data[offset + content_index_start],
+ content_index_size);
+ content_index.Load(this, content_index_vec);
return Loader::ResultStatus::Success;
}
@@ -132,7 +135,7 @@ std::vector Ticket::Serialize() const {
reinterpret_cast(&ticket_body) + sizeof(ticket_body)};
ret.insert(ret.end(), body_span.begin(), body_span.end());
- ret.insert(ret.end(), content_index.begin(), content_index.end());
+ ret.insert(ret.end(), content_index.GetRaw().cbegin(), content_index.GetRaw().cend());
return ret;
}
@@ -167,7 +170,7 @@ std::optional> Ticket::GetTitleKey() const {
return title_key;
}
-bool Ticket::IsPersonal() {
+bool Ticket::IsPersonal() const {
if (ticket_body.console_id == 0u) {
// Common ticket
return false;
@@ -182,4 +185,88 @@ bool Ticket::IsPersonal() {
return ticket_body.console_id == otp.GetDeviceID();
}
+void Ticket::ContentIndex::Initialize() {
+ if (!parent || initialized) {
+ return;
+ }
+
+ if (content_index.size() < sizeof(MainHeader)) {
+ LOG_ERROR(Service_FS, "Ticket content index is too small");
+ return;
+ }
+ MainHeader* main_header = reinterpret_cast(content_index.data());
+ if (main_header->always1 != 1 || main_header->header_size != sizeof(MainHeader) ||
+ main_header->context_index_size != content_index.size() ||
+ main_header->index_header_size != sizeof(IndexHeader)) {
+ u16 always1 = main_header->always1;
+ u16 header_size = main_header->header_size;
+ u32 context_index_size = main_header->context_index_size;
+ u16 index_header_size = main_header->index_header_size;
+ LOG_ERROR(Service_FS,
+ "Ticket content index has unexpected parameters title_id={}, ticket_id={}, "
+ "always1={}, header_size={}, "
+ "size={}, index_header_size={}",
+ parent->GetTitleID(), parent->GetTicketID(), always1, header_size,
+ context_index_size, index_header_size);
+ return;
+ }
+ for (u32 i = 0; i < main_header->index_headers_count; i++) {
+ IndexHeader* curr_header = reinterpret_cast(
+ content_index.data() + main_header->index_headers_offset +
+ main_header->index_header_size * i);
+ if (curr_header->type != 3 || curr_header->entry_size != sizeof(RightsField)) {
+ u16 type = curr_header->type;
+ LOG_WARNING(Service_FS,
+ "Found unsupported index header type, skiping... title_id={}, "
+ "ticket_id={}, type={}",
+ parent->GetTitleID(), parent->GetTicketID(), type);
+ continue;
+ }
+ for (u32 j = 0; j < curr_header->entry_count; j++) {
+ RightsField* field = reinterpret_cast(
+ content_index.data() + curr_header->data_offset + curr_header->entry_size * j);
+ rights.push_back(*field);
+ }
+ }
+ initialized = true;
+}
+
+bool Ticket::ContentIndex::HasRights(u16 content_index) {
+ if (!initialized) {
+ Initialize();
+ if (!initialized)
+ return false;
+ }
+ // From:
+ // https://github.com/d0k3/GodMode9/blob/4424c37a89337ffb074c80807da1e80f358779b7/arm9/source/game/ticket.c#L198
+ if (rights.empty()) {
+ return content_index < 256; // when no fields, true if below 256
+ }
+
+ bool has_right = false;
+
+ // it loops until one of these happens:
+ // - we run out of bit fields
+ // - at the first encounter of an index offset field that's bigger than index
+ // - at the first encounter of a positive indicator of content rights
+ for (u32 i = 0; i < rights.size(); i++) {
+ u16 start_index = rights[i].start_index;
+ if (content_index < start_index) {
+ break;
+ }
+
+ u16 bit_pos = content_index - start_index;
+ if (bit_pos >= 1024) {
+ continue; // not in this field
+ }
+
+ if (rights[i].rights[bit_pos / 8] & (1 << (bit_pos % 8))) {
+ has_right = true;
+ break;
+ }
+ }
+
+ return has_right;
+}
+
} // namespace FileSys
diff --git a/src/core/file_sys/ticket.h b/src/core/file_sys/ticket.h
index ed6d379c0..db97cf09f 100644
--- a/src/core/file_sys/ticket.h
+++ b/src/core/file_sys/ticket.h
@@ -19,6 +19,12 @@ enum class ResultStatus;
namespace FileSys {
class Ticket {
+ struct LimitEntry {
+ u32_be type; // 4 -> Play times?
+ u32_be value;
+ };
+ static_assert(sizeof(LimitEntry) == 0x8, "LimitEntry structure size is wrong");
+
public:
#pragma pack(push, 1)
struct Body {
@@ -42,7 +48,7 @@ public:
INSERT_PADDING_BYTES(1);
u8 audit;
INSERT_PADDING_BYTES(0x42);
- std::array limits;
+ std::array limits;
};
static_assert(sizeof(Body) == 0x164, "Ticket body structure size is wrong");
#pragma pack(pop)
@@ -67,13 +73,66 @@ public:
return serialized_size;
}
- bool IsPersonal();
+ bool IsPersonal() const;
+
+ bool HasRights(u16 index) {
+ return content_index.HasRights(index);
+ }
+
+ class ContentIndex {
+ public:
+ struct MainHeader {
+ u16_be always1;
+ u16_be header_size;
+ u32_be context_index_size;
+ u32_be index_headers_offset;
+ u16_be index_headers_count;
+ u16_be index_header_size;
+ u32_be padding;
+ };
+
+ struct IndexHeader {
+ u32_be data_offset;
+ u32_be entry_count;
+ u32_be entry_size;
+ u32_be total_size;
+ u16_be type;
+ u16_be padding;
+ };
+
+ struct RightsField {
+ u16_be unknown;
+ u16_be start_index;
+ std::array rights;
+ };
+
+ ContentIndex() {}
+
+ void Load(Ticket* p, const std::vector& data) {
+ parent = p;
+ content_index = data;
+ }
+
+ const std::vector& GetRaw() const {
+ return content_index;
+ }
+
+ bool HasRights(u16 content_index);
+
+ private:
+ void Initialize();
+
+ bool initialized = false;
+ std::vector content_index;
+ std::vector rights;
+ Ticket* parent = nullptr;
+ };
private:
Body ticket_body;
u32_be signature_type;
std::vector ticket_signature;
- std::vector content_index;
+ ContentIndex content_index;
size_t serialized_size = 0;
};
diff --git a/src/core/file_sys/title_metadata.cpp b/src/core/file_sys/title_metadata.cpp
index 794a14398..d0cc2838e 100644
--- a/src/core/file_sys/title_metadata.cpp
+++ b/src/core/file_sys/title_metadata.cpp
@@ -1,4 +1,4 @@
-// Copyright 2017 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -6,6 +6,7 @@
#include "common/alignment.h"
#include "common/file_util.h"
#include "common/logging/log.h"
+#include "core/file_sys/cia_container.h"
#include "core/file_sys/signature.h"
#include "core/file_sys/title_metadata.h"
#include "core/loader/loader.h"
@@ -175,15 +176,24 @@ u64 TitleMetadata::GetContentSizeByIndex(std::size_t index) const {
return tmd_chunks[index].size;
}
+bool TitleMetadata::GetContentOptional(std::size_t index) const {
+ return (static_cast(tmd_chunks[index].type) & FileSys::TMDContentTypeFlag::Optional) != 0;
+}
+
std::array TitleMetadata::GetContentCTRByIndex(std::size_t index) const {
std::array ctr{};
std::memcpy(ctr.data(), &tmd_chunks[index].index, sizeof(u16));
return ctr;
}
-bool TitleMetadata::HasEncryptedContent() const {
- return std::any_of(tmd_chunks.begin(), tmd_chunks.end(), [](auto& chunk) {
- return (static_cast(chunk.type) & FileSys::TMDContentTypeFlag::Encrypted) != 0;
+bool TitleMetadata::HasEncryptedContent(const CIAHeader* header) const {
+ return std::any_of(tmd_chunks.begin(), tmd_chunks.end(), [header](auto& chunk) {
+ bool is_crypted =
+ (static_cast(chunk.type) & FileSys::TMDContentTypeFlag::Encrypted) != 0;
+ if (header) {
+ is_crypted = is_crypted && header->IsContentPresent(static_cast(chunk.index));
+ }
+ return is_crypted;
});
}
diff --git a/src/core/file_sys/title_metadata.h b/src/core/file_sys/title_metadata.h
index 620988568..d1ca730a6 100644
--- a/src/core/file_sys/title_metadata.h
+++ b/src/core/file_sys/title_metadata.h
@@ -1,4 +1,4 @@
-// Copyright 2017 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -17,6 +17,8 @@ enum class ResultStatus;
namespace FileSys {
+struct CIAHeader;
+
enum TMDContentTypeFlag : u16 {
Encrypted = 1 << 0,
Disc = 1 << 2,
@@ -97,8 +99,9 @@ public:
u32 GetContentIDByIndex(std::size_t index) const;
u16 GetContentTypeByIndex(std::size_t index) const;
u64 GetContentSizeByIndex(std::size_t index) const;
+ bool GetContentOptional(std::size_t index) const;
std::array GetContentCTRByIndex(std::size_t index) const;
- bool HasEncryptedContent() const;
+ bool HasEncryptedContent(const CIAHeader* header = nullptr) const;
void SetTitleID(u64 title_id);
void SetTitleType(u32 type);
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index 6c2811cf0..85abe0959 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -1,4 +1,4 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -94,17 +94,24 @@ bool EmuWindow::IsWithinTouchscreen(const Layout::FramebufferLayout& layout, uns
std::tuple EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) const {
Settings::StereoRenderOption render_3d_mode = Settings::values.render_3d.GetValue();
+ bool separate_win = false;
+#ifndef ANDROID
+ separate_win =
+ (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows);
+#endif
if (new_x >= framebuffer_layout.width / 2) {
- if (render_3d_mode == Settings::StereoRenderOption::SideBySide ||
- render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide)
+ if ((render_3d_mode == Settings::StereoRenderOption::SideBySide ||
+ render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide) &&
+ !separate_win)
new_x -= framebuffer_layout.width / 2;
else if (render_3d_mode == Settings::StereoRenderOption::CardboardVR)
new_x -=
(framebuffer_layout.width / 2) - (framebuffer_layout.cardboard.user_x_shift * 2);
}
- if (render_3d_mode == Settings::StereoRenderOption::SideBySide ||
- render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide) {
+ if ((render_3d_mode == Settings::StereoRenderOption::SideBySide ||
+ render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide) &&
+ !separate_win) {
new_x = std::max(new_x, framebuffer_layout.bottom_screen.left / 2);
new_x = std::min(new_x, framebuffer_layout.bottom_screen.right / 2 - 1);
} else {
@@ -130,21 +137,28 @@ void EmuWindow::CreateTouchState() {
bool EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
Settings::StereoRenderOption render_3d_mode = Settings::values.render_3d.GetValue();
+ bool separate_win = false;
+#ifndef ANDROID
+ separate_win =
+ (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows);
+#endif
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
return false;
if (framebuffer_x >= framebuffer_layout.width / 2) {
- if (render_3d_mode == Settings::StereoRenderOption::SideBySide ||
- render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide)
+ if ((render_3d_mode == Settings::StereoRenderOption::SideBySide ||
+ render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide) &&
+ !separate_win)
framebuffer_x -= framebuffer_layout.width / 2;
else if (render_3d_mode == Settings::StereoRenderOption::CardboardVR)
framebuffer_x -=
(framebuffer_layout.width / 2) - (framebuffer_layout.cardboard.user_x_shift * 2);
}
std::scoped_lock guard(touch_state->mutex);
- if (render_3d_mode == Settings::StereoRenderOption::SideBySide ||
- render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide) {
+ if ((render_3d_mode == Settings::StereoRenderOption::SideBySide ||
+ render_3d_mode == Settings::StereoRenderOption::ReverseSideBySide) &&
+ !separate_win) {
touch_state->touch_x =
static_cast(framebuffer_x - framebuffer_layout.bottom_screen.left / 2) /
(framebuffer_layout.bottom_screen.right / 2 -
@@ -207,6 +221,10 @@ void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_po
layout = Layout::CustomFrameLayout(
width, height, Settings::values.swap_screen.GetValue(), is_portrait_mode);
break;
+ case Settings::PortraitLayoutOption::PortraitOriginal:
+ layout = Layout::PortraitOriginalLayout(width, height,
+ Settings::values.swap_screen.GetValue());
+ break;
}
} else {
switch (layout_option) {
diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp
index 7cf52a29c..8b284b30c 100644
--- a/src/core/frontend/framebuffer_layout.cpp
+++ b/src/core/frontend/framebuffer_layout.cpp
@@ -1,4 +1,4 @@
-// Copyright 2016 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -51,6 +51,18 @@ FramebufferLayout PortraitTopFullFrameLayout(u32 width, u32 height, bool swapped
return res;
}
+FramebufferLayout PortraitOriginalLayout(u32 width, u32 height, bool swapped) {
+ ASSERT(width > 0);
+ ASSERT(height > 0);
+ const float scale_factor = 1;
+ FramebufferLayout res = LargeFrameLayout(width, height, swapped, false, scale_factor,
+ Settings::SmallScreenPosition::BelowLarge);
+ const int shiftY = -(int)(swapped ? res.bottom_screen.top : res.top_screen.top);
+ res.top_screen = res.top_screen.TranslateY(shiftY);
+ res.bottom_screen = res.bottom_screen.TranslateY(shiftY);
+ return res;
+}
+
FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool swapped, bool upright) {
ASSERT(width > 0);
ASSERT(height > 0);
@@ -115,7 +127,7 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr
// To do that, find the total emulation box and maximize that based on window size
const float window_aspect_ratio = static_cast(height) / width;
float emulation_aspect_ratio;
-
+ u32 gap = (u32)(Settings::values.screen_gap.GetValue() * scale_factor);
float large_height =
swapped ? Core::kScreenBottomHeight * scale_factor : Core::kScreenTopHeight * scale_factor;
float small_height =
@@ -129,9 +141,9 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr
if (vertical) {
// width is just the larger size at this point
emulation_width = std::max(large_width, small_width);
- emulation_height = large_height + small_height;
+ emulation_height = large_height + small_height + gap;
} else {
- emulation_width = large_width + small_width;
+ emulation_width = large_width + small_width + gap;
emulation_height = std::max(large_height, small_height);
}
@@ -156,47 +168,48 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr
// shift the large screen so it is at the top position of the bounding rectangle
large_screen = large_screen.TranslateY((height - total_rect.GetHeight()) / 2);
}
+ gap = static_cast(static_cast(gap) * scale_amount);
switch (small_screen_position) {
case Settings::SmallScreenPosition::TopRight:
// Shift the small screen to the top right corner
- small_screen = small_screen.TranslateX(large_screen.right);
+ small_screen = small_screen.TranslateX(large_screen.right + gap);
small_screen = small_screen.TranslateY(large_screen.top);
break;
case Settings::SmallScreenPosition::MiddleRight:
// Shift the small screen to the center right
- small_screen = small_screen.TranslateX(large_screen.right);
+ small_screen = small_screen.TranslateX(large_screen.right + gap);
small_screen = small_screen.TranslateY(
((large_screen.GetHeight() - small_screen.GetHeight()) / 2) + large_screen.top);
break;
case Settings::SmallScreenPosition::BottomRight:
// Shift the small screen to the bottom right corner
- small_screen = small_screen.TranslateX(large_screen.right);
+ small_screen = small_screen.TranslateX(large_screen.right + gap);
small_screen = small_screen.TranslateY(large_screen.bottom - small_screen.GetHeight());
break;
case Settings::SmallScreenPosition::TopLeft:
// shift the small screen to the upper left then shift the large screen to its right
small_screen = small_screen.TranslateX(large_screen.left);
- large_screen = large_screen.TranslateX(small_screen.GetWidth());
+ large_screen = large_screen.TranslateX(small_screen.GetWidth() + gap);
small_screen = small_screen.TranslateY(large_screen.top);
break;
case Settings::SmallScreenPosition::MiddleLeft:
// shift the small screen to the middle left and shift the large screen to its right
small_screen = small_screen.TranslateX(large_screen.left);
- large_screen = large_screen.TranslateX(small_screen.GetWidth());
+ large_screen = large_screen.TranslateX(small_screen.GetWidth() + gap);
small_screen = small_screen.TranslateY(
((large_screen.GetHeight() - small_screen.GetHeight()) / 2) + large_screen.top);
break;
case Settings::SmallScreenPosition::BottomLeft:
// shift the small screen to the bottom left and shift the large screen to its right
small_screen = small_screen.TranslateX(large_screen.left);
- large_screen = large_screen.TranslateX(small_screen.GetWidth());
+ large_screen = large_screen.TranslateX(small_screen.GetWidth() + gap);
small_screen = small_screen.TranslateY(large_screen.bottom - small_screen.GetHeight());
break;
case Settings::SmallScreenPosition::AboveLarge:
// shift the large screen down and the bottom screen above it
small_screen = small_screen.TranslateY(large_screen.top);
- large_screen = large_screen.TranslateY(small_screen.GetHeight());
+ large_screen = large_screen.TranslateY(small_screen.GetHeight() + gap);
// If the "large screen" is actually smaller, center it
if (large_screen.GetWidth() < total_rect.GetWidth()) {
large_screen =
@@ -212,7 +225,7 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr
large_screen =
large_screen.TranslateX((total_rect.GetWidth() - large_screen.GetWidth()) / 2);
}
- small_screen = small_screen.TranslateY(large_screen.bottom);
+ small_screen = small_screen.TranslateY(large_screen.bottom + gap);
small_screen = small_screen.TranslateX(large_screen.left + large_screen.GetWidth() / 2 -
small_screen.GetWidth() / 2);
break;
@@ -346,7 +359,8 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped, bool
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary,
bool is_portrait) {
- int width, height;
+ u32 width, height, gap;
+ gap = (int)(Settings::values.screen_gap.GetValue()) * res_scale;
if (is_portrait) {
auto layout_option = Settings::values.portrait_layout_option.GetValue();
switch (layout_option) {
@@ -363,9 +377,16 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar
Settings::values.swap_screen.GetValue(), is_portrait);
case Settings::PortraitLayoutOption::PortraitTopFullWidth:
width = Core::kScreenTopWidth * res_scale;
- height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale;
+ // clang-format off
+ height = (static_cast(Core::kScreenTopHeight + Core::kScreenBottomHeight * 1.25) *
+ res_scale) + gap;
+ // clang-format on
return PortraitTopFullFrameLayout(width, height,
Settings::values.swap_screen.GetValue());
+ case Settings::PortraitLayoutOption::PortraitOriginal:
+ width = Core::kScreenTopWidth * res_scale;
+ height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale;
+ return PortraitOriginalLayout(width, height, Settings::values.swap_screen.GetValue());
}
} else {
auto layout_option = Settings::values.layout_option.GetValue();
@@ -418,9 +439,9 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar
Settings::SmallScreenPosition::BelowLarge) {
// vertical, so height is sum of heights, width is larger of widths
width = std::max(largeWidth, smallWidth) * res_scale;
- height = (largeHeight + smallHeight) * res_scale;
+ height = (largeHeight + smallHeight) * res_scale + gap;
} else {
- width = (largeWidth + smallWidth) * res_scale;
+ width = (largeWidth + smallWidth) * res_scale + gap;
height = std::max(largeHeight, smallHeight) * res_scale;
}
@@ -433,7 +454,7 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar
Settings::values.small_screen_position.GetValue());
}
case Settings::LayoutOption::SideScreen:
- width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale;
+ width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale + gap;
height = Core::kScreenTopHeight * res_scale;
if (Settings::values.upright_screen.GetValue()) {
@@ -443,10 +464,28 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar
Settings::values.upright_screen.GetValue(), 1,
Settings::SmallScreenPosition::MiddleRight);
+ case Settings::LayoutOption::HybridScreen:
+ height = Core::kScreenTopHeight * res_scale;
+
+ if (Settings::values.swap_screen.GetValue()) {
+ width = Core::kScreenBottomWidth;
+ } else {
+ width = Core::kScreenTopWidth;
+ }
+ // 2.25f comes from HybridScreenLayout's scale_factor value.
+ width = static_cast((width + (Core::kScreenTopWidth / 2.25f)) * res_scale);
+
+ if (Settings::values.upright_screen.GetValue()) {
+ std::swap(width, height);
+ }
+
+ return HybridScreenLayout(width, height, Settings::values.swap_screen.GetValue(),
+ Settings::values.upright_screen.GetValue());
+
case Settings::LayoutOption::Default:
default:
width = Core::kScreenTopWidth * res_scale;
- height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale;
+ height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale + gap;
if (Settings::values.upright_screen.GetValue()) {
std::swap(width, height);
@@ -479,6 +518,7 @@ FramebufferLayout GetCardboardSettings(const FramebufferLayout& layout) {
if (is_portrait) {
switch (Settings::values.portrait_layout_option.GetValue()) {
case Settings::PortraitLayoutOption::PortraitTopFullWidth:
+ case Settings::PortraitLayoutOption::PortraitOriginal:
cardboard_screen_width = top_screen_width;
cardboard_screen_height = top_screen_height + bottom_screen_height;
bottom_screen_left += (top_screen_width - bottom_screen_width) / 2;
diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h
index adcf26630..81501decd 100644
--- a/src/core/frontend/framebuffer_layout.h
+++ b/src/core/frontend/framebuffer_layout.h
@@ -1,4 +1,4 @@
-// Copyright 2016 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -62,8 +62,8 @@ FramebufferLayout reverseLayout(FramebufferLayout layout);
FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool is_swapped, bool upright);
/**
- * Factory method for constructing the mobile Full Width Top layout
- * Two screens at top, full width, no gap between them
+ * Factory method for constructing the mobile Full Width (Default) layout
+ * Two screens at top, full width (so different heights)
* @param width Window framebuffer width in pixels
* @param height Window framebuffer height in pixels
* @param is_swapped if true, the bottom screen will be displayed above the top screen
@@ -71,6 +71,16 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool is_swapped, boo
*/
FramebufferLayout PortraitTopFullFrameLayout(u32 width, u32 height, bool is_swapped);
+/**
+ * Factory method for constructing the mobile Original layout
+ * Two screens at top, equal heights
+ * @param width Window framebuffer width in pixels
+ * @param height Window framebuffer height in pixels
+ * @param is_swapped if true, the bottom screen will be displayed above the top screen
+ * @return Newly created FramebufferLayout object with mobile portrait screen regions initialized
+ */
+FramebufferLayout PortraitOriginalLayout(u32 width, u32 height, bool is_swapped);
+
/**
* Factory method for constructing a FramebufferLayout with only the top or bottom screen
* @param width Window framebuffer width in pixels
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 50b5a6b25..ffbd11c4a 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -425,8 +425,8 @@ CIAFile::CIAFile(Core::System& system_, Service::FS::MediaType media_type, bool
// If data is being installing from CDN, provide a fake header to the container so that
// it's not uninitialized.
if (from_cdn) {
- FileSys::CIAContainer::Header fake_header{
- .header_size = sizeof(FileSys::CIAContainer::Header),
+ FileSys::CIAHeader fake_header{
+ .header_size = sizeof(FileSys::CIAHeader),
.type = 0,
.version = 0,
.cert_size = 0,
@@ -509,51 +509,7 @@ Result CIAFile::WriteTitleMetadata(std::span tmd_data, std::size_t off
return FileSys::ResultFileNotFound;
}
- // Create any other .app folders which may not exist yet
- std::string app_folder;
- auto main_content_path = GetTitleContentPath(media_type, tmd.GetTitleID(),
- FileSys::TMDContentIndex::Main, is_update);
- Common::SplitPath(main_content_path, &app_folder, nullptr, nullptr);
- FileUtil::CreateFullPath(app_folder);
-
- auto content_count = container.GetTitleMetadata().GetContentCount();
- content_written.resize(content_count);
-
- current_content_file.reset();
- current_content_index = -1;
- content_file_paths.clear();
- for (std::size_t i = 0; i < content_count; i++) {
- auto path = GetTitleContentPath(media_type, tmd.GetTitleID(), i, is_update);
- content_file_paths.emplace_back(path);
- }
-
- if (container.GetTitleMetadata().HasEncryptedContent()) {
- if (!decryption_authorized) {
- LOG_ERROR(Service_AM, "Blocked unauthorized encrypted CIA installation.");
- return {ErrorDescription::NotAuthorized, ErrorModule::AM, ErrorSummary::InvalidState,
- ErrorLevel::Permanent};
- } else {
- if (auto title_key = container.GetTicket().GetTitleKey()) {
- decryption_state->content.resize(content_count);
- for (std::size_t i = 0; i < content_count; ++i) {
- auto ctr = tmd.GetContentCTRByIndex(i);
- decryption_state->content[i].SetKeyWithIV(title_key->data(), title_key->size(),
- ctr.data());
- }
- } else {
- LOG_ERROR(Service_AM, "Could not read title key from ticket for encrypted CIA.");
- // TODO: Correct error code.
- return FileSys::ResultFileNotFound;
- }
- }
- } else {
- LOG_INFO(Service_AM,
- "Title has no encrypted content, skipping initializing decryption state.");
- }
-
- install_state = CIAInstallState::TMDLoaded;
-
- return ResultSuccess;
+ return PrepareToImportContent(tmd);
}
ResultVal CIAFile::WriteContentData(u64 offset, std::size_t length, const u8* buffer) {
@@ -592,6 +548,11 @@ ResultVal CIAFile::WriteContentData(u64 offset, std::size_t length,
buffer + (range_min - offset) + available_to_write);
if ((tmd.GetContentTypeByIndex(i) & FileSys::TMDContentTypeFlag::Encrypted) != 0) {
+ if (!decryption_authorized) {
+ LOG_ERROR(Service_AM, "Blocked unauthorized encrypted CIA installation.");
+ return Result(ErrorDescription::NotAuthorized, ErrorModule::AM,
+ ErrorSummary::InvalidState, ErrorLevel::Permanent);
+ }
decryption_state->content[i].ProcessData(temp.data(), temp.data(), temp.size());
}
@@ -687,6 +648,56 @@ ResultVal CIAFile::Write(u64 offset, std::size_t length, bool flush
return length;
}
+Result CIAFile::PrepareToImportContent(const FileSys::TitleMetadata& tmd) {
+
+ // Create any other .app folders which may not exist yet
+ std::string app_folder;
+ auto main_content_path = GetTitleContentPath(media_type, tmd.GetTitleID(),
+ FileSys::TMDContentIndex::Main, is_update);
+ Common::SplitPath(main_content_path, &app_folder, nullptr, nullptr);
+ FileUtil::CreateFullPath(app_folder);
+
+ auto content_count = container.GetTitleMetadata().GetContentCount();
+ content_written.resize(content_count);
+
+ current_content_file.reset();
+ current_content_index = -1;
+ content_file_paths.clear();
+ for (std::size_t i = 0; i < content_count; i++) {
+ auto path = GetTitleContentPath(media_type, tmd.GetTitleID(), i, is_update);
+ content_file_paths.emplace_back(path);
+ }
+
+ if (container.GetTitleMetadata().HasEncryptedContent(from_cdn ? nullptr
+ : container.GetHeader())) {
+ if (!decryption_authorized) {
+ LOG_ERROR(Service_AM, "Blocked unauthorized encrypted CIA installation.");
+ return {ErrorDescription::NotAuthorized, ErrorModule::AM, ErrorSummary::InvalidState,
+ ErrorLevel::Permanent};
+ } else {
+ if (auto title_key = container.GetTicket().GetTitleKey()) {
+ decryption_state->content.resize(content_count);
+ for (std::size_t i = 0; i < content_count; ++i) {
+ auto ctr = tmd.GetContentCTRByIndex(i);
+ decryption_state->content[i].SetKeyWithIV(title_key->data(), title_key->size(),
+ ctr.data());
+ }
+ } else {
+ LOG_ERROR(Service_AM, "Could not read title key from ticket for encrypted CIA.");
+ // TODO: Correct error code.
+ return FileSys::ResultFileNotFound;
+ }
+ }
+ } else {
+ LOG_INFO(Service_AM,
+ "Title has no encrypted content, skipping initializing decryption state.");
+ }
+
+ install_state = CIAInstallState::TMDLoaded;
+
+ return ResultSuccess;
+}
+
Result CIAFile::ProvideTicket(const FileSys::Ticket& ticket) {
// There is no need to write the ticket to nand, as that will
ASSERT_MSG(from_cdn, "This method should only be used when installing from CDN");
@@ -703,10 +714,37 @@ Result CIAFile::ProvideTicket(const FileSys::Ticket& ticket) {
return ResultSuccess;
}
+Result CIAFile::ProvideTMDForAdditionalContent(const FileSys::TitleMetadata& tmd) {
+ ASSERT_MSG(from_cdn, "This method should only be used when installing from CDN");
+
+ if (install_state != CIAInstallState::TicketLoaded) {
+ LOG_ERROR(Service_AM, "Ticket not provided yet");
+ // TODO: Correct result code.
+ return {ErrCodes::InvalidImportState, ErrorModule::AM, ErrorSummary::InvalidArgument,
+ ErrorLevel::Permanent};
+ }
+
+ auto load_result = container.LoadTitleMetadata(tmd);
+ if (load_result != Loader::ResultStatus::Success) {
+ LOG_ERROR(Service_AM, "Could not read ticket from CIA.");
+ // TODO: Correct result code.
+ return {ErrCodes::InvalidCIAHeader, ErrorModule::AM, ErrorSummary::InvalidArgument,
+ ErrorLevel::Permanent};
+ }
+
+ is_additional_content = true;
+
+ return PrepareToImportContent(container.GetTitleMetadata());
+}
+
const FileSys::TitleMetadata& CIAFile::GetTMD() {
return container.GetTitleMetadata();
}
+FileSys::Ticket& CIAFile::GetTicket() {
+ return container.GetTicket();
+}
+
ResultVal CIAFile::WriteContentDataIndexed(u16 content_index, u64 offset,
std::size_t length, const u8* buffer) {
@@ -728,6 +766,11 @@ ResultVal CIAFile::WriteContentDataIndexed(u16 content_index, u64 o
std::vector temp(buffer, buffer + std::min(static_cast(length), remaining_to_write));
if ((tmd.GetContentTypeByIndex(content_index) & FileSys::TMDContentTypeFlag::Encrypted) != 0) {
+ if (!decryption_authorized) {
+ LOG_ERROR(Service_AM, "Blocked unauthorized encrypted CIA installation.");
+ return Result(ErrorDescription::NotAuthorized, ErrorModule::AM,
+ ErrorSummary::InvalidState, ErrorLevel::Permanent);
+ }
decryption_state->content[content_index].ProcessData(temp.data(), temp.data(), temp.size());
}
@@ -771,8 +814,10 @@ bool CIAFile::Close() {
// Install aborted
if (!complete) {
LOG_ERROR(Service_AM, "CIAFile closed prematurely, aborting install...");
- FileUtil::DeleteDirRecursively(
- GetTitlePath(media_type, container.GetTitleMetadata().GetTitleID()));
+ if (!is_additional_content) {
+ FileUtil::DeleteDirRecursively(
+ GetTitlePath(media_type, container.GetTitleMetadata().GetTitleID()));
+ }
return true;
}
@@ -964,7 +1009,7 @@ InstallStatus InstallCIA(const std::string& path,
Core::System::GetInstance(),
Service::AM::GetTitleMediaType(container.GetTitleMetadata().GetTitleID()));
- if (container.GetTitleMetadata().HasEncryptedContent()) {
+ if (container.GetTitleMetadata().HasEncryptedContent(container.GetHeader())) {
LOG_ERROR(Service_AM, "File {} is encrypted! Aborting...", path);
return InstallStatus::ErrorEncrypted;
}
@@ -1427,57 +1472,111 @@ void Module::Interface::FindDLCContentInfos(Kernel::HLERequestContext& ctx) {
true);
} else {
- auto& content_info_out = rp.PopMappedBuffer();
+ struct AsyncData {
+ Service::FS::MediaType media_type;
+ u64 title_id;
+ std::vector content_requested;
- // Validate that only DLC TIDs are passed in
- u32 tid_high = static_cast(title_id >> 32);
- if (tid_high != TID_HIGH_DLC) {
- IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
- rb.Push(Result(ErrCodes::InvalidTIDInList, ErrorModule::AM,
- ErrorSummary::InvalidArgument, ErrorLevel::Usage));
- return;
- }
+ Result res{0};
+ std::vector out_vec;
+ Kernel::MappedBuffer* content_info_out;
+ };
+ auto async_data = std::make_shared();
+ async_data->media_type = media_type;
+ async_data->title_id = title_id;
+ async_data->content_requested.resize(content_count);
+ content_requested_in.Read(async_data->content_requested.data(), 0,
+ content_count * sizeof(u16));
+ async_data->content_info_out = &rp.PopMappedBuffer();
- std::vector content_requested(content_count);
- content_requested_in.Read(content_requested.data(), 0, content_count * sizeof(u16));
-
- std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
-
- FileSys::TitleMetadata tmd;
- if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) {
- std::size_t write_offset = 0;
- // Get info for each content index requested
- for (std::size_t i = 0; i < content_count; i++) {
- if (content_requested[i] >= tmd.GetContentCount()) {
- LOG_ERROR(Service_AM,
- "Attempted to get info for non-existent content index {:04x}.",
- content_requested[i]);
-
- IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
- rb.Push(-1); // TODO(Steveice10): Find the right error code
- return;
+ ctx.RunAsync(
+ [this, async_data](Kernel::HLERequestContext& ctx) {
+ // Validate that only DLC TIDs are passed in
+ u32 tid_high = static_cast(async_data->title_id >> 32);
+ if (tid_high != TID_HIGH_DLC) {
+ async_data->res = Result(ErrCodes::InvalidTIDInList, ErrorModule::AM,
+ ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+ return 0;
}
- ContentInfo content_info = {};
- content_info.index = content_requested[i];
- content_info.type = tmd.GetContentTypeByIndex(content_requested[i]);
- content_info.content_id = tmd.GetContentIDByIndex(content_requested[i]);
- content_info.size = tmd.GetContentSizeByIndex(content_requested[i]);
- content_info.ownership =
- OWNERSHIP_OWNED; // TODO(Steveice10): Pull this from the ticket.
+ std::string tmd_path =
+ GetTitleMetadataPath(async_data->media_type, async_data->title_id);
- if (FileUtil::Exists(
- GetTitleContentPath(media_type, title_id, content_requested[i]))) {
- content_info.ownership |= OWNERSHIP_DOWNLOADED;
+ // In normal circumstances, if there is no ticket we shouldn't be able to have
+ // any contents either. However to keep compatibility with older emulator builds,
+ // we give rights anyway if the ticket is not installed.
+ bool has_ticket = false;
+ FileSys::Ticket ticket;
+ std::scoped_lock lock(am->am_lists_mutex);
+ auto entries = am->am_ticket_list.find(async_data->title_id);
+ if (entries != am->am_ticket_list.end() &&
+ ticket.Load(async_data->title_id, (*entries).second) ==
+ Loader::ResultStatus::Success) {
+ has_ticket = true;
}
- content_info_out.Write(&content_info, write_offset, sizeof(ContentInfo));
- write_offset += sizeof(ContentInfo);
- }
- }
+ FileSys::TitleMetadata tmd;
+ if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) {
+ // Get info for each content index requested
+ for (std::size_t i = 0; i < async_data->content_requested.size(); i++) {
+ u16_le index = async_data->content_requested[i];
+ if (index >= tmd.GetContentCount()) {
+ LOG_ERROR(
+ Service_AM,
+ "Attempted to get info for non-existent content index {:04x}.",
+ index);
- IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
- rb.Push(ResultSuccess);
+ async_data->res = Result(0xFFFFFFFF);
+ return 0;
+ }
+
+ ContentInfo content_info = {};
+ content_info.index = index;
+ content_info.type = tmd.GetContentTypeByIndex(index);
+ content_info.content_id = tmd.GetContentIDByIndex(index);
+ content_info.size = tmd.GetContentSizeByIndex(index);
+ content_info.ownership =
+ (!has_ticket || ticket.HasRights(index)) ? OWNERSHIP_OWNED : 0;
+
+ if (FileUtil::Exists(GetTitleContentPath(async_data->media_type,
+ async_data->title_id, index))) {
+ bool pending = false;
+ for (auto& import_ctx : am->import_content_contexts) {
+ if (import_ctx.first == async_data->title_id &&
+ import_ctx.second.index == index &&
+ (import_ctx.second.state ==
+ ImportTitleContextState::WAITING_FOR_IMPORT ||
+ import_ctx.second.state ==
+ ImportTitleContextState::WAITING_FOR_COMMIT ||
+ import_ctx.second.state ==
+ ImportTitleContextState::RESUMABLE)) {
+ LOG_DEBUG(Service_AM, "content pending commit index={:016X}",
+ i);
+ pending = true;
+ break;
+ }
+ }
+ if (!pending) {
+ content_info.ownership |= OWNERSHIP_DOWNLOADED;
+ }
+ }
+
+ async_data->out_vec.push_back(content_info);
+ }
+ }
+
+ return 0;
+ },
+ [async_data](Kernel::HLERequestContext& ctx) {
+ IPC::RequestBuilder rb(ctx, 2, 0);
+ rb.Push(async_data->res);
+ if (async_data->res.IsSuccess()) {
+ async_data->content_info_out->Write(async_data->out_vec.data(), 0,
+ async_data->out_vec.size() *
+ sizeof(ContentInfo));
+ }
+ },
+ true);
}
}
@@ -1553,48 +1652,102 @@ void Module::Interface::ListDLCContentInfos(Kernel::HLERequestContext& ctx) {
true);
} else {
- auto& content_info_out = rp.PopMappedBuffer();
+ struct AsyncData {
+ Service::FS::MediaType media_type;
+ u64 title_id;
+ u32 content_count;
+ u32 start_index;
- // Validate that only DLC TIDs are passed in
- u32 tid_high = static_cast(title_id >> 32);
- if (tid_high != TID_HIGH_DLC) {
- IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
- rb.Push(Result(ErrCodes::InvalidTIDInList, ErrorModule::AM,
- ErrorSummary::InvalidArgument, ErrorLevel::Usage));
- rb.Push(0);
- return;
- }
+ Result res{0};
+ std::vector out_vec;
+ Kernel::MappedBuffer* content_info_out;
+ };
+ auto async_data = std::make_shared();
+ async_data->media_type = media_type;
+ async_data->title_id = title_id;
+ async_data->content_count = content_count;
+ async_data->start_index = start_index;
+ async_data->content_info_out = &rp.PopMappedBuffer();
- std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
-
- u32 copied = 0;
- FileSys::TitleMetadata tmd;
- if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) {
- u32 end_index =
- std::min(start_index + content_count, static_cast(tmd.GetContentCount()));
- std::size_t write_offset = 0;
- for (u32 i = start_index; i < end_index; i++) {
- ContentInfo content_info = {};
- content_info.index = static_cast(i);
- content_info.type = tmd.GetContentTypeByIndex(i);
- content_info.content_id = tmd.GetContentIDByIndex(i);
- content_info.size = tmd.GetContentSizeByIndex(i);
- content_info.ownership =
- OWNERSHIP_OWNED; // TODO(Steveice10): Pull this from the ticket.
-
- if (FileUtil::Exists(GetTitleContentPath(media_type, title_id, i))) {
- content_info.ownership |= OWNERSHIP_DOWNLOADED;
+ ctx.RunAsync(
+ [this, async_data](Kernel::HLERequestContext& ctx) {
+ // Validate that only DLC TIDs are passed in
+ u32 tid_high = static_cast(async_data->title_id >> 32);
+ if (tid_high != TID_HIGH_DLC) {
+ async_data->res = Result(ErrCodes::InvalidTIDInList, ErrorModule::AM,
+ ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+ return 0;
}
- content_info_out.Write(&content_info, write_offset, sizeof(ContentInfo));
- write_offset += sizeof(ContentInfo);
- copied++;
- }
- }
+ std::string tmd_path =
+ GetTitleMetadataPath(async_data->media_type, async_data->title_id);
- IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
- rb.Push(ResultSuccess);
- rb.Push(copied);
+ // In normal circumstances, if there is no ticket we shouldn't be able to have
+ // any contents either. However to keep compatibility with older emulator builds,
+ // we give rights anyway if the ticket is not installed.
+ bool has_ticket = false;
+ FileSys::Ticket ticket;
+ std::scoped_lock lock(am->am_lists_mutex);
+ auto entries = am->am_ticket_list.find(async_data->title_id);
+ if (entries != am->am_ticket_list.end() &&
+ ticket.Load(async_data->title_id, (*entries).second) ==
+ Loader::ResultStatus::Success) {
+ has_ticket = true;
+ }
+
+ FileSys::TitleMetadata tmd;
+ if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) {
+ u32 end_index = std::min(async_data->start_index + async_data->content_count,
+ static_cast(tmd.GetContentCount()));
+ for (u32 i = async_data->start_index; i < end_index; i++) {
+ ContentInfo content_info = {};
+ content_info.index = static_cast(i);
+ content_info.type = tmd.GetContentTypeByIndex(i);
+ content_info.content_id = tmd.GetContentIDByIndex(i);
+ content_info.size = tmd.GetContentSizeByIndex(i);
+ content_info.ownership =
+ (!has_ticket || ticket.HasRights(static_cast(i))) ? OWNERSHIP_OWNED
+ : 0;
+
+ if (FileUtil::Exists(GetTitleContentPath(async_data->media_type,
+ async_data->title_id, i))) {
+ bool pending = false;
+ for (auto& import_ctx : am->import_content_contexts) {
+ if (import_ctx.first == async_data->title_id &&
+ import_ctx.second.index == i &&
+ (import_ctx.second.state ==
+ ImportTitleContextState::WAITING_FOR_IMPORT ||
+ import_ctx.second.state ==
+ ImportTitleContextState::WAITING_FOR_COMMIT ||
+ import_ctx.second.state ==
+ ImportTitleContextState::RESUMABLE)) {
+ LOG_DEBUG(Service_AM, "content pending commit index={:016X}",
+ i);
+ pending = true;
+ break;
+ }
+ }
+ if (!pending) {
+ content_info.ownership |= OWNERSHIP_DOWNLOADED;
+ }
+ }
+
+ async_data->out_vec.push_back(content_info);
+ }
+ }
+ return 0;
+ },
+ [async_data](Kernel::HLERequestContext& ctx) {
+ IPC::RequestBuilder rb(ctx, 2, 0);
+ rb.Push(async_data->res);
+ rb.Push(static_cast(async_data->out_vec.size()));
+ if (async_data->res.IsSuccess()) {
+ async_data->content_info_out->Write(async_data->out_vec.data(), 0,
+ async_data->out_vec.size() *
+ sizeof(ContentInfo));
+ }
+ },
+ true);
}
}
@@ -2104,7 +2257,7 @@ void Module::Interface::GetPatchTitleInfos(Kernel::HLERequestContext& ctx) {
std::vector title_id_list;
Result res{0};
- std::vector out;
+ std::vector out;
Kernel::MappedBuffer* title_id_list_buffer;
Kernel::MappedBuffer* title_info_out;
};
@@ -2144,7 +2297,7 @@ void Module::Interface::GetPatchTitleInfos(Kernel::HLERequestContext& ctx) {
return 0;
}
- async_data->out.resize(title_infos->second);
+ async_data->out.resize(title_infos->second / sizeof(TitleInfo));
memcpy(async_data->out.data(), title_infos->first, title_infos->second);
return 0;
},
@@ -2156,7 +2309,7 @@ void Module::Interface::GetPatchTitleInfos(Kernel::HLERequestContext& ctx) {
rb.PushMappedBuffer(*async_data->title_info_out);
} else {
async_data->title_info_out->Write(async_data->out.data(), 0,
- async_data->out.size());
+ async_data->out.size() * sizeof(TitleInfo));
IPC::RequestBuilder rb(ctx, 1, 4);
rb.Push(async_data->res);
@@ -2301,27 +2454,43 @@ void Module::Interface::ListDataTitleTicketInfos(Kernel::HLERequestContext& ctx)
},
true);
} else {
- auto& ticket_info_out = rp.PopMappedBuffer();
+ LOG_DEBUG(Service_AM, "(STUBBED) called, ticket_count={}", ticket_count);
- std::size_t write_offset = 0;
- for (u32 i = 0; i < ticket_count; i++) {
- TicketInfo ticket_info = {};
- ticket_info.title_id = title_id;
- ticket_info.version = 0; // TODO
- ticket_info.size = 0; // TODO
-
- ticket_info_out.Write(&ticket_info, write_offset, sizeof(TicketInfo));
- write_offset += sizeof(TicketInfo);
+ u32 tid_high = static_cast(title_id >> 32);
+ if (tid_high != 0x0004008C && tid_high != 0x0004000D) {
+ LOG_ERROR(Service_AM, "Tried to get infos for non-data title title_id={:016X}",
+ title_id);
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(Result(60, ErrorModule::AM, ErrorSummary::InvalidArgument, ErrorLevel::Usage));
}
- IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
- rb.Push(ResultSuccess);
- rb.Push(ticket_count);
- rb.PushMappedBuffer(ticket_info_out);
+ auto& out_buffer = rp.PopMappedBuffer();
- LOG_WARNING(Service_AM,
- "(STUBBED) ticket_count=0x{:08X}, title_id=0x{:016x}, start_index=0x{:08X}",
- ticket_count, title_id, start_index);
+ std::scoped_lock lock(am->am_lists_mutex);
+ auto range = am->am_ticket_list.equal_range(title_id);
+ auto it = range.first;
+ std::advance(it, std::min(static_cast(start_index),
+ static_cast(std::distance(range.first, range.second))));
+
+ u32 written = 0;
+ for (; it != range.second && written < ticket_count; it++) {
+ FileSys::Ticket ticket;
+ if (ticket.Load(title_id, it->second) != Loader::ResultStatus::Success)
+ continue;
+
+ TicketInfo info = {};
+ info.title_id = ticket.GetTitleID();
+ info.ticket_id = ticket.GetTicketID();
+ info.version = ticket.GetVersion();
+ info.size = static_cast(ticket.GetSerializedSize());
+
+ out_buffer.Write(&info, written * sizeof(TicketInfo), sizeof(TicketInfo));
+ written++;
+ }
+
+ IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
+ rb.Push(ResultSuccess); // No error
+ rb.Push(written);
}
}
@@ -2719,7 +2888,8 @@ void Module::Interface::NeedsCleanup(Kernel::HLERequestContext& ctx) {
bool needs_cleanup = false;
for (auto& import_ctx : am->import_title_contexts) {
- if (import_ctx.second.state == ImportTitleContextState::NEEDS_CLEANUP) {
+ if (import_ctx.second.state == ImportTitleContextState::RESUMABLE ||
+ import_ctx.second.state == ImportTitleContextState::WAITING_FOR_IMPORT) {
needs_cleanup = true;
break;
}
@@ -2727,7 +2897,8 @@ void Module::Interface::NeedsCleanup(Kernel::HLERequestContext& ctx) {
if (!needs_cleanup) {
for (auto& import_ctx : am->import_content_contexts) {
- if (import_ctx.second.state == ImportTitleContextState::NEEDS_CLEANUP) {
+ if (import_ctx.second.state == ImportTitleContextState::RESUMABLE ||
+ import_ctx.second.state == ImportTitleContextState::WAITING_FOR_IMPORT) {
needs_cleanup = true;
}
}
@@ -2745,7 +2916,9 @@ void Module::Interface::DoCleanup(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "(STUBBED) called, media_type={:#02x}", media_type);
for (auto it = am->import_content_contexts.begin(); it != am->import_content_contexts.end();) {
- if (it->second.state == ImportTitleContextState::NEEDS_CLEANUP) {
+ if (it->second.state == ImportTitleContextState::RESUMABLE ||
+ it->second.state == ImportTitleContextState::WAITING_FOR_IMPORT ||
+ it->second.state == ImportTitleContextState::NEEDS_CLEANUP) {
it = am->import_content_contexts.erase(it);
} else {
it++;
@@ -2753,7 +2926,16 @@ void Module::Interface::DoCleanup(Kernel::HLERequestContext& ctx) {
}
for (auto it = am->import_title_contexts.begin(); it != am->import_title_contexts.end();) {
- if (it->second.state == ImportTitleContextState::NEEDS_CLEANUP) {
+ if (it->second.state == ImportTitleContextState::RESUMABLE ||
+ it->second.state == ImportTitleContextState::WAITING_FOR_IMPORT ||
+ it->second.state == ImportTitleContextState::NEEDS_CLEANUP) {
+ if (am->importing_title) {
+ if (am->importing_title->title_id == it->second.title_id &&
+ am->importing_title->media_type ==
+ static_cast(media_type)) {
+ am->importing_title.reset();
+ }
+ }
it = am->import_title_contexts.erase(it);
} else {
it++;
@@ -2865,16 +3047,22 @@ void Module::Interface::CheckContentRights(Kernel::HLERequestContext& ctx) {
u64 tid = rp.Pop();
u16 content_index = rp.Pop();
- // TODO(shinyquagsire23): Read tickets for this instead?
- bool has_rights =
- FileUtil::Exists(GetTitleContentPath(Service::FS::MediaType::NAND, tid, content_index)) ||
- FileUtil::Exists(GetTitleContentPath(Service::FS::MediaType::SDMC, tid, content_index));
+ bool has_ticket = false;
+ FileSys::Ticket ticket;
+ std::scoped_lock lock(am->am_lists_mutex);
+ auto entries = am->am_ticket_list.find(tid);
+ if (entries != am->am_ticket_list.end() &&
+ ticket.Load(tid, (*entries).second) == Loader::ResultStatus::Success) {
+ has_ticket = true;
+ }
+
+ bool has_rights = (!has_ticket || ticket.HasRights(content_index));
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(ResultSuccess); // No error
rb.Push(has_rights);
- LOG_WARNING(Service_AM, "(STUBBED) tid={:016x}, content_index={}", tid, content_index);
+ LOG_DEBUG(Service_AM, "tid={:016x}, content_index={}", tid, content_index);
}
void Module::Interface::CheckContentRightsIgnorePlatform(Kernel::HLERequestContext& ctx) {
@@ -2882,15 +3070,22 @@ void Module::Interface::CheckContentRightsIgnorePlatform(Kernel::HLERequestConte
u64 tid = rp.Pop();
u16 content_index = rp.Pop();
- // TODO(shinyquagsire23): Read tickets for this instead?
- bool has_rights =
- FileUtil::Exists(GetTitleContentPath(Service::FS::MediaType::SDMC, tid, content_index));
+ bool has_ticket = false;
+ FileSys::Ticket ticket;
+ std::scoped_lock lock(am->am_lists_mutex);
+ auto entries = am->am_ticket_list.find(tid);
+ if (entries != am->am_ticket_list.end() &&
+ ticket.Load(tid, (*entries).second) == Loader::ResultStatus::Success) {
+ has_ticket = true;
+ }
+
+ bool has_rights = (!has_ticket || ticket.HasRights(content_index));
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(ResultSuccess); // No error
rb.Push(has_rights);
- LOG_WARNING(Service_AM, "(STUBBED) tid={:016x}, content_index={}", tid, content_index);
+ LOG_DEBUG(Service_AM, "tid={:016x}, content_index={}", tid, content_index);
}
void Module::Interface::BeginImportProgram(Kernel::HLERequestContext& ctx) {
@@ -3298,10 +3493,10 @@ void Module::Interface::CommitImportTitlesImpl(Kernel::HLERequestContext& ctx,
IPC::RequestParser rp(ctx);
const auto media_type = static_cast(rp.Pop());
[[maybe_unused]] u32 count = rp.Pop();
- [[maybe_unused]] u8 database = rp.Pop();
+ bool cleanup = rp.Pop();
- LOG_WARNING(Service_AM, "(STUBBED) update_firm_auto={} is_titles={}", is_update_firm_auto,
- is_titles);
+ LOG_WARNING(Service_AM, "(STUBBED) update_firm_auto={} is_titles={} cleanup={}",
+ is_update_firm_auto, is_titles, cleanup);
auto& title_id_buf = rp.PopMappedBuffer();
@@ -3323,6 +3518,29 @@ void Module::Interface::CommitImportTitlesImpl(Kernel::HLERequestContext& ctx,
}
}
+ if (cleanup) {
+ for (auto it = am->import_content_contexts.begin();
+ it != am->import_content_contexts.end();) {
+ if (it->second.state == ImportTitleContextState::RESUMABLE ||
+ it->second.state == ImportTitleContextState::WAITING_FOR_IMPORT ||
+ it->second.state == ImportTitleContextState::NEEDS_CLEANUP) {
+ it = am->import_content_contexts.erase(it);
+ } else {
+ it++;
+ }
+ }
+
+ for (auto it = am->import_title_contexts.begin(); it != am->import_title_contexts.end();) {
+ if (it->second.state == ImportTitleContextState::RESUMABLE ||
+ it->second.state == ImportTitleContextState::WAITING_FOR_IMPORT ||
+ it->second.state == ImportTitleContextState::NEEDS_CLEANUP) {
+ it = am->import_title_contexts.erase(it);
+ } else {
+ it++;
+ }
+ }
+ }
+
am->ScanForTitles(media_type);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
@@ -3670,7 +3888,7 @@ void Module::Interface::EndImportTmd(Kernel::HLERequestContext& ctx) {
if (tmd_file.Succeeded()) {
struct AsyncData {
Service::AM::TMDFile* tmd_file;
- bool create_context;
+ [[maybe_unused]] bool create_context;
Result res{0};
};
@@ -3687,7 +3905,8 @@ void Module::Interface::EndImportTmd(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb(ctx, 1, 0);
rb.Push(async_data->res);
- if (async_data->create_context) {
+ if (async_data->res.IsSuccess()) {
+ am->importing_title->tmd_provided = true;
const FileSys::TitleMetadata& tmd_info = am->importing_title->cia_file.GetTMD();
ImportTitleContext& context = am->import_title_contexts[tmd_info.GetTitleID()];
@@ -3697,6 +3916,9 @@ void Module::Interface::EndImportTmd(Kernel::HLERequestContext& ctx) {
context.state = ImportTitleContextState::WAITING_FOR_IMPORT;
context.size = 0;
for (size_t i = 0; i < tmd_info.GetContentCount(); i++) {
+ if (tmd_info.GetContentOptional(i)) {
+ continue;
+ }
ImportContentContext content_context;
content_context.content_id = tmd_info.GetContentIDByIndex(i);
content_context.index = static_cast(i);
@@ -3724,13 +3946,68 @@ void Module::Interface::CreateImportContentContexts(Kernel::HLERequestContext& c
const u32 content_count = rp.Pop();
auto content_buf = rp.PopMappedBuffer();
- std::vector content_indices(content_count);
- content_buf.Read(content_indices.data(), 0, content_buf.GetSize());
+ LOG_DEBUG(Service_AM, "");
- IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
- rb.Push(ResultSuccess);
+ if (!am->importing_title) {
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(Result(ErrCodes::InvalidImportState, ErrorModule::AM, ErrorSummary::InvalidState,
+ ErrorLevel::Permanent));
+ return;
+ }
- LOG_WARNING(Service_AM, "(STUBBED)");
+ struct AsyncData {
+ std::vector content_indices;
+
+ Result res{0};
+ };
+ std::shared_ptr async_data = std::make_shared();
+ async_data->content_indices.resize(content_count);
+ content_buf.Read(async_data->content_indices.data(), 0, content_buf.GetSize());
+
+ ctx.RunAsync(
+ [this, async_data](Kernel::HLERequestContext& ctx) {
+ if (!am->importing_title->tmd_provided) {
+ std::string tmd_path = GetTitleMetadataPath(am->importing_title->media_type,
+ am->importing_title->title_id);
+ FileSys::TitleMetadata tmd;
+ if (tmd.Load(tmd_path) != Loader::ResultStatus::Success) {
+ LOG_ERROR(Service_AM, "Couldn't load TMD for title_id={:016X}, mediatype={}",
+ am->importing_title->title_id, am->importing_title->media_type);
+
+ async_data->res =
+ Result(0xFFFFFFFF); // TODO(PabloMK7): Find the right error code
+ return 0;
+ }
+ am->importing_title->cia_file.ProvideTMDForAdditionalContent(tmd);
+ am->importing_title->tmd_provided = true;
+ }
+ const FileSys::TitleMetadata& tmd = am->importing_title->cia_file.GetTMD();
+ for (size_t i = 0; i < async_data->content_indices.size(); i++) {
+ u16 index = async_data->content_indices[i];
+ if (index > tmd.GetContentCount()) {
+ LOG_ERROR(Service_AM,
+ "Tried to create context for invalid index title_id={:016x} index={}",
+ am->importing_title->title_id, index);
+ async_data->res =
+ Result(0xFFFFFFFF); // TODO(PabloMK7): Find the right error code
+ return 0;
+ }
+ ImportContentContext content_context;
+ content_context.content_id = tmd.GetContentIDByIndex(index);
+ content_context.index = static_cast(index);
+ content_context.state = ImportTitleContextState::WAITING_FOR_IMPORT;
+ content_context.size = tmd.GetContentSizeByIndex(index);
+ content_context.current_size = 0;
+ am->import_content_contexts.insert(
+ std::make_pair(am->importing_title->title_id, content_context));
+ }
+ return 0;
+ },
+ [async_data](Kernel::HLERequestContext& ctx) {
+ IPC::RequestBuilder rb(ctx, 1, 0);
+ rb.Push(async_data->res);
+ },
+ true);
}
void Module::Interface::BeginImportContent(Kernel::HLERequestContext& ctx) {
@@ -4145,6 +4422,255 @@ void Module::Interface::ListTicketInfos(Kernel::HLERequestContext& ctx) {
rb.Push(written);
}
+void Module::Interface::GetNumCurrentContentInfos(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp(ctx);
+
+ LOG_DEBUG(Service_AM, "");
+
+ if (!am->importing_title) {
+ // Not importing a title
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
+ rb.Push(ResultSuccess); // No error
+ rb.Push(static_cast(am->importing_title->cia_file.GetTMD().GetContentCount()));
+}
+
+void Module::Interface::FindCurrentContentInfos(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp(ctx);
+
+ LOG_DEBUG(Service_AM, "");
+
+ if (!am->importing_title) {
+ // Not importing a title
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ struct AsyncData {
+ u32 content_count;
+ std::vector content_requested;
+
+ std::vector out_vec;
+ Kernel::MappedBuffer* content_info_out;
+ Result res{0};
+ };
+ auto async_data = std::make_shared();
+ async_data->content_count = rp.Pop();
+
+ auto& content_requested_in = rp.PopMappedBuffer();
+ async_data->content_requested.resize(async_data->content_count);
+ content_requested_in.Read(async_data->content_requested.data(), 0,
+ async_data->content_count * sizeof(u16));
+ async_data->content_info_out = &rp.PopMappedBuffer();
+
+ ctx.RunAsync(
+ [this, async_data](Kernel::HLERequestContext& ctx) {
+ const FileSys::TitleMetadata& tmd = am->importing_title->cia_file.GetTMD();
+ FileSys::Ticket& ticket = am->importing_title->cia_file.GetTicket();
+ // Get info for each content index requested
+ for (std::size_t i = 0; i < async_data->content_count; i++) {
+ u16_le index = async_data->content_requested[i];
+ if (index >= tmd.GetContentCount()) {
+ LOG_ERROR(Service_AM,
+ "Attempted to get info for non-existent content index {:04x}.",
+ index);
+
+ async_data->res = Result(0xFFFFFFFF);
+ return 0;
+ }
+
+ ContentInfo content_info = {};
+ content_info.index = index;
+ content_info.type = tmd.GetContentTypeByIndex(index);
+ content_info.content_id = tmd.GetContentIDByIndex(index);
+ content_info.size = tmd.GetContentSizeByIndex(index);
+ content_info.ownership = ticket.HasRights(index) ? OWNERSHIP_OWNED : 0;
+
+ if (FileUtil::Exists(GetTitleContentPath(am->importing_title->media_type,
+ am->importing_title->title_id, index))) {
+ bool pending = false;
+ for (auto& import_ctx : am->import_content_contexts) {
+ if (import_ctx.first == am->importing_title->title_id &&
+ import_ctx.second.index == index &&
+ (import_ctx.second.state ==
+ ImportTitleContextState::WAITING_FOR_IMPORT ||
+ import_ctx.second.state ==
+ ImportTitleContextState::WAITING_FOR_COMMIT ||
+ import_ctx.second.state == ImportTitleContextState::RESUMABLE)) {
+ LOG_DEBUG(Service_AM, "content pending commit index={:016X}", index);
+ pending = true;
+ break;
+ }
+ }
+ if (!pending) {
+ content_info.ownership |= OWNERSHIP_DOWNLOADED;
+ }
+ }
+ async_data->out_vec.push_back(content_info);
+ }
+ return 0;
+ },
+ [async_data](Kernel::HLERequestContext& ctx) {
+ IPC::RequestBuilder rb(ctx, 1, 0);
+ rb.Push(async_data->res);
+ if (async_data->res.IsSuccess()) {
+ async_data->content_info_out->Write(async_data->out_vec.data(), 0,
+ async_data->out_vec.size() *
+ sizeof(ContentInfo));
+ }
+ },
+ true);
+}
+
+void Module::Interface::ListCurrentContentInfos(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp(ctx);
+
+ LOG_DEBUG(Service_AM, "");
+
+ if (!am->importing_title) {
+ // Not importing a title
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ struct AsyncData {
+ u32 content_count;
+ u32 start_index;
+
+ std::vector out_vec;
+ Kernel::MappedBuffer* content_info_out;
+ Result res{0};
+ };
+ auto async_data = std::make_shared();
+ async_data->content_count = rp.Pop();
+ async_data->start_index = rp.Pop();
+
+ async_data->content_info_out = &rp.PopMappedBuffer();
+
+ ctx.RunAsync(
+ [this, async_data](Kernel::HLERequestContext& ctx) {
+ const FileSys::TitleMetadata& tmd = am->importing_title->cia_file.GetTMD();
+ FileSys::Ticket& ticket = am->importing_title->cia_file.GetTicket();
+ u32 end_index = std::min(async_data->start_index + async_data->content_count,
+ static_cast(tmd.GetContentCount()));
+ for (u32 i = async_data->start_index; i < end_index; i++) {
+ ContentInfo content_info = {};
+ content_info.index = static_cast(i);
+ content_info.type = tmd.GetContentTypeByIndex(i);
+ content_info.content_id = tmd.GetContentIDByIndex(i);
+ content_info.size = tmd.GetContentSizeByIndex(i);
+ content_info.ownership =
+ ticket.HasRights(static_cast(i)) ? OWNERSHIP_OWNED : 0;
+
+ if (FileUtil::Exists(GetTitleContentPath(am->importing_title->media_type,
+ am->importing_title->title_id, i))) {
+ bool pending = false;
+ for (auto& import_ctx : am->import_content_contexts) {
+ if (import_ctx.first == am->importing_title->title_id &&
+ import_ctx.second.index == i &&
+ (import_ctx.second.state ==
+ ImportTitleContextState::WAITING_FOR_IMPORT ||
+ import_ctx.second.state ==
+ ImportTitleContextState::WAITING_FOR_COMMIT ||
+ import_ctx.second.state == ImportTitleContextState::RESUMABLE)) {
+ LOG_DEBUG(Service_AM, "content pending commit index={:016X}", i);
+ pending = true;
+ break;
+ }
+ }
+ if (!pending) {
+ content_info.ownership |= OWNERSHIP_DOWNLOADED;
+ }
+ }
+
+ async_data->out_vec.push_back(content_info);
+ }
+ return 0;
+ },
+ [async_data](Kernel::HLERequestContext& ctx) {
+ IPC::RequestBuilder rb(ctx, 2, 0);
+ rb.Push(async_data->res);
+ rb.Push(static_cast(async_data->out_vec.size()));
+ if (async_data->res.IsSuccess()) {
+ async_data->content_info_out->Write(async_data->out_vec.data(), 0,
+ async_data->out_vec.size() *
+ sizeof(ContentInfo));
+ }
+ },
+ true);
+}
+
+void Module::Interface::CalculateContextRequiredSize(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp(ctx);
+
+ LOG_DEBUG(Service_AM, "");
+
+ auto media_type = static_cast(rp.Pop());
+ u64 title_id = rp.Pop();
+ u32 content_count = rp.Pop();
+ auto& content_requested_in = rp.PopMappedBuffer();
+
+ std::vector content_requested(content_count);
+ content_requested_in.Read(content_requested.data(), 0, content_count * sizeof(u16));
+
+ std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
+ FileSys::TitleMetadata tmd;
+ if (tmd.Load(tmd_path) != Loader::ResultStatus::Success) {
+ LOG_ERROR(Service_AM, "Couldn't load TMD for title_id={:016X}, mediatype={}", title_id,
+ media_type);
+
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(-1); // TODO(PabloMK7): Find the right error code
+ return;
+ }
+ u64 size_out = 0;
+ // Get info for each content index requested
+ for (std::size_t i = 0; i < content_count; i++) {
+ if (content_requested[i] >= tmd.GetContentCount()) {
+ LOG_ERROR(Service_AM, "Attempted to get info for non-existent content index {:04x}.",
+ content_requested[i]);
+
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(-1); // TODO(PabloMK7): Find the right error code
+ return;
+ }
+ if (!tmd.GetContentOptional(content_requested[i])) {
+ LOG_ERROR(Service_AM, "Attempted to get info for non-optional content index {:04x}.",
+ content_requested[i]);
+
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(-1); // TODO(PabloMK7): Find the right error code
+ return;
+ }
+
+ size_out += tmd.GetContentSizeByIndex(content_requested[i]);
+ }
+
+ IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
+ rb.Push(ResultSuccess);
+ rb.Push(size_out);
+}
+
+void Module::Interface::UpdateImportContentContexts(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp(ctx);
+ const u32 content_count = rp.Pop();
+ auto content_buf = rp.PopMappedBuffer();
+
+ std::vector content_indices(content_count);
+ content_buf.Read(content_indices.data(), 0, content_buf.GetSize());
+
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(ResultSuccess);
+
+ LOG_WARNING(Service_AM, "(STUBBED)");
+}
+
void Module::Interface::ExportTicketWrapped(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index afac4dae5..9585f96e3 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -181,8 +181,11 @@ public:
ResultVal Write(u64 offset, std::size_t length, bool flush, bool update_timestamp,
const u8* buffer) override;
+ Result PrepareToImportContent(const FileSys::TitleMetadata& tmd);
Result ProvideTicket(const FileSys::Ticket& ticket);
+ Result ProvideTMDForAdditionalContent(const FileSys::TitleMetadata& tmd);
const FileSys::TitleMetadata& GetTMD();
+ FileSys::Ticket& GetTicket();
CIAInstallState GetCiaInstallState() {
return install_state;
}
@@ -208,6 +211,7 @@ private:
bool decryption_authorized;
bool is_done = false;
bool is_closed = false;
+ bool is_additional_content = false;
// Whether it's installing an update, and what step of installation it is at
bool is_update = false;
@@ -233,11 +237,13 @@ class CurrentImportingTitle {
public:
explicit CurrentImportingTitle(Core::System& system_, u64 title_id_,
Service::FS::MediaType media_type_)
- : cia_file(system_, media_type_, true), title_id(title_id_), media_type(media_type_) {}
+ : cia_file(system_, media_type_, true), title_id(title_id_), media_type(media_type_),
+ tmd_provided(false) {}
CIAFile cia_file;
u64 title_id;
Service::FS::MediaType media_type;
+ bool tmd_provided;
};
// A file handled returned for Tickets to be written into and subsequently installed.
@@ -1005,6 +1011,16 @@ public:
void ListTicketInfos(Kernel::HLERequestContext& ctx);
+ void GetNumCurrentContentInfos(Kernel::HLERequestContext& ctx);
+
+ void FindCurrentContentInfos(Kernel::HLERequestContext& ctx);
+
+ void ListCurrentContentInfos(Kernel::HLERequestContext& ctx);
+
+ void CalculateContextRequiredSize(Kernel::HLERequestContext& ctx);
+
+ void UpdateImportContentContexts(Kernel::HLERequestContext& ctx);
+
void ExportTicketWrapped(Kernel::HLERequestContext& ctx);
protected:
diff --git a/src/core/hle/service/am/am_net.cpp b/src/core/hle/service/am/am_net.cpp
index 4c39cf62b..1ed88ea8b 100644
--- a/src/core/hle/service/am/am_net.cpp
+++ b/src/core/hle/service/am/am_net.cpp
@@ -113,11 +113,11 @@ AM_NET::AM_NET(std::shared_ptr am) : Module::Interface(std::move(am), "a
{0x081F, &AM_NET::GetNumTicketsOfProgram, "GetNumTicketsOfProgram"},
{0x0820, &AM_NET::ListTicketInfos, "ListTicketInfos"},
{0x0821, nullptr, "GetRightsOnlyTicketData"},
- {0x0822, nullptr, "GetNumCurrentContentInfos"},
- {0x0823, nullptr, "FindCurrentContentInfos"},
- {0x0824, nullptr, "ListCurrentContentInfos"},
- {0x0825, nullptr, "CalculateContextRequiredSize"},
- {0x0826, nullptr, "UpdateImportContentContexts"},
+ {0x0822, &AM_NET::GetNumCurrentContentInfos, "GetNumCurrentContentInfos"},
+ {0x0823, &AM_NET::FindCurrentContentInfos, "FindCurrentContentInfos"},
+ {0x0824, &AM_NET::ListCurrentContentInfos, "ListCurrentContentInfos"},
+ {0x0825, &AM_NET::CalculateContextRequiredSize, "CalculateContextRequiredSize"},
+ {0x0826, &AM_NET::UpdateImportContentContexts, "UpdateImportContentContexts"},
{0x0827, nullptr, "DeleteAllDemoLaunchInfos"},
{0x0828, nullptr, "BeginImportTitleForOverWrite"},
{0x0829, &AM_NET::ExportTicketWrapped, "ExportTicketWrapped"},
diff --git a/src/core/hle/service/apt/applet_manager.cpp b/src/core/hle/service/apt/applet_manager.cpp
index 368d2b7ae..2d21f9ae8 100644
--- a/src/core/hle/service/apt/applet_manager.cpp
+++ b/src/core/hle/service/apt/applet_manager.cpp
@@ -1,4 +1,4 @@
-// Copyright 2018 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -573,9 +573,11 @@ Result AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) {
capture_buffer_info.reset();
if (Settings::values.lle_applets) {
+ bool is_setup = system.GetAppLoader().DoingInitialSetup();
auto cfg = Service::CFG::GetModule(system);
- auto process = NS::LaunchTitle(system, FS::MediaType::NAND,
- GetTitleIdForApplet(applet_id, cfg->GetRegionValue()));
+ auto process =
+ NS::LaunchTitle(system, FS::MediaType::NAND,
+ GetTitleIdForApplet(applet_id, cfg->GetRegionValue(is_setup)));
if (process) {
return ResultSuccess;
}
@@ -602,9 +604,11 @@ Result AppletManager::PreloadLibraryApplet(AppletId applet_id) {
last_prepared_library_applet = applet_id;
if (Settings::values.lle_applets) {
+ bool is_setup = system.GetAppLoader().DoingInitialSetup();
auto cfg = Service::CFG::GetModule(system);
- auto process = NS::LaunchTitle(system, FS::MediaType::NAND,
- GetTitleIdForApplet(applet_id, cfg->GetRegionValue()));
+ auto process =
+ NS::LaunchTitle(system, FS::MediaType::NAND,
+ GetTitleIdForApplet(applet_id, cfg->GetRegionValue(is_setup)));
if (process) {
return ResultSuccess;
}
@@ -814,9 +818,11 @@ Result AppletManager::StartSystemApplet(AppletId applet_id, std::shared_ptrregistered) {
+ bool is_setup = system.GetAppLoader().DoingInitialSetup();
auto cfg = Service::CFG::GetModule(system);
- auto process = NS::LaunchTitle(system, FS::MediaType::NAND,
- GetTitleIdForApplet(applet_id, cfg->GetRegionValue()));
+ auto process =
+ NS::LaunchTitle(system, FS::MediaType::NAND,
+ GetTitleIdForApplet(applet_id, cfg->GetRegionValue(is_setup)));
if (!process) {
// TODO: Find the right error code.
return {ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported,
@@ -1422,7 +1428,7 @@ void AppletManager::EnsureHomeMenuLoaded() {
}
auto cfg = Service::CFG::GetModule(system);
- auto menu_title_id = GetTitleIdForApplet(AppletId::HomeMenu, cfg->GetRegionValue());
+ auto menu_title_id = GetTitleIdForApplet(AppletId::HomeMenu, cfg->GetRegionValue(false));
auto process = NS::LaunchTitle(system, FS::MediaType::NAND, menu_title_id);
if (!process) {
LOG_WARNING(Service_APT,
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 39aa3f5df..002bd3728 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -196,7 +196,7 @@ static u32 DecompressLZ11(const u8* in, u8* out) {
bool Module::LoadSharedFont() {
auto cfg = Service::CFG::GetModule(system);
u8 font_region_code;
- switch (cfg->GetRegionValue()) {
+ switch (cfg->GetRegionValue(false)) {
case 4: // CHN
font_region_code = 2;
break;
@@ -229,10 +229,18 @@ bool Module::LoadSharedFont() {
const char16_t* file_name[4] = {u"cbf_std.bcfnt.lz", u"cbf_zh-Hans-CN.bcfnt.lz",
u"cbf_ko-Hang-KR.bcfnt.lz", u"cbf_zh-Hant-TW.bcfnt.lz"};
- const RomFS::RomFSFile font_file =
+ RomFS::RomFSFile font_file =
RomFS::GetFile(romfs_buffer.data(), {file_name[font_region_code - 1]});
- if (font_file.Data() == nullptr)
- return false;
+ if (font_file.Data() == nullptr) {
+ if (font_region_code != 1) {
+ font_file = RomFS::GetFile(romfs_buffer.data(), {file_name[0]});
+ if (font_file.Data() == nullptr) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
struct {
u32_le status;
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index f2d0ad770..4d04af017 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -12,6 +12,7 @@
#include
#include "common/archives.h"
#include "common/file_util.h"
+#include "common/hacks/hack_manager.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/string_util.h"
@@ -21,6 +22,7 @@
#include "core/file_sys/errors.h"
#include "core/file_sys/file_backend.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/result.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/cfg/cfg_defaults.h"
@@ -84,30 +86,227 @@ static constexpr u16 C(const char code[2]) {
}
static const std::array country_codes = {{
- 0, C("JP"), 0, 0, 0, 0, 0, 0, // 0-7
- C("AI"), C("AG"), C("AR"), C("AW"), C("BS"), C("BB"), C("BZ"), C("BO"), // 8-15
- C("BR"), C("VG"), C("CA"), C("KY"), C("CL"), C("CO"), C("CR"), C("DM"), // 16-23
- C("DO"), C("EC"), C("SV"), C("GF"), C("GD"), C("GP"), C("GT"), C("GY"), // 24-31
- C("HT"), C("HN"), C("JM"), C("MQ"), C("MX"), C("MS"), C("AN"), C("NI"), // 32-39
- C("PA"), C("PY"), C("PE"), C("KN"), C("LC"), C("VC"), C("SR"), C("TT"), // 40-47
- C("TC"), C("US"), C("UY"), C("VI"), C("VE"), 0, 0, 0, // 48-55
- 0, 0, 0, 0, 0, 0, 0, 0, // 56-63
- C("AL"), C("AU"), C("AT"), C("BE"), C("BA"), C("BW"), C("BG"), C("HR"), // 64-71
- C("CY"), C("CZ"), C("DK"), C("EE"), C("FI"), C("FR"), C("DE"), C("GR"), // 72-79
- C("HU"), C("IS"), C("IE"), C("IT"), C("LV"), C("LS"), C("LI"), C("LT"), // 80-87
- C("LU"), C("MK"), C("MT"), C("ME"), C("MZ"), C("NA"), C("NL"), C("NZ"), // 88-95
- C("NO"), C("PL"), C("PT"), C("RO"), C("RU"), C("RS"), C("SK"), C("SI"), // 96-103
- C("ZA"), C("ES"), C("SZ"), C("SE"), C("CH"), C("TR"), C("GB"), C("ZM"), // 104-111
- C("ZW"), C("AZ"), C("MR"), C("ML"), C("NE"), C("TD"), C("SD"), C("ER"), // 112-119
- C("DJ"), C("SO"), C("AD"), C("GI"), C("GG"), C("IM"), C("JE"), C("MC"), // 120-127
- C("TW"), 0, 0, 0, 0, 0, 0, 0, // 128-135
- C("KR"), 0, 0, 0, 0, 0, 0, 0, // 136-143
- C("HK"), C("MO"), 0, 0, 0, 0, 0, 0, // 144-151
- C("ID"), C("SG"), C("TH"), C("PH"), C("MY"), 0, 0, 0, // 152-159
- C("CN"), 0, 0, 0, 0, 0, 0, 0, // 160-167
- C("AE"), C("IN"), C("EG"), C("OM"), C("QA"), C("KW"), C("SA"), C("SY"), // 168-175
- C("BH"), C("JO"), 0, 0, 0, 0, 0, 0, // 176-183
- C("SM"), C("VA"), C("BM"), // 184-186
+ // 0-7 Japan
+ 0,
+ C("JP"),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ // 8-15 America
+ C("AI"),
+ C("AG"),
+ C("AR"),
+ C("AW"),
+ C("BS"),
+ C("BB"),
+ C("BZ"),
+ C("BO"),
+ // 16-23 America
+ C("BR"),
+ C("VG"),
+ C("CA"),
+ C("KY"),
+ C("CL"),
+ C("CO"),
+ C("CR"),
+ C("DM"),
+ // 24-31 America
+ C("DO"),
+ C("EC"),
+ C("SV"),
+ C("GF"),
+ C("GD"),
+ C("GP"),
+ C("GT"),
+ C("GY"),
+ // 32-39 America
+ C("HT"),
+ C("HN"),
+ C("JM"),
+ C("MQ"),
+ C("MX"),
+ C("MS"),
+ C("AN"),
+ C("NI"),
+ // 40-47 America
+ C("PA"),
+ C("PY"),
+ C("PE"),
+ C("KN"),
+ C("LC"),
+ C("VC"),
+ C("SR"),
+ C("TT"),
+ // 48-55 America
+ C("TC"),
+ C("US"),
+ C("UY"),
+ C("VI"),
+ C("VE"),
+ 0,
+ 0,
+ 0,
+
+ // 56-63 Invalid
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ // 64-71 Europe
+ C("AL"),
+ C("AU"),
+ C("AT"),
+ C("BE"),
+ C("BA"),
+ C("BW"),
+ C("BG"),
+ C("HR"),
+ // 72-79 Europe
+ C("CY"),
+ C("CZ"),
+ C("DK"),
+ C("EE"),
+ C("FI"),
+ C("FR"),
+ C("DE"),
+ C("GR"),
+ // 80-87 Europe
+ C("HU"),
+ C("IS"),
+ C("IE"),
+ C("IT"),
+ C("LV"),
+ C("LS"),
+ C("LI"),
+ C("LT"),
+ // 88-95 Europe
+ C("LU"),
+ C("MK"),
+ C("MT"),
+ C("ME"),
+ C("MZ"),
+ C("NA"),
+ C("NL"),
+ C("NZ"),
+ // 96-103 Europe
+ C("NO"),
+ C("PL"),
+ C("PT"),
+ C("RO"),
+ C("RU"),
+ C("RS"),
+ C("SK"),
+ C("SI"),
+ // 104-111 Europe
+ C("ZA"),
+ C("ES"),
+ C("SZ"),
+ C("SE"),
+ C("CH"),
+ C("TR"),
+ C("GB"),
+ C("ZM"),
+ // 112-119 Europe
+ C("ZW"),
+ C("AZ"),
+ C("MR"),
+ C("ML"),
+ C("NE"),
+ C("TD"),
+ C("SD"),
+ C("ER"),
+ // 120-127 Europe
+ C("DJ"),
+ C("SO"),
+ C("AD"),
+ C("GI"),
+ C("GG"),
+ C("IM"),
+ C("JE"),
+ C("MC"),
+
+ // 128-135 Taiwan
+ C("TW"),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ // 136-143 Korea
+ C("KR"),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ // 144-151 China? (Hong Kong & Macao)
+ C("HK"),
+ C("MO"),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ // 152-159 Southeast Asia
+ C("ID"),
+ C("SG"), // USA
+ C("TH"),
+ C("PH"),
+ C("MY"), // USA
+ 0,
+ 0,
+ 0,
+
+ // 160-167 China
+ C("CN"),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ // 168-175 Middle East
+ C("AE"), // USA
+ C("IN"), // EUR
+ C("EG"),
+ C("OM"),
+ C("QA"),
+ C("KW"),
+ C("SA"), // USA
+ C("SY"),
+ // 176-183 Middle East
+ C("BH"),
+ C("JO"),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ // 184-186 European Microstates
+ C("SM"),
+ C("VA"),
+ C("BM"),
}};
// Based on PKHeX's lists of subregions at
@@ -200,7 +399,14 @@ void Module::Interface::GetCountryCodeID(Kernel::HLERequestContext& ctx) {
rb.Push(country_code_id);
}
-u32 Module::GetRegionValue() {
+u32 Module::GetRegionValue(bool from_secure_info) {
+ if (from_secure_info) {
+ auto& sec_info = HW::UniqueData::GetSecureInfoA();
+ if (sec_info.IsValid()) {
+ return sec_info.body.region;
+ }
+ }
+
if (Settings::values.region_value.GetValue() == Settings::REGION_VALUE_AUTO_SELECT) {
UpdatePreferredRegionCode();
return preferred_region_code;
@@ -209,12 +415,39 @@ u32 Module::GetRegionValue() {
return Settings::values.region_value.GetValue();
}
+bool Module::IsValidRegionCountry(u32 region, u8 country_code) {
+ switch (region) {
+ case 0: // JPN
+ return country_code == 1;
+ case 1: // USA
+ return (country_code >= 8 && country_code <= 52) || country_code == 153 ||
+ country_code == 156 || country_code == 168 || country_code == 174;
+ case 2: // EUR
+ case 3: // AUS
+ return (country_code >= 64 && country_code <= 127) ||
+ (country_code >= 184 && country_code <= 186) || country_code == 169;
+ case 4: // CHN
+ return country_code == 144 || country_code == 145 || country_code == 160;
+ case 5: // KOR
+ return country_code == 136;
+ case 6: // TWN
+ return country_code == 128;
+ default:
+ break;
+ }
+ return false;
+}
+
void Module::Interface::GetRegion(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
+ u64 caller_tid = ctx.ClientThread()->owner_process.lock()->codeset->program_id;
+ bool from_secure_info = Common::Hacks::hack_manager.OverrideBooleanSetting(
+ Common::Hacks::HackType::REGION_FROM_SECURE, caller_tid, false);
+
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(ResultSuccess);
- rb.Push(static_cast(cfg->GetRegionValue()));
+ rb.Push(static_cast(cfg->GetRegionValue(from_secure_info)));
}
void Module::Interface::SecureInfoGetByte101(Kernel::HLERequestContext& ctx) {
@@ -319,8 +552,12 @@ void Module::Interface::IsCoppacsSupported(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
+ u64 caller_tid = ctx.ClientThread()->owner_process.lock()->codeset->program_id;
+ bool from_secure_info = Common::Hacks::hack_manager.OverrideBooleanSetting(
+ Common::Hacks::HackType::REGION_FROM_SECURE, caller_tid, false);
+
u8 canada_or_usa = 1;
- if (canada_or_usa == cfg->GetRegionValue()) {
+ if (canada_or_usa == cfg->GetRegionValue(from_secure_info)) {
rb.Push(true);
} else {
rb.Push(false);
diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h
index 32b1dd40c..7536680c0 100644
--- a/src/core/hle/service/cfg/cfg.h
+++ b/src/core/hle/service/cfg/cfg.h
@@ -484,7 +484,9 @@ private:
void LoadMCUConfig();
public:
- u32 GetRegionValue();
+ u32 GetRegionValue(bool from_secure_info);
+
+ static bool IsValidRegionCountry(u32 region, u8 country_code);
// Utilities for frontend to set config data.
// Note: UpdateConfigNANDSavegame should be called after making changes to config data.
diff --git a/src/core/hle/service/fs/file.cpp b/src/core/hle/service/fs/file.cpp
index 21834b20d..7ba13f935 100644
--- a/src/core/hle/service/fs/file.cpp
+++ b/src/core/hle/service/fs/file.cpp
@@ -1,4 +1,4 @@
-// Copyright 2018 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -79,13 +79,13 @@ void File::Read(Kernel::HLERequestContext& ctx) {
if (!backend->AllowsCachedReads()) {
auto& buffer = rp.PopMappedBuffer();
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
- std::unique_ptr data = std::make_unique(static_cast(operator new(length)));
- const auto read = backend->Read(offset, length, *data);
+ std::unique_ptr data = std::make_unique_for_overwrite(length);
+ const auto read = backend->Read(offset, length, data.get());
if (read.Failed()) {
rb.Push(read.Code());
rb.Push(0);
} else {
- buffer.Write(*data, 0, *read);
+ buffer.Write(data.get(), 0, *read);
rb.Push(ResultSuccess);
rb.Push(static_cast(*read));
}
@@ -106,7 +106,7 @@ void File::Read(Kernel::HLERequestContext& ctx) {
// Output
Result ret{0};
Kernel::MappedBuffer* buffer;
- std::unique_ptr data;
+ std::unique_ptr data;
std::size_t read_size;
};
@@ -122,10 +122,9 @@ void File::Read(Kernel::HLERequestContext& ctx) {
// LOG_DEBUG(Service_FS, "cache={}, offset={}, length={}", cache_ready, offset, length);
ctx.RunAsync(
[this, async_data](Kernel::HLERequestContext& ctx) {
- async_data->data =
- std::make_unique(static_cast(operator new(async_data->length)));
+ async_data->data = std::make_unique_for_overwrite(async_data->length);
const auto read =
- backend->Read(async_data->offset, async_data->length, *async_data->data);
+ backend->Read(async_data->offset, async_data->length, async_data->data.get());
if (read.Failed()) {
async_data->ret = read.Code();
async_data->read_size = 0;
@@ -156,7 +155,7 @@ void File::Read(Kernel::HLERequestContext& ctx) {
rb.Push(async_data->ret);
rb.Push(0);
} else {
- async_data->buffer->Write(*async_data->data, 0, async_data->read_size);
+ async_data->buffer->Write(async_data->data.get(), 0, async_data->read_size);
rb.Push(ResultSuccess);
rb.Push(static_cast(async_data->read_size));
}
@@ -170,6 +169,7 @@ void File::Write(Kernel::HLERequestContext& ctx) {
u64 offset = rp.Pop();
u32 length = rp.Pop();
u32 flags = rp.Pop();
+ auto& buffer = rp.PopMappedBuffer();
LOG_TRACE(Service_FS, "Write {}: offset=0x{:x} length={}, flags=0x{:x}", GetName(), offset,
length, flags);
@@ -181,14 +181,13 @@ void File::Write(Kernel::HLERequestContext& ctx) {
if (file->subfile) {
rb.Push(FileSys::ResultUnsupportedOpenFlags);
rb.Push(0);
- rb.PushMappedBuffer(rp.PopMappedBuffer());
+ rb.PushMappedBuffer(buffer);
return;
}
bool flush = (flags & 0xFF) != 0, update_timestamp = (flags & 0xFF00) != 0;
if (!backend->AllowsCachedReads()) {
std::vector data(length);
- auto& buffer = rp.PopMappedBuffer();
buffer.Read(data.data(), 0, data.size());
ResultVal written =
backend->Write(offset, data.size(), flush, update_timestamp, data.data());
@@ -224,7 +223,7 @@ void File::Write(Kernel::HLERequestContext& ctx) {
async_data->offset = offset;
async_data->flush = flush;
async_data->update_timestamp = update_timestamp;
- async_data->buffer = &rp.PopMappedBuffer();
+ async_data->buffer = &buffer;
async_data->file = file;
ctx.RunAsync(
diff --git a/src/core/hle/service/gsp/gsp_gpu.cpp b/src/core/hle/service/gsp/gsp_gpu.cpp
index 8f07c22e6..6887de663 100644
--- a/src/core/hle/service/gsp/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp/gsp_gpu.cpp
@@ -21,6 +21,7 @@
#include "video_core/gpu.h"
#include "video_core/gpu_debugger.h"
#include "video_core/pica/regs_lcd.h"
+#include "video_core/renderer_base.h"
#include "video_core/right_eye_disabler.h"
SERIALIZE_EXPORT_IMPL(Service::GSP::SessionData)
@@ -613,6 +614,8 @@ Result GSP_GPU::AcquireGpuRight(const Kernel::HLERequestContext& ctx,
ErrorLevel::Success};
}
+ gpu.Renderer().Rasterizer()->SwitchDiskResources(process->codeset->program_id);
+
if (blocking) {
// TODO: The thread should be put to sleep until acquired.
ASSERT_MSG(active_thread_id == std::numeric_limits::max(),
diff --git a/src/core/hw/unique_data.cpp b/src/core/hw/unique_data.cpp
index 3f11da2a7..8d7ac9035 100644
--- a/src/core/hw/unique_data.cpp
+++ b/src/core/hw/unique_data.cpp
@@ -5,6 +5,7 @@
#include
#include "common/common_paths.h"
#include "common/logging/log.h"
+#include "core/file_sys/archive_systemsavedata.h"
#include "core/file_sys/certificate.h"
#include "core/file_sys/otp.h"
#include "core/hw/aes/key.h"
@@ -17,6 +18,7 @@ namespace HW::UniqueData {
static SecureInfoA secure_info_a;
static bool secure_info_a_signature_valid = false;
+static bool secure_info_a_region_changed = false;
static LocalFriendCodeSeedB local_friend_code_seed_b;
static bool local_friend_code_seed_b_signature_valid = false;
static FileSys::OTP otp;
@@ -40,8 +42,10 @@ bool MovableSed::VerifySignature() const {
SecureDataLoadStatus LoadSecureInfoA() {
if (secure_info_a.IsValid()) {
- return secure_info_a_signature_valid ? SecureDataLoadStatus::Loaded
- : SecureDataLoadStatus::InvalidSignature;
+ return secure_info_a_signature_valid
+ ? SecureDataLoadStatus::Loaded
+ : (secure_info_a_region_changed ? SecureDataLoadStatus::RegionChanged
+ : SecureDataLoadStatus::InvalidSignature);
}
std::string file_path = GetSecureInfoAPath();
if (!FileUtil::Exists(file_path)) {
@@ -60,13 +64,31 @@ SecureDataLoadStatus LoadSecureInfoA() {
}
HW::AES::InitKeys();
+ secure_info_a_region_changed = false;
secure_info_a_signature_valid = secure_info_a.VerifySignature();
if (!secure_info_a_signature_valid) {
- LOG_WARNING(HW, "SecureInfo_A signature check failed");
+ // Check if the file has been region changed
+ SecureInfoA copy = secure_info_a;
+ for (u8 orig_reg = 0; orig_reg < Region::COUNT; orig_reg++) {
+ if (orig_reg == secure_info_a.body.region) {
+ continue;
+ }
+ copy.body.region = orig_reg;
+ if (copy.VerifySignature()) {
+ secure_info_a_region_changed = true;
+ LOG_WARNING(HW, "SecureInfo_A is region changed and its signature invalid");
+ break;
+ }
+ }
+ if (!secure_info_a_region_changed) {
+ LOG_WARNING(HW, "SecureInfo_A signature check failed");
+ }
}
- return secure_info_a_signature_valid ? SecureDataLoadStatus::Loaded
- : SecureDataLoadStatus::InvalidSignature;
+ return secure_info_a_signature_valid
+ ? SecureDataLoadStatus::Loaded
+ : (secure_info_a_region_changed ? SecureDataLoadStatus::RegionChanged
+ : SecureDataLoadStatus::InvalidSignature);
}
SecureDataLoadStatus LoadLocalFriendCodeSeedB() {
@@ -262,4 +284,30 @@ std::unique_ptr OpenUniqueCryptoFile(const std::string& filena
return std::make_unique(filename, openmode, key, ctr, flags);
}
+bool IsFullConsoleLinked() {
+ return GetOTP().Valid() && GetSecureInfoA().IsValid() && GetLocalFriendCodeSeedB().IsValid();
+}
+
+void UnlinkConsole() {
+ // Remove all console unique data, as well as the act, nim and frd savefiles
+ const std::string system_save_data_path =
+ FileSys::GetSystemSaveDataContainerPath(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
+ constexpr std::array, 3> save_data_ids{{
+ {0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x01, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x01, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x01, 0x00},
+ }};
+
+ for (auto& id : save_data_ids) {
+ const std::string final_path = FileSys::GetSystemSaveDataPath(system_save_data_path, id);
+ FileUtil::DeleteDirRecursively(final_path, 2);
+ }
+
+ FileUtil::Delete(GetOTPPath());
+ FileUtil::Delete(GetSecureInfoAPath());
+ FileUtil::Delete(GetLocalFriendCodeSeedBPath());
+
+ InvalidateSecureData();
+}
+
} // namespace HW::UniqueData
diff --git a/src/core/hw/unique_data.h b/src/core/hw/unique_data.h
index 294484ffa..dd3a4bb8b 100644
--- a/src/core/hw/unique_data.h
+++ b/src/core/hw/unique_data.h
@@ -17,6 +17,19 @@ class OTP;
namespace HW::UniqueData {
+struct Region {
+ enum : u8 {
+ JPN,
+ USA,
+ EUR,
+ AUS,
+ CHN,
+ KOR,
+ TWN,
+ };
+ static constexpr u8 COUNT = TWN + 1;
+};
+
struct SecureInfoA {
std::array signature;
struct {
@@ -122,6 +135,7 @@ static_assert(sizeof(MovableSedFull) == 0x140);
enum class SecureDataLoadStatus {
Loaded = 0,
InvalidSignature = 1,
+ RegionChanged = 2,
NotFound = -1,
Invalid = -2,
@@ -154,4 +168,7 @@ void InvalidateSecureData();
std::unique_ptr OpenUniqueCryptoFile(const std::string& filename,
const char openmode[], UniqueCryptoFileID id,
int flags = 0);
+
+bool IsFullConsoleLinked();
+void UnlinkConsole();
} // namespace HW::UniqueData
\ No newline at end of file
diff --git a/src/core/loader/artic.cpp b/src/core/loader/artic.cpp
index 5f4bb28f9..9d8aa240c 100644
--- a/src/core/loader/artic.cpp
+++ b/src/core/loader/artic.cpp
@@ -342,7 +342,8 @@ void Apploader_Artic::EnsureClientConnected() {
if (is_initial_setup) {
// Ensure we are running the initial setup app in the correct version
- auto req = client->NewRequest("System_IsAzaharInitialSetup");
+ auto req = client->NewRequest("System_ArticSetupVersion");
+ req.AddParameterU32(SETUP_TOOL_VERSION);
auto resp = client->Send(req);
if (!resp.has_value()) {
client_connected = false;
@@ -355,7 +356,15 @@ void Apploader_Artic::EnsureClientConnected() {
return;
}
- client_connected = *reinterpret_cast(ret_buf->first) == INITIAL_SETUP_APP_VERSION;
+ if (*reinterpret_cast(ret_buf->first) != SETUP_TOOL_VERSION) {
+ system.SetStatus(Core::System::ResultStatus::ErrorArticDisconnected,
+ "\nIncompatible Artic Setup Tool version.\nCheck for Artic Setup Tool "
+ "or Azahar updates.");
+ client_connected = false;
+ client->Stop();
+ } else {
+ client_connected = true;
+ }
}
}
@@ -385,6 +394,21 @@ ResultStatus Apploader_Artic::Load(std::shared_ptr& process) {
if (is_initial_setup) {
+ // If there is already a console linked, check it's the same device.
+ // Otherwise it could cause weird issues with account save data.
+ if (HW::UniqueData::IsFullConsoleLinked()) {
+ auto req = client->NewRequest("System_ReportDeviceID");
+ req.AddParameterU32(HW::UniqueData::GetOTP().GetDeviceID());
+
+ auto resp = client->Send(req);
+ if (!resp.has_value() || !resp->Succeeded())
+ return ResultStatus::ErrorArtic;
+
+ if (resp->GetMethodResult() != 0)
+ return ResultStatus::ErrorArtic;
+ }
+
+ auto cfg = system.ServiceManager().GetService("cfg:u");
// Request console unique data
for (int i = 0; i < 6; i++) {
std::string path;
@@ -448,7 +472,6 @@ ResultStatus Apploader_Artic::Load(std::shared_ptr& process) {
memcpy(&console_id, resp_buff->first, sizeof(u64));
memcpy(&random_id, reinterpret_cast(resp_buff->first) + sizeof(u64),
sizeof(u32));
- auto cfg = system.ServiceManager().GetService("cfg:u");
if (cfg.get()) {
auto cfg_module = cfg->GetModule();
cfg_module->SetConsoleUniqueId(random_id, console_id);
@@ -457,7 +480,6 @@ ResultStatus Apploader_Artic::Load(std::shared_ptr& process) {
} else if (i == 5) {
std::array mac;
memcpy(mac.data(), resp_buff->first, mac.size());
- auto cfg = system.ServiceManager().GetService("cfg:u");
if (cfg.get()) {
auto cfg_module = cfg->GetModule();
cfg_module->GetMacAddress() = Service::CFG::MacToString(mac);
@@ -471,10 +493,25 @@ ResultStatus Apploader_Artic::Load(std::shared_ptr& process) {
if (!HW::UniqueData::GetCTCert().IsValid() || !HW::UniqueData::GetMovableSed().IsValid() ||
!HW::UniqueData::GetSecureInfoA().IsValid() ||
!HW::UniqueData::GetLocalFriendCodeSeedB().IsValid()) {
- LOG_CRITICAL(Loader, "Some console unique data is invalid, aborting...");
+ client->LogOnServer(Network::ArticBaseCommon::LogOnServerType::LOG_ERROR,
+ "Some console unique data is invalid.\n Aborting...");
return ResultStatus::ErrorArtic;
}
+ if (cfg.get()) {
+ auto cfg_module = cfg->GetModule();
+ if (!Service::CFG::Module::IsValidRegionCountry(cfg_module->GetRegionValue(true),
+ cfg_module->GetCountryCode())) {
+ // Report mismatch to server.
+ client->LogOnServer(
+ Network::ArticBaseCommon::LogOnServerType::LOG_ERROR,
+ "The country configuration does not match\n the console region. "
+ "Please select a valid\n country from the emulation settings.");
+ return ResultStatus::ErrorArtic;
+ }
+ cfg_module->SetSystemSetupNeeded(false);
+ }
+
// Set deliver arg so that System Settings goes to the update screen directly
auto apt = Service::APT::GetModule(system);
Service::APT::DeliverArg arg;
diff --git a/src/core/loader/artic.h b/src/core/loader/artic.h
index d102babcc..18ba31d87 100644
--- a/src/core/loader/artic.h
+++ b/src/core/loader/artic.h
@@ -93,7 +93,7 @@ public:
}
private:
- static constexpr u32 INITIAL_SETUP_APP_VERSION = 0;
+ static constexpr u32 SETUP_TOOL_VERSION = 2;
/**
* Loads .code section into memory for booting
* @param process The newly created process
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index a2ce7327e..9ecf64685 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -32,7 +32,7 @@
namespace Loader {
using namespace Common::Literals;
-static const u64 UPDATE_MASK = 0x0000000e00000000;
+static constexpr u64 UPDATE_TID_HIGH = 0x0004000e00000000;
FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
u32 magic;
@@ -283,8 +283,9 @@ ResultStatus AppLoader_NCCH::Load(std::shared_ptr& process) {
LOG_INFO(Loader, "Program ID: {}", program_id);
- update_ncch.OpenFile(Service::AM::GetTitleContentPath(Service::FS::MediaType::SDMC,
- ncch_program_id | UPDATE_MASK));
+ u64 update_tid = (ncch_program_id & 0xFFFFFFFFULL) | UPDATE_TID_HIGH;
+ update_ncch.OpenFile(
+ Service::AM::GetTitleContentPath(Service::FS::MediaType::SDMC, update_tid));
result = update_ncch.Load();
if (result == ResultStatus::Success) {
overlay_ncch = &update_ncch;
@@ -371,8 +372,9 @@ ResultStatus AppLoader_NCCH::DumpRomFS(const std::string& target_path) {
ResultStatus AppLoader_NCCH::DumpUpdateRomFS(const std::string& target_path) {
u64 program_id;
ReadProgramId(program_id);
+ u64 update_tid = (program_id & 0xFFFFFFFFULL) | UPDATE_TID_HIGH;
update_ncch.OpenFile(
- Service::AM::GetTitleContentPath(Service::FS::MediaType::SDMC, program_id | UPDATE_MASK));
+ Service::AM::GetTitleContentPath(Service::FS::MediaType::SDMC, update_tid));
return update_ncch.DumpRomFS(target_path);
}
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index ab4eff6aa..c49aa2704 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -1,4 +1,4 @@
-// Copyright 2015 Citra Emulator Project
+// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -448,8 +448,8 @@ void MemorySystem::UnregisterPageTable(std::shared_ptr