diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..35cd7d21c9 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +liberapay: crueter +custom: 'https://www.paypal.biz/edenemulator' \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 422efb5fdc..89df0b40fe 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,8 @@ - [ ] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions). -- [ ] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md). - [ ] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability. +- [ ] I have read and followed the [website policy](https://git.eden-emu.dev/eden-emu/site-policy). +- [ ] I affirm that the content of this pull request body was written and submitted entirely by me, in my own words, and not by an AI agent or LLM. +- [ ] I affirm that I did not read any of this, and understand that my pull request will be closed if I check this box. +- [ ] I affirm that, by submitting this pull request, I am responsible for all of the changes contained within these commits. ------------------- diff --git a/.gitignore b/.gitignore index 20ed5e93c1..873b99bec2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ # Build directory /[Bb]uild*/ doc-build/ +out/ AppDir/ uruntime diff --git a/.patch/openssl-cmake/0005-cross-compile.patch b/.patch/openssl-cmake/0005-cross-compile.patch new file mode 100644 index 0000000000..31eafac9ad --- /dev/null +++ b/.patch/openssl-cmake/0005-cross-compile.patch @@ -0,0 +1,40 @@ +diff --git a/cmake/ConfigureOpenSSL.cmake b/cmake/ConfigureOpenSSL.cmake +index 3012e05..2ae23ff 100644 +--- a/cmake/ConfigureOpenSSL.cmake ++++ b/cmake/ConfigureOpenSSL.cmake +@@ -108,7 +108,8 @@ function(configure_openssl) + ) + + if(NOT "${CONFIGURE_OPTIONS_OLD}" STREQUAL "") +- if(CONFIGURE_OPTIONS STREQUAL CONFIGURE_OPTIONS_OLD) ++ # TODO(lizzie): Emscripten has issues with rebuilding due to the wrapper it uses ++ if(CMAKE_SYSTEM_NAME MATCHES "Emscripten" OR CONFIGURE_OPTIONS STREQUAL CONFIGURE_OPTIONS_OLD) + message(STATUS "Found previous configure results. Don't perform configuration") + return() + endif() +@@ -134,10 +135,24 @@ function(configure_openssl) + set(VERBOSE_OPTION OUTPUT_QUIET) + endif() + ++ if (CMAKE_SYSTEM_NAME MATCHES "Emscripten") ++ set(EMSCRIPTEN_CMAKE_WRAPPER "emcmake") ++ find_program(EMCC emcc REQUIRED) ++ set(EMSCRIPTEN_LINKER ${EMCC}) ++ list(APPEND CONFIGURE_COMMAND wasm64) ++ else() ++ set(EMSCRIPTEN_CMAKE_WRAPPER "") ++ set(EMSCRIPTEN_LINKER ${CMAKE_LINKER}) ++ endif () ++ + execute_process( +- COMMAND ${CMAKE_COMMAND} -E env ++ COMMAND ${EMSCRIPTEN_CMAKE_WRAPPER} ${CMAKE_COMMAND} -E env + "CFLAGS=${CMAKE_C_FLAGS}" + "CXXFLAGS=${CMAKE_CXX_FLAGS}" ++ "LDFLAGS=${CMAKE_CXX_LINK_FLAGS}" ++ "CC=${CMAKE_C_COMPILER}" ++ "CXX=${CMAKE_CXX_COMPILER}" ++ "LD=${EMSCRIPTEN_LINKER}" + ${CONFIGURE_COMMAND} + WORKING_DIRECTORY ${CONFIGURE_BUILD_DIR} + ${VERBOSE_OPTION} diff --git a/AGENTS.md b/AGENTS.md index 05ab7f1160..69d39fb5bb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,10 @@ # AGENTS -Read and follow the AI policy found in `docs/policies/AI.md`, and the coding policies found in `docs/policies/Coding.md`. +Read and follow the [contribution guidelines](./CONTRIBUTING.md) and our [site policy](https://git.eden-emu.dev/eden-emu/site-policy/src/branch/master).. -Do not, under any circumstances, ever submit PRs or push commits on behalf of the user. +Do not, under any circumstances, ever: + +- Submit PRs, push commits, or request any API calls on behalf of the user. +- Write commit messages, PR descriptions, or issues on behalf of the user. Keep comments to a reasonable level. Do not overexplain or add/remove comments from unrelated parts of the codebase. diff --git a/CMakeLists.txt b/CMakeLists.txt index f647204a4b..61c52c2648 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,9 @@ if (YUZU_STATIC_BUILD) set(fmt_FORCE_BUNDLED ON) set(SPIRV-Headers_FORCE_BUNDLED ON) set(zstd_FORCE_BUNDLED ON) + + # broken, idk why + set(lz4_FORCE_BUNDLED ON) endif() endif() @@ -594,7 +597,7 @@ if (ENABLE_QT) list(APPEND CMAKE_PREFIX_PATH "${Qt6_DIR}") endif() - find_package(Qt6 REQUIRED COMPONENTS Core) + find_package(Qt6 6.5 REQUIRED COMPONENTS Core) if (NOT DEFINED QT_TARGET_PATH) get_target_property(qtcore_path Qt6::Core LOCATION_Release) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8c16de9ddb..d811006e05 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,17 +16,38 @@ Eden is free, open-source, copyleft software, licensed under the terms of the [G ### Policies -- We are trialing a slightly relaxed AI policy to allow high-quality contributors to use AI *responsibly*. Please read our [detailed AI policy](docs/policies/AI.md) for more info. -- Usage of any form of profanity or otherwise unsavory language is generally discouraged. - - This is primarily because it rarely helps to actually understand what's going on. - - Remember that your comments should be focused and actually address what's happening. With very few exceptions, expletives are actively detrimental at best. -- New code must follow the same general style as the surrounding codebase. Exceptions may be granted in certain cases. +- AI usage is allowed, but we reserve the right to close and rework your PR if you don't fully understand the changes you're making. Additionally: + - As a common courtesy, please disclose your AI usage under the PR description, as `Assisted-by: ()`. + - All PR descriptions, issue bodies, and comments **must** be written by you, in your own words. + - AI-written comments/descriptions/bodies are not only difficult for us to read, they also indicate to us that you did not put in the effort to actually understand your changes. These will be closed, deleted, or hidden without warning. + - Spamming of low-effort AI-generated pull requests or issues is considered a [Human Effort Denial of Service](https://tiangolo.com/open-source/contributing/#human-effort-denial-of-service), and will result in the immediate suspension of your Forgejo account, or you getting blocked from the organization on other platforms. +- Usage of any form of profanity or otherwise unsavory language is discouraged but not strictly disallowed. +- New code must follow the same style as the surrounding codebase. Exceptions may be granted in certain cases. - Maintainers reserve the right to change your patches and pull requests at will. We will try to avoid this. - You should generally respect all decisions made by the [code owners](docs/CODEOWNERS) in your particular subsystem. - However, if you feel they are overstepping or are incorrect, don't be afraid to stand your ground! Maintainers are not always correct. -- While we do *not* adhere to the terms of a formal code of conduct, you will generally be expected to respect other developers, contributors, and community members. +- While we do *not* adhere to the terms of a formal code of conduct, you are expected to treat other developers, contributors, and community members respectfully. - You **must** have basic knowledge of [Git](https://git-scm.com/learn). Knowing how to manage your branches and follow proper fork policies is a necessity. +### Pull Requests + +Pull requests are only to be merged by core developers when properly tested and discussions conclude on Discord or other communication channels. Labels are recommended but not required. However, all PRs MUST be namespaced and optionally typed: + +```txt +[cmake] refactor: CPM over submodules +[desktop] feat: implement firmware install from ZIP +[hle] stub fw20 functions +[core] test: raise maximum CPU cores to 6 +[cmake, core] Unbreak FreeBSD Building Process +``` + +- The level of namespacing is generally left to the committer's choice. +- However, we never recommend going more than two levels *except* in `hle`, in which case you may go as many as four levels depending on the specificity of your changes. +- Ocassionally, up to two additional namespaces may be provided for more clarity. + - Changes that affect the entire project (sans CMake changes) should be namespaced as `meta`. +- Maintainers are permitted to change namespaces at will. +- Commits within PRs are not required to be namespaced, but it is highly recommended. + ### Where do I start? Anywhere you like! If you are facing an issue and want to fix it, go ahead. For new features, you are heavily encouraged to open a feature request on GitHub, Codeberg, or Forgejo first, discussing the motivations, potential implementation, and user flow of your desired feature. Our UI/UX designers will work with you to refine your feature before you actually choose to implement it. @@ -38,7 +59,10 @@ You may also search for open issues on [GitHub](https://github.com/eden-emulator There are five primary ways to contribute. - Submit pull requests directly to our source tree - - You must first request an account on our Forgejo. See [Signup](#how-do-i-sign-up) + - You must first [create an account](https://git.eden-emu.dev/user/sign_up). + - You may use an internal account, or you may use a GitHub/Codeberg account linked to our instance. + - Please make sure to read our [site policy](https://git.eden-emu.dev/eden-emu/site-policy/src/branch/master). + - Both your account and your associated fork must be public, *not* limited/private, otherwise our CI workflow will not work on your pull requests. - Submit pull requests to our [GitHub mirror](https://github.com/eden-emulator/Issue-Reports) - Note that this is subject to being removed by DMCA, so don't rely on this. - Submit pull requests to our [Codeberg mirror](https://codeberg.org/eden-emu/eden) @@ -48,33 +72,10 @@ There are five primary ways to contribute. - Alongside the contents of your email, please attach the patch/diff file itself for easy access and use. - Email our developers at [`developers@eden-emu.dev`](mailto:developers@eden-emu.dev) with any of your relevant findings or code changes. -To test your changes, ensure to read the [build documentation](./docs/Build.md) for your specific platform(s) to ensure everything compiles and works properly. You should also make sure that your branch is up-to-date with the upstream `master` branch before opening a pull request. - -### How do I sign up? - -
-To sign up and begin contributing... (click to open) - -Email [crueter@crueter.xyz](mailto:crueter@crueter.xyz) with the following format: - -```txt -Subject: [Eden Git] Registration Request -Username: -Email: -I wish to sign up because... -``` - -Received mail that does not follow this format will be ignored. - -Once your request is processed, you will receive a confirmation email with your temporary password and some information on Git access and policies. If you do not receive a response within 48 hours, feel free to send another email. - -> [!WARNING] -> Some email providers may place the response email in your spam/junk folder; notable offenders include Gmail and Outlook. *Always* ensure to check your Spam or Junk folder. - -
+To test your changes, ensure to read the [build documentation](./docs/Build.md) for your specific platform(s) to ensure everything compiles and works properly. You should also make sure that your branch is up-to-date with the upstream `master` branch before opening a pull request. **You** are responsible for ensuring that your contribution does what it says and doesn't break everything else horribly. ## Non-code Contributions Alongside the other contribution methods listed up top, you can also choose to contribute through documentation, organization, or community guides. These can be done either through the code contribution methods described above, or created externally and shared via our Discord community. -If you have an external tool/page that you believe would be handy to integrate/link into Eden, please additionally email our developers at [`developers@eden-emu.dev`](mailto:developers@eden-emu.dev). **Do not submit vibe-coded or AI generated tools or applications**. +If you have an external tool/page that you believe would be handy to integrate/link into Eden, please additionally email our developers at [`developers@eden-emu.dev`](mailto:developers@eden-emu.dev). diff --git a/README.md b/README.md index 7d3fe5572e..31dacb6e2a 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Written in C++, with builds for Windows, Linux, macOS, Android, FreeBSD and more

Compatibility | - Development | + Contribute | Building | Download | Support | diff --git a/cpmfile.json b/cpmfile.json index 9cac812b7a..4d7cb789f0 100644 --- a/cpmfile.json +++ b/cpmfile.json @@ -202,7 +202,8 @@ "0001-cpmutil-compat.patch", "0002-use-ccache.patch", "0003-use-cmake-compiler-flags.patch", - "0004-use-shell-wrapper.patch" + "0004-use-shell-wrapper.patch", + "0005-cross-compile.patch" ], "repo": "jimmy-park/openssl-cmake", "version": "3.6.2" @@ -351,13 +352,13 @@ }, "zstd": { "find_args": "MODULE", - "hash": "cc5ad4b119a9c2ea57f0b71eeff01113bb506e0d17000159c5409cb8236d22e38c52d5e9e97e7947a4bf1b2dfc44b6c503ab2d9aedbd59458435c6a2849cb029", + "hash": "2b006c3c110c38bd2f5896b42d36a38931c8eae261f30552f9a9fd04458d218d8f1a1425f117fd12af545ed77042e4b2d1a1a9b6286c4d0b9d74ef79f20a8f08", "min_version": "1.5", "options": [ "ZSTD_BUILD_SHARED OFF" ], "repo": "facebook/zstd", "source_subdir": "build/cmake", - "version": "b8d6101fba" + "version": "33618c8" } } diff --git a/dist/dev.eden_emu.eden.svg b/dist/dev.eden_emu.eden.svg index f88b52f625..0c84560260 100644 --- a/dist/dev.eden_emu.eden.svg +++ b/dist/dev.eden_emu.eden.svg @@ -1,230 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/dist/eden.icon/Assets/dev.eden_emu.eden.svg b/dist/eden.icon/Assets/dev.eden_emu.eden.svg index f88b52f625..0c84560260 100644 --- a/dist/eden.icon/Assets/dev.eden_emu.eden.svg +++ b/dist/eden.icon/Assets/dev.eden_emu.eden.svg @@ -1,230 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/dist/icon_variations/1an.svg b/dist/icon_variations/1an.svg index df206b43af..90b0498d48 100644 --- a/dist/icon_variations/1an.svg +++ b/dist/icon_variations/1an.svg @@ -1,289 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/dist/icon_variations/2025.svg b/dist/icon_variations/2025.svg index 96e7afc800..22549b4356 100644 --- a/dist/icon_variations/2025.svg +++ b/dist/icon_variations/2025.svg @@ -1,144 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/dist/icon_variations/aprilfools2026.svg b/dist/icon_variations/aprilfools2026.svg index 7711945aa4..db9c475145 100644 --- a/dist/icon_variations/aprilfools2026.svg +++ b/dist/icon_variations/aprilfools2026.svg @@ -1,89 +1 @@ - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/dist/icon_variations/base.svg b/dist/icon_variations/base.svg index f88b52f625..0c84560260 100644 --- a/dist/icon_variations/base.svg +++ b/dist/icon_variations/base.svg @@ -1,230 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/dist/icon_variations/halloween2025.svg b/dist/icon_variations/halloween2025.svg index da683396bc..66202eb10c 100644 --- a/dist/icon_variations/halloween2025.svg +++ b/dist/icon_variations/halloween2025.svg @@ -1,106 +1 @@ - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/dist/icon_variations/newyear2025.svg b/dist/icon_variations/newyear2025.svg index 5448c488e0..4f09259de4 100644 --- a/dist/icon_variations/newyear2025.svg +++ b/dist/icon_variations/newyear2025.svg @@ -1,672 +1 @@ - - - - - - New Year 2025 Logo - - - Madeline_Dev - mailto:madelvidel@gmail.com - - - 2025 - - 2025 Eden Emulator Project - https://git.eden-emu.dev - - - - + \ No newline at end of file diff --git a/dist/icon_variations/original_small.svg b/dist/icon_variations/original_small.svg index 41db18afc1..b3486a9e81 100644 --- a/dist/icon_variations/original_small.svg +++ b/dist/icon_variations/original_small.svg @@ -1,80 +1 @@ - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/dist/icon_variations/saintpatrick2026.svg b/dist/icon_variations/saintpatrick2026.svg index b125f4fb80..2aa36794fd 100644 --- a/dist/icon_variations/saintpatrick2026.svg +++ b/dist/icon_variations/saintpatrick2026.svg @@ -1,196 +1 @@ - - - - - - - - - Madeline_Dev - mailto:madelvidel@gmail.com - - - 2025 - - 2025 Eden Emulator Project - https://git.eden-emu.dev - - - - + \ No newline at end of file diff --git a/dist/icon_variations/valentines2026.svg b/dist/icon_variations/valentines2026.svg index 7a68ed3e67..c7382d4f2e 100644 --- a/dist/icon_variations/valentines2026.svg +++ b/dist/icon_variations/valentines2026.svg @@ -1,211 +1 @@ - - - - - - - - - Madeline_Dev - mailto:madelvidel@gmail.com - - - 2025 - - 2025 Eden Emulator Project - https://git.eden-emu.dev - - - - + \ No newline at end of file diff --git a/dist/icons/controller/applet_dual_joycon_dark_disabled.png b/dist/icons/controller/applet_dual_joycon_dark_disabled.png index a4d38b633d..c60efbbcde 100644 Binary files a/dist/icons/controller/applet_dual_joycon_dark_disabled.png and b/dist/icons/controller/applet_dual_joycon_dark_disabled.png differ diff --git a/dist/icons/controller/applet_dual_joycon_midnight_disabled.png b/dist/icons/controller/applet_dual_joycon_midnight_disabled.png index ac5cf51179..1549849857 100644 Binary files a/dist/icons/controller/applet_dual_joycon_midnight_disabled.png and b/dist/icons/controller/applet_dual_joycon_midnight_disabled.png differ diff --git a/dist/icons/controller/applet_single_joycon_right_midnight.png b/dist/icons/controller/applet_single_joycon_right_midnight.png index dc3be54eef..65ca65a86b 100644 Binary files a/dist/icons/controller/applet_single_joycon_right_midnight.png and b/dist/icons/controller/applet_single_joycon_right_midnight.png differ diff --git a/dist/languages/ar.ts b/dist/languages/ar.ts index 73ab8a2039..aeba95374e 100644 --- a/dist/languages/ar.ts +++ b/dist/languages/ar.ts @@ -37,8 +37,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">الموقع الإلكتروني</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">رمز المصدر</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">المساهمون</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">تويتر</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">الترخيص</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -343,7 +343,7 @@ This would ban both their forum username and their IP address. Multicore CPU Emulation - محاكاة وحدة المعالجة المركزية متعددة النواة + محاكاة المعالج متعدد الأنوية @@ -367,7 +367,7 @@ Doesn't affect performance/stability but may allow HD texture mods to load. Limit Speed Percent - الحد من السرعة في المئة + نسبة تحديد السرعة @@ -381,7 +381,7 @@ Disabling it means unlocking the framerate to the maximum your PC can reach. Turbo Speed - سرعة تيربو + السرعة الفائقة @@ -391,7 +391,7 @@ Disabling it means unlocking the framerate to the maximum your PC can reach. Slow Speed - سرعة بطيئة + السرعة البطيئة @@ -411,149 +411,159 @@ Can help reduce stuttering at lower framerates. يساعد في تقليل التلعثم عند معدلات الإطارات المنخفضة. - + + Enable cheats by default + تفعيل رموز الغش بشكل افتراضي + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + يفعل رموز الغش الاعتيادية عند بدء اللعبة. وتظل إدخالات «الرمز الرئيسي» مفعلة دائمًا. ولا يزال من الممكن تشغيل أو إيقاف رموز الغش الفردية من خيار رموز الغش في شريط القوائم أثناء تشغيل اللعبة. + + + Accuracy: :دقة المحاكاة - + Change the accuracy of the emulated CPU (for debugging only). تغيير دقة وحدة المعالجة المركزية المحاكية (للتصحيح فقط). - - + + Backend: :الخلفية - + CPU Clocks سرعات وحدة المعالجة المركزية - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. يرفع هذا الإعداد تردد المعالج المُحاكى، مما يُزيل بعض مُحددات معدل الإطارات. قد تُلاحظ انخفاضًا في الأداء عند استخدام معالجات أضعف، وقد لا تعمل بعض الألعاب بشكلٍ صحيح. - + Custom CPU Ticks - علامات وحدة المعالجة المركزية المخصصة + دورات المعالج المخصصة - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. تعيين قيمة مخصصة لدقات وحدة المعالجة المركزية. القيم الأعلى يمكن أن تزيد الأداء، ولكنها قد تسبب حالات توقف تام. يوصى باستخدام نطاق 77-21000. - + Enable Host MMU Emulation (fastmem) (fastmem) المضيف MMU تفعيل محاكاة - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. يُسرّع هذا التحسين وصول برنامج الضيف إلى الذاكرة. يؤدي تفعيله إلى قراءة/كتابة ذاكرة الضيف مباشرةً في الذاكرة، واستخدام وحدة ذاكرة الجهاز المضيف MMU. أما تعطيله، فيُجبر جميع عمليات الوصول إلى الذاكرة على استخدام محاكاة وحدة ذاكرة الجهاز البرمجية MMU. - + Unfuse FMA (improve performance on CPUs without FMA) إلغاء استخدام FMA (تحسين الأداء على وحدات المعالجة المركزية بدون FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. أصلاً FMA يعمل هذا الخيار على تحسين السرعة عن طريق تقليل دقة تعليمات الضرب والإضافة المدمجة على وحدات المعالجة المركزية التي لا تدعم - + Faster FRSQRTE and FRECPE FRSQRTE و FRECPE أسرع - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. يعمل هذا الخيار على تحسين سرعة بعض وظائف النقاط العائمة التقريبية باستخدام تقريبات أصلية أقل دقة. - + Faster ASIMD instructions (32 bits only) أسرع (32 بت فقط) ASIMD تعليمات - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. يعمل هذا الخيار على تحسين سرعة وظائف النقطة العائمة ASIMD ذات 32 بت من خلال التشغيل باستخدام أوضاع تقريب غير صحيحة. - + Inaccurate NaN handling NaN معالجة غير دقيقة لـ - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. NaN يعمل هذا الخيار على تحسين السرعة عن طريق إزالة فحص. يرجى ملاحظة أن هذا يقلل أيضًا من دقة بعض تعليمات النقاط العائمة. - + Disable address space checks تعطيل عمليات التحقق من مساحة العنوان - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. يعمل هذا الخيار على تحسين السرعة من خلال إلغاء فحص الأمان قبل كل عملية ذاكرة. قد يؤدي تعطيله إلى السماح بتنفيذ تعليمات برمجية عشوائية. - + Ignore global monitor تجاهل الشاشة العالمية - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. يُحسّن هذا الخيار السرعة بالاعتماد فقط على دلالات cmpxchg لضمان سلامة تعليمات الوصول الحصري. يُرجى ملاحظة أن هذا قد يؤدي إلى توقفات وحالات تسابق أخرى. - + API: :واجهة برمجة التطبيقات - + Changes the output graphics API. Vulkan is recommended. يُغيّر واجهة برمجة تطبيقات الرسومات الناتجة. Vulkan يُنصح باستخدام - + Device: - :جهاز + :كارت الشاشة - + This setting selects the GPU to use (Vulkan only). (Vulkan فقط) يحدد هذا الإعداد وحدة معالجة الرسومات التي سيتم استخدامها - + Resolution: :الدقة - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -562,27 +572,27 @@ Options lower than 1X can cause artifacts. قد تؤدي الخيارات الأقل من 1X إلى حدوث تشوهات. - + Window Adapting Filter: :مرشح التكيف مع النافذة - + FSR Sharpness: FSR حدة: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. يحدد مدى وضوح الصورة باستخدام التباين الديناميكي لـ FSR أو SGSR. - + Anti-Aliasing Method: :طريقة مضاد التعرج - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -591,22 +601,22 @@ FXAA can produce a more stable picture in lower resolutions. يُمكن لـ FXAA إنتاج صورة أكثر ثباتًا بدقة أقل. - + Enable post-processing effects تفعيل تأثيرات المعالجة اللاحقة - + Applies post-processing effects to the final image. يُطبق تأثيرات ما بعد المعالجة على الصورة النهائية. - + Fullscreen Mode: :وضع ملء الشاشة - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -615,12 +625,12 @@ Exclusive fullscreen may offer better performance and better Freesync/Gsync supp قد يوفر وضع ملء الشاشة الحصري أداءً أفضل ودعمًا أفضل لتقنيتي Freesync/Gsync. - + Aspect Ratio: :نسبة الأبعاد - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -629,48 +639,48 @@ Also controls the aspect ratio of captured screenshots. كما يتحكم في نسبة العرض إلى الارتفاع للقطات الشاشة الملتقطة. - + Use persistent pipeline cache استخدام ذاكرة التخزين المؤقتة الدائمة للأنابيب - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. يسمح بحفظ التظليلات في وحدة التخزين لتحميلها بشكل أسرع عند تشغيل اللعبة في المرات التالية. لا يُقصد من تعطيله سوى تصحيح الأخطاء. - + Use asynchronous GPU emulation استخدم محاكاة وحدة معالجة الرسومات غير المتزامنة - + Uses an extra CPU thread for rendering. This option should always remain enabled. يستخدم خيط معالجة إضافي للمعالجة الرسومية. يجب أن يبقى هذا الخيار مُفعّلاً دائماً. - + NVDEC emulation: NVDEC محاكاة: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. يُحدد كيفية فك تشفير الفيديوهات.يمكن استخدام وحدة المعالجة المركزية CPU أو وحدة معالجة الرسومات GPU لفك التشفير، أو عدم فك التشفير إطلاقًا (شاشة سوداء على الفيديوهات).في معظم الحالات، يُوفر فك تشفير وحدة معالجة الرسومات GPU أفضل أداء. - + ASTC Decoding Method: ASTC طريقة فك تشفير: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -682,77 +692,58 @@ stuttering but may present artifacts. وحدة المعالجة المركزية بشكل غير متزامن: استخدمها لفك تشفير قوام ASTC عند الطلب. يزيل هذا الخيار تقطع فك تشفير ASTC، ولكنه قد يُظهر بعض العيوب. - + ASTC Recompression Method: ASTC طريقة إعادة ضغط: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - تفتقر معظم وحدات معالجة الرسومات إلى دعم قوام ASTC، ويجب فك ضغطها إلى صيغة وسيطة: RGBA8. -BC1/BC3: سيتم إعادة ضغط الصيغة الوسيطة إلى صيغة BC1 أو BC3، مما يوفر مساحة على ذاكرة الوصول العشوائي للفيديو VRAM ولكنه يُضعف جودة الصورة. + تفتقر معظم وحدات معالجة الرسومات إلى دعم نسيج ASTC، لذا يتعين عليها فك الضغط إلى تنسيق وسيط: RGBA8. +BC1/BC3: سيتم إعادة ضغط التنسيق الوسيط إلى تنسيق BC1 أو BC3، +مما يوفر مساحة ذاكرة الفيديو VRAM ولكنه يؤدي إلى انخفاض جودة الصورة. - + Frame Pacing Mode (Vulkan only) (Vulkan فقط) وضع توقيت الإطارات - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. يتحكم في كيفية إدارة المحاكي لسرعة الإطارات لتقليل التقطع وجعل معدل الإطارات أكثر سلاسة واتساقًا. - + VRAM Usage Mode: VRAM وضع استهلاك: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. يُحدد ما إذا كان ينبغي على المُحاكي تفضيل توفير الذاكرة أو الاستفادة القصوى من ذاكرة الفيديو المُتاحة لتحسين الأداء. قد يؤثر الوضع المُكثّف على أداء تطبيقات أخرى، مثل برامج التسجيل. - + Skip CPU Inner Invalidation تخطي إبطال وحدة المعالجة المركزية الداخلية - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسّن زمن الوصول. قد يؤدي هذا إلى أعطال مؤقتة. - - GPU Readback Before NCE Invalidation - NCE إعادة قراءة وحدة معالجة الرسومات قبل إبطال صلاحية - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - يفرغ بيانات ذاكرة المعالج الرسومي المؤقتة ويعيدها إلى ذاكرة المحاكي قبل أن تلغي تقنية التشغيل المباشر عمل الصفحة بالكامل، مما يحافظ على البيانات أثناء استمرار المعالج المركزي في تخزينها - - - - Patch Runtime NROs for NCE - تعديل ملفات تشغيل اللعبة فوراً لتتوافق مع تقنية التشغيل المباشر - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - يعدل كود تشغيل اللعبة تلقائياً عند فتحها. هذا الإجراء ضروري لتشغيل بعض الألعاب بدون مشاكل. - - - + VSync Mode: VSync وضع: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -763,12 +754,12 @@ Immediate (no synchronization) presents whatever is available and can exhibit te يُظهر الوضع الفوري (بدون مزامنة) كل ما هو متاح، وقد يُظهر تمزقًا. - + Sync Memory Operations مزامنة عمليات الذاكرة - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. @@ -777,44 +768,44 @@ Unreal Engine 4 games often see the most significant changes thereof. التغييرات الأكثر أهمية Unreal Engine 4 غالبًا ما تشهد ألعاب. - + Enable asynchronous presentation (Vulkan only) (Vulkan فقط) تفعيل العرض التقديمي غير المتزامن - + Slightly improves performance by moving presentation to a separate CPU thread. تحسين الأداء بشكل طفيف عن طريق نقل العرض التقديمي إلى مؤشر ترابط منفصل في وحدة المعالجة المركزية. - + Force maximum clocks (Vulkan only) (Vulkan فقط) فرض الحد الأقصى للساعات - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. يعمل في الخلفية أثناء انتظار أوامر الرسومات لمنع وحدة معالجة الرسومات من خفض سرعة الساعة. - + Anisotropic Filtering: :الترشيح متباين الخواص - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. يتحكم بجودة عرض الملمس بزوايا مائلة. من الآمن ضبطه على 16x على معظم وحدات معالجة الرسومات. - + GPU Mode: :وضع وحدة معالجة الرسومات - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. @@ -823,12 +814,12 @@ Particles tend to only render correctly with Accurate mode. لا تُعرض الجسيمات بشكل صحيح إلا في وضع «دقيق». - + DMA Accuracy: DMA دقة: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. @@ -837,12 +828,12 @@ Default follows the GPU Accuracy setting. يُتبع الإعداد الافتراضي إعداد «دقة وحدة معالجة الرسومات» - + GPU Fence Behavior: :سلوك حاجز وحدة معالجة الرسومات - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -855,44 +846,44 @@ Default follows the GPU Mode setting. يتبع الخيار افتراضي إعداد وضع وحدة معالجة الرسومات. - + Enable asynchronous shader compilation تفعيل تجميع التظليل غير المتزامن - + May reduce shader stutter. قد يقلل من تقطع التظليل. - + GPU Clocks سرعات وحدة معالجة الرسومات - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. يجعل اللعبة تعتقد أن عمل وحدة معالجة الرسومات ينتهي بشكل أسرع مما هو عليه في الواقع، لذلك تتوقف عن خفض الدقة ومسافة العرض لتتناسب مع سرعات جهاز Switch. - + GPU Unswizzle إلغاء ترتيب بيانات وحدة معالجة الرسومات - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. باستخدام حوسبة وحدة معالجة الرسومات BCn 3D يسرع فك تشفير نسيج. قم بتعطيله في حالة حدوث أعطال أو مشاكل في الرسومات. - + GPU Unswizzle Max Texture Size الحد الأقصى لحجم النسيج في وحدة معالجة الرسومات بعد إعادة ترتيب البيانات - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. @@ -901,48 +892,48 @@ Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size حجم تدفق إلغاء ترتيب بيانات وحدة معالجة الرسومات - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. يحدد الحد الأقصى لكمية بيانات النسيج (بالميغابايت) التي تتم معالجتها لكل إطار. يمكن أن تقلل القيم الأعلى من التقطع أثناء تحميل النسيج، ولكنها قد تؤثر على اتساق الإطارات. - + GPU Unswizzle Chunk Size حجم كتلة إلغاء ترتيب بيانات وحدة معالجة الرسومات - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. يُحدد هذا الخيار عدد شرائح العمق التي تتم معالجتها في عملية إرسال واحدة. زيادة هذا الخيار قد تُحسّن الإنتاجية على وحدات معالجة الرسومات المتطورة، ولكنها قد تُسبب أخطاء في إعادة تعيين وقت الاستجابة أو انقطاع الاتصال ببرنامج التشغيل على الأجهزة ذات المواصفات الأقل. - + Use Vulkan pipeline cache Vulkan استخدام ذاكرة التخزين المؤقتة لخط أنابيب - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. يُفعّل ذاكرة التخزين المؤقت لخطوط الأنابيب الخاصة ببائع وحدة معالجة الرسومات. بتخزين ملفات ذاكرة التخزين المؤقتة للخطوط الداخلية Vulkan يمكن أن يؤدي هذا الخيار إلى تحسين وقت تحميل التظليل بشكل كبير في الحالات التي لا يقوم فيها برنامج تشغيل. - + Enable Compute Pipelines (Intel Vulkan Only) (Intel Vulkan فقط) تفعيل خطوط أنابيب الحوسبة - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. @@ -951,1208 +942,1208 @@ Compute pipelines are always enabled on all other drivers. خطوط أنابيب الحوسبة مفعلة دائمًا على جميع برامج التشغيل الأخرى. - + Enable Reactive Flushing تفعيل التنظيف التفاعلي - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. يستخدم التنظيف التفاعلي بدلاً من التنظيف التنبئي، مما يسمح بمزامنة الذاكرة بشكل أكثر دقة. - + Sync to framerate of video playback المزامنة مع معدل الإطارات لتشغيل الفيديو - + Run the game at normal speed during video playback, even when the framerate is unlocked. قم بتشغيل اللعبة بالسرعة العادية أثناء تشغيل الفيديو، حتى عندما يكون معدل الإطارات مفتوحًا. - + Barrier feedback loops حلقات التغذية الراجعة للحواجز - + Improves rendering of transparency effects in specific games. يحسن عرض تأثيرات الشفافية في بعض الألعاب المحددة. - + Enable buffer history تفعيل سجل التخزين المؤقت - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب. - + Fix bloom effects إصلاح تأثيرات التوهج - + Removes bloom in Burnout. يزيل التوهج في وضع الاحتراق. - + Extended Dynamic State الحالة الديناميكية الموسعة - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. يتحكم في عدد الميزات التي يمكن استخدامها في الحالة الديناميكية الموسعة.تسمح الحالات الأعلى بمزيد من الميزات ويمكن أن تزيد من الأداء، ولكنها قد تسبب مشكلات رسومية إضافية. - + Vertex Input Dynamic State حالة ديناميكية لإدخال الرأس - + Enables vertex input dynamic state feature for better quality and performance. يتيح ميزة الحالة الديناميكية لإدخال الرأس لتحسين الجودة والأداء. - + Sample Shading تظليل العينة - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. يسمح لمظلل الأجزاء بالتنفيذ لكل عينة في جزء متعدد العينات بدلاً من مرة واحدة لكل جزء. يحسن جودة الرسومات على حساب الأداء. القيم الأعلى تحسن الجودة ولكنها تقلل من الأداء. - + RNG Seed مولد الأرقام العشوائية - + Controls the seed of the random number generator. Mainly used for speedrunning. يتحكم في بذرة مولد الأرقام العشوائية. يُستخدم بشكل رئيسي في سباقات السرعة. - + Device Name اسم الجهاز - + The name of the console. اسم وحدة التحكم. - + Homebrew Args Homebrew وسائط - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). (noglsl -مثل) عند التشغيل Homebrew سطر الأوامر الوسائط المُمررة إلى - + Custom RTC Date: :تاريخ التوقيت الحقيقي المخصص - + This option allows to change the clock of the console. Can be used to manipulate time in games. يتيح لك هذا الخيار تغيير ساعة وحدة التحكم. يمكن استخدامه للتحكم بالوقت في الألعاب. - + The number of seconds from the current unix time عدد الثواني من وقت يونكس الحالي - + Language: :اللغة - + This option can be overridden when region setting is auto-select يمكن تجاوز هذا الخيار عند تحديد إعداد المنطقة تلقائيًا - + Region: :المنطقة - + The region of the console. منطقة وحدة التحكم. - + Time Zone: :المنطقة الزمنية - + The time zone of the console. المنطقة الزمنية لوحدة التحكم. - + Sound Output Mode: :وضع إخراج الصوت - + Console Mode: :وضع وحدة التحكم - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - يُحدد ما إذا كان الجهاز في وضع الإرساء أو الوضع المحمول. + يُحدد ما إذا كان الجهاز في وضع المنصة أو الوضع المحمول. ستتغير دقة الألعاب وتفاصيلها وأجهزة التحكم المدعومة بناءً على هذا الإعداد. يُمكن أن يُساعد الضبط على الوضع المحمول على تحسين أداء الأجهزة منخفضة المواصفات. - + Prompt for user profile on boot المطالبة بملف تعريف المستخدم عند التشغيل - + Useful if multiple people use the same PC. مفيد إذا كان هناك عدة أشخاص يستخدمون نفس الكمبيوتر. - + Pause when not in focus توقف عند عدم التركيز - + Pauses emulation when focusing on other windows. يوقف المحاكاة عند التركيز على نوافذ أخرى. - + Confirm before stopping emulation تأكيد قبل إيقاف المحاكاة - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. يتجاوز المطالبات التي تطلب تأكيد إيقاف المحاكاة. يؤدي تفعيله إلى تجاوز هذه المطالبات والخروج مباشرة من المحاكاة. - + Hide mouse on inactivity إخفاء الماوس عند عدم النشاط - + Hides the mouse after 2.5s of inactivity. يخفي الماوس بعد 2.5 ثانية من عدم النشاط. - + Check for updates التحقق من توفر التحديثات - + Whether or not to check for updates upon startup. ما إذا كان يجب التحقق من التحديثات عند بدء التشغيل أم لا. - + Enable Gamemode تفعيل وضع اللعبة - + Force X11 as Graphics Backend كخلفية رسومات X11 فرض - + Custom frontend الواجهة الأمامية المخصصة - + Real applet تطبيق صغير حقيقي - - + + Disabled معطل - + Never أبداً - + On Load عند التحميل - + Always دائماً - + CPU وحدة المعالجة المركزية - + GPU وحدة معالجة الرسومات - + CPU Asynchronous وحدة المعالجة المركزية غير المتزامنة - + Uncompressed (Best quality) Uncompressed (أفضل جودة) - + BC1 (Low quality) BC1 (جودة منخفضة) - + BC3 (Medium quality) BC3 (جودة متوسطة) - - + + Auto تلقائي - + 30 FPS 30 إطارًا في الثانية - + 60 FPS 60 إطارًا في الثانية - + 90 FPS 90 إطارًا في الثانية - + 120 FPS 120 إطارًا في الثانية - + Conservative محافظ - + Aggressive عدواني - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null لا شيء - + Fast سريع - - - + + + Accurate دقه - - - + + + Default افتراضي - + Unsafe (fast) غير آمن (سريع) - + Safe (stable) آمن (مستقر) - + Immediate فوري - + Balanced متوازن - + Unsafe غير آمن - + Paranoid (disables most optimizations) شديد الحذر (يعطل معظم التحسينات) - + Debugging تصحيح الأخطاء - + Dynarmic Dynarmic - + NCE NCE - + Borderless Windowed نافذة بلا حدود - + Exclusive Fullscreen شاشة كاملة حصرية - + No Video Output لا يوجد إخراج فيديو - + CPU Video Decoding فك تشفير فيديو وحدة المعالجة المركزية - + GPU Video Decoding (Default) فك تشفير فيديو وحدة معالجة الرسومات (افتراضي) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [تجريبي] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [تجريبي] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [تجريبي] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [تجريبي] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [تجريبي] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Nearest Neighbor - + Bilinear Bilinear - + Bicubic Bicubic - + Gaussian Gaussian - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX Super Resolution - + Area Area - + MMPX MMPX - + Zero-Tangent Zero-Tangent - + B-Spline B-Spline - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution دقة فائقة للألعاب من سنابدراغون - + Snapdragon Game Super Resolution EdgeDir دقة فائقة للألعاب من سنابدراغون EdgeDir - + None لا شيء - + FXAA FXAA - + SMAA SMAA - + Default (16:9) (16:9) افتراضي - + Force 4:3 4:3 فرض - + Force 21:9 21:9 فرض - + Force 16:10 16:10 فرض - + Stretch to Window تمديد إلى النافذة - + Automatic تلقائي - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) اليابانية (日本語) - + American English الإنجليزية الأمريكية - + French (français) الفرنسية (français) - + German (Deutsch) الألمانية (Deutsch) - + Italian (italiano) الإيطالية (Italiano) - + Spanish (español) الإسبانية (español) - + Chinese الصينية - + Korean (한국어) الكورية (한국어) - + Dutch (Nederlands) الهولندية (Nederlands) - + Portuguese (português) البرتغالية (Português) - + Russian (Русский) الروسية (Русский) - + Taiwanese تايواني - + British English الإنجليزية البريطانية - + Canadian French الكندية الفرنسية - + Latin American Spanish أمريكا اللاتينية الإسبانية - + Simplified Chinese الصينية المبسطة - + Traditional Chinese (正體中文) الصينية التقليدية (正體中文) - + Brazilian Portuguese (português do Brasil) البرتغالية البرازيلية (português do Brasil) - + Polish (polska) البولندية (polska) - + Thai (แบบไทย) التايلاندية (แบบไทย) - - + + Japan اليابان - + USA الولايات المتحدة الأمريكية - + Europe أوروبا - + Australia أستراليا - + China الصين - + Korea كوريا - + Taiwan تايوان - + Auto (%1) Auto select time zone تلقائي (%1) - + Default (%1) Default time zone افتراضي (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Egypt - + Eire Eire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Iceland - + Iran Iran - + Israel Israel - + Jamaica Jamaica - + Kwajalein Kwajalein - + Libya Libya - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Poland - + Portugal Portugal - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapore - + Turkey Turkey - + UCT UCT - + Universal Universal - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono أحادي - + Stereo مجسم - + Surround محيطي - + 4GB DRAM (Default) 4GB DRAM (افتراضي) - + 6GB DRAM (Unsafe) 6GB DRAM (غير آمنة) - + 8GB DRAM 8GB DRAM - + 10GB DRAM (Unsafe) 10GB DRAM (غير آمنة) - + 12GB DRAM (Unsafe) 12GB DRAM (غير آمنة) - + Docked - الإرساء + المنصة - + Handheld محمول - - + + Normal قياسي - - + + Boost تعزيز - - + + Overclock كسر السرعة - + Always ask (Default) اسأل دائمًا (افتراضي) - + Only if game specifies not to stop فقط إذا حددت اللعبة عدم التوقف - + Never ask لا تسأل أبدا - + Very Small (16 MB) صغير جدًا (16 ميغابايت) - + Small (32 MB) صغير (32 ميغابايت) - + Normal (128 MB) قياسي (128 ميغابايت) - + Large (256 MB) كبير (256 ميغابايت) - + Very Large (512 MB) كبير جدًا (512 ميغابايت) - + Very Low (4 MB) منخفض جدًا (4 ميغابايت) - + Low (8 MB) منخفض (8 ميغابايت) - + Normal (16 MB) قياسي (16 ميغابايت) - + Medium (32 MB) متوسط (32 ميغابايت) - + High (64 MB) عالي (64 ميغابايت) - + Very Low (32) منخفض جدًا (32) - + Low (64) منخفض (64) - + Normal (128) قياسي (128) - + Medium (256) متوسط (256) - + High (512) عالي (512) - + ExtendedDynamicState 1 الحالة الديناميكية الممتدة 1 - + ExtendedDynamicState 2 الحالة الديناميكية الممتدة 2 - + ExtendedDynamicState 3 الحالة الديناميكية الممتدة 3 - + Tree View عرض قائمة - + Grid View عرض شبكة @@ -2574,7 +2565,7 @@ Enabling it bypasses such prompts and directly exits the emulation. Arguments String - سلسلة الحجج + نص أوامر التشغيل @@ -3515,7 +3506,7 @@ Would you like to delete the old save data? Docked - الإرساء + المنصة @@ -3974,7 +3965,7 @@ Would you like to delete the old save data? Pressed - مضغوط + ضغط العصا @@ -3988,7 +3979,7 @@ Would you like to delete the old save data? Range - نطاق + النطاق @@ -5609,7 +5600,7 @@ Drag points to change position, or double-click table cells to edit values. Show Play Time Column - عرض عمود زمن اللعب + عرض عمود وقت اللعب @@ -5688,7 +5679,7 @@ Drag points to change position, or double-click table cells to edit values. Press any controller button to vibrate the controller. - اضغط على أي زر في جهاز التحكم لإحداث اهتزاز في الجهاز. + اضغط على أي زر في ذراع التحكم لاختبار الاهتزاز. @@ -5798,7 +5789,7 @@ Drag points to change position, or double-click table cells to edit values. Discord Presence - التواجد على ديسكورد + التواجد في ديسكورد @@ -6113,50 +6104,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL غير متوفر! - + OpenGL shared contexts are not supported. OpenGL لا يتم دعم السياقات المشتركة - + Eden has not been compiled with OpenGL support. OpenGL لم يتم تجميع إيدن بدعم - - - + + + Error while initializing OpenGL! OpenGL حدث خطأ أثناء تهيئة - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. أو قد لا يكون لديك أحدث برنامج تشغيل للرسومات OpenGL قد لا تدعم بطاقة الرسومات الخاصة بك - + Error while initializing OpenGL 4.6! OpenGL 4.6 حدث خطأ أثناء تهيئة - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 أو قد لا يكون لديك أحدث برنامج تشغيل للرسومات OpenGL 4.6 قد لا تدعم بطاقة الرسومات الخاصة بك.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 قد لا تدعم وحدة معالجة الرسومات لديك ملحقًا واحدًا أو أكثر من ملحقات OpenGL المطلوبة. يُرجى التأكد من تثبيت أحدث برنامج تشغيل للرسومات.<br><br>GL Renderer:<br>1%<br><br>إضافات غير مدعومة: <br>2% - + This build doesn't have OpenGL support. هذا الإصدار لا يدعم OpenGL. @@ -6251,17 +6242,17 @@ Please go to Configure -> System -> Network and make a selection. Manage Play Time - إدارة زمن اللعب + إدارة وقت اللعب Edit Play Time Data - تعديل بيانات زمن التشغيل + تعديل بيانات وقت اللعب Remove Play Time Data - إزالة بيانات زمن اللعب + إزالة بيانات وقت اللعب @@ -6423,7 +6414,7 @@ Please go to Configure -> System -> Network and make a selection. Play time - زمن اللعب + وقت اللعب @@ -6602,7 +6593,7 @@ Debug Message: Change Docked Mode - تغيير وضع الإرساء + تغيير وضع المنصة @@ -6712,7 +6703,7 @@ Debug Message: Toggle Turbo Speed - تفعيل/تعطيل سرعة تيربو + تفعيل/تعطيل السرعة الفائقة @@ -6923,801 +6914,824 @@ Debug Message: &محاكاة - + + &Cheats + &رموز الغش + + + &View &عرض - + &Reset Window Size &إعادة تعيين حجم النافذة - + &Debugging &تصحيح الأخطاء - + &Game List Mode &وضع قائمة الألعاب - + Game &Icon Size حجم &أيقونة اللعبة - + Reset Window Size to &720p 720p إعادة تعيين حجم النافذة إلى - + Reset Window Size to 720p 720p إعادة تعيين حجم النافذة إلى - + Reset Window Size to &900p 900p إعادة تعيين حجم النافذة إلى - + Reset Window Size to 900p 900p إعادة تعيين حجم النافذة إلى - + Reset Window Size to &1080p 1080p إعادة تعيين حجم النافذة إلى - + Reset Window Size to 1080p 1080p إعادة تعيين حجم النافذة إلى - + &Multiplayer &متعدد اللاعبين - + &Tools &أدوات - + Am&iibo أم&يبو - + Launch &Applet تشغيل &التطبيق المصغر - + &TAS &TAS - + &Create Home Menu Shortcut &إنشاء اختصار لقائمة الشاشة الرئيسية - + Install &Firmware تثبيت &الفيرموير - + &Help &مساعدة - + &Install Files to NAND... &تثبيت الملفات في الذاكرة الداخلية - + L&oad File... ت&حميل ملف - + Load &Folder... تحميل &مجلد - + E&xit خ&روج - - + + &Pause &إيقاف مؤقت - + &Stop &إيقاف - + &Verify Installed Contents &التحقق من المحتويات المثبتة - + &About Eden &حول إيدن - + Single &Window Mode وضع &النافذة الواحدة - + Con&figure... الإع&دادات - + Ctrl+, Ctrl+, - + Enable Overlay Display Applet تفعيل التطبيق المصغر لعرض الطبقة - + Show &Filter Bar عرض &شريط التصفية - + Show &Status Bar عرض &شريط الحالة - + Show Status Bar عرض شريط الحالة - + &Browse Public Game Lobby &تصفح قائمة الألعاب العامة - + &Create Room &إنشاء غرفة - + &Leave Room &مغادرة الغرفة - + &Direct Connect to Room &الاتصال المباشر بالغرفة - + &Show Current Room &عرض الغرفة الحالية - + F&ullscreen م&لء الشاشة - + &Restart &إعادة التشغيل - + Load/Remove &Amiibo... تحميل/إزالة &أميبو - + Open &Mods Page صفحة &التعديلات - + &User Handbook &دليل المستخدم - + &Capture Screenshot &التقاط لقطة للشاشة - + &Album &الألبوم - + &Set Nickname and Owner &تعيين الاسم المستعار والمالك - + &Delete Game Data حذف بيانات اللعبة - + &Restore Amiibo &استعادة أميبو - + &Format Amiibo &تنسيق أميبو - + &Mii Editor &Mii محرر - + &Configure TAS... &TAS إعدادات - + Configure C&urrent Game... إعدادات اللعبة ال&حالية - - + + &Start &بدء - + &Reset &إعادة تعيين - - + + R&ecord ت&سجيل - + Open &Controller Menu &قائمة ذراع التحكم - + Install Decryption &Keys تثبيت &مفاتيح فك التشفير - + &Home Menu &القائمة الرئيسية - + &Desktop &سطح المكتب - + &Application Menu &قائمة التطبيقات - + &Root Data Folder &مجلد البيانات الرئيسي - + &NAND Folder &مجلد الذاكرة الداخلية - + &SDMC Folder &مجلد بطاقة الذاكرة - + &Mod Folder &مجلد التعديلات - + &Log Folder &مجلد السجلات - + From Folder من مجلد - + From ZIP من ملف مضغوط - + &Eden Dependencies &تبعيات إيدن - + &Data Manager &إدارة البيانات - + &Tree View &عرض قائمة - + &Grid View &عرض شبكة - + Game Icon Size حجم أيقونة اللعبة - - + + None لا شيء - + Show Game &Name عرض اسم &اللعبة - + Show &Performance Overlay عرض &طبقة الأداء - + Post-Processing &Shaders... المعالجة اللاحقة &الظلال... - + &Carousel View &عرض دائري - + Small (32x32) (32x32) صغير - + Standard (64x64) (64x64) قياسي - + Large (128x128) (128x128) كبير - + Full Size (256x256) (256x256) حجم كامل - + Broken Vulkan Installation Detected Vulkan تم الكشف عن تلف في تثبيت - + Vulkan initialization failed during boot. أثناء التشغيل Vulkan فشل تهيئة. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping تشغيل لعبة - + Loading Web Applet... جارٍ تحميل تطبيق الويب... - - + + Disable Web Applet تعطيل تطبيق الويب - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) قد يؤدي تعطيل أداة الويب إلى سلوك غير محدد، ويجب استخدامه فقط مع لعبة Super Mario 3D All-Stars. هل أنت متأكد من رغبتك في تعطيل أداة الويب؟ (يمكن إعادة تفعيلها في إعدادات التصحيح.) - + The amount of shaders currently being built كمية التظليلات التي يتم بناؤها حاليًا - + The current selected resolution scaling multiplier. - مضاعف قياس الدقة المحددة حالياً. + مضاعف قياس الدقة المحدد حالياً. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Switch سرعة المحاكاة الحالية. تشير القيم الأعلى أو الأقل من 100٪ إلى أن المحاكاة تعمل بشكل أسرع أو أبطأ من. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. عدد الإطارات في الثانية التي تعرضها اللعبة حاليًا. يختلف هذا العدد من لعبة إلى أخرى ومن مشهد إلى آخر. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. الوقت المستغرق لمحاكاة إطار على جهاز سويتش، بدون احتساب تحديد الإطارات أو المزامنة العمودية. لمحاكاة بسرعة كاملة، يجب أن يكون هذا في حدود 16.67 مللي ثانية كحد أقصى. - + Unmute إلغاء كتم الصوت - + Mute كتم الصوت - + Reset Volume إعادة تعيين مستوى الصوت - + Configure Effects... إعداد التأثيرات... - + &Clear Recent Files &مسح الملفات الحديثة - + + Disable All Cheats + تعطيل جميع رموز الغش + + + + Enable All Cheats + تفعيل جميع رموز الغش + + + + Unnamed Cheat + رمز الغش بدون اسم + + + &Continue &متابعة - + Warning: Outdated Game Format تحذير: تنسيق اللعبة قديم - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. أنت تستخدم تنسيق مجلد ROM المُفكك لهذه اللعبة، وهو تنسيق قديم استُبدل بآخر مثل NCA وNAX وXCI وNSP. تفتقر مجلدات ROM المُفككة إلى الأيقونات والبيانات الوصفية ودعم التحديثات. <br>لتوضيح تنسيقات Switch المختلفة التي يدعمها Eden، يُرجى مراجعة دليل المستخدم. لن تظهر هذه الرسالة مرة أخرى. - - + + Error while loading ROM! ROM خطأ أثناء تحميل - + The ROM format is not supported. غير مدعوم ROM تنسيق. - + An error occurred initializing the video core. حدث خطأ أثناء تهيئة نواة الفيديو. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. عادةً ما يحدث هذا بسبب برامج تشغيل وحدة معالجة الرسومات القديمة. يرجى الاطلاع على السجل لمزيد من التفاصيل. انظر: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>كيفية الوصول إلى ملفات السجلات</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. حدث خطأ أثناء تحميل ROM! %1 - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. %1<br>Discord/Stoat يرجى إعادة تحميل ملفاتك أو طلب المساعدة على - + An unknown error occurred. Please see the log for more details. حدث خطأ غير معروف. يرجى الاطلاع على السجل لمزيد من التفاصيل. - - + + (64-bit) (64-bit) - - + + (32-bit) (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - + Closing software... جارٍ إغلاق البرنامج... - + Save Data بيانات الحفظ - + Mod Data بيانات التعديل - + Error Opening %1 Folder خطأ في فتح المجلد %1 - - + + Folder does not exist! المجلد غير موجود! - + Remove Installed Game Contents? إزالة محتويات اللعبة المثبتة؟ - + Remove Installed Game Update? إزالة تحديث اللعبة المثبت؟ - + Remove Installed Game DLC? إزالة المحتوى القابل للتنزيل المثبت للعبة؟ - + Remove Entry إزالة الإدخال - + Delete OpenGL Transferable Shader Cache? OpenGL Shader حذف ذاكرة التخزين المؤقتة القابلة للنقل لـ - + Delete Vulkan Transferable Shader Cache? Vulkan Shader حذف ذاكرة التخزين المؤقتة القابلة للنقل لـ - + Delete All Transferable Shader Caches? حذف جميع مخازن ذاكرة التظليل القابلة للنقل؟ - + Remove Custom Game Configuration? إزالة إعدادات اللعبة المخصص؟ - + Remove Cache Storage? إزالة ذاكرة التخزين المؤقتة؟ - + Remove File إزالة الملف - + Remove Play Time Data - إزالة بيانات زمن اللعب + إزالة بيانات وقت اللعب - + Reset play time? - إعادة تعيين زمن اللعب؟ + إعادة تعيين وقت اللعب؟ - - + + RomFS Extraction Failed! RomFS فشل استخراج - + There was an error copying the RomFS files or the user cancelled the operation. أو قام المستخدم بإلغاء العملية RomFS حدث خطأ أثناء نسخ ملفات - + Full كامل - + Skeleton Skeleton - + Select RomFS Dump Mode RomFS حدد وضع تفريغ - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. الرجاء تحديد الطريقة التي تريد بها تفريغ RomFS. <br>سيتم نسخ جميع الملفات إلى المجلد الجديد في أثناء <br>قيام الهيكل العظمي بإنشاء بنية المجلد فقط. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root لا توجد مساحة فارغة كافية في %1 لاستخراج نظام الملفات RomFS. يُرجى تحرير مساحة أو اختيار مجلد تفريغ آخر من: المحاكاة > التكوين > النظام > نظام الملفات > تفريغ الجذر. - + Extracting RomFS... RomFS استخراج... - - + + Cancel إلغاء - + RomFS Extraction Succeeded! بنجاح RomFS تم استخراج! - + The operation completed successfully. تمت العملية بنجاح. - + Error Opening %1 خطأ في فتح %1 - + Select Directory حدد المجلد - + Properties خصائص - + The game properties could not be loaded. تعذر تحميل خصائص اللعبة. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. تشغيل الملف القابل للتنفيذ (%1)؛؛جميع الملفات (*.*) - + Load File تحميل الملف - + Open Extracted ROM Directory المستخرج ROM فتح ملف - + Invalid Directory Selected تم تحديد مجلد غير صالح - + The directory you have selected does not contain a 'main' file. لا يحتوي المجلد الذي حددته على ملف رئيسي - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) + (*.nca *.nsp *.nsz *.xci *.xcz) ملفات سويتش القابلة للتثبيت +(*.nca) أرشيف محتوى نينتندو +(*.nsp *.nsz) حزمة إرسال نينتندو +(*.xci *.xcz) NX صورة خرطوشة - + Install Files تثبيت الملفات - + %n file(s) remaining %n ملف (ملفات) متبقية%n ملف (ملفات) متبقية%n ملف (ملفات) متبقية%n ملف (ملفات) متبقية%n ملف (ملفات) متبقية%n ملف (ملفات) متبقية - + Installing file "%1"... تثبيت الملف ”%1“... - - + + Install Results نتائج التثبيت - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. لتجنب أي تعارضات محتملة، ننصح المستخدمين بعدم تثبيت الألعاب الأساسية على الذاكرة الداخلية. يرجى استخدام هذه الميزة فقط لتثبيت التحديثات والمحتوى القابل للتنزيل. - + %n file(s) were newly installed %n تم تثبيت ملف (ملفات) جديدة @@ -7729,7 +7743,7 @@ Please, only use this feature to install updates and DLC. - + %n file(s) were overwritten %n تم استبدال ملف (ملفات) @@ -7741,7 +7755,7 @@ Please, only use this feature to install updates and DLC. - + %n file(s) failed to install %n فشل تثبيت ملف (ملفات) @@ -7753,324 +7767,324 @@ Please, only use this feature to install updates and DLC. - + System Application تطبيق النظام - + System Archive أرشيف النظام - + System Application Update تحديث تطبيق النظام - + Firmware Package (Type A) حزمة الفيرموير (النوع أ) - + Firmware Package (Type B) حزمة الفيرموير (النوع ب) - + Game لعبة - + Game Update تحديث اللعبة - + Game DLC الخاص باللعبة DLC الـ - + Delta Title Delta عنوان - + Select NCA Install Type... NCA حدد نوع تثبيت... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) يرجى تحديد نوع اللعبة التي ترغب في تثبيت NCA عليها: (في معظم الحالات، يكون الإعداد الافتراضي "لعبة" مناسبًا.) - + Failed to Install فشل التثبيت - + The title type you selected for the NCA is invalid. غير صالح NCA نوع العنوان الذي حددته لـ. - + File not found لم يتم العثور على الملف - + File "%1" not found لم يتم العثور على الملف "%1" - + OK موافق - + Function Disabled الوظيفة معطلة - + Compatibility list reporting is currently disabled. Check back later! تقارير قائمة التوافق معطلة حاليًا. يرجى التحقق لاحقًا! - + Error opening URL خطأ في فتح الرابط - + Unable to open the URL "%1". تعذر فتح الرابط ”%1“ - + TAS Recording TAS تسجيل - + Overwrite file of player 1? الكتابة فوق ملف اللاعب 1؟ - + Invalid config detected تم اكتشاف إعدادات غير صالح - + Handheld controller can't be used on docked mode. Pro controller will be selected. - لا يمكن استخدام وحدة التحكم المحمولة في وضع الإرساء. سيتم اختيار وحدة تحكم احترافية. + لا يمكن استخدام وحدة التحكم المحمولة في وضع المنصة. سيتم اختيار وحدة تحكم احترافية. - - + + Amiibo أميبو - - + + The current amiibo has been removed تمت إزالة أميبو الحالي. - + Error خطأ - - + + The current game is not looking for amiibos اللعبة الحالية لا تبحث عن أميبو - + Amiibo File (%1);; All Files (*.*) جميع الملفات (%1)؛؛ ملف أميبو (*.*) - + Load Amiibo تحميل أميبو - + Error loading Amiibo data خطأ أثناء تحميل بيانات أميبو - + The selected file is not a valid amiibo الملف المحدد ليس أميبو صالح - + The selected file is already on use الملف المحدد قيد الاستخدام بالفعل - + An unknown error occurred حدث خطأ غير معروف - + No firmware available لا يوجد فيرموير متوفر - + Firmware Corrupted الفيرموير تالف - + Unknown applet تطبيق غير معروف - + Applet doesn't map to a known value. لا يرتبط التطبيق المصغر بقيمة معروفة. - + Record not found لم يتم العثور على السجل - + Applet not found. Please reinstall firmware. لم يتم العثور على التطبيق المصغر. يرجى إعادة تثبيت الفيرموير. - + Capture Screenshot التقاط لقطة شاشة - + PNG Image (*.png) PNG Image (*.png) - + TAS state: Running %1/%2 حالة TAS: تشغيل %1/%2 - + TAS state: Recording %1 حالة TAS: تسجيل %1 - + TAS state: Idle %1/%2 حالة TAS: خامل %1/%2 - + TAS State: Invalid حالة TAS: غير صالحة - + &Stop Running &إيقاف التشغيل - + Stop R&ecording إيقاف ال&تسجيل - + Building: %n shader(s) بناء: %n تظليل(ات)بناء: %n تظليل(ات)بناء: %n تظليل(ات)بناء: %n تظليل(ات)بناء: %n تظليل(ات)بناء: %n تظليل(ات) - + Scale: %1x %1 is the resolution scaling factor الدقة: %1x - + Speed: %1% / %2% السرعة: %1% / %2% - + Speed: %1% السرعة: %1% - + Game: %1 FPS اللعبة: %1 إطار - + Frame: %1 ms الإطار: %1 ms - + NO AA NO AA - + NO FX NO FX - + FX FX - + VOLUME: MUTE الصوت: كتم الصوت - + VOLUME: %1% Volume percentage (e.g. 50%) %1% :الصوت - + Derivation Components Missing مكونات الاشتقاق مفقودة - + Decryption keys are missing. Install them now? مفاتيح فك التشفير مفقودة. هل تريد تثبيتها الآن؟ - + Wayland Detected! Wayland تم الكشف عن - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8081,74 +8095,74 @@ Would you like to force it for future launches? هل ترغب في فرض استخدامه في عمليات التشغيل المستقبلية؟ - + Use X11 X11 استخدم - + Continue with Wayland Wayland متابعة مع - + Don't show again لا تعرض مرة أخرى - + Restart Required إعادة التشغيل مطلوبة - + Restart Eden to apply the X11 backend. X11 أعد تشغيل إيدن لتطبيق الخلفية - + Slow بطيء - + Turbo تيربو - + Unlocked إلغاء القفل - + Select RomFS Dump Target RomFS حدد هدف تفريغ - + Please select which RomFS you would like to dump. الذي تريد تفريغه RomFS الرجاء تحديد - + Are you sure you want to close Eden? هل أنت متأكد من أنك تريد إغلاق إيدن؟ - - - + + + Eden إيدن - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. هل أنت متأكد من أنك تريد إيقاف المحاكاة؟ سيتم فقدان أي تقدم لم يتم حفظه. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? @@ -8244,7 +8258,7 @@ Would you like to bypass this and exit anyway? Docked - الإرساء + المنصة @@ -9185,7 +9199,7 @@ p, li { white-space: pre-wrap; } Play Time: %1 - زمن اللعب: %1 + وقت اللعب: %1 @@ -10317,7 +10331,7 @@ This is recommended if you want to share data between emulators. Docked - الإرساء + المنصة @@ -10647,7 +10661,7 @@ By selecting "From Eden", previous save data stored in Ryujinx will be Set Play Time Data - تعيين بيانات زمن التشغيل + تعيين بيانات وقت اللعب @@ -10667,7 +10681,7 @@ By selecting "From Eden", previous save data stored in Ryujinx will be Total play time reached maximum. - وصل إجمالي زمن التشغيل إلى الحد الأقصى. + وصل إجمالي وقت اللعب إلى الحد الأقصى. diff --git a/dist/languages/ca.ts b/dist/languages/ca.ts index 534d4e4af1..0442081541 100644 --- a/dist/languages/ca.ts +++ b/dist/languages/ca.ts @@ -30,8 +30,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Lloc web</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Codi font</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Col·laboradors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Llicència</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -397,252 +397,262 @@ Can help reduce stuttering at lower framerates. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Precisió: - + Change the accuracy of the emulated CPU (for debugging only). - - + + Backend: Motor: - + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks Ticks del CPU personalitzats - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) Desactivar FMA (millora el rendiment en CPUs sense FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. - + Faster FRSQRTE and FRECPE FRSQRTE i FRECPE més ràpid - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Aquest paràmetre millora la velocitat d'algunes funcions de coma flotant, amb l'ús d'aproximacions natives menys precises. - + Faster ASIMD instructions (32 bits only) Instruccions ASIMD més ràpides (només 32 bits) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. - + Inaccurate NaN handling Gestió imprecisa NaN - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. - + Disable address space checks Desactiva les comprovacions d'espai d'adreces - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor Ignorar monitorització global - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. - + API: API: - + Changes the output graphics API. Vulkan is recommended. - + Device: Dispositiu: - + This setting selects the GPU to use (Vulkan only). - + Resolution: Resolució: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: Filtre d'adaptació de finestra: - + FSR Sharpness: Nitidesa FSR: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Mètode de suavitzat de vores - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Mode pantalla completa: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. - + Aspect Ratio: Relació d'aspecte: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: Emulació NVDEC: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. - + ASTC Decoding Method: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -651,75 +661,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: Mode de sincronització vertical: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -727,79 +717,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) - + Slightly improves performance by moving presentation to a separate CPU thread. - + Force maximum clocks (Vulkan only) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. - + Anisotropic Filtering: Filtrat anisotròpic: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: Mode de la GPU: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: Precisió DMA: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -808,1290 +798,1290 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. - + Enable Compute Pipelines (Intel Vulkan Only) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. - + Sync to framerate of video playback - + Run the game at normal speed during video playback, even when the framerate is unlocked. - + Barrier feedback loops - + Improves rendering of transparency effects in specific games. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed Llavor de GNA - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name Nom del dispositiu - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: Idioma: - + This option can be overridden when region setting is auto-select - + Region: Regió: - + The region of the console. - + Time Zone: Zona horària: - + The time zone of the console. - + Sound Output Mode: - + Console Mode: Mode de la consola - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity Ocultar el cursor del ratolí en cas d'inactivitat - + Hides the mouse after 2.5s of inactivity. - + Check for updates - + Whether or not to check for updates upon startup. - + Enable Gamemode Activa el mode joc - + Force X11 as Graphics Backend - + Custom frontend - + Real applet - - + + Disabled - + Never Mai - + On Load - + Always Sempre - + CPU CPU - + GPU GPU - + CPU Asynchronous - + Uncompressed (Best quality) - + BC1 (Low quality) - + BC3 (Medium quality) - - + + Auto Auto - + 30 FPS 30 FPS - + 60 FPS 60 FPS - + 90 FPS 90 FPS - + 120 FPS 120 FPS - + Conservative Conservador - + Aggressive Agressiu - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) OpenGL GLASM (Ensamblat d'ombrejadors, només NVIDIA) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V (Experimental, només AMD/Mesa) - + Null Nul - + Fast Ràpid - - - + + + Accurate Precís - - - + + + Default Valor predeterminat - + Unsafe (fast) Insegur (ràpid) - + Safe (stable) Segur (estable) - + Immediate - + Balanced Equilibrat - + Unsafe Insegur - + Paranoid (disables most optimizations) Paranoic (desactiva la majoria d'optimitzacions) - + Debugging Depuració - + Dynarmic Dynarmic - + NCE NCE - + Borderless Windowed Finestra sense vores - + Exclusive Fullscreen Pantalla completa exclusiva - + No Video Output Sense sortida de vídeo - + CPU Video Decoding Descodificació de vídeo a la CPU - + GPU Video Decoding (Default) Descodificació de vídeo a la GPU (Valor predeterminat) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [EXPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [EXPERIMENTAL] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [EXPERIMENTAL] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Veí més proper - + Bilinear Bilineal - + Bicubic Bicúbic - + Gaussian Gaussià - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution Super resolució AMD FidelityFX - + Area Àrea - + MMPX MMPX - + Zero-Tangent Tangència zero - + B-Spline B-Spline - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Cap - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Valor predeterminat (16:9) - + Force 4:3 Forçar 4:3 - + Force 21:9 Forçar 21:9 - + Force 16:10 - + Stretch to Window Estirar a la finestra - + Automatic Automàtic - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Japonès (日本語) - + American English Anglès americà - + French (français) Francès (français) - + German (Deutsch) Alemany (Deutsch) - + Italian (italiano) Italià (italiano) - + Spanish (español) Castellà (español) - + Chinese Xinès - + Korean (한국어) Coreà (한국어) - + Dutch (Nederlands) Holandès (Nederlands) - + Portuguese (português) Portuguès (português) - + Russian (Русский) Rus (Русский) - + Taiwanese Taiwanès - + British English Anglès britànic - + Canadian French Francès canadenc - + Latin American Spanish Espanyol llatinoamericà - + Simplified Chinese Xinès simplificat - + Traditional Chinese (正體中文) Xinès tradicional (正體中文) - + Brazilian Portuguese (português do Brasil) Portuguès brasiler (português do Brasil) - + Polish (polska) Polonès (polska) - + Thai (แบบไทย) Tailandès (แบบไทย) - - + + Japan Japó - + USA EUA - + Europe Europa - + Australia Austràlia - + China Xina - + Korea Corea - + Taiwan Taiwan - + Auto (%1) Auto select time zone Auto (%1) - + Default (%1) Default time zone Per defecte (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Egipte - + Eire Eire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hong Kong - + HST HST - + Iceland Islàndia - + Iran Iran - + Israel Isreal - + Jamaica Jamaica - + Kwajalein Kwajalein - + Libya Líbia - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polònia - + Portugal Portugal - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapur - + Turkey Turquia - + UCT UCT - + Universal Universal - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Estèreo - + Surround Envoltant - + 4GB DRAM (Default) 4GB DRAM (Insegur) - + 6GB DRAM (Unsafe) 6GB DRAM (Insegur) - + 8GB DRAM 8GB DRAM - + 10GB DRAM (Unsafe) 10GB DRAM (Insegur) - + 12GB DRAM (Unsafe) 12GB DRAM (Insegur) - + Docked Sobretaula - + Handheld Portàtil - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) - + Only if game specifies not to stop Tan sols si el joc especifica no parar - + Never ask No preguntar mai - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) - + High (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6042,50 +6032,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL no disponible! - + OpenGL shared contexts are not supported. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! Error al inicialitzar OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. La seva GPU no suporta OpenGL, o no té instal·lat els últims controladors gràfics. - + Error while initializing OpenGL 4.6! Error inicialitzant OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 La seva GPU no suporta OpenGL 4.6, o no té instal·lats els últims controladors gràfics.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 És possible que la seva GPU no suporti una o més extensions necessàries d'OpenGL. Si us plau, asseguris de tenir els últims controladors de la tarjeta gràfica.<br><br>GL Renderer:<br>%1<br><br>Extensions no suportades:<br>%2 - + This build doesn't have OpenGL support. Aquesta compilació no té suport per a OpenGL. @@ -6851,1132 +6841,1152 @@ Debug Message: &Emulació - + + &Cheats + + + + &View &Veure - + &Reset Window Size &Reiniciar tamany de finestra - + &Debugging &Depuració - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p Reiniciar el tamany de la finestra a &720p - + Reset Window Size to 720p Reiniciar el tamany de la finestra a 720p - + Reset Window Size to &900p Reiniciar el tamany de la finestra a &900p - + Reset Window Size to 900p Reiniciar el tamany de la finestra a 900p - + Reset Window Size to &1080p Reiniciar el tamany de la finestra a &1080p - + Reset Window Size to 1080p Reiniciar el tamany de la finestra a 1080p - + &Multiplayer - + &Tools &Eines - + Am&iibo - + Launch &Applet - + &TAS &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help &Ajuda - + &Install Files to NAND... &instal·lar arxius a la NAND... - + L&oad File... C&arregar arxiu... - + Load &Folder... Carregar &carpeta... - + E&xit S&ortir - - + + &Pause &Pausar - + &Stop &Aturar - + &Verify Installed Contents - + &About Eden - + Single &Window Mode Mode una sola &finestra - + Con&figure... Con&figurar... - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar Mostrar la barra de &filtre - + Show &Status Bar Mostrar la barra d'&estat - + Show Status Bar Mostrar barra d'estat - + &Browse Public Game Lobby - + &Create Room - + &Leave Room - + &Direct Connect to Room - + &Show Current Room - + F&ullscreen P&antalla completa - + &Restart &Reiniciar - + Load/Remove &Amiibo... Carregar/Eliminar &Amiibo... - + Open &Mods Page Obrir la pàgina de &mods - + &User Handbook - + &Capture Screenshot &Captura de pantalla - + &Album - + &Set Nickname and Owner - + &Delete Game Data - + &Restore Amiibo - + &Format Amiibo - + &Mii Editor Editor de &Mii - + &Configure TAS... &Configurar TAS... - + Configure C&urrent Game... Configurar joc a&ctual... - - + + &Start &Iniciar - + &Reset &Reiniciar - - + + R&ecord E&nregistrar - + Open &Controller Menu - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None Cap - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) Petit (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute Desilenciar - + Mute Silenciar - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) (64-bit) - - + + (32-bit) (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full Complet - + Skeleton Esquelet - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel Cancel·lar - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties Propietats - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File Carregar arxiu - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files Instal·lar arxius - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game Joc - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK D'acord - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor Escala: %1x - + Speed: %1% / %2% Velocitat: %1% / %2% - + Speed: %1% Velocitat: %1% - + Game: %1 FPS Joc: %1 FPS - + Frame: %1 ms Fotograma: %1 ms - + NO AA SENSE AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) VOLUMEN: %1% - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -7984,74 +7994,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow Lent - + Turbo Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/cs.ts b/dist/languages/cs.ts index abbc0b4db0..25fea3b56e 100644 --- a/dist/languages/cs.ts +++ b/dist/languages/cs.ts @@ -30,7 +30,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> @@ -397,252 +397,262 @@ Can help reduce stuttering at lower framerates. - - Accuracy: - Přesnost: - - - - Change the accuracy of the emulated CPU (for debugging only). + + Enable cheats by default - - - Backend: + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + Accuracy: + Přesnost: + + + + Change the accuracy of the emulated CPU (for debugging only). + + + + + + Backend: + + + + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) Rozložit FMA instrukce (zlepší výkon na CPU bez FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. - + Faster FRSQRTE and FRECPE Rychlejší FRSQRTE a FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. - + Faster ASIMD instructions (32 bits only) Rychlejší instrukce ASIMD (Pouze 32 bitové) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. - + Inaccurate NaN handling Nepřesné zpracování NaN - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. - + Disable address space checks Zakázat kontrolu adres paměti - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor Ignorovat globální hlídač. - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. - + API: API: - + Changes the output graphics API. Vulkan is recommended. - + Device: Zařízení: - + This setting selects the GPU to use (Vulkan only). - + Resolution: Rozlišení: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: - + FSR Sharpness: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Režim celé obrazovky: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. - + Aspect Ratio: Poměr stran: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. - + ASTC Decoding Method: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -651,75 +661,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -727,79 +717,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) - + Slightly improves performance by moving presentation to a separate CPU thread. - + Force maximum clocks (Vulkan only) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. - + Anisotropic Filtering: Anizotropní filtrování: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -808,1290 +798,1290 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. - + Enable Compute Pipelines (Intel Vulkan Only) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. - + Sync to framerate of video playback - + Run the game at normal speed during video playback, even when the framerate is unlocked. - + Barrier feedback loops - + Improves rendering of transparency effects in specific games. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed RNG Seed - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name Název Zařízení - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: Jazyk: - + This option can be overridden when region setting is auto-select - + Region: Region: - + The region of the console. - + Time Zone: Časové Pásmo: - + The time zone of the console. - + Sound Output Mode: - + Console Mode: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation Potvrzení před zastavením emulace - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity Skrýt myš při neaktivitě - + Hides the mouse after 2.5s of inactivity. - + Check for updates - + Whether or not to check for updates upon startup. - + Enable Gamemode - + Force X11 as Graphics Backend - + Custom frontend - + Real applet - - + + Disabled - + Never - + On Load - + Always - + CPU CPU - + GPU - + CPU Asynchronous - + Uncompressed (Best quality) - + BC1 (Low quality) - + BC3 (Medium quality) - - + + Auto Automatické - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative - + Aggressive - + Vulkan Vulkan - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null - + Fast - - - + + + Accurate Přesné - - - + + + Default Výchozí - + Unsafe (fast) - + Safe (stable) - + Immediate - + Balanced - + Unsafe Nebezpečné - + Paranoid (disables most optimizations) Paranoidní (zakáže většinu optimizací) - + Debugging - + Dynarmic - + NCE - + Borderless Windowed Okno bez okrajů - + Exclusive Fullscreen Exkluzivní - + No Video Output - + CPU Video Decoding - + GPU Video Decoding (Default) - + 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] - + 2X (1440p/2160p) - + 3X (2160p/3240p) - + 4X (2880p/4320p) - + 5X (3600p/5400p) - + 6X (4320p/6480p) - + 7X (5040p/7560p) - + 8X (5760p/8640p) - + Nearest Neighbor - + Bilinear Bilineární - + Bicubic - + Gaussian - + Lanczos - + ScaleForce - + AMD FidelityFX Super Resolution - + Area - + MMPX - + Zero-Tangent - + B-Spline - + Mitchell - + Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Žádné - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Výchozí (16:9) - + Force 4:3 Vynutit 4:3 - + Force 21:9 Vynutit 21:9 - + Force 16:10 - + Stretch to Window Roztáhnout podle okna - + Automatic - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Japonština (日本語) - + American English - + French (français) Francouzština (français) - + German (Deutsch) Nemčina (Deutsch) - + Italian (italiano) Italština (Italiano) - + Spanish (español) Španělština (español) - + Chinese Čínština - + Korean (한국어) Korejština (한국어) - + Dutch (Nederlands) Holandština (Nederlands) - + Portuguese (português) Portugalština (português) - + Russian (Русский) Ruština (Русский) - + Taiwanese Tajwanština - + British English Britská Angličtina - + Canadian French Kanadská Francouzština - + Latin American Spanish Latinsko Americká Španělština - + Simplified Chinese Zjednodušená Čínština - + Traditional Chinese (正體中文) Tradiční Čínština (正體中文) - + Brazilian Portuguese (português do Brasil) Brazilská Portugalština (português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan Japonsko - + USA USA - + Europe Evropa - + Australia Austrálie - + China Čína - + Korea Korea - + Taiwan Taiwan - + Auto (%1) Auto select time zone - + Default (%1) Default time zone - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Egypt - + Eire Eire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Island - + Iran Iran - + Israel Israel - + Jamaica Jamajka - + Kwajalein Kwajalein - + Libya Lybie - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polsko - + Portugal Portugalsko - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapur - + Turkey Turecko - + UCT UCT - + Universal Univerzální - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Stereo - + Surround Surround - + 4GB DRAM (Default) - + 6GB DRAM (Unsafe) - + 8GB DRAM - + 10GB DRAM (Unsafe) - + 12GB DRAM (Unsafe) - + Docked Zadokovaná - + Handheld Příruční - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) Vždy se zeptat (Výchozí) - + Only if game specifies not to stop - + Never ask - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) - + High (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6033,50 +6023,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL není k dispozici! - + OpenGL shared contexts are not supported. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! Chyba při inicializaci OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Vaše grafická karta pravděpodobně nepodporuje OpenGL nebo nejsou nainstalovány nejnovější ovladače. - + Error while initializing OpenGL 4.6! Chyba při inicializaci OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Vaše grafická karta pravděpodobně nepodporuje OpenGL 4.6 nebo nejsou nainstalovány nejnovější ovladače.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Vaše grafická karta pravděpodobně nepodporuje jedno nebo více rozšíření OpenGL. Ujistěte se prosím, že jsou nainstalovány nejnovější ovladače.<br><br>GL Renderer:<br>%1<br><br>Nepodporované rozšíření:<br>%2 - + This build doesn't have OpenGL support. @@ -6841,1132 +6831,1152 @@ Debug Message: &Emulace - + + &Cheats + + + + &View &Pohled - + &Reset Window Size &Resetovat Velikost Okna - + &Debugging &Ladění - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p Nastavit velikost okna na &720p - + Reset Window Size to 720p Nastavit velikost okna na 720p - + Reset Window Size to &900p Resetovat Velikost Okna na &900p - + Reset Window Size to 900p Resetovat Velikost Okna na 900p - + Reset Window Size to &1080p Nastavit velikost okna na &1080p - + Reset Window Size to 1080p Nastavit velikost okna na 1080p - + &Multiplayer - + &Tools &Nástroje - + Am&iibo - + Launch &Applet - + &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help &Pomoc - + &Install Files to NAND... &Instalovat soubory na NAND... - + L&oad File... Načís&t soubor... - + Load &Folder... Načíst sl&ožku... - + E&xit E&xit - - + + &Pause &Pauza - + &Stop &Stop - + &Verify Installed Contents &Ověřit Nainstalovaný Obsah - + &About Eden - + Single &Window Mode &Režim jednoho okna - + Con&figure... &Nastavení - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar Zobrazit &filtrovací panel - + Show &Status Bar Zobrazit &stavový řádek - + Show Status Bar Zobrazit Staus Bar - + &Browse Public Game Lobby - + &Create Room &Vytvořit Místnost - + &Leave Room &Opustit Místnost - + &Direct Connect to Room - + &Show Current Room - + F&ullscreen &Celá obrazovka - + &Restart &Restartovat - + Load/Remove &Amiibo... - + Open &Mods Page Otevřít stránku s &modifikacemi - + &User Handbook - + &Capture Screenshot Za&chytit snímek obrazovky - + &Album - + &Set Nickname and Owner &Nastavit Přezdívku a Vlastníka - + &Delete Game Data &Odstranit Herní Data - + &Restore Amiibo &Obnovit Amiibo - + &Format Amiibo - + &Mii Editor - + &Configure TAS... - + Configure C&urrent Game... Nastavení současné hry - - + + &Start &Start - + &Reset &Resetovat - - + + R&ecord - + Open &Controller Menu Otevřít &Menu Ovladače - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -7974,74 +7984,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/da.ts b/dist/languages/da.ts index 4e34f94af9..d96fd013f6 100644 --- a/dist/languages/da.ts +++ b/dist/languages/da.ts @@ -30,7 +30,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> @@ -399,252 +399,262 @@ Can help reduce stuttering at lower framerates. - - Accuracy: - Nøjagtighed - - - - Change the accuracy of the emulated CPU (for debugging only). + + Enable cheats by default - - - Backend: + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + Accuracy: + Nøjagtighed + + + + Change the accuracy of the emulated CPU (for debugging only). + + + + + + Backend: + + + + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) Adskil FMA (forbedr ydeevne på CPUer uden FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. - + Faster FRSQRTE and FRECPE Hurtigere FRSQRTE og FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. - + Faster ASIMD instructions (32 bits only) Hurtigere ASIMD-instrukser (kun 32-bit) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. - + Inaccurate NaN handling Unøjagtig NaN-håndtering - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. - + Disable address space checks Deaktivér adresseplads-kontrol - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor Ignorér global overvågning - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. - + API: API: - + Changes the output graphics API. Vulkan is recommended. - + Device: Enhed: - + This setting selects the GPU to use (Vulkan only). - + Resolution: Opløsning: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: Vinduestilpassende Filter: - + FSR Sharpness: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Anti-Aliaseringsmetode: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Fuldskærmstilstand: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. - + Aspect Ratio: Skærmformat: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: NVDEC-emulering: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. - + ASTC Decoding Method: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -653,75 +663,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -729,79 +719,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) - + Slightly improves performance by moving presentation to a separate CPU thread. - + Force maximum clocks (Vulkan only) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. - + Anisotropic Filtering: Anisotropisk Filtrering: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -810,1290 +800,1290 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. - + Enable Compute Pipelines (Intel Vulkan Only) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. - + Sync to framerate of video playback - + Run the game at normal speed during video playback, even when the framerate is unlocked. - + Barrier feedback loops - + Improves rendering of transparency effects in specific games. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed RNG-Seed - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: - + This option can be overridden when region setting is auto-select - + Region: Region - + The region of the console. - + Time Zone: Tidszone - + The time zone of the console. - + Sound Output Mode: - + Console Mode: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity Skjul mus ved inaktivitet - + Hides the mouse after 2.5s of inactivity. - + Check for updates - + Whether or not to check for updates upon startup. - + Enable Gamemode - + Force X11 as Graphics Backend - + Custom frontend - + Real applet - - + + Disabled - + Never - + On Load - + Always - + CPU CPU - + GPU - + CPU Asynchronous - + Uncompressed (Best quality) - + BC1 (Low quality) - + BC3 (Medium quality) - - + + Auto Automatisk - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative - + Aggressive - + Vulkan - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null - + Fast - - - + + + Accurate Nøjagtig - - - + + + Default Standard - + Unsafe (fast) - + Safe (stable) - + Immediate - + Balanced - + Unsafe Usikker - + Paranoid (disables most optimizations) Paranoid (deaktiverer de fleste optimeringer) - + Debugging - + Dynarmic - + NCE - + Borderless Windowed Uindrammet Vindue - + Exclusive Fullscreen Eksklusiv Fuld Skærm - + No Video Output Ingen Video-Output - + CPU Video Decoding CPU-Video Afkodning - + GPU Video Decoding (Default) GPU-Video Afkodning (Standard) - + 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0,75X (540p/810p) [EKSPERIMENTEL] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) - + 8X (5760p/8640p) - + Nearest Neighbor Nærmeste Nabo - + Bilinear Bilineær - + Bicubic Bikubisk - + Gaussian Gausisk - + Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution - + Area - + MMPX - + Zero-Tangent - + B-Spline - + Mitchell - + Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Ingen - + FXAA FXAA - + SMAA - + Default (16:9) Standard (16:9) - + Force 4:3 Tving 4:3 - + Force 21:9 Tving 21:9 - + Force 16:10 - + Stretch to Window Stræk til Vindue - + Automatic - + 2x - + 4x - + 8x - + 16x - + Japanese (日本語) Japansk (日本語) - + American English - + French (français) Fransk (français) - + German (Deutsch) Tysk (Deutsch) - + Italian (italiano) Italiensk (italiano) - + Spanish (español) Spansk (español) - + Chinese Kinesisk - + Korean (한국어) Koreansk (한국어) - + Dutch (Nederlands) Hollandsk (Nederlands) - + Portuguese (português) Portugisisk (português) - + Russian (Русский) Russisk (Русский) - + Taiwanese Taiwanesisk - + British English Britisk Engelsk - + Canadian French Candadisk Fransk - + Latin American Spanish Latinamerikansk Spansk - + Simplified Chinese Forenklet Kinesisk - + Traditional Chinese (正體中文) Traditionelt Kinesisk (正體中文) - + Brazilian Portuguese (português do Brasil) Braziliansk Portugisisk (português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan Japan - + USA USA - + Europe Europa - + Australia Australien - + China Kina - + Korea Korea - + Taiwan Taiwan - + Auto (%1) Auto select time zone - + Default (%1) Default time zone - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Ægypten - + Eire Eire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Island - + Iran Iran - + Israel Israel - + Jamaica Jamaica - + Kwajalein Kwajalein - + Libya Libyen - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polen - + Portugal Portugal - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapore - + Turkey Tyrkiet - + UCT UCT - + Universal Universel - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Stereo - + Surround Surround - + 4GB DRAM (Default) - + 6GB DRAM (Unsafe) - + 8GB DRAM - + 10GB DRAM (Unsafe) - + 12GB DRAM (Unsafe) - + Docked Dokket - + Handheld Håndholdt - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) - + Only if game specifies not to stop - + Never ask - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) - + High (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6041,50 +6031,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! - + OpenGL shared contexts are not supported. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 - + This build doesn't have OpenGL support. @@ -6849,1132 +6839,1152 @@ Debug Message: &Emulering - + + &Cheats + + + + &View - + &Reset Window Size - + &Debugging - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p - + Reset Window Size to 720p - + Reset Window Size to &900p - + Reset Window Size to 900p - + Reset Window Size to &1080p - + Reset Window Size to 1080p - + &Multiplayer - + &Tools - + Am&iibo - + Launch &Applet - + &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help &Hjælp - + &Install Files to NAND... - + L&oad File... - + Load &Folder... - + E&xit - - + + &Pause - + &Stop - + &Verify Installed Contents - + &About Eden - + Single &Window Mode - + Con&figure... - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar - + Show &Status Bar - + Show Status Bar Vis Statuslinje - + &Browse Public Game Lobby - + &Create Room - + &Leave Room - + &Direct Connect to Room - + &Show Current Room - + F&ullscreen - + &Restart - + Load/Remove &Amiibo... - + Open &Mods Page - + &User Handbook - + &Capture Screenshot - + &Album - + &Set Nickname and Owner - + &Delete Game Data - + &Restore Amiibo - + &Format Amiibo - + &Mii Editor - + &Configure TAS... - + Configure C&urrent Game... - - + + &Start - + &Reset - - + + R&ecord - + Open &Controller Menu - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -7982,74 +7992,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/de.ts b/dist/languages/de.ts index a911437c44..6cbfc362c3 100644 --- a/dist/languages/de.ts +++ b/dist/languages/de.ts @@ -37,8 +37,8 @@ li.checked::marker { content: „\2612“; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Webseite</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Quell-Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Mitwirkende</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Hermelin</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Lizenz</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -411,149 +411,159 @@ Can help reduce stuttering at lower framerates. Kann dazu beitragen, Ruckler bei niedrigeren Bildraten zu reduzieren. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Genauigkeit der Emulation: - + Change the accuracy of the emulated CPU (for debugging only). Ändere die Genauigkeit der emulierten CPU (ausschließlich für debugging). - - + + Backend: Backend: - + CPU Clocks CPU-Takte - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. Erhöht den Takt der emulierten CPU Berichte, was manche FPS-Begrenzer entfernt. Schwächere CPUs haben eventuell schlechtere Leistung, und bestimmte Spiele verhalten vielleicht sich nicht richtig. - + Custom CPU Ticks Benutzerdefinierte CPU-Ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. Lege einen benutzerdefinierten Wert für die CPU-Ticks fest. Höhere Werte können die Leistung steigern, jedoch auch zu Verklemmungen führen. Es wird ein Bereich von 77 bis 21000 empfohlen. - + Enable Host MMU Emulation (fastmem) Host-MMU-Emulation aktivieren (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. Diese Optimierung beschleunigt Speicherzugriffe durch das Gastprogramm. Wenn aktiviert, erfolgen Speicherlese- und -schreibvorgänge des Gastes direkt im Speicher und nutzen die MMU des Hosts. Das Deaktivieren erzwingt die Verwendung der Software-MMU-Emulation für alle Speicherzugriffe. - + Unfuse FMA (improve performance on CPUs without FMA) Unfuse FMA (erhöht Leistung auf CPUs ohne FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Diese Option verbessert die Geschwindigkeit, indem die Genauigkeit von "Fused-Multiply-Add"-Anweisungen auf CPUs ohne native FMA-Unterstützung reduziert wird. - + Faster FRSQRTE and FRECPE Schnelleres FRSQRTE und FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Diese Option verbessert die Geschwindigkeit einiger ungenauen Fließkomma-Funktionen, indem weniger genaue native Annäherungen benutzt werden. - + Faster ASIMD instructions (32 bits only) Schnellere ASIMD-Instruktionen (nur 32-Bit) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Diese Option verbessert die Geschwindigkeit von 32-Bit-ASIMD-Fließkomma-Funktionen, indem diese mit inkorrekten Rundungsmodi ausgeführt werden. - + Inaccurate NaN handling Ungenaue NaN-Verarbeitung - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Diese Option verbessert die Geschwindigkeit durch Wegfall der NaN-Prüfung. Bitte beachte, dass dies auch die Genauigkeit bestimmter Gleitkommaoperationen verringert. - + Disable address space checks Adressraumprüfungen deaktivieren - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. Diese Option verbessert die Geschwindigkeit, indem sie eine Sicherheitsprüfung vor jedem Speicherzugriff überspringt. Wird sie deaktiviert, kann dies zur Ausführung von beliebigem Code führen. - + Ignore global monitor Globalen Monitor ignorieren - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Diese Option erhöht die Geschwindigkeit, indem sie sich ausschließlich auf die Semantik von `cmpxchg` stützt, um die Sicherheit von Befehlen für exklusiven Zugriff zu gewährleisten. Bitte beachte, dass dies zu Verklemmungen und anderen Race Conditions führen kann. - + API: API: - + Changes the output graphics API. Vulkan is recommended. Ändert die Ausgabe-Grafik-API. Vulkan wird empfohlen. - + Device: Gerät: - + This setting selects the GPU to use (Vulkan only). Diese Einstellung wählt aus welche Grafikkarte benutzt werden soll (Nur Vulkan). - + Resolution: Auflösung: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -562,27 +572,27 @@ Höhere Auflösungen erfordern mehr VRAM und Bandbreite. Optionen unter 1x können Artefakte verursachen. - + Window Adapting Filter: Bildschirmanpassungsfilter: - + FSR Sharpness: FSR-Schärfe: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. Legt fest, wie scharf das Bild mithilfe des dynamischen Kontrasts von FSR oder SGSR dargestellt wird. - + Anti-Aliasing Method: Kantenglättungs-Methode: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -591,22 +601,22 @@ SMAA bietet die beste Bildqualität. FXAA liefert bei niedrigeren Auflösungen ein stabileres Bild. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Vollbild-Modus: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -615,12 +625,12 @@ Der randlose Modus bietet die beste Kompatibilität mit der Bildschirmtastatur, Der exklusive Vollbildmodus bietet möglicherweise eine bessere Leistung und eine bessere Freesync-/G-Sync-Unterstützung. - + Aspect Ratio: Seitenverhältnis: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -629,36 +639,36 @@ Die meisten Spiele unterstützen nur das Seitenverhältnis 16:9, sodass Anpassun Steuert außerdem das Seitenverhältnis der aufgenommenen Bildschirmfotos. - + Use persistent pipeline cache Persistenten Rohrleitungs-Cache verwenden - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Ermöglicht das Speichern von Shadern, um sie beim nächsten Spielstart schneller laden zu können. Die Deaktivierung ist ausschließlich für Fehlerbehebungszwecke vorgesehen. - + Use asynchronous GPU emulation Asynchrone GPU-Emulation verwenden - + Uses an extra CPU thread for rendering. This option should always remain enabled. Verwendet einen zusätzlichen CPU-Thread für das Rendern. Diese Option sollte immer aktiviert bleiben. - + NVDEC emulation: NVDEC-Emulation: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -667,12 +677,12 @@ Dabei kann entweder die CPU oder die GPU für die Dekodierung verwendet werden, In den meisten Fällen bietet die GPU-Dekodierung die beste Leistung. - + ASTC Decoding Method: ASTC-Dekodier-Methode: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -685,12 +695,12 @@ CPU asynchron: Die Dekodierung von ASTC-Texturen erfolgt bei Bedarf über die CP kann jedoch zu Artefakten führen. - + ASTC Recompression Method: ASTC-Rekompression-Methode: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. @@ -699,64 +709,44 @@ BC1/BC3: Das Zwischenformat wird wieder in das BC1- oder BC3-Format komprimiert, was VRAM spart, jedoch zu Einbußen bei der Bildqualität führt. - + Frame Pacing Mode (Vulkan only) Frame-Pacing-Modus (nur Vulkan) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. Steuert, wie der Emulator das Frame-Pacing verwaltet, um Ruckeln zu reduzieren und die Bildrate flüssiger und gleichmäßiger zu gestalten. - + VRAM Usage Mode: VRAM-Nutzungs Modus: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. Legt fest, ob der Emulator vorrangig Speicherplatz sparen oder den verfügbaren Grafikspeicher zur Leistungsoptimierung maximal ausnutzen soll. Der aggressive Modus kann die Leistung anderer Anwendungen, wie z. B. Aufnahmesoftware, beeinträchtigen. - + Skip CPU Inner Invalidation CPU-interne Invalidierung überspringen - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. Überspringt bestimmte Cache-Invalidierungen auf CPU-Seite während Speicherupdates, reduziert die CPU-Auslastung und verbessert die Leistung. Dies verursacht vielleicht Abstürze. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: VSync-Modus: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -767,12 +757,12 @@ Postkasten kann eine geringere Latenz als FIFO aufweisen und verursacht kein Tea Sofort (ohne Synchronisation) zeigt alles an, was verfügbar ist, und kann Tearing verursachen. - + Sync Memory Operations Speicheroperationen synchronisieren - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. @@ -781,44 +771,44 @@ Diese Option behebt Probleme in Spielen, kann jedoch zu Leistungseinbußen führ Bei Spielen mit Unreal Engine 4 sind die Auswirkungen oft am deutlichsten spürbar. - + Enable asynchronous presentation (Vulkan only) Aktiviere asynchrone Präsentation (Nur Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. Verbessert die Leistung geringfügig, indem die Darstellung auf einen separaten CPU-Thread verlagert wird. - + Force maximum clocks (Vulkan only) Erzwinge Maximale Taktrate (Vulkan only) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Lässt im Hintergrund die GPU Aufgaben erledigen während diese auf Grafikbefehle wartet, damit diese nicht herunter taktet. - + Anisotropic Filtering: Anisotrope Filterung: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. Steuert die Qualität der Texturwiedergabe bei schrägen Blickwinkeln. Bei den meisten Grafikkarten kann dieser Wert bedenkenlos auf 16x eingestellt werden. - + GPU Mode: GPU-Modus: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. @@ -827,12 +817,12 @@ Die meisten Spiele werden im Modus Schnell in Ordnung gerendert, für einige ist Partikel werden in der Regel nur im Modus Akkurat korrekt gerendert. - + DMA Accuracy: DMA-Genauigkeit: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. @@ -841,12 +831,12 @@ Unsicher ist schneller, während Sicher stabiler ist und in manchen Spielen Prob Standard folgt der GPU-Genauigkeit Einstellung. - + GPU Fence Behavior: GPU-Zaunobjekt-Verhalten: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -855,44 +845,44 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation Aktiviere asynchrones Shader-Kompilieren - + May reduce shader stutter. Kann Shader-Ruckler reduzieren. - + GPU Clocks GPU-Takte - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. Führt dazu, dass das Spiel glaubt, die Arbeit der GPU würde früher fertig sein, als sie eigentlich ist. Dadurch hört das Spiel auf die Auflösung und Render-Distanz zu verringern um sich den Takten der Switch anzupassen. - + GPU Unswizzle GPU-Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. Beschleunigt die Dekodierung von BCn-3D-Texturen mithilfe von GPU-Rechenleistung. Deaktiviere diese Option, falls Abstürze oder Grafikfehler auftreten. - + GPU Unswizzle Max Texture Size GPU-Unswizzle max. Texturgröße - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. @@ -901,48 +891,48 @@ Während die GPU für mittelgroße und große Texturen schneller ist, kann die C Passen Sie diesen Wert an, um das Gleichgewicht zwischen GPU-Beschleunigung und CPU-Overhead zu finden. - + GPU Unswizzle Stream Size GPU-Unswizzle-Streamgröße - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. Legt die maximale Menge an Texturdaten (in MiB) fest, die pro Bild verarbeitet wird. Höhere Werte können Ruckeln beim Laden von Texturen verringern, können sich jedoch auf die Bildrate auswirken. - + GPU Unswizzle Chunk Size GPU-Unswizzle Chunk-Größe - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. Legt die Anzahl der Tiefenschnitte fest, die in einem einzelnen Durchlauf verarbeitet werden. Eine Erhöhung dieses Werts kann den Durchsatz auf High-End-GPUs verbessern, bei schwächerer Hardware jedoch zu TDR- oder Treiber-Auszeiten führen. - + Use Vulkan pipeline cache Vulkan-Pipeline-Cache verwenden - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. Aktiviert den herstellerspezifischen Pipeline-Cache der GPU. Diese Option kann die Ladezeit von Shadern erheblich verkürzen, wenn der Vulkan-Treiber die Pipeline-Cache-Dateien nicht intern speichert. - + Enable Compute Pipelines (Intel Vulkan Only) Aktiviere Compute-Pipelines (Nur Intel Vulkan) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. @@ -951,182 +941,182 @@ Diese Einstellung ist nur bei proprietären Intel-Treibern vorhanden und kann be Bei allen anderen Treibern sind die Rechen-Rohrleitungen immer aktiviert. - + Enable Reactive Flushing Aktiviere Reactives Flushing - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Benutzt Reactive-Flushing anstatt Predictive-Flushing, welches akkurateres Speicher-Synchronisieren erlaubt. - + Sync to framerate of video playback Synchronisiere mit Bildrate von Video-Wiedergaben - + Run the game at normal speed during video playback, even when the framerate is unlocked. Lasse das Spiel in der normalen Geschwindigkeit abspielen, trotz freigeschalteter Bildrate - + Barrier feedback loops Barrier-Feedback-Schleifen - + Improves rendering of transparency effects in specific games. Verbessert das Rendering von Transparenzeffekten in bestimmten Spielen. - + Enable buffer history Puffer-Verlauf aktivieren - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. Ermöglicht den Zugriff auf frühere Pufferzustände. Diese Option kann in manchen Spielen die Darstellungsqualität und die Leistungsstabilität verbessern. - + Fix bloom effects Bloom-Effekte beheben - + Removes bloom in Burnout. Entfernt Bloom in Burnout. - + Extended Dynamic State Erweiterter dynamischer Zustand - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. Legt die Anzahl der Funktionen fest, die im erweiterten dynamischen Modus verwendet werden können. Höhere Stufen ermöglichen mehr Funktionen und können die Leistung steigern, können jedoch zusätzliche grafische Probleme verursachen. - + Vertex Input Dynamic State Dynamischer Zustand der Scheitelpunkteingabe - + Enables vertex input dynamic state feature for better quality and performance. Aktiviert die Funktion für den dynamischen Status der Scheitelpunkteingabe, um eine bessere Qualität und Leistung zu erzielen. - + Sample Shading Probe-Schattierung - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. Ermöglicht es dem Fragment-Shader, pro Abtastwert in einem mehrfach abgetasteten Fragment ausgeführt zu werden, anstatt nur einmal pro Fragment. Verbessert die Grafikqualität auf Kosten der Leistung. Höhere Werte verbessern die Qualität, beeinträchtigen jedoch die Leistung. - + RNG Seed Startwert für den Zufallszahlengenerator - + Controls the seed of the random number generator. Mainly used for speedrunning. Steuert den Startwert des Zufallszahlengenerators. Wird hauptsächlich für Schnelldurchläufe verwendet. - + Device Name Gerätename - + The name of the console. Der Name der Konsole. - + Homebrew Args Homebrew-Argumente - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). Befehlszeilenargumente, die beim Start an Homebrew übergeben werden (z. B. -noglsl). - + Custom RTC Date: Benutzerdefinierte Echtzeituhrdatum: - + This option allows to change the clock of the console. Can be used to manipulate time in games. Diese Option erlaubt die Änderung der Uhr der Konsole. Kann benutzt werden um Zeit in Spielen zu manipulieren. - + The number of seconds from the current unix time Die Anzahl der Sekunden seit dem aktuellen Unix-Zeitstempel - + Language: Sprache: - + This option can be overridden when region setting is auto-select Diese Option kann überschrieben werden, wenn die Regionseinstellung auf „Automatische Auswahl“ steht - + Region: Region: - + The region of the console. Die Region der Konsole. - + Time Zone: Zeitzone: - + The time zone of the console. Die Zeitzone der Konsole. - + Sound Output Mode: Tonausgangsmodus: - + Console Mode: Konsolenmodus: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. @@ -1135,1026 +1125,1026 @@ Je nach dieser Einstellung ändern sich bei Spielen die Auflösung, die Detailst Die Einstellung auf „Handgerät“ kann dazu beitragen, die Leistung auf Systemen mit geringerer Leistung zu verbessern. - + Prompt for user profile on boot Beim Systemstart nach dem Benutzerprofil fragen - + Useful if multiple people use the same PC. Nützlich, wenn mehrere Personen denselben PC nutzen. - + Pause when not in focus Pausieren, wenn nicht im Fokus - + Pauses emulation when focusing on other windows. Pausiert die Emulation, wenn der Fokus auf andere Fenster wechselt. - + Confirm before stopping emulation Vor dem Stoppen der Emulation bestätigen - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. Überschreibt die Abfragen zur Bestätigung des Beendens der Emulation. Wenn diese Option aktiviert ist, werden solche Abfragen umgangen und die Emulation wird direkt beendet. - + Hide mouse on inactivity Mauszeiger verbergen - + Hides the mouse after 2.5s of inactivity. Verbirgt den Mauszeiger nach 2,5 Sekunden Inaktivität. - + Check for updates Auf Aktualisierungen überprüfen - + Whether or not to check for updates upon startup. Ob nach Aktualisierungen während des Startens gesucht werden soll. - + Enable Gamemode Spielmodus aktivieren - + Force X11 as Graphics Backend X11 als Grafik-Backend erzwingen - + Custom frontend Benutzerdefiniertes Frontend - + Real applet Echtes Applet - - + + Disabled Deaktiviert - + Never Niemals - + On Load Beim Laden - + Always Immer - + CPU CPU - + GPU GPU - + CPU Asynchronous CPU Asynchron - + Uncompressed (Best quality) Unkomprimiert (Beste Qualität) - + BC1 (Low quality) BC1 (Niedrige Qualität) - + BC3 (Medium quality) BC3 (Mittlere Qualität) - - + + Auto Auto - + 30 FPS 30 BpS - + 60 FPS 60 BpS - + 90 FPS 90 BpS - + 120 FPS 120 BpS - + Conservative Konservativ - + Aggressive Aggressiv - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) OpenGL GLASM (Assembler-Shader, nur NVIDIA) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V (experimentell, nur AMD/Mesa) - + Null Null - + Fast Schnell - - - + + + Accurate Akkurat - - - + + + Default Vorgabe - + Unsafe (fast) Unsicher (schnell) - + Safe (stable) Sicher (stabil) - + Immediate Direkt - + Balanced Ausgeglichen - + Unsafe Unsicher - + Paranoid (disables most optimizations) Paranoid (deaktiviert die meisten Optimierungen) - + Debugging Fehlerbehebung - + Dynarmic Dynarmic - + NCE NCE - + Borderless Windowed Rahmenloses Fenster - + Exclusive Fullscreen Exklusiver Vollbildmodus - + No Video Output Keine Videoausgabe - + CPU Video Decoding CPU Video Dekodierung - + GPU Video Decoding (Default) GPU Video Dekodierung (Standard) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [EXPERIMENTELL] - + 0.5X (360p/540p) [EXPERIMENTAL] 0,5X (360p/540p) [EXPERIMENTELL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0,75X (540p/810p) [EXPERIMENTELL] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [EXPERIMENTELL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1,5X (1080p/1620p) [EXPERIMENTELL] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Nearest-Neighbor - + Bilinear Bilinear - + Bicubic Bikubisch - + Gaussian Gaussian - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX Super-Auflösung - + Area Bereich - + MMPX MMPX - + Zero-Tangent Nulltangente - + B-Spline B-Spline - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution Snapdragon Spiel-Superauflösung - + Snapdragon Game Super Resolution EdgeDir Snapdragon Spiel-Superauflösung EdgeDir - + None Keiner - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Vorgabe (16:9) - + Force 4:3 4:3 erzwingen - + Force 21:9 21:9 erzwingen - + Force 16:10 16:10 erzwingen - + Stretch to Window Auf Fenster anpassen - + Automatic Automatisch - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Japanisch (日本語) - + American English Amerikanisches Englisch - + French (français) Französisch (français) - + German (Deutsch) Deutsch (German) - + Italian (italiano) Italienisch (italiano) - + Spanish (español) Spanisch (español) - + Chinese Chinesisch - + Korean (한국어) Koreanisch (한국어) - + Dutch (Nederlands) Niederländisch (Nederlands) - + Portuguese (português) Portugiesisch (português) - + Russian (Русский) Russisch (Русский) - + Taiwanese Taiwanesisch - + British English Britisches Englisch - + Canadian French Kanadisches Französisch - + Latin American Spanish Lateinamerikanisches Spanisch - + Simplified Chinese Vereinfachtes Chinesisch - + Traditional Chinese (正體中文) Traditionelles Chinesisch (正體中文) - + Brazilian Portuguese (português do Brasil) Brasilianisches Portugiesisch (português do Brasil) - + Polish (polska) Polnisch (Polen) - + Thai (แบบไทย) Thailändisch (Thailändische Version) - - + + Japan Japan - + USA USA - + Europe Europa - + Australia Australien - + China China - + Korea Korea - + Taiwan Taiwan - + Auto (%1) Auto select time zone Automatisch (%1) - + Default (%1) Default time zone Standard (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Kuba - + EET EET - + Egypt Ägypten - + Eire Eire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Island - + Iran Iran - + Israel Israel - + Jamaica Jamaika - + Kwajalein Kwajalein - + Libya Libyen - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polen - + Portugal Portugal - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapur - + Turkey Türkei - + UCT UCT - + Universal Universal - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Stereo - + Surround Surround - + 4GB DRAM (Default) 4GB DRAM (Vorgabe) - + 6GB DRAM (Unsafe) 6GB DRAM (Unsicher) - + 8GB DRAM 8GB DRAM - + 10GB DRAM (Unsafe) 10GB DRAM (Unsicher) - + 12GB DRAM (Unsafe) 12GB DRAM (Unsicher) - + Docked Angedockt - + Handheld Handgerät - - + + Normal Normal - - + + Boost Beschleunigung - - + + Overclock Übertaktung - + Always ask (Default) Immer fragen (Vorgabe) - + Only if game specifies not to stop Nur wenn ein Spiel vorgibt, nicht zu stoppen - + Never ask Niemals fragen - + Very Small (16 MB) Sehr klein (16 MB) - + Small (32 MB) Klein (32 MB) - + Normal (128 MB) Normal (128 MB) - + Large (256 MB) Groß (256 MB) - + Very Large (512 MB) Sehr groß (512 MB) - + Very Low (4 MB) Sehr niedrig (4 MB) - + Low (8 MB) Niedrig (8 MB) - + Normal (16 MB) Normal (16 MB) - + Medium (32 MB) Mittel (32 MB) - + High (64 MB) Hoch (64 MB) - + Very Low (32) Sehr niedrig (32) - + Low (64) Niedrig (64) - + Normal (128) Normal (128) - + Medium (256) Mittel (256) - + High (512) Hoch (512) - + ExtendedDynamicState 1 ErweiterterDynamischerZustand 1 - + ExtendedDynamicState 2 ErweiterterDynamischerZustand 2 - + ExtendedDynamicState 3 ErweiterterDynamischerZustand 3 - + Tree View Baumansicht - + Grid View Rasteransicht @@ -6126,50 +6116,50 @@ Bitte gehe zu „Konfigurieren“ -> „System“ -> „Netzwerk“ und tr GRenderWindow - - + + OpenGL not available! OpenGL nicht verfügbar! - + OpenGL shared contexts are not supported. Gemeinsame OpenGL-Kontexte werden nicht unterstützt. - + Eden has not been compiled with OpenGL support. Eden wurde nicht mit OpenGL-Unterstützung kompiliert. - - - + + + Error while initializing OpenGL! Fehler beim Initialisieren von OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Deine Grafikkarte unterstützt kein OpenGL oder du hast nicht den neusten Treiber installiert. - + Error while initializing OpenGL 4.6! Fehler beim Initialisieren von OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Deine Grafikkarte unterstützt OpenGL 4.6 nicht, oder du benutzt nicht die neuste Treiberversion.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Deine Grafikkarte unterstützt anscheinend nicht eine oder mehrere von yuzu benötigten OpenGL-Erweiterungen. Bitte stelle sicher, dass du den neusten Grafiktreiber installiert hast.<br><br>GL Renderer:<br>%1<br><br>Nicht unterstützte Erweiterungen:<br>%2 - + This build doesn't have OpenGL support. Diese Version bietet keine OpenGL-Unterstützung. @@ -6935,800 +6925,820 @@ Fehlerbehebungs-Meldung: &Emulation - + + &Cheats + + + + &View &Anzeige - + &Reset Window Size &Fenstergröße zurücksetzen - + &Debugging &Fehlerbehebung - + &Game List Mode &Spielelisten-Modus - + Game &Icon Size Spielsymbolgröße - + Reset Window Size to &720p Fenstergröße auf &720p zurücksetzen - + Reset Window Size to 720p Fenstergröße auf 720p zurücksetzen - + Reset Window Size to &900p Fenstergröße auf &900p zurücksetzen - + Reset Window Size to 900p Fenstergröße auf 900p zurücksetzen - + Reset Window Size to &1080p Fenstergröße auf &1080p zurücksetzen - + Reset Window Size to 1080p Fenstergröße auf 1080p zurücksetzen - + &Multiplayer &Mehrspieler - + &Tools &Werkzeuge - + Am&iibo Am&iibo - + Launch &Applet &Applet starten - + &TAS &TAS - + &Create Home Menu Shortcut &Startmenü-Verknüpfung erstellen - + Install &Firmware Installieren &Firmware - + &Help &Hilfe - + &Install Files to NAND... &Dateien im NAND installieren... - + L&oad File... Datei &laden... - + Load &Folder... &Verzeichnis laden... - + E&xit S&chließen - - + + &Pause &Pause - + &Stop &Stop - + &Verify Installed Contents Installierte Inhalte &überprüfen - + &About Eden &Über Eden - + Single &Window Mode &Einzelfenster-Modus - + Con&figure... Kon&figurieren... - + Ctrl+, Strg+, - + Enable Overlay Display Applet Applet für die Überlagerungsanzeige aktivieren - + Show &Filter Bar &Filterleiste anzeigen - + Show &Status Bar &Statusleiste anzeigen - + Show Status Bar Statusleiste anzeigen - + &Browse Public Game Lobby &Öffentliche Spiele-Lobbys durchsuchen - + &Create Room &Raum erstellen - + &Leave Room &Raum verlassen - + &Direct Connect to Room &Direkte Verbindung zum Raum - + &Show Current Room &Aktuellen Raum anzeigen - + F&ullscreen Vollbild (&u) - + &Restart Neusta&rt - + Load/Remove &Amiibo... &Amiibo laden/entfernen... - + Open &Mods Page &Mods-Seite öffnen - + &User Handbook - + &Capture Screenshot &Bildschirmfoto aufnehmen - + &Album &Album - + &Set Nickname and Owner Spitzname und Besitzer &festlegen - + &Delete Game Data Spiel-Daten &löschen - + &Restore Amiibo Amiibo &wiederherstellen - + &Format Amiibo Amiibo &formatieren - + &Mii Editor &Mii-Editor - + &Configure TAS... &TAS &konfigurieren... - + Configure C&urrent Game... &Spiel-Einstellungen ändern... - - + + &Start &Start - + &Reset &Zurücksetzen - - + + R&ecord Aufnahme - + Open &Controller Menu Öffne &Controller-Menü - + Install Decryption &Keys Entschlüsselungsschlüssel installieren - + &Home Menu &Startmenü - + &Desktop &Desktop - + &Application Menu &Anwendungsmenü - + &Root Data Folder &Stammdatenordner - + &NAND Folder &NAND-Ordner - + &SDMC Folder &SDMC-Ordner - + &Mod Folder &Mod-Ordner - + &Log Folder &Protokoll-Ordner - + From Folder Aus Ordner - + From ZIP Aus ZIP - + &Eden Dependencies &Eden-Abhängigkeiten - + &Data Manager &Datenverwalter - + &Tree View &Baumansicht - + &Grid View &Rasteransicht - + Game Icon Size Spielsymbolgröße - - + + None Keine - + Show Game &Name Spiel&name anzeigen - + Show &Performance Overlay Leistungsüberlagerung anzeigen - + Post-Processing &Shaders... - + &Carousel View &Karussellansicht - + Small (32x32) Klein (32x32) - + Standard (64x64) Standard (64x64) - + Large (128x128) Groß (128x128) - + Full Size (256x256) Volle Größe (256x256) - + Broken Vulkan Installation Detected Defekte Vulkan-Installation erkannt - + Vulkan initialization failed during boot. Initialisierung von Vulkan ist beim Systemstart fehlgeschlagen. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping Spiel wird ausgeführt - + Loading Web Applet... Web-Applet wird geladen... - - + + Disable Web Applet Web-Applet deaktivieren - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) Das Deaktivieren des Web-Applets kann zu unvorhersehbarem Verhalten führen und sollte nur bei „Super Mario 3D All-Stars“ verwendet werden. Möchtest du das Web-Applet wirklich deaktivieren? (Dies kann in den Fehlerbehebungs-Einstellungen wieder aktiviert werden.) - + The amount of shaders currently being built Die Anzahl der Shader, die derzeit erstellt werden - + The current selected resolution scaling multiplier. Der aktuell ausgewählte Skalierungsfaktor für die Auflösung. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Aktuelle Emulationsgeschwindigkeit. Werte über oder unter 100 % bedeuten, dass die Emulation schneller oder langsamer läuft als auf einer Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Wie viele Bilder pro Sekunde das Spiel derzeit anzeigt. Dies variiert von Spiel zu Spiel und von Szene zu Szene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Die Zeit, die für die Emulation eines Switch-Frames benötigt wird, ohne Berücksichtigung von Framelimiting oder V-Sync. Bei einer Emulation mit voller Geschwindigkeit sollte dieser Wert höchstens 16,67 ms betragen. - + Unmute Stummschaltung aufheben - + Mute Stummschalten - + Reset Volume Lautstärke zurücksetzen - + Configure Effects... - + &Clear Recent Files &Zuletzt verwendete Dateien löschen - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue &Fortfahren - + Warning: Outdated Game Format Warnung: Veraltetes Spielformat - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. Du verwendest für dieses Spiel das dekontruierte ROM-Verzeichnisformat - ein veraltetes Format, das durch andere Formate wie NCA, NAX, XCI oder NSP abgelöst wurde. Dekonstruierten ROM-Verzeichnissen fehlen Symbole, Metadaten und die Unterstützung für Aktualisierungen. <br>Eine Erläuterung der verschiedenen Switch-Formate, die Eden unterstützt, findest du in unserem Benutzerhandbuch. Diese Meldung wird nicht erneut angezeigt. - - + + Error while loading ROM! Fehler beim Laden des ROMs! - + The ROM format is not supported. Das ROM-Format wird nicht unterstützt. - + An error occurred initializing the video core. Beim Initialisieren des Videokerns ist ein Fehler aufgetreten. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. Fehler beim Laden des ROMs! %1 - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. %1<br>Bitte erstelle deine Dateien erneut oder bitte auf Discord/Stoat um Hilfe. - + An unknown error occurred. Please see the log for more details. Es ist ein unbekannter Fehler aufgetreten. Weitere Informationen findest du im Protokoll. - - + + (64-bit) (64-bit) - - + + (32-bit) (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - + Closing software... Software wird geschlossen... - + Save Data Speicherdaten - + Mod Data Mod-Daten - + Error Opening %1 Folder Fehler beim Öffnen des Ordners %1 - - + + Folder does not exist! Der Ordner existiert nicht! - + Remove Installed Game Contents? Installierte Spielinhalte entfernen? - + Remove Installed Game Update? Installierte Spielaktualisierung entfernen? - + Remove Installed Game DLC? Installiertes Spiel-DLC entfernen? - + Remove Entry Eintrag entfernen - + Delete OpenGL Transferable Shader Cache? Den übertragbaren Shader-Cache von OpenGL löschen? - + Delete Vulkan Transferable Shader Cache? Den übertragbaren Shader-Cache von Vulkan löschen? - + Delete All Transferable Shader Caches? Alle übertragbaren Shader-Caches löschen? - + Remove Custom Game Configuration? Benutzerdefinierte Spielkonfiguration entfernen? - + Remove Cache Storage? Cache-Speicher löschen? - + Remove File Datei entfernen - + Remove Play Time Data Wiedergabezeitdaten löschen - + Reset play time? Spielzeit zurücksetzen? - - + + RomFS Extraction Failed! RomFS-Extraktion fehlgeschlagen! - + There was an error copying the RomFS files or the user cancelled the operation. Beim Kopieren der RomFS-Dateien ist ein Fehler aufgetreten oder der Benutzer hat den Vorgang abgebrochen. - + Full Vollständig - + Skeleton Skelett - + Select RomFS Dump Mode RomFS-Auslesemodus auswählen - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Bitte wähle aus, wie das RomFS kopiert werden soll. <br>Vollständig kopiert alle Dateien in das neue Verzeichnis, während <br>Skelett lediglich die Verzeichnisstruktur erstellt. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root Unter %1 ist nicht genügend Speicherplatz vorhanden, um das RomFS zu extrahieren. Bitte schaffe Speicherplatz oder wähle unter „Emulation > Konfigurieren > System > Dateisystem > Dump-Stammverzeichnis“ ein anderes Dump-Verzeichnis aus. - + Extracting RomFS... RomFS wird extrahiert... - - + + Cancel Abbrechen - + RomFS Extraction Succeeded! RomFS wurde erfolgreich extrahiert! - + The operation completed successfully. Der Vorgang wurde erfolgreich abgeschlossen. - + Error Opening %1 Fehler beim Öffnen von %1 - + Select Directory Verzeichnis auswählen - + Properties Eigenschaften - + The game properties could not be loaded. Die Spieleigenschaften konnten nicht geladen werden. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch-Ausführungsdatei (%1);;Alle Dateien (*.*) - + Load File Datei laden - + Open Extracted ROM Directory Verzeichnis mit dem extrahierten ROM öffnen - + Invalid Directory Selected Ungültiges Verzeichnis ausgewählt - + The directory you have selected does not contain a 'main' file. Das von dir ausgewählte Verzeichnis enthält keine „main“-Datei. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - Installierbare Switch-Dateien (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX-Kassetten-Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) + - + Install Files Dateien installieren - + %n file(s) remaining %n Datei(en) verbleiben%n Datei(en) verbleiben - + Installing file "%1"... Datei „%1“ wird installiert... - - + + Install Results Installationsergebnisse - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Um mögliche Konflikte zu vermeiden, raten wir davon ab, Basisspiele auf dem NAND-Speicher zu installieren. Bitte nutze diese Funktion ausschließlich zur Installation von Aktualisierungen und DLCs. - + %n file(s) were newly installed %n Datei(en) wurden neu installiert @@ -7736,7 +7746,7 @@ Bitte nutze diese Funktion ausschließlich zur Installation von Aktualisierungen - + %n file(s) were overwritten %n Datei(en) wurden überschrieben @@ -7744,7 +7754,7 @@ Bitte nutze diese Funktion ausschließlich zur Installation von Aktualisierungen - + %n file(s) failed to install %n Datei(en) konnten nicht installiert werden @@ -7752,324 +7762,324 @@ Bitte nutze diese Funktion ausschließlich zur Installation von Aktualisierungen - + System Application Systemanwendung - + System Archive Systemarchiv - + System Application Update System-Anwendungsaktualisierung - + Firmware Package (Type A) Firmware-Paket (Typ A) - + Firmware Package (Type B) Firmware-Paket (Typ B) - + Game Spiel - + Game Update Spielaktualisierung - + Game DLC Spiel-DLC - + Delta Title Delta-Titel - + Select NCA Install Type... NCA-Installationstyp auswählen... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Bitte wähle den Titeltyp aus, unter dem du diese NCA installieren möchtest: (In den meisten Fällen ist die Vorgabe „Spiel“ ausreichend.) - + Failed to Install Installation fehlgeschlagen - + The title type you selected for the NCA is invalid. Der von dir für die NCA ausgewählte Titel ist ungültig. - + File not found Datei nicht gefunden - + File "%1" not found Datei „%1“ nicht gefunden - + OK OK - + Function Disabled Funktion deaktiviert - + Compatibility list reporting is currently disabled. Check back later! Die Anzeige der Kompatibilitätsliste ist derzeit deaktiviert. Schaue später noch einmal vorbei! - + Error opening URL Fehler beim Öffnen der URL - + Unable to open the URL "%1". Die URL „%1“ kann nicht geöffnet werden. - + TAS Recording TAS-Aufnahme - + Overwrite file of player 1? Datei von Spieler 1 überschreiben? - + Invalid config detected Ungültige Konfiguration erkannt - + Handheld controller can't be used on docked mode. Pro controller will be selected. Der Handgerät-Controller kann im angedockten Modus nicht verwendet werden. Es wird der Pro-Controller ausgewählt. - - + + Amiibo Amiibo - - + + The current amiibo has been removed Das aktuelle amiibo wurde entfernt - + Error Fehler - - + + The current game is not looking for amiibos Das aktuelle Spiel sucht nicht nach Amiibos - + Amiibo File (%1);; All Files (*.*) Amiibo-Datei (%1);; Alle Dateien (*.*) - + Load Amiibo Amiibo laden - + Error loading Amiibo data Fehler beim Laden der Amiibo-Daten - + The selected file is not a valid amiibo Die ausgewählte Datei ist kein gültiges amiibo - + The selected file is already on use Die ausgewählte Datei wird bereits verwendet - + An unknown error occurred Ein unbekannter Fehler ist aufgetreten - + No firmware available Keine Firmware verfügbar - + Firmware Corrupted Firmware beschädigt - + Unknown applet Unbekanntes Applet - + Applet doesn't map to a known value. „Applet“ lässt sich keinem bekannten Wert zuordnen. - + Record not found Aufnahme nicht gefunden - + Applet not found. Please reinstall firmware. Applet nicht gefunden. Bitte installiere die Firmware neu. - + Capture Screenshot Bildschirmfoto aufnehmen - + PNG Image (*.png) PNG-Bild (*.png) - + TAS state: Running %1/%2 TAS-Status: %1/%2 läuft - + TAS state: Recording %1 TAS-Status: %1 wird aufgenommen - + TAS state: Idle %1/%2 TAS-Status: Leerlauf %1/%2 - + TAS State: Invalid TAS-Status: Ungültig - + &Stop Running &Ausführung beenden - + Stop R&ecording Aufnahme beenden - + Building: %n shader(s) Erstellung: %n SchattiererErstelle: %n Shader - + Scale: %1x %1 is the resolution scaling factor Maßstab: 1:1 - + Speed: %1% / %2% Geschwindigkeit: %1% / %2% - + Speed: %1% Geschwindigkeit: %1% - + Game: %1 FPS Spiel: %1 FPS - + Frame: %1 ms Frame: %1 ms - + NO AA Kein AA - + NO FX - + FX - + VOLUME: MUTE LAUTSTÄRKE: STUMM - + VOLUME: %1% Volume percentage (e.g. 50%) LAUTSTÄRKE: %1% - + Derivation Components Missing Ableitungskomponenten fehlen - + Decryption keys are missing. Install them now? Entschlüsselungsschlüssel fehlen. Möchtest du diese jetzt installieren? - + Wayland Detected! Wayland erkannt! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8080,74 +8090,74 @@ Es wird empfohlen, stattdessen X11 zu verwenden. Möchtest du dies für zukünftige Starts erzwingen? - + Use X11 X11 verwenden - + Continue with Wayland Mit Wayland fortfahren - + Don't show again Nicht mehr anzeigen - + Restart Required Neustart erforderlich - + Restart Eden to apply the X11 backend. Starte Eden neu, um das X11-Backend zu aktivieren. - + Slow Langsam - + Turbo Turbo - + Unlocked Entsperrt - + Select RomFS Dump Target RomFS-Ausleseziel auswählen - + Please select which RomFS you would like to dump. Bitte wähle aus, welches RomFS du auslesen möchtest. - + Are you sure you want to close Eden? Möchtest du Eden wirklich schließen? - - - + + + Eden Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Möchtest du die Emulation wirklich beenden? Alle nicht gespeicherten Fortschritte gehen dabei verloren. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/el.ts b/dist/languages/el.ts index b3ec9c6f5e..2e910d1835 100644 --- a/dist/languages/el.ts +++ b/dist/languages/el.ts @@ -30,7 +30,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> @@ -399,252 +399,262 @@ Can help reduce stuttering at lower framerates. - - Accuracy: - Ακρίβεια: - - - - Change the accuracy of the emulated CPU (for debugging only). + + Enable cheats by default - - - Backend: + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + Accuracy: + Ακρίβεια: + + + + Change the accuracy of the emulated CPU (for debugging only). + + + + + + Backend: + + + + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) Αχρησιμοποίητο FMA (βελτιώνει την απόδοση σε επεξεργαστές χωρίς FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. - + Faster FRSQRTE and FRECPE Ταχύτερη FRSQRTE και FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. - + Faster ASIMD instructions (32 bits only) Ταχύτερες οδηγίες ASIMD (μόνο 32 bits) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. - + Inaccurate NaN handling Ανακριβής χειρισμός NaN - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. - + Disable address space checks Απενεργοποίηση ελέγχου χώρου διευθύνσεων - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor Αγνοήση καθολικής επίβλεψης - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. - + API: API: - + Changes the output graphics API. Vulkan is recommended. - + Device: Συσκευή: - + This setting selects the GPU to use (Vulkan only). - + Resolution: Ανάλυση: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: Φίλτρο Προσαρμογής Παραθύρου: - + FSR Sharpness: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Μέθοδος Anti-Aliasing: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Λειτουργία Πλήρους Οθόνης: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. - + Aspect Ratio: Αναλογία Απεικόνισης: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: Εξομοίωση NVDEC: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. - + ASTC Decoding Method: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -653,75 +663,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -729,79 +719,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) - + Slightly improves performance by moving presentation to a separate CPU thread. - + Force maximum clocks (Vulkan only) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. - + Anisotropic Filtering: Ανισοτροπικό Φιλτράρισμα: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -810,1290 +800,1290 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. - + Enable Compute Pipelines (Intel Vulkan Only) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. - + Sync to framerate of video playback - + Run the game at normal speed during video playback, even when the framerate is unlocked. - + Barrier feedback loops - + Improves rendering of transparency effects in specific games. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed RNG Seed - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: - + This option can be overridden when region setting is auto-select - + Region: Περιφέρεια: - + The region of the console. - + Time Zone: Ζώνη Ώρας: - + The time zone of the console. - + Sound Output Mode: - + Console Mode: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity Απόκρυψη δρομέα ποντικιού στην αδράνεια - + Hides the mouse after 2.5s of inactivity. - + Check for updates - + Whether or not to check for updates upon startup. - + Enable Gamemode - + Force X11 as Graphics Backend - + Custom frontend - + Real applet - - + + Disabled - + Never - + On Load - + Always - + CPU CPU - + GPU - + CPU Asynchronous - + Uncompressed (Best quality) - + BC1 (Low quality) - + BC3 (Medium quality) - - + + Auto Αυτόματη - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative - + Aggressive - + Vulkan Vulkan - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null - + Fast - - - + + + Accurate Ακριβής - - - + + + Default Προεπιλεγμένο - + Unsafe (fast) - + Safe (stable) - + Immediate - + Balanced - + Unsafe Επισφαλής - + Paranoid (disables most optimizations) - + Debugging - + Dynarmic - + NCE - + Borderless Windowed Παραθυροποιημένο Χωρίς Όρια - + Exclusive Fullscreen Αποκλειστική Πλήρης Οθόνη - + No Video Output Χωρίς Έξοδο Βίντεο - + CPU Video Decoding Αποκωδικοποίηση Βίντεο CPU - + GPU Video Decoding (Default) Αποκωδικοποίηση Βίντεο GPU (Προεπιλογή) - + 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [ΠΕΙΡΑΜΑΤΙΚΟ] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) - + 8X (5760p/8640p) - + Nearest Neighbor Πλησιέστερος Γείτονας - + Bilinear Διγραμμικό - + Bicubic Δικυβικό - + Gaussian Gaussian - + Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution - + Area - + MMPX - + Zero-Tangent - + B-Spline - + Mitchell - + Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Κανένα - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Προεπιλογή (16:9) - + Force 4:3 Επιβολή 4:3 - + Force 21:9 Επιβολή 21:9 - + Force 16:10 Επιβολή 16:10 - + Stretch to Window Επέκταση στο Παράθυρο - + Automatic Αυτόματα - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Ιαπωνικά (日本語) - + American English - + French (français) Γαλλικά (Français) - + German (Deutsch) Γερμανικά (Deutsch) - + Italian (italiano) Ιταλικά (Italiano) - + Spanish (español) Ισπανικά (Español) - + Chinese Κινέζικα - + Korean (한국어) Κορεάτικα (한국어) - + Dutch (Nederlands) Ολλανδικά (Nederlands) - + Portuguese (português) Πορτογαλικά (Português) - + Russian (Русский) Ρώσικα (Русский) - + Taiwanese Ταϊβανέζικα - + British English Βρετανικά Αγγλικά - + Canadian French Καναδικά Γαλλικά - + Latin American Spanish Λατινοαμερικάνικα Ισπανικά - + Simplified Chinese Απλοποιημένα Κινέζικα - + Traditional Chinese (正體中文) Παραδοσιακά Κινέζικα (正體中文) - + Brazilian Portuguese (português do Brasil) Πορτογαλικά Βραζιλίας (Português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan Ιαπωνία - + USA ΗΠΑ - + Europe Ευρώπη - + Australia Αυστραλία - + China Κίνα - + Korea Κορέα - + Taiwan Ταϊβάν - + Auto (%1) Auto select time zone - + Default (%1) Default time zone - + CET CET - + CST6CDT CST6CDT - + Cuba Κούβα - + EET EET - + Egypt Αίγυπτος - + Eire - + EST EST - + EST5EDT EST5EDT - + GB - + GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Γκρήνουιτς - + Hongkong Χονγκ Κονγκ - + HST HST - + Iceland Ισλανδία - + Iran Ιράν - + Israel Ισραήλ - + Jamaica Ιαμαϊκή - + Kwajalein - + Libya Λιβύη - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Ναβάχο - + NZ - + NZ-CHAT - + Poland Πολωνία - + Portugal Πορτογαλία - + PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Σιγκαπούρη - + Turkey Τουρκία - + UCT UCT - + Universal Παγκόσμια - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu - + Mono Μονοφωνικό - + Stereo Στέρεοφωνικό - + Surround - + 4GB DRAM (Default) - + 6GB DRAM (Unsafe) - + 8GB DRAM - + 10GB DRAM (Unsafe) - + 12GB DRAM (Unsafe) - + Docked Docked - + Handheld Handheld - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) - + Only if game specifies not to stop - + Never ask - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) - + High (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6032,50 +6022,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! Το OpenGL δεν είναι διαθέσιμο! - + OpenGL shared contexts are not supported. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! Σφάλμα κατα την αρχικοποίηση του OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 - + This build doesn't have OpenGL support. @@ -6840,1132 +6830,1152 @@ Debug Message: - + + &Cheats + + + + &View - + &Reset Window Size - + &Debugging - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p - + Reset Window Size to 720p - + Reset Window Size to &900p - + Reset Window Size to 900p - + Reset Window Size to &1080p - + Reset Window Size to 1080p - + &Multiplayer &Πολλαπλών Παικτών - + &Tools - + Am&iibo - + Launch &Applet - + &TAS &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help - + &Install Files to NAND... - + L&oad File... - + Load &Folder... - + E&xit - - + + &Pause &Παύση - + &Stop &Σταμάτημα - + &Verify Installed Contents - + &About Eden - + Single &Window Mode - + Con&figure... - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar - + Show &Status Bar - + Show Status Bar - + &Browse Public Game Lobby &Περιήγηση σε δημόσιο λόμπι παιχνιδιού - + &Create Room &Δημιουργία δωματίου - + &Leave Room &Αποχωρήσει από το δωμάτιο - + &Direct Connect to Room &Άμεση σύνδεση σε Δωμάτιο - + &Show Current Room &Εμφάνιση τρέχοντος δωματίου - + F&ullscreen - + &Restart - + Load/Remove &Amiibo... - + Open &Mods Page - + &User Handbook - + &Capture Screenshot - + &Album - + &Set Nickname and Owner - + &Delete Game Data - + &Restore Amiibo - + &Format Amiibo - + &Mii Editor - + &Configure TAS... - + Configure C&urrent Game... - - + + &Start &Έναρξη - + &Reset - - + + R&ecord - + Open &Controller Menu - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -7973,74 +7983,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/es.ts b/dist/languages/es.ts index 8cda19bc6b..0bca795e9a 100644 --- a/dist/languages/es.ts +++ b/dist/languages/es.ts @@ -37,8 +37,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Sitio web</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Código fuente</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Colaboradores</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licencia</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -411,49 +411,59 @@ Can help reduce stuttering at lower framerates. Puede ayudar a reducir los tirones o parpadeos en las tasas de fotogramas bajas. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Precisión: - + Change the accuracy of the emulated CPU (for debugging only). Cambia la precisión de la CPU emulada (solo para depuración) - - + + Backend: Motor: - + CPU Clocks Relojes de CPU - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks Ticks de CPU personalizados - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. Establece un valor personalizado para los ticks de la CPU. Valores más altos pueden aumentar el rendimiento, pero también pueden causar bloqueos. Se recomienda un rango de 77-21000. - + Enable Host MMU Emulation (fastmem) Activar la emulación del huesped MMU (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -462,99 +472,99 @@ Al actualizarlo, las lecturas/escrituras de memoria del programa invitado se rea Desactivando este opción obliga a que todos los accesos a la memoria utilicen el Software MMU emulado. - + Unfuse FMA (improve performance on CPUs without FMA) Desactivar FMA (mejora el rendimiento en las CPU sin FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Esta opción mejora el rendimiento al reducir la precisión de las instrucciones fused-multiply-add en las CPU sin soporte nativo FMA. - + Faster FRSQRTE and FRECPE FRSQRTE y FRECPE rápidos - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Esta opción mejora la velocidad de algunas funciones aproximadas de punto flotante mediante el uso de aproximaciones nativas menos precisas. - + Faster ASIMD instructions (32 bits only) Instrucciones ASIMD rápidas (solo 32 bits) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Esta opción mejora la velocidad de las funciones de punto flotante ASIMD de 32 bits al ejecutarlas con redondeos incorrectos. - + Inaccurate NaN handling Gestión imprecisa NaN - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Esta opción mejora el rendimiento al no hacer comprobaciones "NaN". Ten en cuenta que, a cambio, reduce la precisión de ciertas instrucciones de coma flotante. - + Disable address space checks Desactivar comprobación del espacio de destino - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. Esta opción mejora la velocidad eliminando una verificación de seguridad antes de cada operación de memoria. - + Ignore global monitor Ignorar monitorización global - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Esta opción mejora el rendimiento al depender solo de la semántica de cmpxchg para garantizar la seguridad de las instrucciones de acceso exclusivas. Ten en cuenta que puede resultar en bloqueos y otras condiciones de carrera. - + API: API: - + Changes the output graphics API. Vulkan is recommended. Cambia la API de salida gráfica. Se recomienda Vulkan. - + Device: Dispositivo: - + This setting selects the GPU to use (Vulkan only). Este ajuste selecciona la GPU a usar (solo Vulkan). - + Resolution: Resolución: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -563,27 +573,27 @@ Las resoluciones altas requieren más VRAM y ancho de banda. Las opciones inferiores a 1X pueden generar errores visuales. - + Window Adapting Filter: Filtro adaptable de ventana: - + FSR Sharpness: Nitidez FSR: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. Determina el grado de nitidez que tendrá la imagen usando el contraste dinámico de FSR o SGSR. - + Anti-Aliasing Method: Método de suavizado de bordes: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -592,22 +602,22 @@ SMAA ofrece mejor calidad. FXAA puede producir mejores resultados visuales en resoluciones bajas. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Modo pantalla completa: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -616,12 +626,12 @@ Ventana sin bordes ofrece la mejor compatibilidad con el teclado en pantalla que Pantalla completa exclusiva puede ofrecer mejor rendimiento y mejor soporte para FreeSync/G-Sync/VRR. - + Aspect Ratio: Relación de aspecto: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -630,36 +640,36 @@ La mayoría de los juegos solo admiten 16:9, por lo que se requieren modificacio También controla la relación de aspecto de las capturas de pantalla. - + Use persistent pipeline cache Usar el caché de canalización persistente - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Permite almacenar los sombreadores para que carguen más rápido la próxima vez que inicies el juego. Desactivarlo solo está destinado para depuración. - + Use asynchronous GPU emulation Usar emulación asíncrona de la GPU - + Uses an extra CPU thread for rendering. This option should always remain enabled. Usa un hilo adicional de la CPU para el renderizado. Esta opción siempre debe permanecer activada. - + NVDEC emulation: Emulación NVDEC: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -668,12 +678,12 @@ Puede usar la CPU, GPU o no descodificar (mostrará una pantalla en negro durant En la mayoría de casos, descodificar mediante la GPU es la mejor opción. - + ASTC Decoding Method: Modo descodificación ASTC: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -685,12 +695,12 @@ GPU: utiliza los sombreadores computables de la GPU para descodificar las textur CPU asíncrona: usa la CPU para descodificar las texturas ASTC bajo demanda. Elimina los tirones causados por la descodificación ASTC, pero puede generar errores visuales. - + ASTC Recompression Method: Modo recompresión ASTC: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. @@ -698,64 +708,44 @@ BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, BC1/BC3: El formato intermedio será recomprimido a BC1 o BC3, lo que ahorra VRAM, pero degrada la calidad de la imagen. - + Frame Pacing Mode (Vulkan only) Modo de ritmo de fotogramas (solo Vulkan) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. Controla cómo el emulador gestiona el ritmo de los fotogramas para reducir los tirones y hacer que la velocidad de los fotogramas sea más suave y consistente. - + VRAM Usage Mode: Modo de uso de la VRAM: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. Selecciona si el emulador prefiere ahorrar memoria o maximizar el uso de memoria de video disponible para mejorar el rendimiento. El modo agresivo puede afectar al rendimiento de otras aplicaciones, como a los programas de grabación. - + Skip CPU Inner Invalidation Saltar invalidación interna de la CPU - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. Omite ciertas invalidaciones de caché durante las actualizaciones de memoria, reduciendo el uso de la CPU y mejorando la latencia. Esto puede causar bloqueos leves. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: Modo VSync: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -766,12 +756,12 @@ Mailbox ofrece menor latencia que FIFO y evita el tearing, aunque puede perder a Immediate (sin sincronización) muestra los fotogramas tan pronto están disponibles, pero puede generar desgarros de imagen. - + Sync Memory Operations Sincronizar operaciones de memoria - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. @@ -780,56 +770,56 @@ Esta opción arregla errores en los juegos, pero puede afectar negativamente al Los juegos con Unreal Engine 4 son con frecuencia los que muestran cambios significantes en esto. - + Enable asynchronous presentation (Vulkan only) Activar presentación asíncrona (solo Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. Mejora el rendimiento ligeramente al usar un hilo de CPU adicional para la presentación. - + Force maximum clocks (Vulkan only) Forzar relojes al máximo (solo Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Ejecuta los procesos en segundo plano mientras se espera a las instrucciones gráficas para evitar que la GPU reduzca su velocidad de reloj. - + Anisotropic Filtering: Filtrado anisotrópico: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. Controla la calidad del renderizado de texturas en ángulos oblicuos. Es seguro configurarlo en 16x en la mayoría de las GPU. - + GPU Mode: Modo de la GPU: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: Precisión de DMA: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. @@ -838,12 +828,12 @@ Inseguro es más rápido, mientras que seguro es más estable y puede solucionar Predeterminado sigue el ajuste de la precisión de GPU. - + GPU Fence Behavior: Comportamiento de vallado de la GPU: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -852,44 +842,44 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation Activa la compilación de shaders asincrónicos - + May reduce shader stutter. Puede reducir los tirones causados por la carga de sombreadores. - + GPU Clocks Relojes de GPU - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle Desentrelazado de la GPU - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. Acelera la decodificación de texturas 3D BCn mediante computación de la GPU. Desactívela si experimenta problemas o fallos gráficos. - + GPU Unswizzle Max Texture Size Tamaño máximo de textura de desentrelazado de la GPU - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. @@ -898,46 +888,46 @@ Aunque la GPU es más rápida para texturas medianas y grandes, la CPU puede ser Ajuste este valor para encontrar el equilibrio entre la aceleración de la GPU y la sobrecarga de la CPU. - + GPU Unswizzle Stream Size Tamaño del flujo de desentrelazado de la GPU - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. Establece la cantidad máxima de datos de textura (en MiB) procesados ​​por cada fotograma. Valores más altos pueden reducir la distorsión durante la carga de texturas, pero pueden afectar a la consistencia de los fotogramas. - + GPU Unswizzle Chunk Size Tamaño del trozo de desentrelazado de la GPU - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. Determina la cantidad de cortes de profundidad procesados ​​en un solo envío. Aumentar este valor puede mejorar el rendimiento en una GPU de gama alta, pero puede causar tirones y problemas en los tiempos de respuesta en hardware más modesto. - + Use Vulkan pipeline cache Usar caché de canalización de Vulkan - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. Activa la caché de canalización específica del fabricante. Esta opción puede mejorar los tiempos de cargas de sombreadores en el caso de que el controlador de Vulkan no lo almacene internamente. - + Enable Compute Pipelines (Intel Vulkan Only) Activar la canalizaciones de cómputo (solo Intel Vulkan) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. @@ -946,182 +936,182 @@ Este ajuste solo existe para los controladores propietarios de Intel y puede cau En los demás controladores, la canalización de cómputo siempre está activada. - + Enable Reactive Flushing Activar limpieza reactiva - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Usa limpieza de memoria reactiva en vez de predictiva, permitiendo una sincronización de memoria más precisa. - + Sync to framerate of video playback Sincronizar a fotogramas de reproducción de vídeo - + Run the game at normal speed during video playback, even when the framerate is unlocked. Ejecuta el juego a velocidad normal durante la reproducción de vídeos, incluso cuando no hay límite de fotogramas. - + Barrier feedback loops Bucles de feedback de barrera - + Improves rendering of transparency effects in specific games. Mejora la renderización de los efectos de transparencia en ciertos juegos. - + Enable buffer history Activar el historial del búfer - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. Habilita el acceso a estados de búfer anteriores. Esta opción puede mejorar la calidad de renderizado y la consistencia en el rendimiento de algunos juegos. - + Fix bloom effects Arreglar efectos de resplandor - + Removes bloom in Burnout. Elimina el resplandor en Burnout. - + Extended Dynamic State Estado dinámico extendido - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. Controla el número de funciones que pueden ser usadas en el Estado Dinámico Extendido. Números más altos permiten úsar más funciones y pueden aumentar el rendimiento, pero tambén pueden causar errores gráficos. - + Vertex Input Dynamic State Estado dinámico de entrada de vértices - + Enables vertex input dynamic state feature for better quality and performance. Activa la función de estado dinámico de entrada de vértices para una mejor calidad y rendimiento. - + Sample Shading Sombreado de muestra - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. Permite que el sombreador de fragmentos se ejecute por muestra en un fragmento multimuestreado, en lugar de una sola vez por fragmento. Mejora la calidad de los gráficos a costa de rendimiento. Los valores más altos mejoran la calidad, pero reducen el rendimiento. - + RNG Seed Semilla de GNA - + Controls the seed of the random number generator. Mainly used for speedrunning. Controla la semilla del generador de números aleatorios. Usado principalmente para speedrunning. - + Device Name Nombre del dispositivo - + The name of the console. El nombre de la consola - + Homebrew Args Argumentos Homebrew - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). Argumentos en la línea de comandos pasados al homebrew al ser lanzado (p.e. -noglsl). - + Custom RTC Date: Fecha Personalizada RTC: - + This option allows to change the clock of the console. Can be used to manipulate time in games. Esta opción permite cambiar el reloj de la consola. Puede ser usado para manipular el tiempo en juegos. - + The number of seconds from the current unix time Número de segundos de la hora actual de Unix - + Language: Idioma: - + This option can be overridden when region setting is auto-select Esta opción puede ser reemplazada cuando la configuración de región está en selección automática. - + Region: Región: - + The region of the console. La Región de la Consola. - + Time Zone: Zona horaria: - + The time zone of the console. La zona horaria de la consola. - + Sound Output Mode: Método de salida de sonido: - + Console Mode: Modo consola: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. @@ -1130,1025 +1120,1025 @@ Los juegos cambiarán su resolución, detalles y compatibilidad con los mandos s Configurar el modo portátil puede mejorar el rendimiento en sistemas de gama baja. - + Prompt for user profile on boot Solicitud para perfil de usuario al arrancar - + Useful if multiple people use the same PC. Útil si múltiples personas usan la misma PC - + Pause when not in focus Pausar cuando la ventana no esté activa - + Pauses emulation when focusing on other windows. Pausa la emulación cuando otra ventana diferente está activa. - + Confirm before stopping emulation Confirmar detención - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. Anula las solicitudes de confirmación para detener la emulación. Al habilitar esta opción, se omiten dichas solicitudes y se sale directamente de la emulación. - + Hide mouse on inactivity Ocultar el cursor por inactividad. - + Hides the mouse after 2.5s of inactivity. Oculta el mouse después de 2.5s de inactividad. - + Check for updates Buscar actualizaciones - + Whether or not to check for updates upon startup. Si se deben buscar actualizaciones al iniciar o no. - + Enable Gamemode Activar Modo Juego - + Force X11 as Graphics Backend Forzar X11 como motor gráfico - + Custom frontend Interfaz personalizada - + Real applet Applet real - - + + Disabled Desactivado - + Never Nunca - + On Load Al cargar - + Always Siempre - + CPU CPU - + GPU GPU - + CPU Asynchronous CPU asíncrona - + Uncompressed (Best quality) Sin compresión (Mejor calidad) - + BC1 (Low quality) BC1 (Calidad baja) - + BC3 (Medium quality) BC3 (Calidad media) - - + + Auto Auto - + 30 FPS 30 FPS - + 60 FPS 60 FPS - + 90 FPS 90 FPS - + 120 FPS 120 FPS - + Conservative Conservativo - + Aggressive Agresivo - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) OpenGL GLASM (Ensamblado de sombreadores, solo NVIDIA) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V (Experimental, solo AMD/Mesa) - + Null Ninguno - + Fast Rápido - - - + + + Accurate Preciso - - - + + + Default Predeterminado - + Unsafe (fast) Inseguro (rápido) - + Safe (stable) Seguro (estable) - + Immediate Inmediato - + Balanced Balanceado - + Unsafe Impreciso - + Paranoid (disables most optimizations) Paranoico (Deshabilita la mayoría de optimizaciones) - + Debugging Depuración - + Dynarmic DynARMic - + NCE NCE - + Borderless Windowed Ventana sin bordes - + Exclusive Fullscreen Pantalla completa - + No Video Output Sin salida de vídeo - + CPU Video Decoding Decodificación de vídeo en la CPU - + GPU Video Decoding (Default) Decodificación de vídeo en GPU (Por defecto) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] x0,5 (360p/540p) [EXPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] x0,75 (540p/810p) [EXPERIMENTAL] - + 1X (720p/1080p) x1 (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] x1,5 (1080p/1620p) [EXPERIMENTAL] - + 2X (1440p/2160p) x2 (1440p/2160p) - + 3X (2160p/3240p) x3 (2160p/3240p) - + 4X (2880p/4320p) x4 (2880p/4320p) - + 5X (3600p/5400p) x5 (3600p/5400p) - + 6X (4320p/6480p) x6 (4320p/6480p) - + 7X (5040p/7560p) x7 (5040p/7560p) - + 8X (5760p/8640p) x8 (5760p/8640p) - + Nearest Neighbor Vecino más próximo - + Bilinear Bilineal - + Bicubic Bicúbico - + Gaussian Gaussiano - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution Super Resolución AMD FidelityFX - + Area Área - + MMPX MMPX - + Zero-Tangent Tangente cero - + B-Spline Ranura B - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution Super resolución de juego Snapdragon - + Snapdragon Game Super Resolution EdgeDir Filo direcorio de super resolución de juego Snapdragon - + None Ninguno - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Predeterminado (16:9) - + Force 4:3 Forzar 4:3 - + Force 21:9 Forzar 21:9 - + Force 16:10 Forzar 16:10 - + Stretch to Window Estirar a la ventana - + Automatic Automático - + 2x x2 - + 4x x4 - + 8x x8 - + 16x x16 - + Japanese (日本語) Japonés (日本語) - + American English Inglés estadounidense - + French (français) Francés (français) - + German (Deutsch) Alemán (deutsch) - + Italian (italiano) Italiano (italiano) - + Spanish (español) Español - + Chinese Chino - + Korean (한국어) Coreano (한국어) - + Dutch (Nederlands) Holandés (nederlands) - + Portuguese (português) Portugués (português) - + Russian (Русский) Ruso (Русский) - + Taiwanese Taiwanés - + British English Inglés británico - + Canadian French Francés canadiense - + Latin American Spanish Español latinoamericano - + Simplified Chinese Chino simplificado - + Traditional Chinese (正體中文) Chino tradicional (正體中文) - + Brazilian Portuguese (português do Brasil) Portugués brasileño (português do Brasil) - + Polish (polska) Polaco (polska) - + Thai (แบบไทย) Tailandés (แบบไทย) - - + + Japan Japón - + USA EEUU - + Europe Europa - + Australia Australia - + China China - + Korea Corea - + Taiwan Taiwán - + Auto (%1) Auto select time zone Auto (%1) - + Default (%1) Default time zone Predeterminada (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Egipto - + Eire Eire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Islandia - + Iran Irán - + Israel Israel - + Jamaica Jamaica - + Kwajalein Kwajalein - + Libya Libia - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polonia - + Portugal Portugal - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapur - + Turkey Turquía - + UCT UCT - + Universal Universal - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulú - + Mono Mono - + Stereo Estéreo - + Surround Envolvente - + 4GB DRAM (Default) 4GB DRAM (Por defecto) - + 6GB DRAM (Unsafe) 6GB DRAM (Inseguro) - + 8GB DRAM 8GB DRAM - + 10GB DRAM (Unsafe) 10GB DRAM (Inseguro) - + 12GB DRAM (Unsafe) 12GB DRAM (Inseguro) - + Docked Sobremesa - + Handheld Portátil - - + + Normal Normal - - + + Boost Impulso - - + + Overclock Overclock - + Always ask (Default) Preguntar siempre (Por defecto) - + Only if game specifies not to stop Solo si el juego pide no ser cerrado - + Never ask Nunca preguntar - + Very Small (16 MB) Muy pequeño (16 MB) - + Small (32 MB) Pequeño (32 MB) - + Normal (128 MB) Normal (128 MB) - + Large (256 MB) Grande (256 MB) - + Very Large (512 MB) Muy grande (512 MB) - + Very Low (4 MB) Muy bajo (4 MB) - + Low (8 MB) Bajo (8 MB) - + Normal (16 MB) Normal (16 MB) - + Medium (32 MB) Medio (32 MB) - + High (64 MB) Alto (64 MB) - + Very Low (32) Muy bajo (32) - + Low (64) Bajo (64) - + Normal (128) Normal (128) - + Medium (256) Medio (256) - + High (512) Alto (512) - + ExtendedDynamicState 1 ModoDynamicoExtendido 1 - + ExtendedDynamicState 2 ModoDynamicoExtendido 2 - + ExtendedDynamicState 3 ModoDynamicoExtendido 3 - + Tree View Vista en árbol - + Grid View Vista en cuadrícula @@ -6119,50 +6109,50 @@ Por favor, vaya a Configuración -> Sistema -> Red y selecciona una interf GRenderWindow - - + + OpenGL not available! ¡OpenGL no está disponible! - + OpenGL shared contexts are not supported. Los contextos compartidos de OpenGL no son compatibles. - + Eden has not been compiled with OpenGL support. Eden no ha sido compilado con soporte para OpenGL. - - - + + + Error while initializing OpenGL! ¡Error al inicializar OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Tu GPU no soporta OpenGL, o no tienes instalados los últimos controladores gráficos. - + Error while initializing OpenGL 4.6! ¡Error al iniciar OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Tu GPU no soporta OpenGL 4.6, o no tienes instalado el último controlador de la tarjeta gráfica.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Es posible que la GPU no soporte una o más extensiones necesarias de OpenGL . Por favor, asegúrate de tener los últimos controladores de la tarjeta gráfica.<br><br>GL Renderer:<br>%1<br><br>Extensiones no soportadas:<br>%2 - + This build doesn't have OpenGL support. Esta compilación no tiene soporte para OpenGL. @@ -6929,800 +6919,820 @@ Mensaje de depuración: &Emulación - + + &Cheats + + + + &View &Ver - + &Reset Window Size &Reiniciar tamaño de ventana - + &Debugging &Depuración - + &Game List Mode Modo de la lista de &juegos - + Game &Icon Size Tamaño del &icono de los juegos - + Reset Window Size to &720p Reiniciar el tamaño de la ventana a &720p - + Reset Window Size to 720p Reiniciar el tamaño de la ventana a 720p - + Reset Window Size to &900p Reiniciar el tamaño de la ventana a &900p - + Reset Window Size to 900p Reiniciar el tamaño de la ventana a 900p - + Reset Window Size to &1080p Reiniciar el tamaño de la ventana a &1080p - + Reset Window Size to 1080p Reiniciar el tamaño de la ventana a 1080p - + &Multiplayer &Multijugador - + &Tools &Herramientas - + Am&iibo Am&iibo - + Launch &Applet Ejecutar &Applet - + &TAS &TAS - + &Create Home Menu Shortcut &Crear un acceso directo al menú de inicio - + Install &Firmware Instalar &Firmware - + &Help &Ayuda - + &Install Files to NAND... &Instalar archivos en NAND... - + L&oad File... C&argar archivo... - + Load &Folder... Cargar &carpeta - + E&xit S&alir - - + + &Pause &Pausar - + &Stop &Detener - + &Verify Installed Contents &Verificar los contenidos instalados - + &About Eden &Acerca de Eden - + Single &Window Mode Modo &ventana - + Con&figure... Con&figurar... - + Ctrl+, Ctrl+, - + Enable Overlay Display Applet Activar applet de visualización superpuesta - + Show &Filter Bar Mostrar barra de &búsqueda - + Show &Status Bar Mostrar barra de &estado - + Show Status Bar Mostrar barra de estado - + &Browse Public Game Lobby &Buscar en la sala de juegos públicos - + &Create Room &Crear sala - + &Leave Room &Abandonar sala - + &Direct Connect to Room &Conexión directa a una sala - + &Show Current Room &Mostrar sala actual - + F&ullscreen P&antalla completa - + &Restart &Reiniciar - + Load/Remove &Amiibo... Cargar/Eliminar &Amiibo... - + Open &Mods Page Abrir página de &mods - + &User Handbook Manual de &usuario - + &Capture Screenshot &Captura de pantalla - + &Album &Álbum - + &Set Nickname and Owner &Darle nombre y propietario - + &Delete Game Data &Borrar datos de juego - + &Restore Amiibo &Restaurar Amiibo - + &Format Amiibo &Formatear Amiibo - + &Mii Editor &Editor de Mii - + &Configure TAS... &Configurar TAS... - + Configure C&urrent Game... Configurar el j&uego actual... - - + + &Start &Iniciar - + &Reset &Reiniciar - - + + R&ecord G&rabar - + Open &Controller Menu Abrir el menú de &mandos - + Install Decryption &Keys Instalar &llaves de desencriptación - + &Home Menu &Menú de inicio - + &Desktop &Escritorio - + &Application Menu &Menú de la aplicación - + &Root Data Folder Carpeta de datos &raíz - + &NAND Folder Carpeta &NAND - + &SDMC Folder Carpeta &SDMC - + &Mod Folder Carpeta de &mods - + &Log Folder Carpeta de &registros - + From Folder Desde una carpeta - + From ZIP Desde un archivo ZIP - + &Eden Dependencies &Dependencias de Eden - + &Data Manager Gestor de &datos - + &Tree View Vista en &árbol - + &Grid View Vista en &cuadrícula - + Game Icon Size Tamaño del icono de los juegos - - + + None Nada - + Show Game &Name Mostrar el &nombre del juego - + Show &Performance Overlay Mostrar superposición de &rendimiento - + Post-Processing &Shaders... - + &Carousel View Vista de &carrusel - + Small (32x32) Pequeño (32x32) - + Standard (64x64) Estandar (64x64) - + Large (128x128) Grande (128x128) - + Full Size (256x256) Tamaño completo (256x256) - + Broken Vulkan Installation Detected Detectada instalación fallida de Vulkan - + Vulkan initialization failed during boot. La inicialización de Vulkan falló durante el arranque. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping Ejecutando un juego - + Loading Web Applet... Cargando applet web... - - + + Disable Web Applet Desactivar applet web - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) Desactivar el applet web puede causar comportamientos inesperados y debería solo ser usado con Super Mario 3D All-Stars. ¿Está seguro de que quiere desactivar el applet web? (Puede ser activado en las ajustes de depuración.) - + The amount of shaders currently being built La cantidad de sombreadores que se están contruyendo actualmente - + The current selected resolution scaling multiplier. El multiplicador de escalado de resolución seleccionado actualmente. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Velocidad de emulación actual. Los valores superiores o inferiores al 100% indican que la emulación se ejecuta más rápida o más lenta que en una Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. La cantidad de fotogramas por segundo que muestra el juego actualmente. Esto varía según el juego y la escena. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tiempo empleado en emular un fotograma de la Switch, sin contar la limitación de fotogramas ni la sincronización vertical. Para una emulación a máxima velocidad, debería ser de 16,67 ms como máximo. - + Unmute Desilenciar - + Mute Silenciar - + Reset Volume Restablecer volumen - + Configure Effects... - + &Clear Recent Files &Limpiar archivos recientes - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue &Continuar - + Warning: Outdated Game Format Advertencia: formato del juego obsoleto - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. Estás usando el formato de directorio ROM deconstruido para este juego, el cual es un formato obsoleto que ha sido reemplazado por otros como NCA, NAX, XCI o NSP. Los directorios ROM deconstruidos carecen de iconos, metadatos y compatibilidad con actualizaciones.<br>Para obtener una explicación de los distintos formatos de Switch compatibles con Eden, consulta nuestro manual de usuario. Este mensaje no volverá a aparecer de nuevo. - - + + Error while loading ROM! ¡Error al cargar la ROM! - + The ROM format is not supported. El formato de la ROM no está soportado. - + An error occurred initializing the video core. Se produjo un error al inicializar el núcleo de video. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. ¡Error al cargar la ROM! %1 - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. %1<br>Por favor vuelva a volcar sus archivos, o pida ayuda en Discord/Stoat. - + An unknown error occurred. Please see the log for more details. Ha ocurrido un error desconocido. Por favor mire el registro para más detalles. - - + + (64-bit) (64-bit) - - + + (32-bit) (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - + Closing software... Cerrando el programa... - + Save Data Datos de guardado - + Mod Data Datos del mod - + Error Opening %1 Folder Error abriendo la carpeta %1 - - + + Folder does not exist! ¡La carpeta no existe! - + Remove Installed Game Contents? ¿Eliminar el contenido instalado del juego? - + Remove Installed Game Update? ¿Eliminar la actualización instalada del juego? - + Remove Installed Game DLC? ¿Eliminar el contenido descargable instalado del juego? - + Remove Entry Eliminar entrada - + Delete OpenGL Transferable Shader Cache? ¿Desea eliminar el caché transferible de sombreadores de OpenGL? - + Delete Vulkan Transferable Shader Cache? ¿Desea eliminar el caché transferible de sombreadores de Vulkan? - + Delete All Transferable Shader Caches? ¿Desea eliminar todo el caché transferible de sombreadores? - + Remove Custom Game Configuration? ¿Borrar configuración personalizada del juego? - + Remove Cache Storage? ¿Borrar el almacenamiento de caché? - + Remove File Eliminar archivo - + Remove Play Time Data Eliminar datos del tiempo de juego - + Reset play time? ¿Reiniciar el tiempo de juego? - - + + RomFS Extraction Failed! ¡Fallo al extraer el RomFS! - + There was an error copying the RomFS files or the user cancelled the operation. Ocurrió un error al copiar los archivos de la RomFS o el usuario canceló la operación. - + Full Completo - + Skeleton Esqueleto - + Select RomFS Dump Mode Seleccione el método de volcado del RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Por favor selecciona como quieres que sea volcada la RomFS.<br>Completa copiará todos los archivos en el nuevo directorio mientras que <br>esqueleto solo creará la estructura de los directorios. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root No hay suficiente espacio libre en %1 para extraer la RomFS. Por favor libera espacio o selecciona un directorio de volcado diferente en Emulación > Configurar > Sistema > Sistema de archivos > Volcado raiz - + Extracting RomFS... Extrayendo el RomFS... - - + + Cancel Cancelar - + RomFS Extraction Succeeded! ¡La extracción del RomFS ha sido un éxito! - + The operation completed successfully. La operación se completó con éxito. - + Error Opening %1 Error al abrir %1 - + Select Directory Seleccionar directorio - + Properties Propiedades - + The game properties could not be loaded. No se pudieron cargar las propiedades del juego. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Ejecutable de Switch (%1);;Todos los archivos (*.*) - + Load File Cargar archivo - + Open Extracted ROM Directory Abrir directorio de la ROM extraída - + Invalid Directory Selected Seleccionado directorio inválido - + The directory you have selected does not contain a 'main' file. El directorio seleccionado no contiene un archivo 'main'. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - Archivo de Switch instalable (*.nca *.nsp *.xci);;Archivo de contenido de Nintendo (*.nca);;Paquete de envío de Nintendo (*.nsp);;Imagen de cartucho NX (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) + - + Install Files Instalar archivos - + %n file(s) remaining %n archivo(s) restantes%n archivo(s) restantes%n archivo(s) restantes - + Installing file "%1"... Instalando el archivo "%1"... - - + + Install Results Resultados de la instalación - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Para evitar posibles conflictos, desaconsejamos instalar juegos base en la NAND. Por favor, use solo esta función para instalar actualizaciones y contenido descargable. - + %n file(s) were newly installed %n archivo(s) se instalaron recientemente @@ -7731,7 +7741,7 @@ Por favor, use solo esta función para instalar actualizaciones y contenido desc - + %n file(s) were overwritten %n archivo(s) fueron sobreescritos @@ -7740,7 +7750,7 @@ Por favor, use solo esta función para instalar actualizaciones y contenido desc - + %n file(s) failed to install fallo al instalar %n archivo(s) @@ -7749,324 +7759,324 @@ Por favor, use solo esta función para instalar actualizaciones y contenido desc - + System Application Aplicación del sistema - + System Archive Archivo del sistema - + System Application Update Actualización de la aplicación del sistema - + Firmware Package (Type A) Paquete de firmware (Tipo A) - + Firmware Package (Type B) Paquete de firmware (Tipo B) - + Game Juego - + Game Update Actualización del juego - + Game DLC Contenido descargable del juego - + Delta Title Título Delta - + Select NCA Install Type... Seleccione el tipo de instalación NCA... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Seleccione el tipo de título en el que desea instalar este NCA: (En la mayoría de los casos, la opción predeterminada "Juego" es suficiente). - + Failed to Install Fallo al instalar - + The title type you selected for the NCA is invalid. El tipo de título que ha seleccionado para el NCA es inválido. - + File not found Archivo no encontrado - + File "%1" not found Archivo "%1" no encontrado - + OK Aceptar - + Function Disabled Función desactivada - + Compatibility list reporting is currently disabled. Check back later! Los informes de la lista de compatibilidad están deshabilitados. ¡Vuelva más tarde! - + Error opening URL Error abriendo URL - + Unable to open the URL "%1". No se pudo abrir URL "%1". - + TAS Recording Grabación TAS - + Overwrite file of player 1? ¿Sobrescribir el archivo del jugador 1? - + Invalid config detected Detectada configuración inválida - + Handheld controller can't be used on docked mode. Pro controller will be selected. El mando del modo portátil no puede usarse en el modo sobremesa. El mando pro será seleccionado en su lugar. - - + + Amiibo Amiibo - - + + The current amiibo has been removed El amiibo actual fue borrado - + Error Error - - + + The current game is not looking for amiibos El juego actual no está buscando amiibos - + Amiibo File (%1);; All Files (*.*) Archivo Amiibo (%1);; Todos los archivos (*.*) - + Load Amiibo Cargar Amiibo - + Error loading Amiibo data Error al cargar los datos del Amiibo - + The selected file is not a valid amiibo El archivo seleccionado no es un amiibo válido - + The selected file is already on use El archivo seleccionado se encuentra en uso - + An unknown error occurred Ha ocurrido un error desconocido - + No firmware available No hay firmware disponible - + Firmware Corrupted Firmware corrompido - + Unknown applet Applet desconocido - + Applet doesn't map to a known value. Applet no asigna a un valor conocido. - + Record not found Grabación no encontrada - + Applet not found. Please reinstall firmware. Apple no encontrado. Por favor vuelva a instalar el firmware. - + Capture Screenshot Captura de pantalla - + PNG Image (*.png) Imagen PNG (*.png) - + TAS state: Running %1/%2 Estado de TAS: Ejecutando %1/%2 - + TAS state: Recording %1 Estado de TAS: Grabando %1 - + TAS state: Idle %1/%2 Estado de TAS: Inactivo %1/%2 - + TAS State: Invalid Estado de TAS: Inválido - + &Stop Running &Parar de ejecutarse - + Stop R&ecording &Parar grabación - + Building: %n shader(s) Construyendo: %n sombreador(es)Construyendo: %n sombreador(es)Construyendo: %n sombreador(es) - + Scale: %1x %1 is the resolution scaling factor Escala: %1x - + Speed: %1% / %2% Velocidad: %1% / %2% - + Speed: %1% Velocidad: %1% - + Game: %1 FPS Juego: %1 FPS - + Frame: %1 ms Fotograma: %1 ms - + NO AA NO AA - + NO FX - + FX - + VOLUME: MUTE VOLUMEN: SILENCIADO - + VOLUME: %1% Volume percentage (e.g. 50%) VOLUMEN: %1% - + Derivation Components Missing Componentes de derivación ausentes - + Decryption keys are missing. Install them now? Las claves de desencriptado están ausentes. ¿Desea instalarlas ahora? - + Wayland Detected! ¡Wayland detectado! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8077,74 +8087,74 @@ Se recomienda usar X11 en su lugar. ¿Le gustaría forzar a usarlo en futuras ejecuciones? - + Use X11 Usar X11 - + Continue with Wayland Continuar con Wayland - + Don't show again No mostrar de nuevo - + Restart Required Reinicio requerido - + Restart Eden to apply the X11 backend. Reinicie Eden para aplicar el motor X11. - + Slow Lento - + Turbo Turbo - + Unlocked Desbloqueado - + Select RomFS Dump Target Seleccione el destinatario para el volcado del RomFS - + Please select which RomFS you would like to dump. Por favor seleccione que RomFS desea volcar. - + Are you sure you want to close Eden? ¿Está seguro de que quiere cerrar Eden? - - - + + + Eden Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. ¿Está seguro de que desea parar la emulación? Cualquier progreso sin guardar se perderá. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/fi.ts b/dist/languages/fi.ts index 5b075f0b0e..49a9b231e9 100644 --- a/dist/languages/fi.ts +++ b/dist/languages/fi.ts @@ -30,8 +30,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Sivusto</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Lähdekoodi</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Tekijät</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Lisenssi</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -399,252 +399,262 @@ Can help reduce stuttering at lower framerates. - - Accuracy: + + Enable cheats by default - - Change the accuracy of the emulated CPU (for debugging only). - - - - - - Backend: + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. - CPU Clocks + Accuracy: + Change the accuracy of the emulated CPU (for debugging only). + + + + + + Backend: + + + + + CPU Clocks + + + + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. - + Faster FRSQRTE and FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. - + Faster ASIMD instructions (32 bits only) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. - + Inaccurate NaN handling - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. - + Disable address space checks - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. - + API: - + Changes the output graphics API. Vulkan is recommended. - + Device: - + This setting selects the GPU to use (Vulkan only). - + Resolution: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: - + FSR Sharpness: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. - + Aspect Ratio: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. - + ASTC Decoding Method: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -653,75 +663,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -729,79 +719,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) - + Slightly improves performance by moving presentation to a separate CPU thread. - + Force maximum clocks (Vulkan only) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. - + Anisotropic Filtering: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -810,1290 +800,1290 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. - + Enable Compute Pipelines (Intel Vulkan Only) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. - + Sync to framerate of video playback - + Run the game at normal speed during video playback, even when the framerate is unlocked. - + Barrier feedback loops - + Improves rendering of transparency effects in specific games. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: - + This option can be overridden when region setting is auto-select - + Region: - + The region of the console. - + Time Zone: - + The time zone of the console. - + Sound Output Mode: - + Console Mode: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity - + Hides the mouse after 2.5s of inactivity. - + Check for updates - + Whether or not to check for updates upon startup. - + Enable Gamemode - + Force X11 as Graphics Backend - + Custom frontend - + Real applet - - + + Disabled - + Never - + On Load - + Always - + CPU - + GPU - + CPU Asynchronous - + Uncompressed (Best quality) - + BC1 (Low quality) - + BC3 (Medium quality) - - + + Auto - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative - + Aggressive - + Vulkan - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null - + Fast - - - + + + Accurate - - - + + + Default - + Unsafe (fast) - + Safe (stable) - + Immediate - + Balanced - + Unsafe - + Paranoid (disables most optimizations) - + Debugging - + Dynarmic - + NCE - + Borderless Windowed - + Exclusive Fullscreen - + No Video Output - + CPU Video Decoding - + GPU Video Decoding (Default) - + 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] - + 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] - + 2X (1440p/2160p) - + 3X (2160p/3240p) - + 4X (2880p/4320p) - + 5X (3600p/5400p) - + 6X (4320p/6480p) - + 7X (5040p/7560p) - + 8X (5760p/8640p) - + Nearest Neighbor - + Bilinear - + Bicubic - + Gaussian - + Lanczos - + ScaleForce - + AMD FidelityFX Super Resolution - + Area - + MMPX - + Zero-Tangent - + B-Spline - + Mitchell - + Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None - + FXAA - + SMAA - + Default (16:9) - + Force 4:3 - + Force 21:9 - + Force 16:10 - + Stretch to Window - + Automatic - + 2x - + 4x - + 8x - + 16x - + Japanese (日本語) - + American English - + French (français) - + German (Deutsch) - + Italian (italiano) - + Spanish (español) - + Chinese - + Korean (한국어) - + Dutch (Nederlands) - + Portuguese (português) - + Russian (Русский) - + Taiwanese - + British English - + Canadian French - + Latin American Spanish - + Simplified Chinese - + Traditional Chinese (正體中文) - + Brazilian Portuguese (português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan - + USA - + Europe - + Australia - + China - + Korea - + Taiwan - + Auto (%1) Auto select time zone - + Default (%1) Default time zone - + CET - + CST6CDT - + Cuba - + EET - + Egypt - + Eire - + EST - + EST5EDT - + GB - + GB-Eire - + GMT - + GMT+0 - + GMT-0 - + GMT0 - + Greenwich - + Hongkong - + HST - + Iceland - + Iran - + Israel - + Jamaica - + Kwajalein - + Libya - + MET - + MST - + MST7MDT - + Navajo - + NZ - + NZ-CHAT - + Poland - + Portugal - + PRC - + PST8PDT - + ROC - + ROK - + Singapore - + Turkey - + UCT - + Universal - + UTC - + W-SU - + WET - + Zulu - + Mono - + Stereo - + Surround - + 4GB DRAM (Default) - + 6GB DRAM (Unsafe) - + 8GB DRAM - + 10GB DRAM (Unsafe) - + 12GB DRAM (Unsafe) - + Docked - + Handheld - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) - + Only if game specifies not to stop - + Never ask - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) - + High (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6010,50 +6000,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! openGL ei ole saatavilla! - + OpenGL shared contexts are not supported. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! Virhe käynnistäessä OpenGL ydintä! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. - + Error while initializing OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 - + This build doesn't have OpenGL support. @@ -6818,1132 +6808,1152 @@ Debug Message: &Emulaatio - + + &Cheats + + + + &View &Katso - + &Reset Window Size - + &Debugging - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p - + Reset Window Size to 720p - + Reset Window Size to &900p - + Reset Window Size to 900p - + Reset Window Size to &1080p - + Reset Window Size to 1080p - + &Multiplayer - + &Tools - + Am&iibo - + Launch &Applet - + &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help &Apu - + &Install Files to NAND... - + L&oad File... - + Load &Folder... - + E&xit P&oistu - - + + &Pause &Pysäytä - + &Stop &Lopeta - + &Verify Installed Contents - + &About Eden - + Single &Window Mode - + Con&figure... - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar - + Show &Status Bar - + Show Status Bar Näytä statuspalkki - + &Browse Public Game Lobby - + &Create Room - + &Leave Room - + &Direct Connect to Room - + &Show Current Room - + F&ullscreen - + &Restart - + Load/Remove &Amiibo... - + Open &Mods Page - + &User Handbook - + &Capture Screenshot - + &Album - + &Set Nickname and Owner - + &Delete Game Data - + &Restore Amiibo - + &Format Amiibo - + &Mii Editor - + &Configure TAS... - + Configure C&urrent Game... - - + + &Start &Käynnistä - + &Reset - - + + R&ecord - + Open &Controller Menu - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -7951,74 +7961,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/fr.ts b/dist/languages/fr.ts index 2f2ddd1481..a4673da187 100644 --- a/dist/languages/fr.ts +++ b/dist/languages/fr.ts @@ -37,8 +37,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Site web</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Code source</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributeurs</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Revolt</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licence</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -410,49 +410,59 @@ Can help reduce stuttering at lower framerates. Peut aider à réduire les saccades à des framerates faibles. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Précision : - + Change the accuracy of the emulated CPU (for debugging only). Modifie la précision du CPU émulé (réservé au débogage). - - + + Backend: Arrière-plan : - + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks Ticks CPU personnalisés - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. Définissez une valeur personnalisée pour les cycles CPU. Des valeurs plus élevées peuvent améliorer les performances, mais risquent de provoquer des blocages. Une plage de 77-21000 est recommandée. - + Enable Host MMU Emulation (fastmem) Activer l'émulation MMU de l'hôte (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -461,100 +471,100 @@ L'activer permet à l'invité de lire/écrire directement dans la mém Désactiver cela force tous les accès mémoire à utiliser l'émulation logicielle de la MMU. - + Unfuse FMA (improve performance on CPUs without FMA) Désactivation du FMA (améliore les performances des CPU sans FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Cette option améliore la vitesse en réduisant la précision des instructions de multiplication et addition fusionnées sur les processeurs qui ne prennent pas en charge nativement FMA. - + Faster FRSQRTE and FRECPE FRSQRTE et FRECPE plus rapides - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Cette option améliore la vitesse de certaines fonctions à virgule flottante approximatives en utilisant des approximations natives moins précises. - + Faster ASIMD instructions (32 bits only) Instructions ASIMD plus rapides (32 bits seulement) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Cette option améliore la vitesse des fonctions à virgule flottante ASIMD sur 32 bits en utilisant des modes d'arrondi incorrects. - + Inaccurate NaN handling Traitement NaN imprécis - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Cette option améliore la vitesse en supprimant la vérification des NaN. Veuillez noter que cela réduit également la précision de certaines instructions en virgule flottante. - + Disable address space checks Désactiver les vérifications de l'espace d'adresse - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. Cette option améliore la vitesse en supprimant une vérification de sécurité avant chaque opération mémoire. La désactiver peut permettre l’exécution de code arbitraire. - + Ignore global monitor Ignorer le moniteur global - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Cette option améliore la vitesse en se basant uniquement sur la sémantique de cmpxchg pour garantir la sécurité des instructions d'accès exclusif. Veuillez noter que cela peut entraîner des blocages et d'autres conditions de concurrence. - + API: API : - + Changes the output graphics API. Vulkan is recommended. Modifie l’API graphique utilisée en sortie. Vulkan est recommandé. - + Device: Appareil : - + This setting selects the GPU to use (Vulkan only). Ce paramètre permet de sélectionner le GPU à utiliser (Vulkan uniquement). - + Resolution: Résolution : - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -563,27 +573,27 @@ Des résolutions plus élevées nécessitent plus de VRAM et de bande passante. Des options inférieures à 1X peuvent provoquer des artefacts. - + Window Adapting Filter: Filtre de fenêtre adaptatif : - + FSR Sharpness: Netteté FSR : - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Méthode d'anticrénelage : - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -592,22 +602,22 @@ SMAA offre la meilleure qualité. FXAA peut produire une image plus stable à des résolutions plus faibles. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Mode Plein écran : - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -616,12 +626,12 @@ Sans bordure offre la meilleure compatibilité avec le clavier à l'écran Le mode plein écran exclusif peut offrir de meilleures performances et un meilleur support Freesync/Gsync. - + Aspect Ratio: Format : - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -630,35 +640,35 @@ La plupart des jeux ne supportent que le format 16:9, donc des modifications son Contrôle également le format des captures d’écran. - + Use persistent pipeline cache Conserver le cache du rendu graphique - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Permet de sauvegarder les shaders sur le stockage pour un chargement plus rapide lors des démarrages ultérieurs du jeu. Le désactiver est uniquement destiné au débogage. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: Émulation NVDEC : - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -667,12 +677,12 @@ Elles peuvent être décodées soit par le CPU, soit par le GPU, ou pas du tout Dans la plupart des cas, le décodage GPU offre les meilleures performances. - + ASTC Decoding Method: Méthode de décodage ASTC : - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -684,12 +694,12 @@ GPU : Utiliser les shaders de calcul du GPU pour décoder les textures ASTC (rec CPU asynchrone : Utiliser le CPU pour décoder les textures ASTC à la demande. Élimine les saccades liées au décodage ASTC, mais peut provoquer des artefacts. - + ASTC Recompression Method: Méthode de recompression ASTC : - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. @@ -697,64 +707,44 @@ BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, BC1/BC3 : Le format intermédiaire sera recompressé en BC1 ou BC3, ce qui économise de la VRAM mais dégrade la qualité de l’image. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: Mode d'utilisation de la VRAM : - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. Permet de choisir si l’émulateur doit privilégier la conservation de la mémoire ou utiliser au maximum la mémoire vidéo disponible pour les performances. Le mode agressif peut affecter les performances d’autres applications, comme les logiciels d’enregistrement. - + Skip CPU Inner Invalidation Ignorer l'invalidation interne du CPU - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. Ignore certaines invalidations de cache lors des mises à jour de la mémoire, réduisant l’utilisation du CPU et améliorant la latence. Cela peut provoquer des plantages légers. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: Mode VSync : - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -765,12 +755,12 @@ Mailbox peut offrir une latence inférieure à FIFO et n’entraîne pas de déc Immediate (pas de synchronisation) affiche ce qui est disponible et peut provoquer du déchirement. - + Sync Memory Operations Synchroniser les opérations mémoire - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. @@ -779,68 +769,68 @@ Cette option corrige des problèmes dans les jeux, mais peut dégrader les perfo Les jeux Unreal Engine 4 sont souvent ceux qui bénéficient le plus de ce réglage. - + Enable asynchronous presentation (Vulkan only) Activer la présentation asynchrone (Vulkan uniquement) - + Slightly improves performance by moving presentation to a separate CPU thread. Améliore légèrement les performances en déplaçant la présentation vers un thread CPU séparé. - + Force maximum clocks (Vulkan only) Forcer la fréquence d'horloge maximale (Vulkan uniquement) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Les exécutions fonctionnent en arrière-plan en attendant les commandes graphiques pour empêcher le GPU de réduire sa vitesse de fréquence d'horloge. - + Anisotropic Filtering: Filtrage anisotropique : - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. Contrôle la qualité du rendu des textures sous des angles obliques. Il est sûr de le régler à 16x sur la plupart des GPU. - + GPU Mode: Mode GPU : - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: Précision du DMA : - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -849,89 +839,89 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation Activer la compilation asynchrone des shaders - + May reduce shader stutter. Peut réduire les saccades dues aux shaders. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache Utiliser le cache de pipeline Vulkan - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. Active le cache de pipeline spécifique au fournisseur de GPU. Cette option peut améliorer considérablement le temps de chargement des shaders dans les cas où le pilote Vulkan ne stocke pas les fichiers de cache de pipeline en interne. - + Enable Compute Pipelines (Intel Vulkan Only) Activer les pipelines de calcul (Vulkan sur Intel uniquement) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. @@ -940,84 +930,84 @@ Ce réglage n’existe que pour les pilotes propriétaires Intel et peut provoqu Les pipelines de calcul sont toujours activés sur tous les autres pilotes. - + Enable Reactive Flushing Activer le Vidage Réactif - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Utilise une purge réactive au lieu d'une purge prédictive, permettant une synchronisation de la mémoire plus précise. - + Sync to framerate of video playback Synchro la fréquence d'image de la relecture du vidéo - + Run the game at normal speed during video playback, even when the framerate is unlocked. Éxécuter le jeu à une vitesse normale pendant la relecture du vidéo, même-ci la fréquence d'image est dévérouillée. - + Barrier feedback loops Boucles de rétroaction de barrière - + Improves rendering of transparency effects in specific games. Améliore le rendu des effets de transparence dans des jeux spécifiques. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State État dynamique étendu - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading Échantillonnage de shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. Permet au shader de fragments de s’exécuter pour chaque échantillon dans un fragment multi-échantillonné, au lieu d’une seule fois par fragment. @@ -1025,96 +1015,96 @@ Améliore la qualité graphique au prix de performances réduites. Des valeurs plus élevées améliorent la qualité mais dégradent les performances. - + RNG Seed Seed RNG - + Controls the seed of the random number generator. Mainly used for speedrunning. Contrôle la graine du générateur de nombres aléatoires. Principalement utilisé pour le speedrun. - + Device Name Nom de l'appareil - + The name of the console. Nom de la console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: Date RTC personnalisée : - + This option allows to change the clock of the console. Can be used to manipulate time in games. Cette option permet de modifier l’horloge de la console. Peut être utilisée pour manipuler le temps dans les jeux. - + The number of seconds from the current unix time Nombre de secondes écoulées depuis le 1er janvier 1970. - + Language: Langue : - + This option can be overridden when region setting is auto-select Cette option peut être remplacée lorsque la région est sur auto. - + Region: Région : - + The region of the console. Région de la console. - + Time Zone: Fuseau horaire : - + The time zone of the console. Fuseau horaire de la console. - + Sound Output Mode: Mode de sortie sonore : - + Console Mode: Mode console : - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. @@ -1123,1026 +1113,1026 @@ Les jeux adaptent leur résolution, leurs paramètres graphiques et les manettes Passer en mode Portable peut améliorer les performances sur les systèmes peu puissants. - + Prompt for user profile on boot Choisir l’utilisateur au démarrage. - + Useful if multiple people use the same PC. Utile si plusieurs personnes utilisent le même PC. - + Pause when not in focus Pause lorsque la fenêtre n’est pas active. - + Pauses emulation when focusing on other windows. Met l’émulation en pause dès que l’utilisateur change de fenêtre. - + Confirm before stopping emulation Confirmer avant d'arrêter l'émulation - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. Ignore les demandes de confirmation pour arrêter l’émulation. L’activer permet de contourner ces confirmations et de quitter directement l’émulation. - + Hide mouse on inactivity Cacher la souris en cas d'inactivité - + Hides the mouse after 2.5s of inactivity. Cache le curseur après 2,5 secondes d’inactivité. - + Check for updates Rechercher des mises à jours - + Whether or not to check for updates upon startup. Vérifier ou non les mises à jour au démarrage. - + Enable Gamemode Activer le mode jeu - + Force X11 as Graphics Backend Forcer X11 comme moteur graphique - + Custom frontend Interface personnalisée - + Real applet Applet réel - - + + Disabled Désactivé - + Never Jamais - + On Load Au chargement - + Always Toujours - + CPU CPU - + GPU GPU - + CPU Asynchronous CPU Asynchrone - + Uncompressed (Best quality) Non compressé (Meilleure qualité) - + BC1 (Low quality) BC1 (Basse qualité) - + BC3 (Medium quality) BC3 (Qualité moyenne) - - + + Auto Auto - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative Conservateur - + Aggressive Agressif - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null Nul - + Fast Rapide - - - + + + Accurate Précis - - - + + + Default Par défaut - + Unsafe (fast) Insecure (rapide) - + Safe (stable) Sûr (stable) - + Immediate - + Balanced Moyen - + Unsafe Risqué - + Paranoid (disables most optimizations) Paranoïaque (désactive la plupart des optimisations) - + Debugging Débogage - + Dynarmic Dynamique - + NCE NCE - + Borderless Windowed Fenêtré sans bordure - + Exclusive Fullscreen Plein écran exclusif - + No Video Output Pas de sortie vidéo - + CPU Video Decoding Décodage Vidéo sur le CPU - + GPU Video Decoding (Default) Décodage Vidéo sur le GPU (par défaut) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [EXPÉRIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [EXPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [EXPÉRIMENTAL] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1,25X (900p/1350p) [EXPÉRIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [EXPÉRIMENTAL] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Plus proche voisin - + Bilinear Bilinéaire - + Bicubic Bicubique - + Gaussian Gaussien - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX Super Resolution - + Area Area (Par zone) - + MMPX MMPX - + Zero-Tangent Zero-Tangent - + B-Spline B-Spline - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Aucun - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Par défaut (16:9) - + Force 4:3 Forcer le 4:3 - + Force 21:9 Forcer le 21:9 - + Force 16:10 Forcer le 16:10 - + Stretch to Window Étirer à la fenêtre - + Automatic Automatique - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Japonais (日本語) - + American English Anglais Américain - + French (français) Français (français) - + German (Deutsch) Allemand (Deutsch) - + Italian (italiano) Italien (italiano) - + Spanish (español) Espagnol (español) - + Chinese Chinois - + Korean (한국어) Coréen (한국어) - + Dutch (Nederlands) Néerlandais (Nederlands) - + Portuguese (português) Portugais (português) - + Russian (Русский) Russe (Русский) - + Taiwanese Taïwanais - + British English Anglais Britannique - + Canadian French Français Canadien - + Latin American Spanish Espagnol d'Amérique Latine - + Simplified Chinese Chinois Simplifié - + Traditional Chinese (正體中文) Chinois Traditionnel (正體中文) - + Brazilian Portuguese (português do Brasil) Portugais Brésilien (português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan Japon - + USA É.-U.A. - + Europe Europe - + Australia Australie - + China Chine - + Korea Corée - + Taiwan Taïwan - + Auto (%1) Auto select time zone Auto (%1) - + Default (%1) Default time zone Par défaut (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Égypte - + Eire Eire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hong Kong - + HST HST - + Iceland Islande - + Iran Iran - + Israel Israël - + Jamaica Jamaïque - + Kwajalein Kwajalein - + Libya Libye - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Pologne - + Portugal Portugal - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapour - + Turkey Turquie - + UCT UCT - + Universal Universel - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Stéréo - + Surround Surround - + 4GB DRAM (Default) 4 GB DRAM (Par défaut) - + 6GB DRAM (Unsafe) 6 GB DRAM (Risqué) - + 8GB DRAM 8GO DRAM - + 10GB DRAM (Unsafe) 10GO DRAM (Insecure) - + 12GB DRAM (Unsafe) 12GO DRAM (Insecure) - + Docked Mode TV - + Handheld Mode Portable - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) Toujours demander (par défaut) - + Only if game specifies not to stop Uniquement si le jeu précise de ne pas s'arrêter - + Never ask Jamais demander - + Very Small (16 MB) Très petit (16Mo) - + Small (32 MB) Petit (32Mo) - + Normal (128 MB) Normal (128Mo) - + Large (256 MB) Large (256Mo) - + Very Large (512 MB) Très large (512Mo) - + Very Low (4 MB) Très faible (4 Mo) - + Low (8 MB) Faible (8 Mo) - + Normal (16 MB) Normal (16 Mo) - + Medium (32 MB) Moyen (32 Mo) - + High (64 MB) Élevé (64 Mo) - + Very Low (32) Très faible (32) - + Low (64) Faible (64) - + Normal (128) Normal (128) - + Medium (256) Moyen (256) - + High (512) Élevé (512) - + ExtendedDynamicState 1 État dynamique étendu 1 - + ExtendedDynamicState 2 État dynamique étendu 2 - + ExtendedDynamicState 3 État dynamique étendu 3 - + Tree View Vue en liste - + Grid View Vue en grille @@ -6097,50 +6087,50 @@ Veuillez aller dans Configurer -> Système -> Réseau puis en choisir une. GRenderWindow - - + + OpenGL not available! OpenGL n'est pas disponible ! - + OpenGL shared contexts are not supported. Les contextes OpenGL partagés ne sont pas pris en charge. - + Eden has not been compiled with OpenGL support. Eden n'a pas été compilé avec le support OpenGL - - - + + + Error while initializing OpenGL! Erreur lors de l'initialisation d'OpenGL ! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Votre GPU peut ne pas prendre en charge OpenGL, ou vous n'avez pas les derniers pilotes graphiques. - + Error while initializing OpenGL 4.6! Erreur lors de l'initialisation d'OpenGL 4.6 ! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Votre GPU peut ne pas prendre en charge OpenGL 4.6 ou vous ne disposez pas du dernier pilote graphique: %1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Votre GPU peut ne pas prendre en charge une ou plusieurs extensions OpenGL requises. Veuillez vous assurer que vous disposez du dernier pilote graphique.<br><br>GL Renderer :<br>%1<br><br>Extensions non prises en charge :<br>%2 - + This build doesn't have OpenGL support. @@ -6907,1132 +6897,1152 @@ Message de débogage : &Émulation - + + &Cheats + + + + &View &Vue - + &Reset Window Size &Réinitialiser la taille de la fenêtre - + &Debugging &Débogage - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p &Réinitialiser la taille de la fenêtre à 720p - + Reset Window Size to 720p Réinitialiser la taille de la fenêtre à 720p - + Reset Window Size to &900p Réinitialiser la taille de la fenêtre à &900p - + Reset Window Size to 900p Réinitialiser la taille de la fenêtre à 900p - + Reset Window Size to &1080p Réinitialiser la taille de la fenêtre à &1080p - + Reset Window Size to 1080p Réinitialiser la taille de la fenêtre à 1080p - + &Multiplayer &Multijoueur - + &Tools &Outils - + Am&iibo Am&iibo - + Launch &Applet - + &TAS &TAS - + &Create Home Menu Shortcut &Créer un Raccourci du Menu d'Accueil - + Install &Firmware Installer le &Firmware - + &Help &Aide - + &Install Files to NAND... &Installer des fichiers sur la NAND... - + L&oad File... &Charger un fichier... - + Load &Folder... &Charger un dossier - + E&xit Q&uitter - - + + &Pause &Pause - + &Stop &Arrêter - + &Verify Installed Contents &Vérifier les contenus installés - + &About Eden &À propos d'Eden - + Single &Window Mode &Mode fenêtre unique - + Con&figure... &Configurer... - + Ctrl+, Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar &Afficher la barre de filtre - + Show &Status Bar &Afficher la barre d'état - + Show Status Bar Afficher la barre d'état - + &Browse Public Game Lobby &Parcourir le menu des jeux publics - + &Create Room &Créer un salon - + &Leave Room &Quitter le salon - + &Direct Connect to Room &Connexion directe au salon - + &Show Current Room &Afficher le salon actuel - + F&ullscreen P&lein écran - + &Restart &Redémarrer - + Load/Remove &Amiibo... Charger/Retirer un &Amiibo… - + Open &Mods Page Ouvrir la &page des mods - + &User Handbook - + &Capture Screenshot &Capture d'écran - + &Album - + &Set Nickname and Owner &Définir le surnom et le propriétaire - + &Delete Game Data &Supprimer les données du jeu - + &Restore Amiibo &Restaurer l'amiibo - + &Format Amiibo &Formater l'amiibo - + &Mii Editor - + &Configure TAS... &Configurer TAS... - + Configure C&urrent Game... Configurer le j&eu actuel... - - + + &Start &Démarrer - + &Reset &Réinitialiser - - + + R&ecord En&registrer - + Open &Controller Menu Ouvrir le &menu des manettes - + Install Decryption &Keys Installer les &clés de déchiffrement - + &Home Menu - + &Desktop &Bureau - + &Application Menu &Menu de l'Application - + &Root Data Folder &Dossier de Données (Root) Principal. - + &NAND Folder &Dossier NAND - + &SDMC Folder &Dossier SDMC - + &Mod Folder &Dossier Mod - + &Log Folder &Dossier Log - + From Folder Depuis un dossier - + From ZIP Depuis une archive ZIP - + &Eden Dependencies Dépendances d'&Eden - + &Data Manager &Gestionnaire de données - + &Tree View - + &Grid View - + Game Icon Size - - + + None Aucun - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute Remettre le son - + Mute Couper le son - + Reset Volume Réinitialiser le volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue &Continuer - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) (64-bit) - - + + (32-bit) (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... Fermeture du logiciel... - + Save Data Données de sauvegarde - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? Réinitialiser le temps de jeu ? - - + + RomFS Extraction Failed! L'extraction de la RomFS a échoué ! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel Annuler - + RomFS Extraction Succeeded! Extraction de la RomFS réussi ! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties Propriétés - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game Jeu - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install Échec de l'installation - + The title type you selected for the NCA is invalid. - + File not found Fichier non trouvé - + File "%1" not found - + OK OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo Amiibo - - + + The current amiibo has been removed - + Error Erreur - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo Charger un Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted Firmware corrompu - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE VOLUME : MUET - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! Wayland détecté ! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8040,74 +8050,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/hu.ts b/dist/languages/hu.ts index 29ba70527e..527f1c0029 100644 --- a/dist/languages/hu.ts +++ b/dist/languages/hu.ts @@ -30,7 +30,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> @@ -399,195 +399,205 @@ Can help reduce stuttering at lower framerates. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Pontosság: - + Change the accuracy of the emulated CPU (for debugging only). - - + + Backend: Backend: - + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) FMA kikapcsolása (javítja a teljesítményt FMA nélküli CPU-kon) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Ez az opció a fused-multiply-add utasítások pontosságának csökkentésével javítja a sebességet olyan CPU-k esetén, amelyek nem rendelkeznek natív FMA támogatással. - + Faster FRSQRTE and FRECPE Gyorsabb FRSQRTE és FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Ez az opció javítja néhány közelítő lebegőpontos függvény sebességét azáltal, hogy kevésbé pontos natív megközelítést használ. - + Faster ASIMD instructions (32 bits only) Gyorsabb ASIMD utasítások (csak 32 bit) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Ez az opció növeli a 32 bites ASIMD lebegőpontos függvények sebességét a helytelen kerekítési módok használatával. - + Inaccurate NaN handling Pontatlan NaN kezelés - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Ez az opció növeli a sebességet a NaN ellenőrzés kihagyásával. Kérjük, vedd figyelembe, hogy ez bizonyos lebegőpontos utasítások pontosságát is csökkenti. - + Disable address space checks Címtartomány-ellenőrzések kikapcsolása - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor Globális monitorozás mellőzése - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. - + API: API: - + Changes the output graphics API. Vulkan is recommended. - + Device: Eszköz: - + This setting selects the GPU to use (Vulkan only). - + Resolution: Felbontás: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: Ablakadaptív szűrő: - + FSR Sharpness: FSR élesség: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Élsimítási módszer: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Teljes képernyős mód: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -596,47 +606,47 @@ A borderless (szegély nélküli) biztosítja a legjobb kompatibilitást a képe Az exkluzív teljes képernyő jobb teljesítményt és jobb Freesync/Gsync támogatást kínálhat. - + Aspect Ratio: Képarány: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Lehetővé teszi az árnyékolók tárolását a gyorsabb betöltés érdekében a következő játékindításokkor. Kikapcsolása csak hibakeresésre szolgál. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: NVDEC emuláció: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -645,12 +655,12 @@ A dekódoláshoz használhatja a CPU-t vagy a GPU-t, vagy egyáltalán nem vége A legtöbb esetben a GPU dekódolás nyújtja a legjobb teljesítményt. - + ASTC Decoding Method: ASTC dekódoló módszer: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -659,75 +669,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: ASTC újraszűrési módszer: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: VRAM használati mód: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: VSync mód: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -735,79 +725,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) Aszinkron prezentálás engedélyezése (csak Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. Kicsit javítja a teljesítményt azáltal, hogy a megjelenítést külön CPU szálra helyezi át. - + Force maximum clocks (Vulkan only) Maximális órajelek kényszerítése (csak Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. A háttérben fut, miközben várja a grafikai parancsokat, hogy a GPU ne csökkentse az órajelét. - + Anisotropic Filtering: Anizotropikus szűrés: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -816,1290 +806,1290 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache Vulkan pipeline gyorsítótár használata. - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. - + Enable Compute Pipelines (Intel Vulkan Only) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing Reaktív ürítés használata - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Reaktív ürítést használ a prediktív ürítés helyett, ami pontosabb memóriaszinkronizálást tesz lehetővé. - + Sync to framerate of video playback Szinkronizálás a videolejátszás képkockasebességéhez - + Run the game at normal speed during video playback, even when the framerate is unlocked. A játék futtatása normál sebességgel videolejátszás közben, még akkor is, ha a képkockasebesség fel van oldva. - + Barrier feedback loops - + Improves rendering of transparency effects in specific games. Javítja az átlátszósági effektek megjelenítését bizonyos játékokban. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name Eszköznév - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: Egyéni RTC dátum: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: Nyelv: - + This option can be overridden when region setting is auto-select - + Region: Régió: - + The region of the console. - + Time Zone: Időzóna: - + The time zone of the console. - + Sound Output Mode: Hangkimeneti mód: - + Console Mode: Konzol mód: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation Emuláció leállításának megerősítése - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity Egér elrejtése inaktivitáskor - + Hides the mouse after 2.5s of inactivity. - + Check for updates - + Whether or not to check for updates upon startup. - + Enable Gamemode Játékmód engedélyezése - + Force X11 as Graphics Backend - + Custom frontend Egyéni frontend - + Real applet Valódi applet - - + + Disabled - + Never - + On Load - + Always - + CPU CPU - + GPU GPU - + CPU Asynchronous CPU aszinkron - + Uncompressed (Best quality) Tömörítetlen (legjobb minőség) - + BC1 (Low quality) BC1 (alacsony minőség) - + BC3 (Medium quality) BC3 (közepes minőség) - - + + Auto Automatikus - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative Takarékos - + Aggressive Aggresszív - + Vulkan Vulkan - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null Null - + Fast - - - + + + Accurate Pontos - - - + + + Default Alapértelmezett - + Unsafe (fast) - + Safe (stable) - + Immediate - + Balanced - + Unsafe Nem biztonságos - + Paranoid (disables most optimizations) Paranoid (a legtöbb optimalizálást letiltja) - + Debugging - + Dynarmic Dinamikus - + NCE NCE - + Borderless Windowed Szegély nélküli ablak - + Exclusive Fullscreen Exkluzív teljes képernyő - + No Video Output Nincs videokimenet - + CPU Video Decoding CPU videódekódolás - + GPU Video Decoding (Default) GPU videódekódolás (alapértelmezett) - + 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [KÍSÉRLETI] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [KÍSÉRLETI] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [KÍSÉRLETI] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Legközelebbi szomszéd - + Bilinear Bilineáris - + Bicubic Bikubikus - + Gaussian Gauss-féle - + Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution - + Area - + MMPX - + Zero-Tangent - + B-Spline - + Mitchell - + Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Nincs - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Alapértelmezett (16:9) - + Force 4:3 4:3 kényszerítése - + Force 21:9 21:9 kényszerítése - + Force 16:10 16:10 kényszerítése - + Stretch to Window Ablakhoz nyújtás - + Automatic Automatikus - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Japán (日本語) - + American English Amerikai angol - + French (français) Francia (français) - + German (Deutsch) Német (Deutsch) - + Italian (italiano) Olasz (italiano) - + Spanish (español) Spanyol (español) - + Chinese Kínai - + Korean (한국어) Koreai (한국어) - + Dutch (Nederlands) Holland (Nederlands) - + Portuguese (português) Portugál (português) - + Russian (Русский) Orosz (Русский) - + Taiwanese Tajvani - + British English Brit Angol - + Canadian French Kanadai francia - + Latin American Spanish Latin-amerikai spanyol - + Simplified Chinese Egyszerűsített kínai - + Traditional Chinese (正體中文) Hagyományos kínai (正體中文) - + Brazilian Portuguese (português do Brasil) Brazíliai portugál (português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan Japán - + USA USA - + Europe Európa - + Australia Ausztrália - + China Kína - + Korea Korea - + Taiwan Tajvan - + Auto (%1) Auto select time zone Automatikus (%1) - + Default (%1) Default time zone Alapértelmezett (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Kuba - + EET EET - + Egypt Egyiptom - + Eire Eire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Izland - + Iran Irán - + Israel Izrael - + Jamaica Jamaika - + Kwajalein Kwajalein - + Libya Líbia - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navahó - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Lengyelország - + Portugal Portugália - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Szingapúr - + Turkey Törökország - + UCT UCT - + Universal Univerzális - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Sztereó - + Surround Térhangzás - + 4GB DRAM (Default) 4GB DRAM (Alapértelmezett) - + 6GB DRAM (Unsafe) 6GB DRAM (Nem biztonságos) - + 8GB DRAM - + 10GB DRAM (Unsafe) - + 12GB DRAM (Unsafe) - + Docked Dokkolt - + Handheld Kézi - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) Mindig kérdezz rá (alapértelmezett) - + Only if game specifies not to stop Csak akkor, ha a játék kifejezetten kéri a folytatást. - + Never ask Soha ne kérdezz rá - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) - + High (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6025,50 +6015,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL nem elérhető! - + OpenGL shared contexts are not supported. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! Hiba történt az OpenGL inicializálása során! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Lehetséges, hogy a GPU-d nem támogatja az OpenGL-t, vagy nem a legfrissebb grafikus illesztőprogram van telepítve. - + Error while initializing OpenGL 4.6! Hiba történt az OpenGL 4.6 inicializálása során! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Lehetséges, hogy a GPU-d nem támogatja az OpenGL 4.6-ot, vagy nem a legfrissebb grafikus illesztőprogram van telepítve.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Előfordulhat, hogy a GPU-d nem támogat egy vagy több szükséges OpenGL kiterjesztést. Győződj meg róla, hogy a legújabb videokártya-illesztőprogramot használod.<br><br>GL Renderer:<br>%1<br><br>Nem támogatott kiterjesztések:<br>%2 - + This build doesn't have OpenGL support. @@ -6834,1132 +6824,1152 @@ Debug Message: &Emuláció - + + &Cheats + + + + &View &Nézet - + &Reset Window Size &Ablakméret visszaállítása - + &Debugging &Hibakeresés - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p Ablakfelbontás visszaállítása erre: &720p - + Reset Window Size to 720p Ablakfelbontás visszaállítása 720p-re - + Reset Window Size to &900p Ablakfelbontás visszaállítása erre: &900p - + Reset Window Size to 900p Ablakfelbontás visszaállítása 900p-re - + Reset Window Size to &1080p Ablakfelbontás visszaállítása erre: &1080p - + Reset Window Size to 1080p Ablakfelbontás visszaállítása 1080p-re - + &Multiplayer &Multiplayer - + &Tools &Eszközök - + Am&iibo - + Launch &Applet - + &TAS &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help &Segítség - + &Install Files to NAND... &Fájlok telepítése a NAND-ra... - + L&oad File... F&ájl betöltése... - + Load &Folder... &Mappa betöltése... - + E&xit K&ilépés - - + + &Pause &Szünet - + &Stop &Leállítás - + &Verify Installed Contents &Telepített tartalom ellenőrzése - + &About Eden - + Single &Window Mode &Egyablakos mód - + Con&figure... Kon&figurálás... - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar &Szűrősáv mutatása - + Show &Status Bar &Állapotsáv mutatása - + Show Status Bar Állapotsáv mutatása - + &Browse Public Game Lobby &Nyilvános játéklobbi böngészése - + &Create Room &Szoba létrehozása - + &Leave Room &Szoba elhagyása - + &Direct Connect to Room &Közvetlen csatlakozás szobához - + &Show Current Room &Jelenlegi szoba megjelenítése - + F&ullscreen T&eljes képernyő - + &Restart &Újraindítás - + Load/Remove &Amiibo... &Amiibo betöltése/törlése... - + Open &Mods Page &Modok oldal megnyitása - + &User Handbook - + &Capture Screenshot &Képernyőkép készítése - + &Album - + &Set Nickname and Owner &Becenév és tulajdonos beállítása - + &Delete Game Data &Játékadatok törlése - + &Restore Amiibo &Amiibo helyreállítása - + &Format Amiibo &Amiibo formázása - + &Mii Editor - + &Configure TAS... &TAS konfigurálása... - + Configure C&urrent Game... J&elenlegi játék konfigurálása... - - + + &Start &Indítás - + &Reset &Visszaállítás - - + + R&ecord F&elvétel - + Open &Controller Menu &Vezérlő menü megnyitása - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -7967,74 +7977,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/id.ts b/dist/languages/id.ts index 7792d12f35..ab30f9b70e 100644 --- a/dist/languages/id.ts +++ b/dist/languages/id.ts @@ -37,7 +37,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> @@ -407,49 +407,59 @@ Can help reduce stuttering at lower framerates. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Akurasi: - + Change the accuracy of the emulated CPU (for debugging only). - - + + Backend: Backend: - + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks Siklus CPU Kustom - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) Aktifkan Emulasi Host MMU (memori cepat) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -458,147 +468,147 @@ Saat diaktifkan, dapat menyebablkan reads/writes memori tamu dilakukan langsung Menonaktifkan opsi ini akan memaksa semua akses memori untuk menggunakan Emulasi MMU Perangkat Lunak. - + Unfuse FMA (improve performance on CPUs without FMA) Pisahkan FMA (meningkatkan performa pada CPU tanpa FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Opsi ini meningkatkan kecepatan dengan mengurangi akurasi instruksi fused-multiply-add pada CPU tanpa dukungan FMA asli. - + Faster FRSQRTE and FRECPE FRSQRTE dan FRECPE lebih cepat - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Opsi ini meningkatkan kecepatan beberapa fungsi titik mengambang perkiraan dengan menggunakan perkiraan asli yang kurang akurat. - + Faster ASIMD instructions (32 bits only) Instruksi ASIMD lebih cepat (hanya untuk 32 bits) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Opsi ini meningkatkan kecepatan fungsi floating-point ASIMD 32 bit dengan menjalankannya dengan mode pembulatan yang salah. - + Inaccurate NaN handling Penanganan NaN tidak akurat - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Opsi ini meningkatkan kecepatan dengan menghilangkan pemeriksaan NaN. Harap dicatat ini juga mengurangi akurasi instruksi titik mengambang tertentu. - + Disable address space checks Matikan pengecekan adress space - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor Abaikan monitor global - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Opsi ini meningkatkan kecepatan dengan hanya mengandalkan semantik cmpxchg untuk memastikan keamanan instruksi akses eksklusif. Harap dicatat ini dapat menyebabkan deadlock dan kondisi perlombaan lainnya. - + API: API: - + Changes the output graphics API. Vulkan is recommended. - + Device: Perangkat: - + This setting selects the GPU to use (Vulkan only). - + Resolution: Resolusi: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: Filter Menyelaraskan dengan Layar: - + FSR Sharpness: Ketajaman FSR - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Metode Anti-Aliasing: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Mode Layar Penuh: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -607,47 +617,47 @@ Borderless menawarkan kompatibilitas terbaik dengan keyboard di layar yang dimin Layar penuh eksklusif mungkin menawarkan performa yang lebih baik dan dukungan Freesync/Gsync yang lebih baik. - + Aspect Ratio: Rasio Aspek: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Memungkinkan penyimpanan shader untuk mempercepat pengambilan pada saat game berikutnya dimulai. Menonaktifkannya hanya dimaksudkan untuk debugging. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: Emulasi NVDEC: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -656,12 +666,12 @@ Ini dapat menggunakan CPU atau GPU untuk dekode, atau tidak melakukan dekode sam Dalam kebanyakan kasus, dekode GPU memberikan kinerja terbaik. - + ASTC Decoding Method: ASTC Metode Dekoding: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -670,75 +680,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: ASTC Metode Pemampatan Ulang: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: Mode Penggunaan VRAM: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation Abaikan Invalidasi Internal CPU - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: Mode Sinkronisasi Vertikal - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -746,79 +736,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations Sinkronisasi Operasi Memori - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) Aktifkan presentasi asinkron (hanya Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. Meningkatkan kinerja sedikit dengan memindahkan presentasi ke thread CPU terpisah. - + Force maximum clocks (Vulkan only) Paksa jam maximum (Vulkan only) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Berjalan bekerja di latar belakang sambil menunggu perintah grafis untuk mencegah GPU agar tidak menurunkan kecepatan jamnya. - + Anisotropic Filtering: Anisotropic Filtering: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: Mode GPU: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: Akurasi DMA - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -827,1291 +817,1291 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation Gunakan kompilasi shader asinkron - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache Gunakan pipeline cache Vulkan - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. Memungkinkan cache pipeline spesifik vendor GPU. Opsi ini dapat meningkatkan waktu pemuatan shader secara signifikan dalam kasus di mana driver Vulkan tidak menyimpan file cache pipeline secara internal. - + Enable Compute Pipelines (Intel Vulkan Only) Aktifkan Pipa Komputasi (Hanya Intel Vulkan) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing Aktifkan Reactive Flushing - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Menggunakan pemadatan reaktif alih-alih pemadatan prediktif, memungkinkan sinkronisasi memori yang lebih akurat. - + Sync to framerate of video playback Sinkronkan dengan kecepatan pemutaran video - + Run the game at normal speed during video playback, even when the framerate is unlocked. Jalankan permainan dengan kecepatan normal selama pemutaran video, bahkan ketika framerate tidak terkunci. - + Barrier feedback loops Loop umpan balik penghalang - + Improves rendering of transparency effects in specific games. Meningkatkan rendering efek transparansi dalam game tertentu. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects Perbaiki efek bloom - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading Pencahayaan Sampel - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed Benih RNG - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name Nama Perangkat - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: Tanggal RTC Kustom: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: Bahasa - + This option can be overridden when region setting is auto-select - + Region: Wilayah: - + The region of the console. - + Time Zone: Zona Waktu: - + The time zone of the console. - + Sound Output Mode: Mode keluaran suara. - + Console Mode: Mode Konsol - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation Konfirmasi sebelum menghentikan emulasi - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity Sembunyikan mouse saat tidak aktif - + Hides the mouse after 2.5s of inactivity. - + Check for updates Cek Pembaruan - + Whether or not to check for updates upon startup. - + Enable Gamemode Aktifkan Mode Permainan - + Force X11 as Graphics Backend - + Custom frontend Tampilan depan kustom - + Real applet Aplikasi nyata - - + + Disabled - + Never Tidak Pernah - + On Load - + Always Selalu - + CPU CPU - + GPU GPU - + CPU Asynchronous CPU sinkron - + Uncompressed (Best quality) Tidak terkompresi (Kualitas Terbaik) - + BC1 (Low quality) BC1 (Kualitas rendah) - + BC3 (Medium quality) BC3 (Kualitas sedang) - - + + Auto Otomatis - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative Konservatif - + Aggressive Agresif - + Vulkan Vulkan - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null Null - + Fast Cepat - - - + + + Accurate Akurat - - - + + + Default Bawaan - + Unsafe (fast) - + Safe (stable) - + Immediate - + Balanced Seimbang - + Unsafe Berbahaya - + Paranoid (disables most optimizations) Paranoid (menonaktifkan sebagian besar optimasi) - + Debugging - + Dynarmic Dynarmic - + NCE NCE - + Borderless Windowed Layar Tanpa Batas - + Exclusive Fullscreen Layar Penuh Eksklusif - + No Video Output Tidak ada Keluaran Suara - + CPU Video Decoding Penguraian Video menggunakan CPU - + GPU Video Decoding (Default) Penguraian Video menggunakan GPU (Bawaan) - + 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [EKSPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [EKSPERIMENTAL] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [EKSPERIMENTAL] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Nearest Neighbor - + Bilinear Biliner - + Bicubic Bikubik - + Gaussian Gaussian - + Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution - + Area - + MMPX - + Zero-Tangent - + B-Spline - + Mitchell - + Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Tak ada - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Bawaan (16:9) - + Force 4:3 Paksa 4:3 - + Force 21:9 Paksa 21:9 - + Force 16:10 Paksa 16:10 - + Stretch to Window Regangkan ke Layar - + Automatic Otomatis - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Jepang (日本語) - + American English Bahasa Inggris Amerika - + French (français) Prancis (français) - + German (Deutsch) Jerman (Deutsch) - + Italian (italiano) Italia (italiano) - + Spanish (español) Spanyol (español) - + Chinese Cina - + Korean (한국어) Korea (한국어) - + Dutch (Nederlands) Belanda (Nederlands) - + Portuguese (português) Portugis (português) - + Russian (Русский) Rusia (Русский) - + Taiwanese Taiwan - + British English Inggris Britania - + Canadian French Prancis Kanada - + Latin American Spanish Spanyol Amerika Latin - + Simplified Chinese Cina Sederhana - + Traditional Chinese (正體中文) Cina Tradisional (正體中文) - + Brazilian Portuguese (português do Brasil) Portugis Brazil (português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan Jepang - + USA USA - + Europe Eropa - + Australia Australia - + China Tiongkok - + Korea Korea - + Taiwan Taiwan - + Auto (%1) Auto select time zone Auto (%1) - + Default (%1) Default time zone Bawaan (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Kuba - + EET EET - + Egypt Mesir - + Eire Éire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Éire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Islandia - + Iran Iran - + Israel Israel - + Jamaica Jamaika - + Kwajalein Kwajalein - + Libya Libya - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polandia - + Portugal Portugal - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapura - + Turkey Turki - + UCT UCT - + Universal Universal - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Stereo - + Surround Surround - + 4GB DRAM (Default) 4GB DRAM (Bawaan) - + 6GB DRAM (Unsafe) 6GB DRAM (Tidak Aman) - + 8GB DRAM - + 10GB DRAM (Unsafe) 10GB DRAM (Tidak Aman) - + 12GB DRAM (Unsafe) 12GB DRAM (Tidak Aman) - + Docked Terpasang - + Handheld Jinjing - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) Selalu tanyakan (Bawaan) - + Only if game specifies not to stop Hanya jika permainan menentukan untuk tidak berhenti - + Never ask Jangan pernah bertanya - + Very Small (16 MB) Sangat Kecil (16 MB) - + Small (32 MB) Kecil (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) Sedang (256) - + High (512) Tinggi (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6060,50 +6050,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL tidak tersedia! - + OpenGL shared contexts are not supported. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! Terjadi kesalahan menginisialisasi OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. VGA anda mungkin tidak mendukung OpenGL, atau anda tidak memiliki pemacu piranti (driver) grafis terbaharu. - + Error while initializing OpenGL 4.6! Terjadi kesalahan menginisialisasi OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 VGA anda mungkin tidak mendukung OpenGL 4.6, atau anda tidak memiliki pemacu piranti (driver) grafis terbaharu.<br><br>Pemuat GL:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 VGA anda mungkin tidak mendukung satu atau lebih ekstensi OpenGL. Mohon pastikan bahwa anda memiliki pemacu piranti (driver) grafis terbaharu.<br><br>Pemuat GL:<br>%1<br><br>Ekstensi yang tidak didukung:<br>%2 - + This build doesn't have OpenGL support. @@ -6868,1132 +6858,1152 @@ Debug Message: &Emulasi - + + &Cheats + + + + &View - + &Reset Window Size - + &Debugging - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p Atur ulang ukuran bingkai ke &720p - + Reset Window Size to 720p Atur ulang ukuran bingkai ke 720p - + Reset Window Size to &900p Atur ulang ukuran bingkai ke &900p - + Reset Window Size to 900p Atur ulang ukuran bingkai ke 900p - + Reset Window Size to &1080p - + Reset Window Size to 1080p - + &Multiplayer - + &Tools - + Am&iibo - + Launch &Applet - + &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help - + &Install Files to NAND... - + L&oad File... - + Load &Folder... - + E&xit - - + + &Pause &Jeda - + &Stop - + &Verify Installed Contents - + &About Eden - + Single &Window Mode - + Con&figure... - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar - + Show &Status Bar - + Show Status Bar Munculkan Status Bar - + &Browse Public Game Lobby - + &Create Room - + &Leave Room - + &Direct Connect to Room - + &Show Current Room - + F&ullscreen - + &Restart - + Load/Remove &Amiibo... - + Open &Mods Page - + &User Handbook - + &Capture Screenshot - + &Album - + &Set Nickname and Owner - + &Delete Game Data - + &Restore Amiibo - + &Format Amiibo - + &Mii Editor - + &Configure TAS... - + Configure C&urrent Game... - - + + &Start &Mulai - + &Reset - - + + R&ecord R&ekam - + Open &Controller Menu - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8001,74 +8011,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/it.ts b/dist/languages/it.ts index 2cf9191129..19aaec9afd 100644 --- a/dist/languages/it.ts +++ b/dist/languages/it.ts @@ -37,8 +37,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Sito web</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Codice sorgente</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributori</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licenza</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -410,49 +410,59 @@ Can help reduce stuttering at lower framerates. Può ridurre lo stuttering quando il framerate è basso. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Precisione: - + Change the accuracy of the emulated CPU (for debugging only). Cambia la precisione della CPU emulata (solo per debug) - - + + Backend: Back-end: - + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks Tick CPU personalizzati - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. Imposta un valore personalizzato per i tick della CPU. Valori più alti possono aumentare le prestazioni, ma possono anche causare stalli nei giochi. Si consiglia un valore compreso tra 77 e 21000. - + Enable Host MMU Emulation (fastmem) Abilita l'emulazione della MMU nell'host (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -461,100 +471,100 @@ Abilitandola, le letture/scritture nella memoria del guest vengono eseguite dire Disabilitandola, tutti gli accessi alla memoria vengono costretti a utilizzare l'emulazione software della MMU. - + Unfuse FMA (improve performance on CPUs without FMA) Non fondere FMA (migliora le prestazioni della CPU senza FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Quest'opzione migliora la velocità riducendo la precisione delle istruzioni fused-multiply-add (FMA) sulle CPU senza il supporto nativo a FMA. - + Faster FRSQRTE and FRECPE FRSQRTE e FRECPE più veloci - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Quest'opzione migliora la velocità di alcune funzioni in virgola mobile approssimate utilizzando delle approssimazioni native meno accurate. - + Faster ASIMD instructions (32 bits only) Istruzioni ASIMD più veloci (solo 32 bit) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Quest'opzione migliora la velocità delle funzioni in virgola mobile ASIMD a 32 bit eseguendole con modalità di arrotondamento non corrette. - + Inaccurate NaN handling Gestione inaccurata NaN - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Quest'opzione migliora la velocità rimuovendo il controllo dei valori NaN. Tieni presente che ciò riduce la precisione di alcune istruzioni in virgola mobile. - + Disable address space checks Disattiva i controlli dello spazio degli indirizzi - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. Quest'opzione migliora la velocità eliminando un controllo di sicurezza prima di ogni operazione di memoria. Disabilitarla potrebbe permettere l'esecuzione di codice malevolo. - + Ignore global monitor Ignora il monitor globale - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Quest'opzione migliora la velocità affidandosi alla semantica di cmpxchg per garantire sicurezza nelle istruzioni con accesso esclusivo. Nota che questo può causare stalli e altre race condition. - + API: API: - + Changes the output graphics API. Vulkan is recommended. Cambia l'API dell'output grafico. Vulkan è consigliato. - + Device: Dispositivo: - + This setting selects the GPU to use (Vulkan only). Quest'opzione seleziona la GPU da usare (solo con Vulkan). - + Resolution: Risoluzione: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -563,27 +573,27 @@ Alte risoluzioni hanno bisogno di piu VRAM e banda. Opzioni inferiori a 1X possono causare artefatti. - + Window Adapting Filter: Filtro di adattamento alla finestra: - + FSR Sharpness: Nitidezza FSR: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Metodo di anti-aliasing: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -592,22 +602,22 @@ SMAA offre la migliore qualità. FXAA può produrre un'immagine più stabile nelle risoluzioni più basse. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Modalità schermo intero: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -616,12 +626,12 @@ Exclusive fullscreen may offer better performance and better Freesync/Gsync supp "Schermo intero esclusivo" può offrire prestazioni maggiori e un supporto migliore al Freesync/Gsync. - + Aspect Ratio: Rapporto d'aspetto: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -630,36 +640,36 @@ La maggior parte dei giochi supporta solo 16:9, quindi le mod sono necessarie pe Controlla anche il rapporto d'aspetto degli screenshot. - + Use persistent pipeline cache Usa la cache persistente delle pipeline - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Permette di salvare gli shader su disco per velocizzarne il caricamento negli avvii successivi del gioco. Disabilitarla ha senso solo quando si effettua il debug. - + Use asynchronous GPU emulation Abilita l'emulazione asincrona della GPU - + Uses an extra CPU thread for rendering. This option should always remain enabled. Utilizza un thread aggiuntivo della CPU per il rendering. Quest'opzione dovrebbe sempre rimanere abilitata. - + NVDEC emulation: Emulazione NVDEC: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -668,12 +678,12 @@ In most cases, GPU decoding provides the best performance. Nella maggior parte dei casi, la decodifica tramite GPU fornisce prestazioni migliori. - + ASTC Decoding Method: Metodo di decodifica ASTC: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -685,12 +695,12 @@ GPU: Usa i compute shader della GPU per decodificare le texture ASTC (consigliat CPU (Asincrono): Usa la CPU per decodificare le texture ASTC se richiesto. Elimina lo stuttering causato dalla decodifica ma potrebbe generare artefatti visivi. - + ASTC Recompression Method: Metodo di ricompressione ASTC: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. @@ -698,64 +708,44 @@ BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, BC1/BC3: Il formato intermedio sarà ricompresso nel formato BC1 o BC3, risparmiando VRAM ma peggiorando la qualità visiva. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: Modalità di utilizzo della VRAM: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. Determina se l'emulatore dovrebbe risparmiare memoria o utilizzarne il più possibile per massimizzare le prestazioni. La modalità aggressiva potrebbe impattare sulle prestazioni di altre applicazioni, come i programmi di registrazione. - + Skip CPU Inner Invalidation Salta invalidamento interno CPU - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. Salta alcuni invalidamenti della cache durante gli aggiornamenti della memoria, riducendo l'uso della CPU e migliorando la latenza. Questo potrebbe causare soft-crash. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: Modalità VSync: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -766,12 +756,12 @@ Mailbox può avere una latenza minore di FIFO e non ha tearing ma potrebbe perde Immediate (no sincronizzazione) mostra tutto il disponibile, quindi anche tearing. - + Sync Memory Operations Sincronizza operazioni di memoria - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. @@ -780,68 +770,68 @@ Questa opzione dovrebbe risolvere problemi in alcuni giochi, ma potrebbe ridurre I giochi con Unreal Engine 4 sembrano essere i più colpiti. - + Enable asynchronous presentation (Vulkan only) Abilita la presentazione asincrona (solo Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. Migliora di poco le prestazioni spostando la presentazione su un thread della CPU separato. - + Force maximum clocks (Vulkan only) Forza clock massimi (solo Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Esegue del lavoro in background durante l'attesa dei comandi grafici per evitare che la GPU diminuisca la sua velocità di clock. - + Anisotropic Filtering: Filtro anisotropico: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. Controlla la qualità del rendering delle texture negli angoli obliqui. Si può utilizzare in modo sicuro al 16x su quasi tutte le GPU. - + GPU Mode: Modalità GPU: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: Precisione DMA: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -850,89 +840,89 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation Abilita la compilazione asincrona degli shader - + May reduce shader stutter. Può ridurre i fenomeni di stuttering (scatti) causati dagli shader. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache Usa la cache delle pipeline di Vulkan - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. Abilita la cache delle pipeline specifica del produttore della GPU. Quest'opzione può ridurre di molto i tempi di caricamento degli shader nei casi in cui il driver Vulkan non memorizza la cache delle pipeline internamente. - + Enable Compute Pipelines (Intel Vulkan Only) Abilita le compute pipeline (solo per Vulkan su Intel) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. @@ -941,181 +931,181 @@ Quest'impostazione esiste solo per i driver proprietari Intel e potrebbe fa Le compute pipelines sono sempre attivate su tutti gli altri drivers. - + Enable Reactive Flushing Abilita il flushing reattivo - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Utilizza il flushing reattivo invece di quello predittivo, al fine di ottenere una sincronizzazione della memoria più accurata. - + Sync to framerate of video playback Sincronizza il framerate a quello del video - + Run the game at normal speed during video playback, even when the framerate is unlocked. Esegue il gioco a velocità normale durante le cutscene, anche quando il framerate è sbloccato. - + Barrier feedback loops Barrier feedback loops - + Improves rendering of transparency effects in specific games. Migliora il rendering degli effetti di trasparenza in alcuni giochi. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State Stato dinamico esteso - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. Controlla il numero di funzionalità che possono essere usate con lo stato dinamico esteso. Gli stati più alti consentono più funzionalità e possono migliorare le prestazioni, ma possono causare ulteriori problemi grafici. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading Sample shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. Permette al fragment shader di eseguire per campione in un frammento multi-campione invece che una volta per frammento. Migliora la qualità grafica a scapito delle prestazioni. Alti valori migliorano la qualità ma peggiorano le prestazioni. - + RNG Seed Seed RNG - + Controls the seed of the random number generator. Mainly used for speedrunning. Controlla il seme del generatore di numeri casuali. Principalmente utilizzato per le speedrun. - + Device Name Nome del dispositivo - + The name of the console. Il nome della console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: Data RTC personalizzata: - + This option allows to change the clock of the console. Can be used to manipulate time in games. Quest'opzione permette di modificare l'orologio della console. Può essere usato per manipolare il tempo nei giochi. - + The number of seconds from the current unix time Il numero di secondi dal tempo Unix attuale - + Language: Lingua: - + This option can be overridden when region setting is auto-select Può essere rimpiazzato se il fuso orario della Regione è impostato su Auto - + Region: Regione: - + The region of the console. La regione della console. - + Time Zone: Fuso orario: - + The time zone of the console. Il fuso orario della console. - + Sound Output Mode: Modalità di output del suono: - + Console Mode: Modalità console: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. @@ -1124,1026 +1114,1026 @@ I giochi ne terranno conto e modificheranno la risoluzione, i dettagli e i contr Impostare l'opzione su "Portatile" può aiutare a migliorare le prestazioni sui sistemi meno potenti. - + Prompt for user profile on boot Scegli il profilo utente all'avvio - + Useful if multiple people use the same PC. Utile se più persone utilizzano lo stesso PC. - + Pause when not in focus Metti in pausa quando la finestra non è in primo piano - + Pauses emulation when focusing on other windows. Mette in pausa l'emulazione quando altre finestre sono in primo piano. - + Confirm before stopping emulation Chiedi conferma prima di arrestare l'emulazione - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. Sovrascrive le richieste di conferma per fermare l'emulazione. Abilitarla bypassa queste richieste e l'emulazione cesserà immediatamente. - + Hide mouse on inactivity Nascondi il puntatore del mouse se inattivo - + Hides the mouse after 2.5s of inactivity. Nasconde il mouse dopo 2,5 secondi di inattività. - + Check for updates Controlla la presenza di aggiornamenti - + Whether or not to check for updates upon startup. Determina se controllare o meno la presenza di aggiornamenti all'avvio. - + Enable Gamemode Abilita Gamemode - + Force X11 as Graphics Backend Forza l'uso del back-end grafico X11 - + Custom frontend Frontend personalizzato - + Real applet Applet reale - - + + Disabled Disabilitato - + Never Mai - + On Load Al caricamento - + Always Sempre - + CPU CPU - + GPU GPU - + CPU Asynchronous CPU (Asincrono) - + Uncompressed (Best quality) Nessuna compressione (qualità migliore) - + BC1 (Low quality) BC1 (qualità bassa) - + BC3 (Medium quality) BC3 (qualità media) - - + + Auto Automatico - + 30 FPS 30 FPS - + 60 FPS 60 FPS - + 90 FPS 90 FPS - + 120 FPS 120 FPS - + Conservative Conservativa - + Aggressive Aggressiva - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) OpenGL GLASM (shader assembly, solo NVIDIA) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V (sperimentale, solo AMD/MESA) - + Null Nullo - + Fast Veloce - - - + + + Accurate Accurata - - - + + + Default Predefinito - + Unsafe (fast) Non sicuro (veloce) - + Safe (stable) Sicuro (stabile) - + Immediate - + Balanced Bilanciata - + Unsafe Non sicura - + Paranoid (disables most optimizations) Paranoica (disabilita la maggior parte delle ottimizzazioni) - + Debugging Debug - + Dynarmic Dynarmic - + NCE NCE - + Borderless Windowed Finestra senza bordi - + Exclusive Fullscreen Schermo intero esclusivo - + No Video Output Nessun output video - + CPU Video Decoding Decodifica video CPU - + GPU Video Decoding (Default) Decodifica video GPU (predefinita) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [SPERIMENTALE] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [SPERIMENTALE] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [SPERIMENTALE] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [SPERIMENTALE] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [SPERIMENTALE] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Nearest neighbor - + Bilinear Bilineare - + Bicubic Bicubico - + Gaussian Gaussiano - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX Super Resolution - + Area Area - + MMPX MMPX - + Zero-Tangent Zero-Tangent - + B-Spline B-Spline - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Nessuna - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Predefinito (16:9) - + Force 4:3 Forza 4:3 - + Force 21:9 Forza 21:9 - + Force 16:10 Forza 16:10 - + Stretch to Window Allunga a finestra - + Automatic Automatico - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Giapponese (日本語) - + American English Inglese americano - + French (français) Francese (français) - + German (Deutsch) Tedesco (Deutsch) - + Italian (italiano) Italiano - + Spanish (español) Spagnolo (español) - + Chinese Cinese - + Korean (한국어) Coreano (한국어) - + Dutch (Nederlands) Olandese (Nederlands) - + Portuguese (português) Portoghese (português) - + Russian (Русский) Russo (Русский) - + Taiwanese Taiwanese - + British English Inglese britannico - + Canadian French Francese canadese - + Latin American Spanish Spagnolo latino-americano - + Simplified Chinese Cinese semplificato - + Traditional Chinese (正體中文) Cinese tradizionale (正體中文) - + Brazilian Portuguese (português do Brasil) Portoghese brasiliano (português do Brasil) - + Polish (polska) Polacco (polska) - + Thai (แบบไทย) Thailandese (แบบไทย) - - + + Japan Giappone - + USA USA - + Europe Europa - + Australia Australia - + China Cina - + Korea Corea - + Taiwan Taiwan - + Auto (%1) Auto select time zone Automatico (%1) - + Default (%1) Default time zone Predefinito (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Egitto - + Eire Eire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Islanda - + Iran Iran - + Israel Israele - + Jamaica Giamaica - + Kwajalein Kwajalein - + Libya Libia - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polonia - + Portugal Portogallo - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapore - + Turkey Turchia - + UCT UCT - + Universal Universale - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Stereo - + Surround Surround - + 4GB DRAM (Default) 4GB DRAM (Predefinito) - + 6GB DRAM (Unsafe) 6GB DRAM (Non sicuro) - + 8GB DRAM 8GB DRAM - + 10GB DRAM (Unsafe) 10GB DRAM (Non sicuro) - + 12GB DRAM (Unsafe) 12GB DRAM (Non sicuro) - + Docked Dock - + Handheld Portatile - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) Chiedi sempre (Predefinito) - + Only if game specifies not to stop Solo se il gioco richiede di non essere arrestato - + Never ask Non chiedere mai - + Very Small (16 MB) Molto piccola (16 MB) - + Small (32 MB) Piccola (32 MB) - + Normal (128 MB) Normale (128 MB) - + Large (256 MB) Grande (256 MB) - + Very Large (512 MB) Molto grande (512 MB) - + Very Low (4 MB) Molto bassa (4 MB) - + Low (8 MB) Bassa (8 MB) - + Normal (16 MB) Normale (16 MB) - + Medium (32 MB) Media (32 MB) - + High (64 MB) Alta (64 MB) - + Very Low (32) Molto basso (32) - + Low (64) Basso (64) - + Normal (128) Normale (128) - + Medium (256) Medio (256) - + High (512) Alto (512) - + ExtendedDynamicState 1 Stato dinamico esteso 1 - + ExtendedDynamicState 2 Stato dinamico esteso 2 - + ExtendedDynamicState 3 Stato dinamico esteso 3 - + Tree View Vista ad albero - + Grid View Vista a griglia @@ -6117,50 +6107,50 @@ Vai su Configura -> Sistema -> Rete e selezionane una. GRenderWindow - - + + OpenGL not available! OpenGL non disponibile! - + OpenGL shared contexts are not supported. Gli shared context di OpenGL non sono supportati. - + Eden has not been compiled with OpenGL support. Eden non è stato compilato con il supporto a OpenGL. - - - + + + Error while initializing OpenGL! Errore durante l'inizializzazione di OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. La tua GPU potrebbe non supportare OpenGL, o non hai installato l'ultima versione dei driver video. - + Error while initializing OpenGL 4.6! Errore durante l'inizializzazione di OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 La tua GPU potrebbe non supportare OpenGL 4.6, o non hai installato l'ultima versione dei driver video.<br><br>Renderer GL:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 La tua GPU potrebbe non supportare una o più estensioni OpenGL richieste. Assicurati di aver installato i driver video più recenti.<br><br>Renderer GL:<br>%1<br><br>Estensioni non supportate:<br>%2 - + This build doesn't have OpenGL support. @@ -6927,800 +6917,820 @@ Messaggio debug: &Emulazione - + + &Cheats + + + + &View &Visualizza - + &Reset Window Size &Ripristina dimensioni della finestra - + &Debugging &Debug - + &Game List Mode &Modalità della lista dei giochi - + Game &Icon Size Dimensione delle &icone dei giochi - + Reset Window Size to &720p Ripristina le dimensioni della finestra a &720p - + Reset Window Size to 720p Ripristina le dimensioni della finestra a 720p - + Reset Window Size to &900p Ripristina le dimensioni della finestra a &900p - + Reset Window Size to 900p Ripristina le dimensioni della finestra a 900p - + Reset Window Size to &1080p Ripristina le dimensioni della finestra a &1080p - + Reset Window Size to 1080p Ripristina le dimensioni della finestra a 1080p - + &Multiplayer &Multigiocatore - + &Tools &Strumenti - + Am&iibo Am&iibo - + Launch &Applet Avvia &applet - + &TAS &TAS - + &Create Home Menu Shortcut &Crea scorciatoia per il menù Home - + Install &Firmware Installa &firmware - + &Help &Aiuto - + &Install Files to NAND... &Installa file su NAND... - + L&oad File... Carica &file... - + Load &Folder... Carica &cartella... - + E&xit &Esci - - + + &Pause &Pausa - + &Stop Arre&sta - + &Verify Installed Contents &Verifica i contenuti installati - + &About Eden &Informazioni su Eden - + Single &Window Mode &Modalità finestra singola - + Con&figure... Configura... - + Ctrl+, Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar Mostra barra del &filtro - + Show &Status Bar Mostra barra di &stato - + Show Status Bar Mostra barra di stato - + &Browse Public Game Lobby &Sfoglia lobby di gioco pubblica - + &Create Room &Crea stanza - + &Leave Room &Esci dalla stanza - + &Direct Connect to Room Collegamento &diretto a una stanza - + &Show Current Room &Mostra stanza attuale - + F&ullscreen Schermo intero - + &Restart &Riavvia - + Load/Remove &Amiibo... Carica/Rimuovi &Amiibo... - + Open &Mods Page Apri la pagina delle &mod - + &User Handbook - + &Capture Screenshot Cattura schermo - + &Album &Album - + &Set Nickname and Owner &Imposta nickname e proprietario - + &Delete Game Data &Rimuovi i dati di gioco - + &Restore Amiibo &Ripristina gli Amiibo - + &Format Amiibo &Formatta gli Amiibo - + &Mii Editor Editor &Mii - + &Configure TAS... &Configura TAS... - + Configure C&urrent Game... Configura il gioco in uso... - - + + &Start &Avvia - + &Reset &Reimposta - - + + R&ecord R&egistra - + Open &Controller Menu Apri il menù dei &controller - + Install Decryption &Keys Installa le &chiavi di crittografia - + &Home Menu Menù &Home - + &Desktop &Desktop - + &Application Menu &Menù delle applicazioni - + &Root Data Folder Cartella &principale dei dati - + &NAND Folder Cartella &NAND - + &SDMC Folder Cartella &SDMC - + &Mod Folder Cartella delle &mod - + &Log Folder Cartella dei &log - + From Folder Da una cartella - + From ZIP Da un file ZIP - + &Eden Dependencies &Dipendenze di Eden - + &Data Manager Gestione &dati - + &Tree View Vista ad &albero - + &Grid View Vista a &griglia - + Game Icon Size Dimensione delle icone dei giochi - - + + None Nessuno - + Show Game &Name Mostra i nomi dei giochi - + Show &Performance Overlay Mostra &prestazioni in sovrimpressione - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) Piccola (32x32) - + Standard (64x64) Normale (64x64) - + Large (128x128) Grande (128x128) - + Full Size (256x256) Intera (256x256) - + Broken Vulkan Installation Detected Rilevata installazione di Vulkan non funzionante - + Vulkan initialization failed during boot. L'inizializzazione di Vulkan è fallita durante l'avvio. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping Gioco in esecuzione - + Loading Web Applet... Caricamento dell'applet web... - - + + Disable Web Applet Disabilita l'applet web - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) Disabilitare l'applet web potrebbe causare dei comportamenti indesiderati e andrebbe fatto solo con Super Mario 3D All-Stars. Sei sicuro di voler procedere? (Puoi riabilitarlo quando vuoi nelle impostazioni di debug.) - + The amount of shaders currently being built Il numero di shader in fase di compilazione - + The current selected resolution scaling multiplier. Il moltiplicatore attuale della risoluzione. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Velocità attuale dell'emulazione. Valori più alti o più bassi di 100% indicano che l'emulazione sta funzionando più velocemente o lentamente rispetto a una Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Il numero di fotogrammi al secondo che il gioco sta attualmente renderizzando. Può variare in base al gioco e alla situazione. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tempo necessario per emulare un fotogramma della Switch, senza tenere conto del limite al framerate o del V-Sync. Per un'emulazione alla massima velocità, il valore non dovrebbe essere superiore a 16.67 ms. - + Unmute Riattiva - + Mute Silenzia - + Reset Volume Reimposta volume - + Configure Effects... - + &Clear Recent Files &Cancella i file recenti - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue &Continua - + Warning: Outdated Game Format Attenzione: Formato del gioco obsoleto - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. Stai usando una cartella contenente una ROM decostruita per avviare questo gioco, che è un formato obsoleto e sostituito da NCA, NAX, XCI o NSP. Le ROM decostruite non hanno icone né metadati e non supportano gli aggiornamenti.<br>Per una spiegazione sui vari formati della console Switch supportati da Eden, consulta il manuale utente. Non riceverai di nuovo questo avviso. - - + + Error while loading ROM! Errore nel caricamento della ROM! - + The ROM format is not supported. Il formato della ROM non è supportato. - + An error occurred initializing the video core. Errore durante l'inizializzazione del componente video di base - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. Errore nel caricamento della ROM! %1 - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. %1<br>Esegui un nuovo dump dei tuoi file o chiedi aiuto su Discord/Stoat. - + An unknown error occurred. Please see the log for more details. Si è verificato un errore sconosciuto. Consulta il log per maggiori dettagli. - - + + (64-bit) (64 bit) - - + + (32-bit) (32 bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - + Closing software... Chiusura del software in corso... - + Save Data Dati di salvataggio - + Mod Data Dati delle mod - + Error Opening %1 Folder Impossibile aprire la cartella %1 - - + + Folder does not exist! La cartella non esiste! - + Remove Installed Game Contents? Rimuovere il contenuto del gioco installato? - + Remove Installed Game Update? Rimuovere l'aggiornamento installato? - + Remove Installed Game DLC? Rimuovere il DLC installato? - + Remove Entry Rimuovi voce - + Delete OpenGL Transferable Shader Cache? Vuoi rimuovere la cache trasferibile degli shader OpenGL? - + Delete Vulkan Transferable Shader Cache? Vuoi rimuovere la cache trasferibile degli shader Vulkan? - + Delete All Transferable Shader Caches? Vuoi rimuovere tutte le cache trasferibili degli shader? - + Remove Custom Game Configuration? Rimuovere la configurazione personalizzata del gioco? - + Remove Cache Storage? Rimuovere la cache del gioco? - + Remove File Rimuovi file - + Remove Play Time Data Reimposta il tempo di gioco - + Reset play time? Vuoi reimpostare il tempo di gioco? - - + + RomFS Extraction Failed! Estrazione RomFS fallita! - + There was an error copying the RomFS files or the user cancelled the operation. Si è verificato un errore durante la copia dei file del RomFS o l'operazione è stata annullata dall'utente. - + Full Completa - + Skeleton Cartelle - + Select RomFS Dump Mode Seleziona la modalità di estrazione del RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Seleziona come vorresti estrarre il RomFS. <br>La modalità Completa copierà tutti i file in una nuova cartella mentre<br>la modalità Cartelle creerà solamente la struttura delle cartelle. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root Non c'è abbastanza spazio disponibile in %1 per estrarre il RomFS. Libera lo spazio o seleziona una cartella di estrazione diversa in Emulazione > Configura > Sistema > File system > Cartella di estrazione - + Extracting RomFS... Estrazione RomFS in corso... - - + + Cancel Annulla - + RomFS Extraction Succeeded! Estrazione RomFS riuscita! - + The operation completed successfully. L'operazione è stata completata con successo. - + Error Opening %1 Impossibile aprire %1 - + Select Directory Seleziona cartella - + Properties Proprietà - + The game properties could not be loaded. Non è stato possibile caricare le proprietà del gioco. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Eseguibile Switch (%1);;Tutti i file (*.*) - + Load File Carica file - + Open Extracted ROM Directory Apri la cartella della ROM estratta - + Invalid Directory Selected Cartella selezionata non valida - + The directory you have selected does not contain a 'main' file. La cartella che hai selezionato non contiene un file "main". - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - File Switch installabili (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) + - + Install Files Installa file - + %n file(s) remaining %n file rimanente%n di file rimanenti%n file rimanenti - + Installing file "%1"... Installazione del file "%1"... - - + + Install Results Risultati dell'installazione - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Per evitare possibli conflitti, sconsigliamo di installare i giochi base su NAND. Usa questa funzione solo per installare aggiornamenti e DLC. - + %n file(s) were newly installed %n nuovo file è stato installato @@ -7729,7 +7739,7 @@ Usa questa funzione solo per installare aggiornamenti e DLC. - + %n file(s) were overwritten %n file è stato sovrascritto @@ -7738,7 +7748,7 @@ Usa questa funzione solo per installare aggiornamenti e DLC. - + %n file(s) failed to install %n file non è stato installato a causa di errori @@ -7747,324 +7757,324 @@ Usa questa funzione solo per installare aggiornamenti e DLC. - + System Application Applicazione di sistema - + System Archive Archivio di sistema - + System Application Update Aggiornamento di un'applicazione di sistema - + Firmware Package (Type A) Pacchetto firmware (tipo A) - + Firmware Package (Type B) Pacchetto firmware (tipo B) - + Game Gioco - + Game Update Aggiornamento di gioco - + Game DLC DLC - + Delta Title Titolo delta - + Select NCA Install Type... Seleziona il tipo di installazione NCA... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Seleziona il tipo del file NCA da installare: (Nella maggior parte dei casi, il valore predefinito "Gioco" va bene) - + Failed to Install Installazione fallita - + The title type you selected for the NCA is invalid. Il tipo che hai selezionato per il file NCA non è valido. - + File not found File non trovato - + File "%1" not found File "%1" non trovato - + OK OK - + Function Disabled Funzionalità disabilitata - + Compatibility list reporting is currently disabled. Check back later! La segnalazione della compatibilità è al momento disabilitata. Torna a controllare più avanti! - + Error opening URL Impossibile aprire l'URL - + Unable to open the URL "%1". Non è stato possibile aprire l'URL "%1". - + TAS Recording Registrazione TAS - + Overwrite file of player 1? Vuoi sovrascrivere il file del giocatore 1? - + Invalid config detected Rilevata configurazione non valida - + Handheld controller can't be used on docked mode. Pro controller will be selected. Il controller portatile non può essere utilizzato in modalità dock. Verrà selezionato il controller Pro. - - + + Amiibo Amiibo - - + + The current amiibo has been removed L'Amiibo corrente è stato rimosso - + Error Errore - - + + The current game is not looking for amiibos Il gioco in uso non è alla ricerca di Amiibo - + Amiibo File (%1);; All Files (*.*) File Amiibo (%1);; Tutti i file (*.*) - + Load Amiibo Carica Amiibo - + Error loading Amiibo data Impossibile caricare i dati dell'Amiibo - + The selected file is not a valid amiibo Il file selezionato non è un Amiibo valido - + The selected file is already on use Il file selezionato è già in uso - + An unknown error occurred Si è verificato un errore sconosciuto - + No firmware available Nessun firmware disponibile - + Firmware Corrupted Firmware corrotto - + Unknown applet Applet sconosciuto - + Applet doesn't map to a known value. L'applet non è associato a un valore noto. - + Record not found Non trovato - + Applet not found. Please reinstall firmware. Applet non trovato. Reinstalla il firmware. - + Capture Screenshot Cattura screenshot - + PNG Image (*.png) Immagine PNG (*.png) - + TAS state: Running %1/%2 Stato TAS: In esecuzione (%1/%2) - + TAS state: Recording %1 Stato TAS: Registrazione in corso (%1) - + TAS state: Idle %1/%2 Stato TAS: In attesa (%1/%2) - + TAS State: Invalid Stato TAS: Non valido - + &Stop Running &Interrompi esecuzione - + Stop R&ecording Interrompi r&egistrazione - + Building: %n shader(s) Compilazione di %n shaderCompilazione di %n shaderCompilazione di %n shader - + Scale: %1x %1 is the resolution scaling factor Risoluzione: %1x - + Speed: %1% / %2% Velocità: %1% / %2% - + Speed: %1% Velocità: %1% - + Game: %1 FPS Gioco: %1 FPS - + Frame: %1 ms Frame: %1 ms - + NO AA NO AA - + NO FX - + FX - + VOLUME: MUTE VOLUME: MUTO - + VOLUME: %1% Volume percentage (e.g. 50%) VOLUME: %1% - + Derivation Components Missing Componenti di derivazione mancanti - + Decryption keys are missing. Install them now? Chiavi di crittografia mancanti. Vuoi installarle ora? - + Wayland Detected! Wayland rilevato! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8075,74 +8085,74 @@ Si consiglia invece di usare X11. Vuoi forzare l'uso di quest'ultimo per i prossimi avvii? - + Use X11 Usa X11 - + Continue with Wayland Continua con Wayland - + Don't show again Non mostrare di nuovo - + Restart Required Riavvio richiesto - + Restart Eden to apply the X11 backend. Riavvia Eden per usare il back-end X11. - + Slow Lento - + Turbo Turbo - + Unlocked Sbloccato - + Select RomFS Dump Target Seleziona RomFS da estrarre - + Please select which RomFS you would like to dump. Seleziona quale RomFS vorresti estrarre. - + Are you sure you want to close Eden? Sei sicuro di voler uscire da Eden? - - - + + + Eden Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Sei sicuro di voler arrestare l'emulazione? Tutti i progressi non salvati verranno perduti. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/ja_JP.ts b/dist/languages/ja_JP.ts index 2341618395..9520bc56fd 100644 --- a/dist/languages/ja_JP.ts +++ b/dist/languages/ja_JP.ts @@ -30,7 +30,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> @@ -399,252 +399,262 @@ Can help reduce stuttering at lower framerates. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: エミュレーション精度: - + Change the accuracy of the emulated CPU (for debugging only). - - + + Backend: バックエンド: - + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) FMAの融合を解除 (FMAに対応していないCPUのパフォーマンスを向上させる) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. このオプションは, ネイティブのFMAサポートがないCPU上で, 融合積和(fused-multiply-add)命令の精度を下げて高速化します. - + Faster FRSQRTE and FRECPE Faster FRSQRTE and FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. このオプションは、より精度の低い近似値を使用することで、近似浮動小数点関数の速度を向上させます。 - + Faster ASIMD instructions (32 bits only) 高速なASIMD命令 (32bitのみ) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. このオプションは、不正確な丸めモードで実行することにより、32ビットASIMD浮動小数点関数の速度を向上させます。 - + Inaccurate NaN handling 不正確な非数値の取り扱い - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. - + Disable address space checks アドレス空間チェックの無効化 - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. - + API: API: - + Changes the output graphics API. Vulkan is recommended. - + Device: 使用デバイス: - + This setting selects the GPU to use (Vulkan only). - + Resolution: 解像度: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: ウィンドウ適応フィルター: - + FSR Sharpness: FSR シャープネス: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: アンチエイリアス方式: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: フルスクリーンモード: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. - + Aspect Ratio: アスペクト比: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: NVDEC エミュレーション: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. - + ASTC Decoding Method: ASTC デコード方式: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -653,75 +663,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: ASTC 再圧縮方式: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: 垂直同期: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -732,79 +722,79 @@ Mailbox は FIFO よりも遅延が小さくティアリングがありません Immediate (no synchronization) は表示可能なものをすべて表示し, ティアリング発生の可能性があります. - + Sync Memory Operations メモリ操作の同期 - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) 非同期プレゼンテーション (Vulkan のみ) - + Slightly improves performance by moving presentation to a separate CPU thread. - + Force maximum clocks (Vulkan only) 最大クロック強制 (Vulkan のみ) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. GPUのクロックスピードを下げないように、グラフィックコマンドを待っている間、バックグラウンドで作業を実行させます。 - + Anisotropic Filtering: 異方性フィルタリング: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: GPUモード: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: DMA精度: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -813,1290 +803,1290 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache Vulkan パイプラインキャッシュを使用 - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. - + Enable Compute Pipelines (Intel Vulkan Only) コンピュート・パイプラインの有効化(インテル Vulkan のみ) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. - + Sync to framerate of video playback ビデオ再生のフレームレートに同期する - + Run the game at normal speed during video playback, even when the framerate is unlocked. - + Barrier feedback loops - + Improves rendering of transparency effects in specific games. 特定のゲームにおける透明エフェクトのレンダリングを改善します。 - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed 乱数シード値の変更 - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name デバイス名 - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: 言語: - + This option can be overridden when region setting is auto-select - + Region: 地域: - + The region of the console. - + Time Zone: タイムゾーン: - + The time zone of the console. - + Sound Output Mode: 音声出力モード: - + Console Mode: コンソールモード: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation エミュレーションを停止する前に確認する - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity 非アクティブ時にマウスカーソルを隠す - + Hides the mouse after 2.5s of inactivity. - + Check for updates - + Whether or not to check for updates upon startup. - + Enable Gamemode - + Force X11 as Graphics Backend - + Custom frontend - + Real applet - - + + Disabled 無効 - + Never - + On Load - + Always - + CPU CPU - + GPU GPU - + CPU Asynchronous CPU 非同期 - + Uncompressed (Best quality) 圧縮しない (最高品質) - + BC1 (Low quality) BC1 (低品質) - + BC3 (Medium quality) BC3 (中品質) - - + + Auto 自動 - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative - + Aggressive - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) OpenGL GLASM (アセンブリシェーダー、NVIDIA のみ) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V(実験的、AMD/Mesaのみ) - + Null - + Fast - - - + + + Accurate 正確 - - - + + + Default デフォルト - + Unsafe (fast) - + Safe (stable) - + Immediate - + Balanced - + Unsafe 不安定 - + Paranoid (disables most optimizations) パラノイド (ほとんどの最適化を無効化) - + Debugging - + Dynarmic Dynarmic - + NCE NCE - + Borderless Windowed ボーダーレスウィンドウ - + Exclusive Fullscreen 排他的フルスクリーン - + No Video Output ビデオ出力しない - + CPU Video Decoding ビデオをCPUでデコード - + GPU Video Decoding (Default) ビデオをGPUでデコード (デフォルト) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [実験的] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [実験的] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [実験的] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Nearest Neighbor - + Bilinear Bilinear - + Bicubic Bicubic - + Gaussian Gaussian - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX Super Resolution - + Area - + MMPX MMPX - + Zero-Tangent - + B-Spline - + Mitchell - + Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None なし - + FXAA FXAA - + SMAA SMAA - + Default (16:9) デフォルト (16:9) - + Force 4:3 強制 4:3 - + Force 21:9 強制 21:9 - + Force 16:10 強制 16:10 - + Stretch to Window ウィンドウに合わせる - + Automatic 自動 - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) 日本語 - + American English アメリカ英語 - + French (français) フランス語 (français) - + German (Deutsch) ドイツ語 (Deutsch) - + Italian (italiano) イタリア語 (italiano) - + Spanish (español) スペイン語 (español) - + Chinese 中国語 - + Korean (한국어) 韓国語 (한국어) - + Dutch (Nederlands) オランダ語 (Nederlands) - + Portuguese (português) ポルトガル語 (português) - + Russian (Русский) ロシア語 (Русский) - + Taiwanese 台湾語 - + British English イギリス英語 - + Canadian French カナダフランス語 - + Latin American Spanish ラテンアメリカスペイン語 - + Simplified Chinese 簡体字中国語 - + Traditional Chinese (正體中文) 繁体字中国語 (正體中文) - + Brazilian Portuguese (português do Brasil) ブラジルポルトガル語 (português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan 日本 - + USA アメリカ - + Europe ヨーロッパ - + Australia オーストラリア - + China 中国 - + Korea 韓国 - + Taiwan 台湾 - + Auto (%1) Auto select time zone 自動 (%1) - + Default (%1) Default time zone 既定 (%1) - + CET 中央ヨーロッパ時間 - + CST6CDT CST6CDT - + Cuba キューバ - + EET 東ヨーロッパ標準時 - + Egypt エジプト - + Eire アイルランド - + EST アメリカ東部標準時 - + EST5EDT EST5EDT - + GB GB - + GB-Eire イギリス-アイルランド - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich グリニッジ - + Hongkong 香港 - + HST ハワイ標準時 - + Iceland アイスランド - + Iran イラン - + Israel イスラエル - + Jamaica ジャマイカ - + Kwajalein クェゼリン - + Libya リビア - + MET 中東時間 - + MST MST - + MST7MDT MST7MDT - + Navajo ナバホ - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland ポーランド - + Portugal ポルトガル - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore シンガポール - + Turkey トルコ - + UCT UCT - + Universal ユニバーサル - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu ズールー - + Mono モノラル - + Stereo ステレオ - + Surround サラウンド - + 4GB DRAM (Default) 4GB DRAM (デフォルト) - + 6GB DRAM (Unsafe) 6GB DRAM (不安定) - + 8GB DRAM 8GB DRAM - + 10GB DRAM (Unsafe) - + 12GB DRAM (Unsafe) - + Docked Docked - + Handheld 携帯モード - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) 常に確認する (デフォルト) - + Only if game specifies not to stop ゲームが停止しないように指定しているときのみ - + Never ask 確認しない - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) - + High (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6048,50 +6038,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGLは使用できません! - + OpenGL shared contexts are not supported. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! OpenGL初期化エラー - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. GPUがOpenGLをサポートしていないか、グラフィックスドライバーが最新ではありません。 - + Error while initializing OpenGL 4.6! OpenGL4.6初期化エラー! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 GPUがOpenGL4.6をサポートしていないか、グラフィックスドライバーが最新ではありません。<br><br>GL レンダラ:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 GPUが1つ以上の必要なOpenGL拡張機能をサポートしていない可能性があります。最新のグラフィックドライバを使用していることを確認してください。<br><br>GL レンダラ:<br>%1<br><br>サポートされていない拡張機能:<br>%2 - + This build doesn't have OpenGL support. @@ -6857,1132 +6847,1152 @@ Debug Message: エミュレーション(&E) - + + &Cheats + + + + &View 表示(&V) - + &Reset Window Size ウィンドウサイズのリセット(&R) - + &Debugging デバッグ(&D) - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p &720P - + Reset Window Size to 720p ウィンドウサイズを720Pにリセット - + Reset Window Size to &900p &900P - + Reset Window Size to 900p ウィンドウサイズを900Pにリセット - + Reset Window Size to &1080p &1080P - + Reset Window Size to 1080p ウィンドウサイズを1080Pにリセット - + &Multiplayer マルチプレイヤー (&M) - + &Tools ツール(&T) - + Am&iibo - + Launch &Applet - + &TAS &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help ヘルプ(&H) - + &Install Files to NAND... ファイルをNANDにインストール...(&I) - + L&oad File... ファイルをロード...(&L) - + Load &Folder... フォルダをロード...(&F) - + E&xit 終了(&E) - - + + &Pause 中断(&P) - + &Stop 停止(&S) - + &Verify Installed Contents インストールされたコンテンツを確認(&V) - + &About Eden - + Single &Window Mode シングルウィンドウモード(&W) - + Con&figure... 設定...(&F) - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar フィルターバーを表示 (&F) - + Show &Status Bar ステータスバー(&S) - + Show Status Bar ステータスバーの表示 - + &Browse Public Game Lobby 公開ゲームロビーを参照 (&B) - + &Create Room ルームを作成 (&C) - + &Leave Room ルームを退出 (&L) - + &Direct Connect to Room ルームに直接接続 (&D) - + &Show Current Room 現在のルームを表示 (&S) - + F&ullscreen 全画面表示(&F) - + &Restart 再実行(&R) - + Load/Remove &Amiibo... &Amiibo をロード/削除... - + Open &Mods Page &Modページを開く - + &User Handbook - + &Capture Screenshot スクリーンショットをキャプチャ(&C) - + &Album - + &Set Nickname and Owner オーナーとニックネームを設定 (&S) - + &Delete Game Data ゲームデータの消去 (&D) - + &Restore Amiibo Amiibo を復旧 (&R) - + &Format Amiibo Amiibo を初期化(&F) - + &Mii Editor - + &Configure TAS... TASを設定... (&C) - + Configure C&urrent Game... 現在のゲームを設定...(&U) - - + + &Start 実行(&S) - + &Reset リセット(&R) - - + + R&ecord 記録(&R) - + Open &Controller Menu コントローラーメニューを開く (&C) - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -7990,74 +8000,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? @@ -10590,7 +10600,7 @@ By selecting "From Eden", previous save data stored in Ryujinx will be Failed to save file - + ファイルの保存に失敗しました @@ -10600,43 +10610,44 @@ By selecting "From Eden", previous save data stored in Ryujinx will be Downloading... - + ダウンロード中 Cancel - + キャンセル Could not write to file %1. - + ファイル%1への書き込みに失敗しました Could not commit to file %1. - + ファイル%1へのコミットに失敗しました Failed to download file - + ダウンロードに失敗しました Could not download from %1%2 Error code: %3 - + %1%2からのダウンロードに失敗しました +エラーコード: %3 Download Complete - + ダウンロード完了 Successfully downloaded %1. Would you like to open it? - + %1のダウンロードが完了しました。開きますか? \ No newline at end of file diff --git a/dist/languages/ko_KR.ts b/dist/languages/ko_KR.ts index c78a853a20..7182f4e0c8 100644 --- a/dist/languages/ko_KR.ts +++ b/dist/languages/ko_KR.ts @@ -4,7 +4,7 @@ About Eden - Eden에 대해 + Eden 정보 @@ -37,8 +37,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">웹사이트</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">소스 코드</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">기여자</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">디스코드</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">트위터</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">라이선스</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -411,152 +411,162 @@ Can help reduce stuttering at lower framerates. 낮은 프레임률에서 발생하는 끊김 현상을 줄이는 데 도움될 수 있습니다. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: 정확도: - + Change the accuracy of the emulated CPU (for debugging only). 에뮬레이트된 CPU의 정확도를 변경합니다(디버깅용으로만 사용). - - + + Backend: 백엔드: - + CPU Clocks CPU 클럭 - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. 에뮬레이트된 CPU가 보고하는 클럭 속도를 높여 일부 FPS 제한을 해제합니다. 성능이 낮은 CPU의 경우 성능이 저하될 수 있으며, 일부 게임은 제대로 작동하지 않을 수 있습니다. - + Custom CPU Ticks 사용자 지정 CPU 틱 - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. CPU 틱 값을 사용자 지정으로 설정합니다. 값이 높을수록 성능이 향상될 수 있지만 교착 상태가 발생할 수 있습니다. 77~21000 범위의 값을 권장합니다. - + Enable Host MMU Emulation (fastmem) 호스트 MMU 에뮬레이션 사용(패스트멤) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. - 이 최적화는 게스트 프로그램의 메모리 접근 속도를 높입니다. + 이 최적화는 게스트 프로그램의 메모리 액세스 속도를 높입니다. 이 옵션을 활성화하면 게스트 메모리 읽기/쓰기가 메모리에서 직접 수행되고 호스트의 MMU를 사용하게 됩니다. -이 옵션을 비활성화하면 모든 메모리 접근에 소프트웨어 MMU 에뮬레이션을 사용하도록 강제됩니다. +이 옵션을 비활성화하면 모든 메모리 액세스에 소프트웨어 MMU 에뮬레이션을 사용하도록 강제됩니다. - + Unfuse FMA (improve performance on CPUs without FMA) FMA 분리(FMA를 지원하지 않는 CPU의 성능 향상) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. 이 옵션은 네이티브 FMA를 지원하지 않는 CPU의 fused-multiply-add 명령어 정확도를 낮춰 속도를 향상시킵니다. - + Faster FRSQRTE and FRECPE 더 빠른 FRSQRTE와 FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. 이 옵션은 정확도가 낮은 네이티브 근사값을 사용하여 일부 근사 부동 소수점 함수의 속도를 향상시킵니다. - + Faster ASIMD instructions (32 bits only) 더 빠른 ASIMD 명령어(32비트 전용) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. 이 옵션은 잘못된 반올림 모드를 사용하여 실행함으로써 32비트 ASIMD 부동 소수점 함수의 속도를 향상시킵니다. - + Inaccurate NaN handling 부정확한 NaN 처리 - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. 이 옵션은 NaN 검사를 제거하여 속도를 향상시킵니다. 이로 인해 특정 부동 소수점 명령어의 정확도가 떨어질 수 있다는 점을 유의해 주세요. - + Disable address space checks 주소 공간 검사 비활성화 - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. 이 옵션은 모든 메모리 작업 전에 안전 검사를 제거하여 속도를 향상시킵니다. 이 옵션을 비활성화하면 임의 코드 실행이 허용될 수 있습니다. - + Ignore global monitor 글로벌 모니터 무시 - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. - 이 옵션은 cmpxchg의 의미론에만 의존하여 배타적 접근 명령의 안전성을 보장함으로써 속도를 향상시킵니다. + 이 옵션은 cmpxchg의 의미론에만 의존하여 배타적 액세스 명령의 안전성을 보장함으로써 속도를 향상시킵니다. 이로 인해 교착 상태 및 기타 경합 조건이 발생할 수 있다는 점을 유의해 주세요. - + API: API: - + Changes the output graphics API. Vulkan is recommended. 출력 그래픽 API를 변경합니다. Vulkan을 권장합니다. - + Device: 장치: - + This setting selects the GPU to use (Vulkan only). 이 설정은 사용할 GPU를 선택합니다(Vulkan 전용). - + Resolution: 해상도: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -565,27 +575,27 @@ Options lower than 1X can cause artifacts. 1X보다 낮은 옵션은 아티팩트를 유발할 수 있습니다. - + Window Adapting Filter: 창 적응형 필터: - + FSR Sharpness: FSR 선명도: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. FSR 또는 SGSR의 동적 대비를 사용하여 이미지가 얼마나 선명하게 보일지 결정합니다. - + Anti-Aliasing Method: 안티에일리어싱 방식: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -594,22 +604,22 @@ SMAA는 최고의 화질을 제공합니다. FXAA는 저해상도에서 더 안정적인 화면을 구현할 수 있습니다. - + Enable post-processing effects - + 후처리 효과 활성화 - + Applies post-processing effects to the final image. - + 최종 이미지에 후처리 효과를 적용합니다. - + Fullscreen Mode: 전체 화면 모드: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -618,12 +628,12 @@ Exclusive fullscreen may offer better performance and better Freesync/Gsync supp 전체 화면 전용 모드는 더 나은 성능과 FreeSync/GSync 지원을 제공할 수 있습니다. - + Aspect Ratio: 화면 비율: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -632,36 +642,36 @@ Also controls the aspect ratio of captured screenshots. 또한 캡처된 스크린샷의 화면 비율도 제어합니다. - + Use persistent pipeline cache 지속적 파이프라인 캐시 사용 - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. 셰이더를 저장소에 저장하여 다음 게임 실행 시 더 빠르게 불러올 수 있도록 합니다. 이 옵션을 비활성화하는 것은 디버깅 목적으로만 사용하세요. - + Use asynchronous GPU emulation 비동기 GPU 에뮬레이션 사용 - + Uses an extra CPU thread for rendering. This option should always remain enabled. 렌더링에 추가 CPU 스레드를 사용합니다. 이 옵션은 항상 활성화된 상태로 유지해야 합니다. - + NVDEC emulation: NVDEC 에뮬레이션: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -670,12 +680,12 @@ In most cases, GPU decoding provides the best performance. 대부분의 경우 GPU 디코딩이 가장 좋은 성능을 제공합니다. - + ASTC Decoding Method: ASTC 디코딩 방식: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -687,12 +697,12 @@ GPU: GPU의 컴퓨트 셰이더를 사용하여 ASTC 텍스처를 디코딩합 CPU 비동기: 필요에 따라 CPU를 사용하여 ASTC 텍스처를 디코딩합니다. ASTC 디코딩으로 인한 끊김 현상이 없어지지만, 아티팩트가 발생할 수 있습니다. - + ASTC Recompression Method: ASTC 재압축 방식: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. @@ -701,64 +711,44 @@ BC1/BC3: 중간 형식은 BC1 또는 BC3 형식으로 재압축되어 VRAM을 절약하지만 이미지 품질이 저하됩니다. - + Frame Pacing Mode (Vulkan only) 프레임 페이싱 모드(Vulkan 전용) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. 에뮬레이터가 프레임 페이싱을 관리하는 방식을 제어하여 끊김 현상을 줄이고 프레임 속도를 더욱 부드럽고 일관되게 만듭니다. - + VRAM Usage Mode: VRAM 사용 모드: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. 에뮬레이터가 메모리를 절약할지, 아니면 사용 가능한 비디오 메모리를 최대한 활용하여 성능을 향상시킬지 선택합니다. 적극적 모드는 녹화 소프트웨어와 같은 다른 애플리케이션의 성능에 영향을 줄 수 있습니다. - + Skip CPU Inner Invalidation CPU 내부 무효화 건너뛰기 - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. 메모리 업데이트 중 특정 캐시 무효화를 건너뛰어 CPU 사용량을 줄이고 지연 시간을 개선합니다. 하지만 이로 인해 소프트 크래시가 발생할 수 있습니다. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: 수직 동기화 모드: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -769,12 +759,12 @@ Mailbox는 FIFO보다 지연 시간이 짧고 화면 찢김 현상이 없지만 즉각적(동기화 없음)는 사용 가능한 모든 화면을 표시하며 화면 찢김 현상이 발생할 수 있습니다. - + Sync Memory Operations 메모리 작업 동기화 - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. @@ -783,44 +773,44 @@ Unreal Engine 4 games often see the most significant changes thereof. 대개 언리얼 엔진 4 게임에서 이러한 변경 사항이 가장 두드러지게 나타납니다. - + Enable asynchronous presentation (Vulkan only) 비동기 프레젠테이션 활성화(Vulkan 전용) - + Slightly improves performance by moving presentation to a separate CPU thread. 프레젠테이션을 별도의 CPU 스레드로 이동시켜 성능을 약간 향상시킵니다. - + Force maximum clocks (Vulkan only) 최대 클럭 강제 적용(Vulkan 전용) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. 그래픽 명령을 기다리는 동안 백그라운드에서 작업을 실행하여 GPU 클럭 속도가 저하되는 것을 방지합니다. - + Anisotropic Filtering: 비등방성 필터링: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. 비스듬한 각도에서의 텍스처 렌더링 품질을 제어합니다. 대부분의 GPU에서 16x로 설정해도 안전합니다. - + GPU Mode: GPU 모드: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. @@ -829,12 +819,12 @@ Particles tend to only render correctly with Accurate mode. 특히 조각들은 정확 모드에서만 제대로 렌더링되는 경향이 있습니다. - + DMA Accuracy: DMA 정확도: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. @@ -843,58 +833,62 @@ Default follows the GPU Accuracy setting. 기본값은 GPU 정확도 설정을 따릅니다. - + GPU Fence Behavior: GPU 펜스 동작: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. Accurate further improves compatibility at the cost of some performance. Default follows the GPU Mode setting. - + GPU 펜스 동기화 동작을 제어합니다. +즉시는 가장 빠른 옵션이지만, 일부 문제가 발생할 수 있습니다. +균형은 호환성이 더 우수하며, 특정 게임에서 발생하는 문제를 해결할 수 있습니다. +정확은 호환성을 더욱 향상시키지만, 약간의 성능 저하가 발생할 수 있습니다. +기본값은 GPU 모드 설정을 따릅니다. - + Enable asynchronous shader compilation 비동기 셰이더 컴파일 활성화 - + May reduce shader stutter. 셰이더 끊김 현상을 줄일 수 있습니다. - + GPU Clocks GPU 클럭 - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. 게임이 GPU 작업이 실제보다 더 빨리 완료된다고 착각하게 만들어, 스위치의 클럭 속도에 맞추기 위해 해상도와 렌더 거리를 낮추는 작업을 중단하게 합니다. - + GPU Unswizzle GPU 언스위즐 - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. GPU 컴퓨팅을 사용하여 BCn 3D 텍스처 디코딩을 가속화합니다. 충돌이나 그래픽 결함이 발생하는 경우 이 기능을 비활성화하세요. - + GPU Unswizzle Max Texture Size GPU 언스위즐 최대 텍스처 크기 - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. @@ -903,48 +897,48 @@ GPU는 중간 및 큰 크기의 텍스처에서 더 빠르지만, 매우 작은 이 값을 조정하여 GPU 가속과 CPU 오버헤드 간의 균형을 찾으세요. - + GPU Unswizzle Stream Size GPU 언스위즐 스트림 크기 - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. 프레임당 처리할 최대 텍스처 데이터 양(MiB 단위)을 설정합니다. 값이 높을수록 텍스처 로딩 중 끊김 현상을 줄일 수 있지만 프레임 일관성에 영향을 미칠 수 있습니다. - + GPU Unswizzle Chunk Size GPU 언스위즐 청크 크기 - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. 단일 디스패치에서 처리할 깊이 슬라이스 수를 결정합니다. 이 값을 높이면 고성능 GPU에서 처리량이 향상될 수 있지만, 성능이 낮은 하드웨어에서는 TDR 오류나 드라이버 시간 초과가 발생할 수 있습니다. - + Use Vulkan pipeline cache Vulkan 파이프라인 캐시 사용 - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. GPU 제조사별 파이프라인 캐시를 활성화합니다. 이 옵션은 Vulkan 드라이버가 파이프라인 캐시 파일을 내부에 저장하지 않는 경우 셰이더 로딩 시간을 크게 향상시킬 수 있습니다. - + Enable Compute Pipelines (Intel Vulkan Only) 컴퓨트 파이프라인 활성화(인텔 Vulkan 전용) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. @@ -953,182 +947,182 @@ Compute pipelines are always enabled on all other drivers. 다른 모든 드라이버에서는 컴퓨트 파이프라인이 항상 활성화됩니다. - + Enable Reactive Flushing 반응형 플러싱 활성화 - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. 예측형 플러싱 대신 반응형 플러싱을 사용하여 보다 정확한 메모리 동기화를 가능하게 합니다. - + Sync to framerate of video playback 비디오 재생 프레임 속도에 동기화 - + Run the game at normal speed during video playback, even when the framerate is unlocked. 프레임률 제한이 해제된 경우에도 비디오 재생 중에는 게임을 정상 속도로 실행합니다. - + Barrier feedback loops 피드백 루프 차단 - + Improves rendering of transparency effects in specific games. 특정 게임에서 투명 효과 렌더링을 개선합니다. - + Enable buffer history 버퍼 기록 활성화 - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - 이전 버퍼 상태에 접근할 수 있도록 합니다. + 이전 버퍼 상태에 액세스할 수 있도록 합니다. 이 옵션은 일부 게임에서 렌더링 품질과 성능 일관성을 향상시킬 수 있습니다. - + Fix bloom effects 블룸 효과 수정 - + Removes bloom in Burnout. Burnout에서의 블룸 현상을 제거합니다. - + Extended Dynamic State 확장된 동적 상태 - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. 확장된 동적 상태에서 사용할 수 있는 기능의 수를 제어합니다. 상태 수가 많을수록 더 많은 기능을 사용할 수 있고 성능이 향상될 수 있지만, 추가적인 그래픽 문제가 발생할 수 있습니다. - + Vertex Input Dynamic State 정점 입력 동적 상태 - + Enables vertex input dynamic state feature for better quality and performance. 정점 입력의 동적 상태 기능을 활성화하여 품질과 성능을 향상시킵니다. - + Sample Shading 샘플 셰이딩 - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. 조각 셰이더가 다중샘플 조각에서 한 번당 한 조각이 아닌 샘플별로 실행될 수 있도록 합니다. 성능 저하를 감수하고 그래픽 품질을 향상시킵니다. 값이 높을수록 품질은 향상되지만 성능은 저하됩니다. - + RNG Seed RNG 시드 - + Controls the seed of the random number generator. Mainly used for speedrunning. 난수 생성기의 시드 값을 제어합니다. 주로 스피드런에 사용됩니다. - + Device Name 장치 이름 - + The name of the console. 콘솔의 이름 - + Homebrew Args 홈브루 인수 - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). 홈브루 실행 시 전달되는 명령줄 인수(예: -noglsl). - + Custom RTC Date: 사용자 지정 RTC 날짜: - + This option allows to change the clock of the console. Can be used to manipulate time in games. 이 옵션을 사용하면 콘솔의 시간을 변경할 수 있습니다. 게임 내 시간을 조작하는 데 사용할 수 있습니다. - + The number of seconds from the current unix time 현재 unix 시간으로부터 경과한 초 수 - + Language: 언어: - + This option can be overridden when region setting is auto-select 이 옵션은 지역 설정이 자동 선택으로 되어 있을 경우 번복될 수 있습니다. - + Region: 지역: - + The region of the console. 콘솔의 지역 - + Time Zone: 시간대: - + The time zone of the console. 콘솔의 시간대 - + Sound Output Mode: 소리 출력 모드: - + Console Mode: 콘솔 모드: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. @@ -1137,1026 +1131,1026 @@ Setting to Handheld can help improve performance for low end systems. 휴대 모드로 설정하면 저사양 시스템의 성능을 향상시키는 데 도움이 될 수 있습니다. - + Prompt for user profile on boot 부팅 시 유저 프로필 입력 요청 - + Useful if multiple people use the same PC. 여러 사람이 같은 PC를 사용할 때 유용합니다. - + Pause when not in focus 초점이 맞지 않을 때 일시 중지 - + Pauses emulation when focusing on other windows. 다른 창에 초점을 맞출 때 에뮬레이션을 일시 중지합니다. - + Confirm before stopping emulation 에뮬레이션을 중지하기 전에 확인 - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. 에뮬레이션 중지를 확인하는 메시지를 무시합니다. 이 옵션을 활성화하면 이러한 메시지를 건너뛰고 에뮬레이션을 바로 종료합니다. - + Hide mouse on inactivity 마우스 커서가 비활동 상태일 때 숨기기 - + Hides the mouse after 2.5s of inactivity. 마우스 커서가 2.5초 동안 활동이 없으면 숨깁니다. - + Check for updates 업데이트 확인 - + Whether or not to check for updates upon startup. 시작 시 업데이트를 확인할지 여부. - + Enable Gamemode 게임 모드 활성화 - + Force X11 as Graphics Backend X11을 그래픽 백엔드로 강제 설정 - + Custom frontend 사용자 정의 프론트엔드 - + Real applet 실제 애플릿 - - + + Disabled 비활성화됨 - + Never 안 함 - + On Load 로드 시 - + Always 항상 - + CPU CPU - + GPU GPU - + CPU Asynchronous 비동기 CPU - + Uncompressed (Best quality) 비압축(최고 품질) - + BC1 (Low quality) BC1(저품질) - + BC3 (Medium quality) BC3(중간 품질) - - + + Auto 자동 - + 30 FPS 30 FPS - + 60 FPS 60 FPS - + 90 FPS 90 FPS - + 120 FPS 120 FPS - + Conservative 소극적 - + Aggressive 적극적 - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) OpenGL GLASM(어셈블리 셰이더, NVIDIA 전용) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V(실험적, AMD/Mesa 전용) - + Null Null - + Fast 고속 - - - + + + Accurate 정확 - - - + + + Default 기본값 - + Unsafe (fast) 불안전(빠름) - + Safe (stable) 안전(안정적) - + Immediate 즉시 - + Balanced 균형 - + Unsafe 불안전 - + Paranoid (disables most optimizations) 편집증적(대부분의 최적화를 비활성화함) - + Debugging 디버깅 - + Dynarmic 동적 - + NCE NCE - + Borderless Windowed 테두리 없는 창 - + Exclusive Fullscreen 독점 전체 화면 - + No Video Output 비디오 출력 없음 - + CPU Video Decoding CPU 비디오 디코딩 - + GPU Video Decoding (Default) GPU 비디오 디코딩(기본값) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [실험적] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [실험적] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [실험적] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [실험적] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [실험적] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor 최단입점 - + Bilinear 쌍선형 - + Bicubic 쌍입방 - + Gaussian 가우시안 - + Lanczos 란초스 - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX Super Resolution - + Area 영역 - + MMPX MMPX - + Zero-Tangent 제로탄젠트 - + B-Spline B-스플라인 - + Mitchell 미첼 - + Spline-1 스플라인-1 - + Snapdragon Game Super Resolution Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir Snapdragon Game Super Resolution EdgeDir - + None 없음 - + FXAA FXAA - + SMAA SMAA - + Default (16:9) 기본(16:9) - + Force 4:3 강제 4:3 - + Force 21:9 강제 21:9 - + Force 16:10 강제 16:10 - + Stretch to Window 화면 늘리기 - + Automatic 자동 - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) 일본어(日本語) - + American English 미국식 영어 - + French (français) 프랑스어(français) - + German (Deutsch) 독일어(Deutsch) - + Italian (italiano) 이탈리아어(italiano) - + Spanish (español) 스페인어(español) - + Chinese 중국어 - + Korean (한국어) 한국어(Korean) - + Dutch (Nederlands) 네덜란드어(Nederlands) - + Portuguese (português) 포르투갈어(português) - + Russian (Русский) 러시아어(Русский) - + Taiwanese 대만어 - + British English 영국식 영어 - + Canadian French 캐나다 프랑스어 - + Latin American Spanish 라틴아메리카 스페인어 - + Simplified Chinese 중국어 간체 - + Traditional Chinese (正體中文) 중국어 번체(正體中文) - + Brazilian Portuguese (português do Brasil) 브라질 포르투갈어(português do Brasil) - + Polish (polska) 폴란드어(polska) - + Thai (แบบไทย) 태국어(แบบไทย) - - + + Japan 일본 - + USA 미국 - + Europe 유럽 - + Australia 호주 - + China 중국 - + Korea 대한민국 - + Taiwan 대만 - + Auto (%1) Auto select time zone 자동(%1) - + Default (%1) Default time zone 기본(%1) - + CET CET - + CST6CDT CST6CDT - + Cuba 쿠바 - + EET EET - + Egypt 이집트 - + Eire 아일랜드 - + EST EST - + EST5EDT EST5EDT - + GB 영국 - + GB-Eire 영국-아일랜드 - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich 그리니치 - + Hongkong 홍콩 - + HST HST - + Iceland 아이슬란드 - + Iran 이란 - + Israel 이스라엘 - + Jamaica 자메이카 - + Kwajalein 콰잘레인 - + Libya 리비아 - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo 나바호 - + NZ 뉴질랜드 - + NZ-CHAT 뉴질랜드-채텀 - + Poland 폴란드 - + Portugal 포르투갈 - + PRC 중국 - + PST8PDT PST8PDT - + ROC 대만 - + ROK 대한민국 - + Singapore 싱가포르 - + Turkey 터키 - + UCT UCT - + Universal 세계 - + UTC UTC - + W-SU 모스크바 - + WET WET - + Zulu Zulu - + Mono 모노 - + Stereo 스테레오 - + Surround 서라운드 - + 4GB DRAM (Default) 4GB DRAM(기본값) - + 6GB DRAM (Unsafe) 6GB DRAM(불안전) - + 8GB DRAM 8GB DRAM - + 10GB DRAM (Unsafe) 10GB DRAM(불안전) - + 12GB DRAM (Unsafe) 12GB DRAM(불안전) - + Docked 독 모드 - + Handheld 휴대 모드 - - + + Normal 보통 - - + + Boost 부스트 - - + + Overclock 오버클럭 - + Always ask (Default) 항상 묻기(기본값) - + Only if game specifies not to stop 게임에서 멈추지 말라고 명시한 경우에만 - + Never ask 절대 묻지 않음 - + Very Small (16 MB) 아주 작은 크기(16 MB) - + Small (32 MB) 작은 크기(32 MB) - + Normal (128 MB) 보통 크기(128 MB) - + Large (256 MB) 큰 크기(256 MB) - + Very Large (512 MB) 아주 큰 크기(512 MB) - + Very Low (4 MB) 매우 낮은 크기(4 MB) - + Low (8 MB) 낮은 크기(8 MB) - + Normal (16 MB) 보통 크기(16 MB) - + Medium (32 MB) 중간 크기(32 MB) - + High (64 MB) 높은 크기(64 MB) - + Very Low (32) 매우 낮은 크기(32) - + Low (64) 낮은 크기(64) - + Normal (128) 보통 크기(128) - + Medium (256) 보통(256) - + High (512) 빠름(512) - + ExtendedDynamicState 1 확장된 동적 상태 1 - + ExtendedDynamicState 2 확장된 동적 상태 2 - + ExtendedDynamicState 3 확장된 동적 상태 3 - + Tree View 트리 보기 - + Grid View 격자 보기 @@ -2304,9 +2298,9 @@ Enabling it bypasses such prompts and directly exits the emulation. <div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div> - <div style="white-space: nowrap">이 최적화는 게스트 프로그램의 메모리 접근 속도를 높입니다.</div> - <div style="white-space: nowrap">이 기능을 활성화하면 PageTable::pointers에 대한 접근이 출력된 코드에 인라인으로 포함됩니다.</div> - <div style="white-space: nowrap">이 기능을 비활성화하면 모든 메모리 접근이 Memory::Read/Memory::Write 함수를 통해 이루어지게 됩니다.</div> + <div style="white-space: nowrap">이 최적화는 게스트 프로그램의 메모리 액세스 속도를 높입니다.</div> + <div style="white-space: nowrap">이 기능을 활성화하면 PageTable::pointers에 대한 액세스가 출력된 코드에 인라인으로 포함됩니다.</div> + <div style="white-space: nowrap">이 기능을 비활성화하면 모든 메모리 액세스가 Memory::Read/Memory::Write 함수를 통해 이루어지게 됩니다.</div> @@ -2457,8 +2451,8 @@ Enabling it bypasses such prompts and directly exits the emulation. <div style="white-space: nowrap">Enabling it reduces the overhead of fastmem failure of exclusive memory accesses.</div> - <div style="white-space: nowrap">이 최적화는 게스트 프로그램의 전용 메모리 접근 속도를 향상시킵니다.</div> - <div style="white-space: nowrap">이 옵션을 활성화하면 전용 메모리 접근 시 패스트멤 실패로 인한 오버헤드가 줄어듭니다.</div> + <div style="white-space: nowrap">이 최적화는 게스트 프로그램의 전용 메모리 액세스 속도를 향상시킵니다.</div> + <div style="white-space: nowrap">이 옵션을 활성화하면 전용 메모리 액세스 시 패스트멤 실패로 인한 오버헤드가 줄어듭니다.</div> @@ -3276,7 +3270,7 @@ Would you like to delete the old save data? Configure Effects... - + 효과 구성... @@ -4921,123 +4915,124 @@ Once deleted, these can NOT be recovered. Are you 100% sure you want to delete t Post-Processing Effects - + 후처리 효과 Changes apply immediately while a game is running. - + 변경 사항은 게임이 실행되는 동안 즉시 적용됩니다. Enable post-processing - + 후처리 활성화 Preset: - + 사전 설정: Apply - + 적용 Reset Values - + 값 초기화 Return every effect to the values the preset ships with. - + 모든 효과를 사전 설정된 값으로 되돌립니다. Save As... - + 다른 이름으로 저장... Save Preset - + 사전 설정 저장 Preset name: - + 사전 설정 이름: Clear - + 지우기 Remove every effect in use and deselect the preset. - + 사용 중인 모든 효과를 제거하고 사전 설정 선택을 해제합니다. Add Effect - + 효과 추가 None - + 없음 No effects in use. Pick a preset and press Apply, or add effects one by one. - + 사용 중인 효과가 없습니다. 사전 설정을 선택하고 적용을 누르거나, 효과를 하나씩 추가하세요. Custom chain. Pick a preset above and press Apply to replace it. - + 사용자 지정 체인. 위에서 사전 설정을 선택하고 적용을 눌러 교체하세요. Active preset: %1 (modified). Press Reset Values to go back to how it ships. - + 활성화된 사전 설정: %1 (수정됨). 값 초기화를 누르면 초기 상태로 되돌아갑니다. Active preset: %1 - + 활성화된 사전 설정: %1 Enabled - + 활성화됨 Disabled - + 비활성화됨 Reset to defaults - + 기본값으로 재설정 Effect '%1' was not found. - + '%1' 효과를 찾을 수 없습니다. Effect failed to compile: %1 - + 효과를 컴파일하지 못했습니다: +%1 No usable ReShade FX effects were found. Place .fx files in the post_shaders folder. - + 사용 가능한 ReShade FX 효과를 찾을 수 없습니다. .fx 파일을 post_shaders 폴더에 넣으세요. @@ -5933,12 +5928,12 @@ Drag points to change position, or double-click table cells to edit values. Eden Dependencies - Eden 의존물 + Eden 종속성 <html><head/><body><p><span style=" font-size:28pt;">Eden Dependencies</span></p></body></html> - <html><head/><body><p><span style=" font-size:28pt;">Eden 의존물</span></p></body></html> + <html><head/><body><p><span style=" font-size:28pt;">Eden 종속성</span></p></body></html> @@ -5948,7 +5943,7 @@ Drag points to change position, or double-click table cells to edit values. Dependency - 의존물 + 종속성 @@ -6127,50 +6122,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL을 사용할 수 없습니다! - + OpenGL shared contexts are not supported. OpenGL 공유 콘텍스트는 지원되지 않습니다. - + Eden has not been compiled with OpenGL support. Eden은 OpenGL 지원 기능을 포함하여 컴파일되지 않았습니다. - - - + + + Error while initializing OpenGL! OpenGL을 초기화하는 동안 오류가 발생했습니다! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. 사용하시는 GPU가 OpenGL을 지원하지 않거나, 최신 그래픽 드라이버가 설치되어 있지 않습니다. - + Error while initializing OpenGL 4.6! OpenGL 4.6 초기화 중 오류 발생! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 사용 중인 GPU가 OpenGL 4.6을 지원하지 않거나 최신 그래픽 드라이버가 설치되어 있지 않습니다.<br><br>GL 렌더러:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 사용 중인 GPU가 하나 이상의 필수 OpenGL 확장 기능을 지원하지 않을 수 있습니다. 최신 그래픽 드라이버가 설치되어 있는지 확인해 주세요.<br><br>GL 렌더러:<br>%1<br><br>지원되지 않는 확장 기능:<br>%2 - + This build doesn't have OpenGL support. 이 빌드는 OpenGL을 지원하지 않습니다. @@ -6937,1138 +6932,1158 @@ Debug Message: 에뮬레이션(&E) - + + &Cheats + + + + &View 보기(&V) - + &Reset Window Size 창 크기 재설정(&R) - + &Debugging 디버깅(&D) - + &Game List Mode 게임 목록 모드(&G) - + Game &Icon Size 게임 아이콘 크기(&I) - + Reset Window Size to &720p 창 크기를 720p로 재설정(&7) - + Reset Window Size to 720p 창 크기를 720p로 재설정 - + Reset Window Size to &900p 창 크기를 900p로 재설정(&9) - + Reset Window Size to 900p 창 크기를 900p로 재설정 - + Reset Window Size to &1080p 창 크기를 1080p로 재설정(&1) - + Reset Window Size to 1080p 창 크기를 1080p로 재설정 - + &Multiplayer 멀티플레이어(&M) - + &Tools 도구(&T) - + Am&iibo Amiibo(&i) - + Launch &Applet 애플릿 실행(&A) - + &TAS TAS(&T) - + &Create Home Menu Shortcut HOME 메뉴 바로가기 만들기(&C) - + Install &Firmware 펌웨어 설치(&F) - + &Help 도움말(&H) - + &Install Files to NAND... NAND에 파일 설치(&I) - + L&oad File... 파일 불러오기...(&o) - + Load &Folder... 폴더 불러오기...(&F) - + E&xit 종료(&x) - - + + &Pause 일시중지(&P) - + &Stop 정지(&S) - + &Verify Installed Contents 설치된 콘텐츠 확인(&V) - + &About Eden - Eden에 대해(&A) + Eden 정보(&A) - + Single &Window Mode 단일 창 모드(&W) - + Con&figure... 설정(&f) - + Ctrl+, Ctrl+, - + Enable Overlay Display Applet 오버레이 디스플레이 애플릿 활성화 - + Show &Filter Bar 필터 바 표시(&F) - + Show &Status Bar 상태 표시줄 표시(&S) - + Show Status Bar 상태 표시줄 표시 - + &Browse Public Game Lobby 공개 게임 로비 찾아보기(&B) - + &Create Room 방 만들기(&C) - + &Leave Room 방 나가기(&L) - + &Direct Connect to Room 방에 직접 연결(&D) - + &Show Current Room 현재 방 표시(&S) - + F&ullscreen 전체 화면(&u) - + &Restart 재시작(&R) - + Load/Remove &Amiibo... Amiibo 불러오기/제거(&A)... - + Open &Mods Page 모드 페이지 열기(&M) - + &User Handbook - + 사용자 설명서(&U) - + &Capture Screenshot 스크린샷 캡처(&C) - + &Album 앨범(&A) - + &Set Nickname and Owner 닉네임과 오너 설정(&S) - + &Delete Game Data 게임 데이터 삭제(&D) - + &Restore Amiibo Amiibo 복원(&R) - + &Format Amiibo Amiibo 포맷(&F) - + &Mii Editor Mii 편집기(&M) - + &Configure TAS... TAS 구성...(&C) - + Configure C&urrent Game... 현재 게임 구성...(&u) - - + + &Start 시작(&S) - + &Reset 재설정(&R) - - + + R&ecord 기록(&e) - + Open &Controller Menu 컨트롤러 메뉴 열기(&C) - + Install Decryption &Keys 복호화 키 설치(&K) - + &Home Menu HOME 메뉴(&H) - + &Desktop 데스크톱(&D) - + &Application Menu 애플리케이션 메뉴(&A) - + &Root Data Folder 데이터 폴더 경로(&R) - + &NAND Folder NAND 폴더(&N) - + &SDMC Folder SDMC 폴더(&S) - + &Mod Folder 모드 폴더(&M) - + &Log Folder 로그 폴더(&L) - + From Folder 폴더에서 - + From ZIP ZIP에서 - + &Eden Dependencies - Eden 의존물(&E) + Eden 종속성(&E) - + &Data Manager 데이터 관리자(&D) - + &Tree View 트리 보기(&T) - + &Grid View 격자 보기(&G) - + Game Icon Size 게임 아이콘 크기 - - + + None 없음 - + Show Game &Name 게임 이름 표시(&N) - + Show &Performance Overlay 성능 오버레이 표시(&P) - + Post-Processing &Shaders... - + 후처리 셰이더...(&S) - + &Carousel View 캐러셀 보기(&C) - + Small (32x32) 작은 크기(32x32) - + Standard (64x64) 기본 크기(64x64) - + Large (128x128) 큰 크기(128x128) - + Full Size (256x256) 전체 크기(256x256) - + Broken Vulkan Installation Detected 손상된 Vulkan 설치가 발견됨 - + Vulkan initialization failed during boot. 부팅 중 Vulkan 초기화에 실패했습니다. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping 게임 실행 중 - + Loading Web Applet... 웹 애플릿을 불러오는 중... - - + + Disable Web Applet 웹 애플릿 비활성화 - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) 웹 애플릿을 비활성화하면 예기치 않은 동작이 발생할 수 있으며 슈퍼 마리오 3D 컬렉션에서만 사용해야 합니다. 웹 애플릿을 비활성화하겠습니까? (디버그 설정에서 다시 활성화할 수 있습니다.) - + The amount of shaders currently being built 현재 구축 중인 셰이더 수 - + The current selected resolution scaling multiplier. 현재 선택된 해상도 조정 배율입니다. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. 현재 에뮬레이션 속도입니다. 100%보다 높거나 낮은 값은 에뮬레이션이 스위치보다 빠르거나 느리게 실행되고 있음을 나타냅니다. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. 현재 게임이 표시하는 초당 프레임 수입니다. 이 값은 게임 및 장면에 따라 다릅니다. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 프레임 제한이나 수직 동기화를 제외하고 스위치 프레임을 에뮬레이션하는 데 걸리는 시간입니다. 최고 속도 에뮬레이션의 경우 최대 16.67 밀리초입니다. - + Unmute 음소거 해제 - + Mute 음소거 - + Reset Volume - 볼륨 재설정 + 볼륨 초기화 - + Configure Effects... - + 효과 구성... - + &Clear Recent Files 최근 파일 지우기(&C) - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue 재개(&C) - + Warning: Outdated Game Format 경고: 구식 게임 형식입니다 - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. 현재 이 게임에 대해 구형 형식인 분해된 ROM 디렉터리 형식을 사용하고 있습니다. 이 형식은 NCA, NAX, XCI 또는 NSP와 같은 다른 형식으로 대체되었습니다. 분해된 ROM 디렉터리에는 아이콘, 메타데이터 및 업데이트 지원 기능이 없습니다.<br>Eden에서 지원하는 다양한 스위치 형식에 대한 자세한 내용은 사용자 설명서를 참조해 주세요. 이 메시지는 다시 표시되지 않습니다. - - + + Error while loading ROM! ROM 불러오는 중 오류 발생! - + The ROM format is not supported. 해당 ROM 형식은 지원되지 않습니다. - + An error occurred initializing the video core. 비디오 코어 초기화 중 오류가 발생했습니다. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + 이는 일반적으로 오래된 GPU 드라이버로 인해 발생합니다. 자세한 내용은 로그를 참조해 주세요. 참조: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>로그 파일에 액세스하는 방법</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. ROM 불러오는 중 오류 발생! %1 - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. %1<br>파일을 다시 덤프하거나 디스코드/Stoat에서 도움을 요청해 주세요. - + An unknown error occurred. Please see the log for more details. 알 수 없는 오류가 발생했습니다. 자세한 내용은 로그를 참조해 주세요. - - + + (64-bit) (64비트) - - + + (32-bit) (32비트) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - + Closing software... 소프트웨어 닫는 중... - + Save Data 저장 데이터 - + Mod Data 모드 데이터 - + Error Opening %1 Folder %1 폴더 여는 중 오류 발생 - - + + Folder does not exist! 폴더가 존재하지 않습니다! - + Remove Installed Game Contents? 설치된 게임 콘텐츠를 제거하겠습니까? - + Remove Installed Game Update? 설치된 게임 업데이트를 제거하겠습니까? - + Remove Installed Game DLC? 설치된 게임 DLC를 제거하겠습니까? - + Remove Entry 항목 제거 - + Delete OpenGL Transferable Shader Cache? OpenGL 이동 가능한 셰이더 캐시를 삭제하겠습니까? - + Delete Vulkan Transferable Shader Cache? Vulkan 이동 가능한 셰이더 캐시를 삭제하겠습니까? - + Delete All Transferable Shader Caches? 이동 가능한 셰이더 캐시를 모두 삭제하겠습니까? - + Remove Custom Game Configuration? 사용자 지정 게임 구성을 제거하겠습니까? - + Remove Cache Storage? 캐시 저장소를 제거하겠습니까? - + Remove File 파일 제거 - + Remove Play Time Data 플레이 시간 데이터 제거 - + Reset play time? - 플레이 시간을 재설정하겠습니까? + 플레이 시간을 초기화하겠습니까? - - + + RomFS Extraction Failed! RomFS 추출 실패! - + There was an error copying the RomFS files or the user cancelled the operation. RomFS 파일을 복사하는 중에 오류가 발생했거나 사용자가 작업을 취소했습니다. - + Full 전체 - + Skeleton 뼈대 - + Select RomFS Dump Mode RomFS 덤프 모드 선택 - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. RomFS 덤프 방식을 선택해 주세요. 전체를 선택하면 모든 파일이 새 디렉터리로 복사되고, 뼈대를 선택하면 디렉터리 구조만 생성됩니다. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root %1 위치에 RomFS를 추출할 수 있는 여유 공간이 부족합니다. 공간을 확보하거나 에뮬레이션 > 구성 > 시스템 > 파일 시스템 > 덤프 경로에서 다른 덤프 디렉터리를 선택해 주세요. - + Extracting RomFS... RomFS 추출 중... - - + + Cancel 취소 - + RomFS Extraction Succeeded! RomFS 추출 성공! - + The operation completed successfully. 작업이 성공적으로 완료되었습니다. - + Error Opening %1 %1을(를) 여는 중 오류 발생 - + Select Directory 디렉터리 선택 - + Properties 속성 - + The game properties could not be loaded. 게임 속성을 불러올 수 없습니다. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. 스위치 실행 파일(%1);;모든 파일(*.*) - + Load File 파일 불러오기 - + Open Extracted ROM Directory 추출된 ROM 디렉터리 열기 - + Invalid Directory Selected 유효하지 않은 디렉터리 선택됨 - + The directory you have selected does not contain a 'main' file. 선택한 디렉터리에는 'main' 파일이 없습니다. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - 설치 가능한 스위치 파일(*.nca, *.nsp, *.xci);;닌텐도 콘텐츠 아카이브(*.nca);;닌텐도 제출 패키지(*.nsp);;NX 카트리지 이미지(*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) + - + Install Files 파일 설치 - + %n file(s) remaining %n개 파일 남음 - + Installing file "%1"... "%1" 파일 설치 중... - - + + Install Results 설치 결과 - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. 잠재적인 충돌을 방지하기 위해 저희는 사용자가 기본 게임을 NAND에 설치하는 것은 권장하지 않습니다. 이 기능은 업데이트 및 DLC 설치에만 사용해 주세요. - + %n file(s) were newly installed %n개 파일이 새로 설치됨 - + %n file(s) were overwritten %n개 파일이 덮어쓰기됨 - + %n file(s) failed to install %n개 파일 설치 실패 - + System Application 시스템 애플리케이션 - + System Archive 시스템 아카이브 - + System Application Update 시스템 애플리케이션 업데이트 - + Firmware Package (Type A) 펌웨어 패키지(A타입) - + Firmware Package (Type B) 펌웨어 패키지(B타입) - + Game 게임 - + Game Update 게임 업데이트 - + Game DLC 게임 DLC - + Delta Title 델타 타이틀 - + Select NCA Install Type... NCA 설치 유형 선택... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) 이 NCA를 설치할 타이틀 유형을 선택해 주세요: (대부분의 경우 기본값인 '게임'을 선택하면 됩니다.) - + Failed to Install 설치 실패 - + The title type you selected for the NCA is invalid. NCA에 대해 선택한 타이틀 유형이 유효하지 않습니다. - + File not found 파일을 찾을 수 없음 - + File "%1" not found "%1" 파일을 찾을 수 없음 - + OK 확인 - + Function Disabled 기능 비활성화됨 - + Compatibility list reporting is currently disabled. Check back later! 호환성 목록 보고 옵션이 현재 비활성화되어 있습니다. 나중에 다시 확인해 주세요! - + Error opening URL URL 여는 중 오류 발생 - + Unable to open the URL "%1". "%1" URL을 열 수 없습니다. - + TAS Recording TAS 녹화 - + Overwrite file of player 1? 플레이어 1의 파일을 덮어쓰겠습니까? - + Invalid config detected 무효한 구성이 발견됨 - + Handheld controller can't be used on docked mode. Pro controller will be selected. 휴대 모드 컨트롤러는 독 모드에서 사용할 수 없습니다. Pro 컨트롤러로 선택됩니다. - - + + Amiibo Amiibo - - + + The current amiibo has been removed 현재 amiibo가 제거됨 - + Error 오류 - - + + The current game is not looking for amiibos 현재 게임은 amiibo를 찾고 있지 않습니다 - + Amiibo File (%1);; All Files (*.*) Amiibo 파일(%1);; 모든 파일(*.*) - + Load Amiibo Amiibo 불러오기 - + Error loading Amiibo data Amiibo 데이터 불러오는 중 오류 발생 - + The selected file is not a valid amiibo 선택한 파일은 유효한 amiibo가 아닙니다 - + The selected file is already on use 선택한 파일은 이미 사용 중입니다 - + An unknown error occurred 알 수 없는 오류 발생 - + No firmware available 사용 가능한 펌웨어 없음 - + Firmware Corrupted 펌웨어 손상됨 - + Unknown applet 알 수 없는 애플릿 - + Applet doesn't map to a known value. 애플릿이 알려진 값에 매핑되지 않습니다. - + Record not found 기록을 찾을 수 없음 - + Applet not found. Please reinstall firmware. 애플릿을 찾을 수 없습니다. 펌웨어를 다시 설치해 주세요. - + Capture Screenshot 스크린샷 캡처 - + PNG Image (*.png) PNG 이미지(*.png) - + TAS state: Running %1/%2 TAS 상태: %1/%2 실행 중 - + TAS state: Recording %1 TAS 상태: %1 녹화 중 - + TAS state: Idle %1/%2 TAS 상태: %1/%2 유휴 - + TAS State: Invalid TAS 상태: 무효 - + &Stop Running 실행 중지(&S) - + Stop R&ecording 녹화 중지(&e) - + Building: %n shader(s) 구축 중: %n개 셰이더 - + Scale: %1x %1 is the resolution scaling factor 크기: %1x - + Speed: %1% / %2% 속도: %1% / %2% - + Speed: %1% 속도: %1% - + Game: %1 FPS 게임: %1 FPS - + Frame: %1 ms 프레임: %1 밀리초 - + NO AA AA 없음 - + NO FX - + FX 없음 - + FX - + FX - + VOLUME: MUTE 볼륨: 음소거 - + VOLUME: %1% Volume percentage (e.g. 50%) 볼륨: %1% - + Derivation Components Missing 파생 구성 요소 누락 - + Decryption keys are missing. Install them now? 복호화 키가 없습니다. 지금 설치하겠습니까? - + Wayland Detected! Wayland 발견됨! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8079,74 +8094,74 @@ Would you like to force it for future launches? 향후 출시를 위해 Wayland 사용을 강제하겠습니까? - + Use X11 X11 사용 - + Continue with Wayland Wayland와 계속 - + Don't show again 다시 보지 않기 - + Restart Required 재시작이 필요함 - + Restart Eden to apply the X11 backend. X11 백엔드를 적용하려면 Eden을 다시 시작하세요. - + Slow 저속 - + Turbo 터보 - + Unlocked 제한 해제 - + Select RomFS Dump Target RomFS 덤프 대상 선택 - + Please select which RomFS you would like to dump. 덤프할 RomFS를 선택하세요. - + Are you sure you want to close Eden? 정말 Eden을 닫겠습니까? - - - + + + Eden Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. 정말 에뮬레이션을 중지하겠습니까? 저장되지 않은 진행 상황은 모두 손실됩니다. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? @@ -9349,7 +9364,7 @@ p, li { white-space: pre-wrap; } This game may require firmware to function properly, and you don't have any installed. Please install firmware before launching, or press "OK" to launch anyways. - + 이 게임이 제대로 작동하려면 펌웨어가 필요할 수 있는데, 현재 설치된 펌웨어가 없습니다. 게임을 실행하기 전에 펌웨어를 설치하거나, ​​그냥 "확인"을 눌러 실행해 주세요. diff --git a/dist/languages/nb.ts b/dist/languages/nb.ts index 191099c395..35ed5f0a0b 100644 --- a/dist/languages/nb.ts +++ b/dist/languages/nb.ts @@ -30,7 +30,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> @@ -399,252 +399,262 @@ Can help reduce stuttering at lower framerates. - - Accuracy: - Nøyaktighet: - - - - Change the accuracy of the emulated CPU (for debugging only). + + Enable cheats by default - - - Backend: + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + Accuracy: + Nøyaktighet: + + + + Change the accuracy of the emulated CPU (for debugging only). + + + + + + Backend: + + + + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) Del opp FMA (forbedre ytelsen på prosessorer uten FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. - + Faster FRSQRTE and FRECPE Raskere FRSQRTE og FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. - + Faster ASIMD instructions (32 bits only) Raskere ASIMD-instruksjoner (kun 32-bit) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. - + Inaccurate NaN handling Unøyaktig NaN-håndtering - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. - + Disable address space checks Slå av adresseromskontroller - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor Ignorer global overvåkning - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. - + API: API: - + Changes the output graphics API. Vulkan is recommended. - + Device: Enhet: - + This setting selects the GPU to use (Vulkan only). - + Resolution: Oppløsning: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: Vindustilpasningsfilter: - + FSR Sharpness: FSR-skarphet: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Antialiasingmetode: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Fullskjermmodus: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. - + Aspect Ratio: Bildeforhold: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: NVDEC-emulering: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. - + ASTC Decoding Method: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -653,75 +663,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: VSync-modus: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -729,79 +719,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) Aktiver asynkron presentasjon (kun Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. - + Force maximum clocks (Vulkan only) Tving maksikal klokkehastighet (kun Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Kjører arbeid i bakgrunnen mens den venter på grafikkommandoer for å forhindre at GPU-en senker klokkehastigheten. - + Anisotropic Filtering: Anisotropisk filtrering: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: GPU-modus: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: DMA-nøyaktighet: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -810,1290 +800,1290 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache Bruk Vulkan-rørledningsbuffer - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. - + Enable Compute Pipelines (Intel Vulkan Only) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing Aktiver Reaktiv Tømming - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. - + Sync to framerate of video playback Synkroniser med bildefrekvensen for videoavspilling - + Run the game at normal speed during video playback, even when the framerate is unlocked. Kjør spillet i normal hastighet under videoavspilling, selv når bildefrekvensen er låst opp. - + Barrier feedback loops Tilbakekoblingssløyfer for barrierer - + Improves rendering of transparency effects in specific games. Forbedrer gjengivelsen av transparenseffekter i spesifikke spill. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed RNG-frø - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name Enhetsnavn - + The name of the console. Konsollens navn. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: Selvvalgt RTC-dato: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: Språk: - + This option can be overridden when region setting is auto-select - + Region: Region: - + The region of the console. Konsollens region. - + Time Zone: Tidssone: - + The time zone of the console. Konsollens tidssone. - + Sound Output Mode: Lydutdatamodus: - + Console Mode: Konsollmodus: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation Bekreft før stopping av emulering - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity Gjem mus under inaktivitet - + Hides the mouse after 2.5s of inactivity. - + Check for updates Se etter oppdateringer - + Whether or not to check for updates upon startup. - + Enable Gamemode - + Force X11 as Graphics Backend - + Custom frontend - + Real applet - - + + Disabled Skrudd av - + Never Aldri - + On Load - + Always Alltid - + CPU CPU - + GPU Skjermkort - + CPU Asynchronous - + Uncompressed (Best quality) Ukomprimert (Best kvalitet) - + BC1 (Low quality) BC1 (Lav kvalitet) - + BC3 (Medium quality) BC3 (Middels kvalitet) - - + + Auto Auto - + 30 FPS 30 FPS - + 60 FPS 60 FPS - + 90 FPS 90 FPS - + 120 FPS 120 FPS - + Conservative - + Aggressive Aggressiv - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V (eksperimentelt, kun AMD/Mesa) - + Null Null - + Fast Rask - - - + + + Accurate Nøyaktig - - - + + + Default Standard - + Unsafe (fast) Utrygg (raskt) - + Safe (stable) Trygg (stabil) - + Immediate - + Balanced Balansert - + Unsafe Utrygt - + Paranoid (disables most optimizations) Paranoid (deaktiverer de fleste optimaliseringer) - + Debugging - + Dynarmic - + NCE NCE - + Borderless Windowed Rammeløst vindu - + Exclusive Fullscreen Eksklusiv fullskjerm - + No Video Output Ingen videoutdata - + CPU Video Decoding CPU-videodekoding - + GPU Video Decoding (Default) GPU-videodekoding (Standard) - + 0.25X (180p/270p) [EXPERIMENTAL] 0,25× (180p/270p) [EKSPERIMENTELL] - + 0.5X (360p/540p) [EXPERIMENTAL] 0,5× (360p/540p) [EKSPERIMENTELL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0,75× (540p/810p) [EKSPERIMENTELL] - + 1X (720p/1080p) 1× (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1,25× (900p/1350p) [EKSPERIMENTELL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1,5× (1080p/1620p) [EKSPERIMENTELL] - + 2X (1440p/2160p) 2× (1440p/2160p) - + 3X (2160p/3240p) 3× (2160p/3240p) - + 4X (2880p/4320p) 4× (2880p/4320p) - + 5X (3600p/5400p) 5× (3600p/5400p) - + 6X (4320p/6480p) 6× (4320p/6480p) - + 7X (5040p/7560p) 7× (5040p/7560p) - + 8X (5760p/8640p) 8× (5760p/8640p) - + Nearest Neighbor Nærmeste nabo - + Bilinear Bilineær - + Bicubic Bikubisk - + Gaussian Gaussisk - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX Super Resolution - + Area Område - + MMPX MMPX - + Zero-Tangent - + B-Spline B-Spline - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Ingen - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Standard (16:9) - + Force 4:3 Tving 4:3 - + Force 21:9 Tving 21:9 - + Force 16:10 Tving 16:10 - + Stretch to Window Strekk til vinduet - + Automatic Automatisk - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Japansk (日本語) - + American English Amerikansk engelsk - + French (français) Fransk (français) - + German (Deutsch) Tysk (Deutsch) - + Italian (italiano) Italiensk (italiano) - + Spanish (español) Spansk (español) - + Chinese Kinesisk - + Korean (한국어) Koreansk (한국어) - + Dutch (Nederlands) Nederlandsk (Nederlands) - + Portuguese (português) Portugisisk (português) - + Russian (Русский) Russisk (Русский) - + Taiwanese Taiwansk - + British English Britisk engelsk - + Canadian French Kanadisk fransk - + Latin American Spanish Latinamerikansk spansk - + Simplified Chinese Forenklet kinesisk - + Traditional Chinese (正體中文) Tradisjonell kinesisk (正體中文) - + Brazilian Portuguese (português do Brasil) Brasiliansk portugisisk (português do Brasil) - + Polish (polska) Polsk (polska) - + Thai (แบบไทย) Thai (แบบไทย) - - + + Japan Japan - + USA USA - + Europe Europa - + Australia Australia - + China Folkerepublikken Kina - + Korea Korea - + Taiwan Taiwan (Republikken Kina) - + Auto (%1) Auto select time zone Auto (%1) - + Default (%1) Default time zone Standard (%1) - + CET Sentraleuropeisk tid - + CST6CDT CST6CDT - + Cuba Cuba - + EET Østeuropeisk tid - + Egypt Egypt - + Eire Republikken Irland - + EST EST - + EST5EDT EST5EDT - + GB Storbritannia - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Island - + Iran Iran - + Israel Israel - + Jamaica Jamaica - + Kwajalein Kwajalein - + Libya Libya - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polen - + Portugal Portugal - + PRC Folkerepublikken Kina - + PST8PDT PST8PDT - + ROC Taiwan (Republikken Kina) - + ROK Sør-Korea - + Singapore Singapore - + Turkey Tyrkia - + UCT UCT - + Universal Universalt - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Stereo - + Surround Surround - + 4GB DRAM (Default) 4 GB DRAM (Standard) - + 6GB DRAM (Unsafe) 6 GB DRAM (Utrygt) - + 8GB DRAM 8 GB DRAM - + 10GB DRAM (Unsafe) 10 GB DRAM (Utrygt) - + 12GB DRAM (Unsafe) 12 GB DRAM (Utrygt) - + Docked I dokking - + Handheld Håndholdt - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) Spør alltid (Standard) - + Only if game specifies not to stop - + Never ask Aldri spør - + Very Small (16 MB) Veldig liten (16 MB) - + Small (32 MB) Liten (32 MB) - + Normal (128 MB) Normal (128 MB) - + Large (256 MB) Stor (256 MB) - + Very Large (512 MB) Veldig stor (512 MB) - + Very Low (4 MB) Veldig lav (4 MB) - + Low (8 MB) Lav (8 MB) - + Normal (16 MB) Normal (16 MB) - + Medium (32 MB) Middels (32 MB) - + High (64 MB) Høy (64 MB) - + Very Low (32) Svært lav (32) - + Low (64) Lav (64) - + Normal (128) Normal (128) - + Medium (256) Middels (256) - + High (512) Høy (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6045,50 +6035,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL ikke tilgjengelig! - + OpenGL shared contexts are not supported. Delte OpenGL-kontekster støttes ikke. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! Feil under initialisering av OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Det kan hende at GPU-en din ikke støtter OpenGL, eller at du ikke har den nyeste grafikkdriveren. - + Error while initializing OpenGL 4.6! Feil under initialisering av OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Det kan hende at GPU-en din ikke støtter OpenGL 4.6, eller at du ikke har den nyeste grafikkdriveren.<br><br>GL-renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Det kan hende at GPU-en din ikke støtter én eller flere nødvendige OpenGL-utvidelser. Vennligst sørg for at du har den nyeste grafikkdriveren.<br><br>GL-renderer: <br>%1<br><br>Ikke-støttede utvidelser:<br>%2 - + This build doesn't have OpenGL support. @@ -6854,1132 +6844,1152 @@ Debug Message: &Emulering - + + &Cheats + + + + &View &Vis - + &Reset Window Size &Tilbakestill vindusstørrelse - + &Debugging Feilsøking (&D) - + &Game List Mode &Spilliste-modus - + Game &Icon Size Spill&ikonstørrelse - + Reset Window Size to &720p Tilbakestill vindusstørrelsen til &720p - + Reset Window Size to 720p Tilbakestill vindusstørrelsen til 720p - + Reset Window Size to &900p Tilbakestill vindusstørrelsen til &900p - + Reset Window Size to 900p Tilbakestill vindusstørrelsen til 900p - + Reset Window Size to &1080p Tilbakestill vindusstørrelsen til &1080p - + Reset Window Size to 1080p Tilbakestill vindusstørrelsen til 1080p - + &Multiplayer &Flerspiller - + &Tools Verk&tøy - + Am&iibo am&iibo - + Launch &Applet - + &TAS &TAS - + &Create Home Menu Shortcut - + Install &Firmware Installér &fastvare - + &Help &Hjelp - + &Install Files to NAND... &Installér filer til NAND ... - + L&oad File... La&st inn fil ... - + Load &Folder... Last inn ma&ppe... - + E&xit A&vslutt - - + + &Pause &Pause - + &Stop &Stopp - + &Verify Installed Contents - + &About Eden &Om Eden - + Single &Window Mode Enkelt&vindusmodus - + Con&figure... Se&tt opp ... - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar Vis &filterlinje - + Show &Status Bar Vis &statuslinje - + Show Status Bar Vis statuslinje - + &Browse Public Game Lobby Bla gjennom den offentlige spillo&bbyen - + &Create Room &Opprett rom - + &Leave Room &Forlat rom - + &Direct Connect to Room &Direkte tilkobling til rommet - + &Show Current Room &Vis nåværende rom - + F&ullscreen F&ullskjerm - + &Restart &Omstart - + Load/Remove &Amiibo... Last/Fjern &amiibo ... - + Open &Mods Page Åpne Modifikasjonssiden (&M) - + &User Handbook - + &Capture Screenshot &Ta skjermklipp - + &Album &Album - + &Set Nickname and Owner - + &Delete Game Data &Slett spilldata - + &Restore Amiibo &Gjenopprett amiibo - + &Format Amiibo - + &Mii Editor - + &Configure TAS... &Konfigurer TAS ... - + Configure C&urrent Game... Konfigurer nåværende spill ... - - + + &Start &Start - + &Reset &Omstart - - + + R&ecord T&a opp - + Open &Controller Menu Åpne &kontrollermeny - + Install Decryption &Keys - + &Home Menu &Hjem-meny - + &Desktop &Skrivebord - + &Application Menu &Appmeny - + &Root Data Folder &Rotdatamappe - + &NAND Folder &NAND-mappe - + &SDMC Folder &SDMC-mappe - + &Mod Folder &Mod-mappe - + &Log Folder &Loggmappe - + From Folder Fra mappe - + From ZIP Fra ZIP - + &Eden Dependencies &Eden-avhengigheter - + &Data Manager &Databehandler - + &Tree View &Trevisning - + &Grid View &Rutenettvisning - + Game Icon Size Spillikonstørrelse - - + + None Ingen - + Show Game &Name Vis spill&navn - + Show &Performance Overlay Vis &ytelsesoverlegg - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) Liten (32x32) - + Standard (64x64) Standard (64x64) - + Large (128x128) Stor (128x128) - + Full Size (256x256) Full størrelse (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping Kjører et spill - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute Slå på lyd - + Mute Demp - + Reset Volume Tilbakestill volum - + Configure Effects... - + &Clear Recent Files &Tøm nylige filer - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue &Fortsett - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) (64-bit) - - + + (32-bit) (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... Lukker programvare ... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! Mappen finnes ikke! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File Fjern fil - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full Full - + Skeleton Skjelett - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... Utvinner RomFS... - - + + Cancel Avbryt - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory Velg mappe - + Properties Egenskaper - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... Installerer filen «%1» ... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application Systemapp - + System Archive Systemarkiv - + System Application Update - + Firmware Package (Type A) Fastvarepakke (Type A) - + Firmware Package (Type B) Fastvarepakke (Type B) - + Game Spill - + Game Update Spilloppdatering - + Game DLC Spill-DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found Filen ble ikke funnet - + File "%1" not found - + OK OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL Feil under åpning av URL - + Unable to open the URL "%1". - + TAS Recording TAS-opptak - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo amiibo - - + + The current amiibo has been removed - + Error Feil - - + + The current game is not looking for amiibos Det nåværende spillet ser ikke etter amiiboer - + Amiibo File (%1);; All Files (*.*) amiibo-fil (%1);; Alle filer (*.*) - + Load Amiibo Last inn amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available Ingen fastvare tilgjengelig - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot Ta skjermklipp - + PNG Image (*.png) PNG-bilde (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor Skala: %1x - + Speed: %1% / %2% Hastighet: %1% / %2% - + Speed: %1% Hastighet: %1% - + Game: %1 FPS Spill: %1 FPS - + Frame: %1 ms Ramme: %1 ms - + NO AA INGEN AA - + NO FX - + FX - + VOLUME: MUTE VOLUM: DEMP - + VOLUME: %1% Volume percentage (e.g. 50%) VOLUM: %1% - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -7987,74 +7997,74 @@ Would you like to force it for future launches? - + Use X11 Bruk X11 - + Continue with Wayland - + Don't show again Ikke vis igjen - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow Treg - + Turbo Turbo - + Unlocked Ubegrenset - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/nl.ts b/dist/languages/nl.ts index 8e99ce56d4..f7cae29a1c 100644 --- a/dist/languages/nl.ts +++ b/dist/languages/nl.ts @@ -30,7 +30,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> @@ -402,49 +402,59 @@ Can help reduce stuttering at lower framerates. Kan helpen om haperingen bij lagere framerates te verminderen. - - Accuracy: - Nauwkeurigheid: - - - - Change the accuracy of the emulated CPU (for debugging only). + + Enable cheats by default - - - Backend: + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + Accuracy: + Nauwkeurigheid: + + + + Change the accuracy of the emulated CPU (for debugging only). + + + + + + Backend: + + + + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks Aangepaste CPU-ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) Host MMU-emulatie inschakelen (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -453,205 +463,205 @@ Als u deze optie inschakelt, worden lees- en schrijfbewerkingen in het gastgeheu Als u deze optie uitschakelt, worden alle geheugentoegangen gedwongen om gebruik te maken van software-MMU-emulatie. - + Unfuse FMA (improve performance on CPUs without FMA) Ontbind FMA (verbeterd prestatie op CPU's zonder FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Deze optie verbetert de snelheid door de nauwkeurigheid van fused-multiply-add-instructies op CPU's zonder native FMA-ondersteuning te verminderen. - + Faster FRSQRTE and FRECPE Snellere FRSRTE en FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Deze optie verbetert de snelheid van sommige benaderende drijvende-kommagetal-functies door minder nauwkeurige native benaderingen te gebruiken. - + Faster ASIMD instructions (32 bits only) Snellere ASIMD-instructies (alleen 32-bits) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Deze optie verbetert de snelheid van 32-bits ASIMD-drijvende-kommagetallen door te werken met onjuiste afrondingsmodi. - + Inaccurate NaN handling Onnauwkeurige NaN-verwerking - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Deze optie verbetert de snelheid door NaN-controle te verwijderen. Houd er rekening mee dat dit ook de nauwkeurigheid van bepaalde drijvende-kommainstructies vermindert. - + Disable address space checks Schakel adresruimtecontroles uit - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor Negeer globale monitor - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Deze optie verbetert de snelheid door alleen te vertrouwen op de semantiek van cmpxchg om de veiligheid van exclusieve toegangsinstructies te waarborgen. Houd er rekening mee dat dit kan leiden tot deadlocks en andere race conditions. - + API: API: - + Changes the output graphics API. Vulkan is recommended. - + Device: Apparaat: - + This setting selects the GPU to use (Vulkan only). - + Resolution: Resolutie: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: Window Adapting Filter: - + FSR Sharpness: FSR-scherpte: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Antialiasing-methode: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Volledig scherm modus: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. - + Aspect Ratio: Aspect Ratio: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: NVDEC-emulatie: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. - + ASTC Decoding Method: ASTC Decodeer Methode: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -660,75 +670,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: VSync-modus: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -736,79 +726,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) Schakel asynchrone presentatie in (alleen Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. - + Force maximum clocks (Vulkan only) Forceer maximale klokken (alleen Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Werkt op de achtergrond terwijl er wordt gewacht op grafische opdrachten om te voorkomen dat de GPU zijn kloksnelheid verlaagt. - + Anisotropic Filtering: Anisotrope Filtering: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -817,1290 +807,1290 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache Gebruik Vulkan-pijplijn-cache - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. - + Enable Compute Pipelines (Intel Vulkan Only) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing Schakel Reactive Flushing In - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. - + Sync to framerate of video playback - + Run the game at normal speed during video playback, even when the framerate is unlocked. - + Barrier feedback loops - + Improves rendering of transparency effects in specific games. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed RNG Seed - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name Apparaatnaam - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: Aangepaste RTC Datum: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: Taal: - + This option can be overridden when region setting is auto-select - + Region: Regio: - + The region of the console. - + Time Zone: Tijdzone: - + The time zone of the console. - + Sound Output Mode: Geluidsuitvoermodus: - + Console Mode: Console Modus: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation Bevestig voordat u de emulatie stopt - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity Verberg muis wanneer inactief - + Hides the mouse after 2.5s of inactivity. - + Check for updates - + Whether or not to check for updates upon startup. - + Enable Gamemode - + Force X11 as Graphics Backend - + Custom frontend - + Real applet - - + + Disabled - + Never - + On Load - + Always - + CPU CPU - + GPU - + CPU Asynchronous - + Uncompressed (Best quality) - + BC1 (Low quality) BC1 (Lage Kwaliteit) - + BC3 (Medium quality) BC3 (Gemiddelde kwaliteit) - - + + Auto Auto - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative - + Aggressive - + Vulkan Vulkan - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null Null - + Fast - - - + + + Accurate Accuraat - - - + + + Default Standaard - + Unsafe (fast) - + Safe (stable) - + Immediate - + Balanced - + Unsafe Onveilig - + Paranoid (disables most optimizations) Paranoid (schakelt de meeste optimalisaties uit) - + Debugging - + Dynarmic - + NCE - + Borderless Windowed Randloos Venster - + Exclusive Fullscreen Exclusief Volledig Scherm - + No Video Output Geen Video-uitvoer - + CPU Video Decoding CPU Videodecodering - + GPU Video Decoding (Default) GPU Videodecodering (Standaard) - + 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [EXPERIMENTEEL] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [EXPERIMENTEEL] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Nearest Neighbor - + Bilinear Bilinear - + Bicubic Bicubic - + Gaussian Gaussian - + Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution - + Area - + MMPX - + Zero-Tangent - + B-Spline - + Mitchell - + Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Geen - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Standaart (16:9) - + Force 4:3 Forceer 4:3 - + Force 21:9 Forceer 21:9 - + Force 16:10 Forceer 16:10 - + Stretch to Window Uitrekken naar Venster - + Automatic Automatisch - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Japans (日本語) - + American English Amerikaans-Engels - + French (français) Frans (Français) - + German (Deutsch) Duits (Deutsch) - + Italian (italiano) Italiaans (italiano) - + Spanish (español) Spaans (Español) - + Chinese Chinees - + Korean (한국어) Koreaans (한국어) - + Dutch (Nederlands) Nederlands (Nederlands) - + Portuguese (português) Portugees (português) - + Russian (Русский) Russisch (Русский) - + Taiwanese Taiwanese - + British English Brits-Engels - + Canadian French Canadees-Frans - + Latin American Spanish Latijns-Amerikaans Spaans - + Simplified Chinese Vereenvoudigd Chinees - + Traditional Chinese (正體中文) Traditioneel Chinees (正體中文) - + Brazilian Portuguese (português do Brasil) Braziliaans-Portugees (português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan Japan - + USA USA - + Europe Europa - + Australia Australië - + China China - + Korea Korea - + Taiwan Taiwan - + Auto (%1) Auto select time zone Auto (%1) - + Default (%1) Default time zone Standaard (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Egypte - + Eire Eire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Ijsland - + Iran Iran - + Israel Israel - + Jamaica Jamaica - + Kwajalein Kwajalein - + Libya Libië - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polen - + Portugal Portugal - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapore - + Turkey Turkije - + UCT UCT - + Universal Universeel - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Stereo - + Surround Surround - + 4GB DRAM (Default) - + 6GB DRAM (Unsafe) - + 8GB DRAM - + 10GB DRAM (Unsafe) - + 12GB DRAM (Unsafe) - + Docked Docked - + Handheld Handheld - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) - + Only if game specifies not to stop - + Never ask - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) - + High (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6041,50 +6031,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL niet beschikbaar! - + OpenGL shared contexts are not supported. OpenGL gedeelde contexten worden niet ondersteund. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! Fout tijdens het initialiseren van OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Je GPU ondersteunt mogelijk geen OpenGL, of je hebt niet de laatste grafische stuurprogramma. - + Error while initializing OpenGL 4.6! Fout tijdens het initialiseren van OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Je GPU ondersteunt mogelijk OpenGL 4.6 niet, of je hebt niet het laatste grafische stuurprogramma.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Je GPU ondersteunt mogelijk een of meer vereiste OpenGL-extensies niet. Zorg ervoor dat je het laatste grafische stuurprogramma hebt.<br><br>GL Renderer:<br>%1<br><br>Ondersteunde extensies:<br>%2 - + This build doesn't have OpenGL support. @@ -6850,1132 +6840,1152 @@ Debug Message: &Emulatie - + + &Cheats + + + + &View &Weergeven - + &Reset Window Size &Herstel Venstergrootte - + &Debugging &Debuggen - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p Herstel Venstergrootte naar &720p - + Reset Window Size to 720p Herstel Venstergrootte naar 720p - + Reset Window Size to &900p Herstel Venstergrootte naar &900p - + Reset Window Size to 900p Herstel Venstergrootte naar 900p - + Reset Window Size to &1080p Herstel Venstergrootte naar &1080p - + Reset Window Size to 1080p Herstel Venstergrootte naar 1080p - + &Multiplayer &Multiplayer - + &Tools &Tools - + Am&iibo - + Launch &Applet - + &TAS &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help &Help - + &Install Files to NAND... &Installeer Bestanden naar NAND... - + L&oad File... L&aad Bestand... - + Load &Folder... Laad &Map... - + E&xit A&fsluiten - - + + &Pause &Onderbreken - + &Stop &Stop - + &Verify Installed Contents - + &About Eden - + Single &Window Mode Modus Enkel Venster - + Con&figure... Con&figureer... - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar Toon &Filterbalk - + Show &Status Bar Toon &Statusbalk - + Show Status Bar Toon Statusbalk - + &Browse Public Game Lobby &Bladeren door Openbare Spellobby - + &Create Room &Maak Kamer - + &Leave Room &Verlaat Kamer - + &Direct Connect to Room &Directe Verbinding met Kamer - + &Show Current Room &Toon Huidige Kamer - + F&ullscreen Volledig Scherm - + &Restart &Herstart - + Load/Remove &Amiibo... Laad/Verwijder &Amiibo... - + Open &Mods Page Open &Mod-pagina - + &User Handbook - + &Capture Screenshot &Leg Schermafbeelding Vast - + &Album - + &Set Nickname and Owner - + &Delete Game Data - + &Restore Amiibo - + &Format Amiibo - + &Mii Editor - + &Configure TAS... &Configureer TAS... - + Configure C&urrent Game... Configureer Huidig Spel... - - + + &Start &Start - + &Reset &Herstel - - + + R&ecord Opnemen - + Open &Controller Menu - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -7983,74 +7993,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/pl.ts b/dist/languages/pl.ts index 28a51ae4f8..bcdd945810 100644 --- a/dist/languages/pl.ts +++ b/dist/languages/pl.ts @@ -37,8 +37,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Strona</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Kod źródłowy</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Współtwórcy</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licencja</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -410,49 +410,59 @@ Can help reduce stuttering at lower framerates. Może pomóc zredukować przycięcia przy niższej liczbie klatek. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Precyzja: - + Change the accuracy of the emulated CPU (for debugging only). Zmień dokładność emulowanego CPU (tylko do debugowania). - - + + Backend: Backend: - + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks Niestandardowe cykle CPU - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. Ustaw niestandardową wartość taktów CPU. Wyższe wartości mogą zwiększyć wydajność, ale mogą też powodować zawieszanie się gry. Zalecany zakres to 77–21000. - + Enable Host MMU Emulation (fastmem) Włącz emulację MMU hosta (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -461,100 +471,100 @@ Włączenie powoduje, że odczyty/zapisy pamięci gościa trafiają bezpośredni Wyłączenie wymusza użycie emulacji programowej MMU dla wszystkich dostępów do pamięci. - + Unfuse FMA (improve performance on CPUs without FMA) Unfuse FMA (zwiększ wydajność na procesorach bez FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Ta opcja zwiększa szybkość kosztem dokładności instrukcji FMA (fused-multiply-add) na procesorach bez natywnego wsparcia FMA. - + Faster FRSQRTE and FRECPE Szybsze FRSQRTE i FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Ta opcja poprawia szybkość niektórych funkcji zmiennoprzecinkowych, używając mniej dokładnych natywnych aproksymacji. - + Faster ASIMD instructions (32 bits only) Szybsze instrukcje ASIMD (Tylko 32-bit) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Ta opcja przyspiesza 32-bitowe funkcje zmiennoprzecinkowe ASIMD, uruchamiając je z nieprawidłowymi trybami zaokrąglania. - + Inaccurate NaN handling Niedokładna obsługa NaN - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Ta opcja zwiększa szybkość poprzez wyłączenie sprawdzania NaN. Uwaga: obniża to dokładność niektórych instrukcji zmiennoprzecinkowych. - + Disable address space checks Wyłącz sprawdzanie przestrzeni adresów - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. Ta opcja poprawia szybkość poprzez usunięcie sprawdzania bezpieczeństwa przed każdą operacją pamięci. Wyłączenie może umożliwić wykonanie dowolnego kodu. - + Ignore global monitor Ignoruj ogólne monitorowanie - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Ta opcja zwiększa szybkość, polegając wyłącznie na semantyce „cmpxchg” w celu zapewnienia bezpieczeństwa instrukcji z dostępem wyłącznym. Uwaga: może to prowadzić do zakleszczeń i innych warunków wyścigu. - + API: API: - + Changes the output graphics API. Vulkan is recommended. Zmienia wyjściowe API grafiki. Zalecany jest Vulkan. - + Device: Urządzenie: - + This setting selects the GPU to use (Vulkan only). To ustawienie wybiera używany GPU (tylko Vulkan). - + Resolution: Rozdzielczość: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -563,27 +573,27 @@ Wyższe rozdzielczości wymagają więcej VRAM i przepustowości. Opcje poniżej 1x mogą powodować artefakty. - + Window Adapting Filter: Filtr Adaptującego Okna: - + FSR Sharpness: Ostrość FSR: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Metoda Anty-Aliasingu: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -592,22 +602,22 @@ SMAA oferuje najlepszą jakość. FXAA może zapewnić stabilniejszy obraz w niższych rozdzielczościach. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Tryb Pełnoekranowy: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -616,12 +626,12 @@ Tryb bez ramek zapewnia najlepszą zgodność z klawiaturą ekranową wymaganą Pełny ekran wyłączny może oferować lepszą wydajność i lepsze wsparcie FreeSync/G-Sync. - + Aspect Ratio: Format obrazu: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -630,35 +640,35 @@ Większość gier obsługuje wyłącznie 16:9, więc inne proporcje wymagają mo Kontroluje także proporcje przechwytywanych zrzutów ekranu. - + Use persistent pipeline cache Używaj trwałej pamięci podręcznej (cache) potoków - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Pozwala zapisywać shadery w pamięci masowej, aby przyspieszyć ładowanie przy kolejnych uruchomieniach gry. Wyłączanie tej opcji jest przeznaczone do debugowania. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: Emulacja NVDEC: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -667,12 +677,12 @@ Dekodowanie może być wykonywane przez CPU albo GPU, albo może być całkowici W większości przypadków najlepszą wydajność zapewnia dekodowanie na GPU. - + ASTC Decoding Method: Metoda dekodowania ASTC: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -684,12 +694,12 @@ GPU: użyj shaderów obliczeniowych GPU do dekodowania tekstur ASTC (zalecane). CPU asynchronicznie: użyj CPU do dekodowania na żądanie. Eliminuje zacięcia podczas dekodowania ASTC, ale może powodować artefakty. - + ASTC Recompression Method: Metoda rekompresji ASTC: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. @@ -697,64 +707,44 @@ BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, BC1/BC3: format pośredni zostanie ponownie skompresowany do BC1 lub BC3 — oszczędza VRAM kosztem jakości obrazu. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: Tryb wykorzystania VRAM: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. Określa, czy emulator ma oszczędzać pamięć, czy maksymalnie wykorzystywać dostępną pamięć wideo dla wydajności. Tryb agresywny może pogorszyć działanie innych aplikacji, np. oprogramowania do nagrywania. - + Skip CPU Inner Invalidation Pomiń wewnętrzne unieważnienie procesora CPU - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. Pomija niektóre unieważnienia pamięci podręcznej po stronie CPU podczas aktualizacji pamięci, zmniejszając użycie CPU i poprawiając jego wydajność. Może powodować błędy lub awarie w niektórych grach. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: Tryb synchronizacji pionowej: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -765,12 +755,12 @@ Mailbox może mieć niższe opóźnienia niż FIFO i nie powoduje tearingu, ale Immediate (bez synchronizacji) wyświetla wszystko, co jest dostępne, i może powodować tearing. - + Sync Memory Operations Synchronizuj operacje pamięci - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. @@ -778,68 +768,68 @@ Unreal Engine 4 games often see the most significant changes thereof. Gry z Unreal Engine 4 mogą być najbardziej dotknięte. - + Enable asynchronous presentation (Vulkan only) Włącz asynchroniczną prezentację (tylko Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. Nieznacznie poprawia wydajność, przenosząc prezentację na oddzielny wątek CPU. - + Force maximum clocks (Vulkan only) Wymuś maksymalne zegary (Tylko Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Uruchamia pracę w tle podczas oczekiwania na komendy graficzne aby GPU nie obniżało taktowania. - + Anisotropic Filtering: Filtrowanie anizotropowe: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. Steruje jakością renderowania tekstur pod ostrymi kątami. Na większości GPU bezpieczną wartością jest 16x. - + GPU Mode: Tryb GPU: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: Dokładność DMA: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -848,89 +838,89 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation Włącz asynchroniczną kompilację shaderów - + May reduce shader stutter. Może zmniejszyć zacięcia spowodowane kompilacją shaderów. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache Użyj pamięci podręcznej strumienia dla Vulkana - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. Włącza specyficzną dla producenta GPU pamięć podręczną potoków. Ta opcja może znacząco skrócić czas ładowania shaderów w przypadkach, gdy sterownik Vulkan nie przechowuje wewnętrznie plików pamięci podręcznej potoków. - + Enable Compute Pipelines (Intel Vulkan Only) Włącz potoki obliczeniowe (tylko Intel Vulkan) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. @@ -939,181 +929,181 @@ To ustawienie istnieje wyłącznie dla sterowników Intela i może spowodować b Na wszystkich pozostałych sterownikach potoki obliczeniowe są zawsze włączone. - + Enable Reactive Flushing Włącz reaktywne opróżnianie buforów - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Używa opróżniania reaktywnego zamiast predykcyjnego, co umożliwia dokładniejsze synchronizowanie pamięci. - + Sync to framerate of video playback Synchronizuj do liczby klatek odtwarzanego wideo - + Run the game at normal speed during video playback, even when the framerate is unlocked. Uruchamiaj grę z normalną prędkością podczas odtwarzania wideo, nawet przy odblokowanej liczbie klatek na sekundę. - + Barrier feedback loops Pętle sprzężenia zwrotnego barier - + Improves rendering of transparency effects in specific games. Poprawia renderowanie efektów przezroczystości w niektórych grach. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State Rozszerzony stan dynamiczny - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. Kontroluje liczbę funkcji, które mogą być używane w Extended Dynamic State. Wyższe poziomy pozwalają na użycie większej liczby funkcji i mogą zwiększyć wydajność, ale mogą powodować dodatkowe problemy z grafiką. - + Vertex Input Dynamic State Dynamiczny stan wejścia wierzchołków - + Enables vertex input dynamic state feature for better quality and performance. Włącza funkcję dynamicznego stanu wejścia wierzchołków, poprawiając jakość i wydajność. - + Sample Shading Cieniowanie próbkowe - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. Pozwala wykonywać shader fragmentów dla każdej próbki we fragmencie wielokrotnie próbkowanym zamiast raz dla każdego fragmentu. Poprawia jakość grafiki kosztem wydajności. Wyższe wartości poprawiają jakość, ale obniżają wydajność. - + RNG Seed Ziarno RNG - + Controls the seed of the random number generator. Mainly used for speedrunning. Ustala ziarno generatora liczb losowych. Głównie używane do speedrunów. - + Device Name Nazwa urządzenia - + The name of the console. The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: Własna data RTC - + This option allows to change the clock of the console. Can be used to manipulate time in games. Ta opcja pozwala zmienić zegar konsoli. Może służyć do manipulowania czasem w grach. - + The number of seconds from the current unix time Liczba sekund od bieżącego czasu Unix - + Language: Język: - + This option can be overridden when region setting is auto-select Ta opcja może zostać nadpisana, gdy ustawienie regionu to automatyczny wybór. - + Region: Region: - + The region of the console. Region konsoli. - + Time Zone: Strefa czasowa: - + The time zone of the console. Strefa czasowa konsoli. - + Sound Output Mode: Tryb wyjścia dźwięku: - + Console Mode: Tryb konsoli - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. @@ -1122,1026 +1112,1026 @@ W zależności od tego ustawienia gry zmienią swoją rozdzielczość, szczegó Ustawienie na Handheld może poprawić wydajność na słabszych komputerach. - + Prompt for user profile on boot Pytaj o profil użytkownika przy uruchomieniu. - + Useful if multiple people use the same PC. Przydatne, gdy z tego samego PC korzysta wiele osób. - + Pause when not in focus Wstrzymuj, gdy okno nie jest aktywne - + Pauses emulation when focusing on other windows. Wstrzymuje emulację po przełączeniu na inne okna. - + Confirm before stopping emulation Potwierdzaj przed zatrzymaniem emulacji - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. Nadpisuje monity z prośbą o potwierdzenie zatrzymania emulacji. Włączenie powoduje pominięcie takich monitów i bezpośrednie wyjście z emulacji. - + Hide mouse on inactivity Ukryj mysz przy braku aktywności - + Hides the mouse after 2.5s of inactivity. Ukrywa kursor po 2,5 s bezczynności. - + Check for updates Sprawdź aktualizacje - + Whether or not to check for updates upon startup. Czy sprawdzać aktualizacje przy uruchomieniu. - + Enable Gamemode Włącz Tryb gry - + Force X11 as Graphics Backend Wymuś X11 jako backend grafiki - + Custom frontend Niestandardowy frontend - + Real applet Prawdziwy aplet - - + + Disabled Wyłączone - + Never Nigdy - + On Load Przy wczytywaniu - + Always Zawsze - + CPU CPU - + GPU GPU - + CPU Asynchronous Asynchroniczne CPU - + Uncompressed (Best quality) Brak (najlepsza jakość) - + BC1 (Low quality) BC1 (niska jakość) - + BC3 (Medium quality) BC3 (średnia jakość) - - + + Auto Automatyczny - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative Konserwatywny - + Aggressive Agresywny - + Vulkan Vulkan - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null Null - + Fast Szybkie - - - + + + Accurate Dokładny - - - + + + Default Domyślny - + Unsafe (fast) Niezalecane (szybkie) - + Safe (stable) Bezpieczne (stabilne) - + Immediate - + Balanced Zrównoważony - + Unsafe Niebezpieczny - + Paranoid (disables most optimizations) Paranoiczne (wyłącza większość optymalizacji) - + Debugging Debugowanie - + Dynarmic Dynamiczny - + NCE NCE - + Borderless Windowed W oknie (Bezramkowy) - + Exclusive Fullscreen Exclusive Fullscreen - + No Video Output Brak wyjścia wideo - + CPU Video Decoding Dekodowanie Wideo przez CPU - + GPU Video Decoding (Default) Dekodowanie Wideo przez GPU (Domyślne) - + 0.25X (180p/270p) [EXPERIMENTAL] 0,25x (180p/270p) [EKSPERYMENTALNE] - + 0.5X (360p/540p) [EXPERIMENTAL] 0,5x (360p/540p) [EKSPERYMENTALNE] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [EKSPERYMENTALNE] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [EKSPERYMENTALNE] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [Ekperymentalnie] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Najbliższy sąsiadujący - + Bilinear Bilinearny - + Bicubic Bikubiczny - + Gaussian Kulisty - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX Super Resolution - + Area Obszar - + MMPX MMPX - + Zero-Tangent Zero-Tangent - + B-Spline B-Spline - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Żadna (wyłączony) - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Domyślne (16:9) - + Force 4:3 Wymuś 4:3 - + Force 21:9 Wymuś 21:9 - + Force 16:10 Wymuś 16:10 - + Stretch to Window Rozciągnij do Okna - + Automatic Automatyczne - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Japoński (日本語) - + American English Angielski Amerykański - + French (français) Francuski (français) - + German (Deutsch) Niemiecki (Niemcy) - + Italian (italiano) Włoski (italiano) - + Spanish (español) Hiszpański (español) - + Chinese Chiński - + Korean (한국어) Koreański (한국어) - + Dutch (Nederlands) Duński (Holandia) - + Portuguese (português) Portugalski (português) - + Russian (Русский) Rosyjski (Русский) - + Taiwanese Tajwański - + British English Angielski Brytyjski - + Canadian French Fancuski (Kanada) - + Latin American Spanish Hiszpański (Latin American) - + Simplified Chinese Chiński (Uproszczony) - + Traditional Chinese (正體中文) Chiński tradycyjny (正體中文) - + Brazilian Portuguese (português do Brasil) Portugalski (português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan Japonia - + USA USA - + Europe Europa - + Australia Australia - + China Chiny - + Korea Korea - + Taiwan Tajwan - + Auto (%1) Auto select time zone Auto (%1) - + Default (%1) Default time zone Domyślne (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Egipt - + Eire Irlandia - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Islandia - + Iran Iran - + Israel Izrael - + Jamaica Jamajka - + Kwajalein Kwajalein - + Libya Libia - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polska - + Portugal Portugalia - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapur - + Turkey Turcja - + UCT UCT - + Universal Uniwersalny - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Stereo - + Surround Surround - + 4GB DRAM (Default) 4GB DRAM (Domyślne) - + 6GB DRAM (Unsafe) 6GB DRAM (NIebezpieczne) - + 8GB DRAM 8GB DRAM - + 10GB DRAM (Unsafe) 10GB DRAM (NIebezpieczne) - + 12GB DRAM (Unsafe) 12GB DRAM (NIebezpieczne) - + Docked Zadokowany - + Handheld Przenośnie - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) Zawsze pytaj (Domyślne) - + Only if game specifies not to stop Tylko jeśli gra określa, aby nie zatrzymywać - + Never ask Nie pytaj więcej - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) Średnie (256) - + High (512) Wysokie (512) - + ExtendedDynamicState 1 ExtendedDynamicState 1 - + ExtendedDynamicState 2 ExtendedDynamicState 2 - + ExtendedDynamicState 3 ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6106,50 +6096,50 @@ Przejdź do sekcji Konfiguracja -> System -> Sieć i dokonaj wyboru. GRenderWindow - - + + OpenGL not available! OpenGL niedostępny! - + OpenGL shared contexts are not supported. Współdzielone konteksty OpenGL nie są obsługiwane. - + Eden has not been compiled with OpenGL support. Eden nie został skompilowany z obsługą OpenGL. - - - + + + Error while initializing OpenGL! Błąd podczas inicjowania OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Twoja karta graficzna może nie obsługiwać OpenGL lub nie masz najnowszych sterowników karty graficznej. - + Error while initializing OpenGL 4.6! Błąd podczas inicjowania OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Twoja karta graficzna może nie obsługiwać OpenGL 4.6 lub nie masz najnowszych sterowników karty graficznej.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Twoja karta graficzna może nie obsługiwać co najmniej jednego wymaganego rozszerzenia OpenGL. Upewnij się, że masz najnowsze sterowniki karty graficznej<br><br>GL Renderer:<br>%1<br><br>Nieobsługiwane rozszerzenia:<br>%2 - + This build doesn't have OpenGL support. @@ -6916,801 +6906,821 @@ Komunikat debugowania: &Emulacja - + + &Cheats + + + + &View &Widok - + &Reset Window Size &Resetuj Rozmiar Okna - + &Debugging &Debugowanie - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p Zresetuj rozmiar okna do &720p - + Reset Window Size to 720p Zresetuj rozmiar okna do 720p - + Reset Window Size to &900p Zresetuj Rozmiar okna do &900p - + Reset Window Size to 900p Zresetuj Rozmiar okna do 900p - + Reset Window Size to &1080p Zresetuj rozmiar okna do &1080p - + Reset Window Size to 1080p Zresetuj rozmiar okna do 1080p - + &Multiplayer &Multiplayer - + &Tools &Narzędzia - + Am&iibo Am&iibo - + Launch &Applet - + &TAS &TAS - + &Create Home Menu Shortcut &Utwórz skrót w Menu głównym - + Install &Firmware Zainstaluj &Firmware - + &Help &Pomoc - + &Install Files to NAND... &Zainstaluj pliki na NAND... - + L&oad File... &Załaduj Plik... - + Load &Folder... Załaduj &Folder... - + E&xit &Wyjście - - + + &Pause &Pauza - + &Stop &Stop - + &Verify Installed Contents &Zweryfikuj zainstalowane zasoby - + &About Eden &O Eden - + Single &Window Mode Tryb &Pojedyńczego Okna - + Con&figure... &Konfiguruj... - + Ctrl+, Ctrl+, - + Enable Overlay Display Applet Włącz aplet wyświetlania nakładki - + Show &Filter Bar Pokaż Pasek &Filtrów - + Show &Status Bar Pokaż Pasek &Statusu - + Show Status Bar Pokaż pasek statusu - + &Browse Public Game Lobby &Przeglądaj publiczne lobby gier - + &Create Room &Utwórz Pokój - + &Leave Room &Wyjdź z Pokoju - + &Direct Connect to Room &Bezpośrednie połączenie z pokojem - + &Show Current Room &Pokaż bieżący pokój - + F&ullscreen &Pełny ekran - + &Restart &Restart - + Load/Remove &Amiibo... Załaduj/Usuń &Amiibo... - + Open &Mods Page Otwórz stronę z &Modami - + &User Handbook - + &Capture Screenshot &Zrób zdjęcie - + &Album - + &Set Nickname and Owner &Ustaw nick oraz właściciela - + &Delete Game Data &Usuń dane gry - + &Restore Amiibo &Przywróć Amiibo - + &Format Amiibo &Sformatuj Amiibo - + &Mii Editor - + &Configure TAS... &Skonfiguruj TAS - + Configure C&urrent Game... Skonfiguruj &obecną grę... - - + + &Start &Start - + &Reset &Zresetuj - - + + R&ecord &Nagraj - + Open &Controller Menu Otwórz Menu &kontrolera - + Install Decryption &Keys Zainstaluj &klucze deszyfrujące - + &Home Menu - + &Desktop &Pulpit - + &Application Menu Menu &Aplikacji - + &Root Data Folder Folder &Root (danych głównych) - + &NAND Folder Folder &NAND - + &SDMC Folder Folder &SDMC - + &Mod Folder Folder &modów - + &Log Folder Folder &logów - + From Folder Z Folderu - + From ZIP Z pliku ZIP - + &Eden Dependencies Zależności &Eden - + &Data Manager Manager &Danych - + &Tree View - + &Grid View - + Game Icon Size - - + + None Żadna (wyłączony) - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected Wykryto uszkodzoną instalację Vulkan - + Vulkan initialization failed during boot. Inicjalizacja Vulkana nie powiodła się podczas uruchamiania. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping Gra uruchomiona - + Loading Web Applet... Ładowanie apletu internetowego... - - + + Disable Web Applet Wyłącz Aplet sieciowy - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) Wyłączenie apletu sieciowego może prowadzić do nieprzewidywalnego działania i powinno być używane wyłącznie z Super Mario 3D All-Stars. Na pewno chcesz wyłączyć aplet sieciowy? (Tę opcję można ponownie włączyć w ustawieniach debugowania). - + The amount of shaders currently being built Liczba shaderów aktualnie budowanych - + The current selected resolution scaling multiplier. Aktualnie wybrany mnożnik skalowania rozdzielczości. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Bieżąca prędkość emulacji. Wartości wyższe lub niższe niż 100% oznaczają, że emulacja działa odpowiednio szybciej lub wolniej niż na Switchu. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Liczba klatek na sekundę aktualnie wyświetlanych przez grę. Wartość ta zależy od gry oraz od konkretnej sceny. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Czas potrzebny na emulację jednej klatki Switcha, bez uwzględniania ogranicznika klatek i synchronizacji pionowej. Dla emulacji z pełną prędkością powinno to być maksymalnie 16,67 ms. - + Unmute Wyłącz wyciszenie - + Mute Wycisz - + Reset Volume Zresetuj głośność - + Configure Effects... - + &Clear Recent Files &Usuń Ostatnie pliki - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue &Kontynuuj - + Warning: Outdated Game Format Ostrzeżenie: Nieaktualny format gry - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. Używasz dla tej gry formatu katalogu zdekonstruowanego ROM-u, który jest przestarzały i został zastąpiony innymi formatami, takimi jak NCA, NAX, XCI czy NSP. Katalogi takich ROM-ów nie zawierają ikon, metadanych ani nie obsługują aktualizacji.<br>Aby uzyskać wyjaśnienie dotyczące różnych formatów Switcha obsługiwanych przez Eden, zajrzyj do naszego podręcznika użytkownika. Ten komunikat nie zostanie wyświetlony ponownie. - - + + Error while loading ROM! Błąd podczas wczytywania ROMu! - + The ROM format is not supported. Ten format ROMu nie jest wspierany. - + An error occurred initializing the video core. Wystąpił błąd podczas inicjowania rdzenia wideo. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. Błąd podczas wczytywania ROMu! %1 - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. %1<br>Proszę ponownie zrzucić pliki lub poprosić o pomoc na Discordzie/Stoat. - + An unknown error occurred. Please see the log for more details. Wystąpił nieznany błąd. Więcej informacji można znaleźć w pliku log. - - + + (64-bit) (64-bit) - - + + (32-bit) (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - + Closing software... Zamykanie aplikacji... - + Save Data Zapis danych - + Mod Data Dane modów - + Error Opening %1 Folder Błąd podczas otwierania folderu %1 - - + + Folder does not exist! Folder nie istnieje! - + Remove Installed Game Contents? Usunąć zainstalowaną zawartość gry? - + Remove Installed Game Update? Usunąć zainstalowaną aktualizację gry? - + Remove Installed Game DLC? Usunąć zainstalowane DLC gry? - + Remove Entry Usuń wpis - + Delete OpenGL Transferable Shader Cache? Usunąć przenośną pamięć podręczną shaderów OpenGL? - + Delete Vulkan Transferable Shader Cache? Usunąć przenośną pamięć podręczną shaderów Vulkan? - + Delete All Transferable Shader Caches? Usunąć wszystkie przenośne pamięci podręczne shaderów? - + Remove Custom Game Configuration? Usunąć niestandardową konfigurację gry? - + Remove Cache Storage? Usunąć pamięć podręczną? - + Remove File Usuń plik - + Remove Play Time Data Usuń dane czasu gry - + Reset play time? Zresetować czas gry? - - + + RomFS Extraction Failed! Wyodrębnianie RomFS nie powiodło się! - + There was an error copying the RomFS files or the user cancelled the operation. Wystąpił błąd podczas kopiowania plików RomFS lub użytkownik przerwał operację. - + Full Pełny - + Skeleton Szkielet - + Select RomFS Dump Mode Wybierz tryb zrzutu RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Wybierz sposób wykonania zrzutu RomFS. <br>Tryb „Pełny” skopiuje wszystkie pliki do nowego katalogu, <br>natomiast „Szkielet” utworzy jedynie strukturę katalogów. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root Nie ma wystarczająco miejsca w %1 aby wyodrębnić RomFS. Zwolnij trochę miejsca, albo zmień ścieżkę zrzutu RomFs w Emulacja > Konfiguruj > System > System Plików > Źródło Zrzutu - + Extracting RomFS... Wypakowywanie RomFS... - - + + Cancel Anuluj - + RomFS Extraction Succeeded! Wypakowanie RomFS zakończone pomyślnie! - + The operation completed successfully. Operacja zakończona pomyślnie. - + Error Opening %1 Błąd podczas otwierania %1 - + Select Directory Wybierz folder - + Properties Właściwości - + The game properties could not be loaded. Właściwości tej gry nie mogły zostać załadowane. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Plik wykonywalny Switcha (%1);;Wszystkie pliki (*.*) - + Load File Załaduj plik - + Open Extracted ROM Directory Otwórz folder wypakowanego ROMu - + Invalid Directory Selected Wybrano niewłaściwy folder - + The directory you have selected does not contain a 'main' file. Wybrany folder nie zawiera 'głównego' pliku. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - Instalacyjne pliki Switch'a (*.nca *.nsp *.xci);;Archiwum zawartości Nintendo (*.nca);;Pakiet poddany Nintendo (*.nsp);;Obraz z kartridża NX (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) + - + Install Files Zainstaluj pliki - + %n file(s) remaining Pozostał %n plikPozostały %n plikiPozostało %n plikówPozostało %n plików - + Installing file "%1"... Instalowanie pliku "%1"... - - + + Install Results Wynik instalacji - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Aby uniknąć ewentualnych konfliktów, odradzamy użytkownikom instalowanie gier na NAND. Proszę, używaj tej funkcji tylko do instalowania łatek i DLC. - + %n file(s) were newly installed %n plik został nowo zainstalowany @@ -7720,7 +7730,7 @@ Proszę, używaj tej funkcji tylko do instalowania łatek i DLC. - + %n file(s) were overwritten %n plik został nadpisany @@ -7730,7 +7740,7 @@ Proszę, używaj tej funkcji tylko do instalowania łatek i DLC. - + %n file(s) failed to install Nie udało się zainstalować %n pliku @@ -7740,324 +7750,324 @@ Proszę, używaj tej funkcji tylko do instalowania łatek i DLC. - + System Application Aplikacja systemowa - + System Archive Archiwum systemu - + System Application Update Aktualizacja aplikacji systemowej - + Firmware Package (Type A) Paczka systemowa (Typ A) - + Firmware Package (Type B) Paczka systemowa (Typ B) - + Game Gra - + Game Update Aktualizacja gry - + Game DLC Dodatek do gry - + Delta Title Tytuł Delta - + Select NCA Install Type... Wybierz typ instalacji NCA... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Wybierz typ tytułu, do którego chcesz zainstalować ten NCA, jako: (W większości przypadków domyślna "gra" jest w porządku.) - + Failed to Install Instalacja nieudana - + The title type you selected for the NCA is invalid. Typ tytułu wybrany dla NCA jest nieprawidłowy. - + File not found Nie znaleziono pliku - + File "%1" not found Nie znaleziono pliku "%1" - + OK OK - + Function Disabled Funkcja wyłączona - + Compatibility list reporting is currently disabled. Check back later! Zgłaszanie do listy kompatybilności jest obecnie wyłączone. Spróbuj ponownie później! - + Error opening URL Błąd otwierania adresu URL - + Unable to open the URL "%1". Nie można otworzyć adresu URL "%1". - + TAS Recording Nagrywanie TAS - + Overwrite file of player 1? Nadpisać plik gracza 1? - + Invalid config detected Wykryto nieprawidłową konfigurację - + Handheld controller can't be used on docked mode. Pro controller will be selected. Nie można używać kontrolera handheld w trybie zadokowanym. Zostanie wybrany kontroler Pro. - - + + Amiibo Amiibo - - + + The current amiibo has been removed Amiibo zostało "zdjęte" - + Error Błąd - - + + The current game is not looking for amiibos Ta gra nie szuka amiibo - + Amiibo File (%1);; All Files (*.*) Plik Amiibo (%1);;Wszyskie pliki (*.*) - + Load Amiibo Zamontuj Amiibo - + Error loading Amiibo data Błąd podczas ładowania danych Amiibo - + The selected file is not a valid amiibo Wybrany plik nie jest poprawnym amiibo - + The selected file is already on use Wybrany plik jest już w użyciu - + An unknown error occurred Wystąpił nieznany błąd - + No firmware available Brak dostępnego firmware'u - + Firmware Corrupted Uszkodzony Firmware - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot Zrób zrzut ekranu - + PNG Image (*.png) Obrazek PNG (*.png) - + TAS state: Running %1/%2 Status TAS: Działa %1%2 - + TAS state: Recording %1 Status TAS: Nagrywa %1 - + TAS state: Idle %1/%2 Status TAS: Bezczynny %1%2 - + TAS State: Invalid Status TAS: Niepoprawny - + &Stop Running &Wyłącz - + Stop R&ecording Przestań &Nagrywać - + Building: %n shader(s) Budowanie: %n shaderBudowanie: %n shaderyBudowanie: %n shaderówBudowanie: %n shaderów - + Scale: %1x %1 is the resolution scaling factor Skala: %1x - + Speed: %1% / %2% Prędkość: %1% / %2% - + Speed: %1% Prędkość: %1% - + Game: %1 FPS Gra: %1 FPS - + Frame: %1 ms Klatka: %1 ms - + NO AA BEZ AA - + NO FX - + FX - + VOLUME: MUTE Głośność: Wyciszony - + VOLUME: %1% Volume percentage (e.g. 50%) Głośność: %1% - + Derivation Components Missing Brak komponentów wyprowadzania - + Decryption keys are missing. Install them now? - + Wayland Detected! Wykryto Waylanda! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8067,74 +8077,74 @@ Zaleca się zamiast tego używać X11. Czy chcesz wymusić jego użycie przy przyszłych uruchomieniach? - + Use X11 Używaj X11 - + Continue with Wayland Kontynuuj z Waylandem - + Don't show again Nie pokazuj ponownie - + Restart Required Wymagane ponowne uruchomienie - + Restart Eden to apply the X11 backend. Uruchom ponownie Edena, aby zastosować backend X11. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target Wybierz cel zrzutu RomFS - + Please select which RomFS you would like to dump. Proszę wybrać RomFS, jakie chcesz zrzucić. - + Are you sure you want to close Eden? Czy na pewno chcesz zamknąć Edena? - - - + + + Eden Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Czy na pewno chcesz zatrzymać emulację? Wszystkie niezapisane postępy zostaną utracone. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/pt_BR.ts b/dist/languages/pt_BR.ts index 063a1bff4f..9c8bd66acb 100644 --- a/dist/languages/pt_BR.ts +++ b/dist/languages/pt_BR.ts @@ -37,8 +37,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Código Fonte</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contribuidores</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licença</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -409,49 +409,59 @@ Can help reduce stuttering at lower framerates. Pode ajudar a reduzir travamentos (engasgos) em taxas de quadros mais baixas. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Precisão: - + Change the accuracy of the emulated CPU (for debugging only). Muda a precisão do CPU emulado (apenas para depuração). - - + + Backend: Backend: - + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks Ciclos de CPU Personalizados - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. Defina um valor personalizado de ciclos da CPU. Valores mais altos podem aumentar o desempenho, mas também podem causar travamentos. É recomendado usar um intervalo entre 77-21000. - + Enable Host MMU Emulation (fastmem) Ativar Emulação de MMU do Anfitrião (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -460,99 +470,99 @@ Ativá-la faz com que as leituras/escritas de memória do convidado sejam feitas Desativar esta opção força todos os acessos à memória a usarem a Emulação de MMU por Software. - + Unfuse FMA (improve performance on CPUs without FMA) FMA inseguro (melhora desempenho no CPU sem FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Essa opção melhora a velocidade ao reduzir a precisão de instruções de fused-multiply-add em CPUs sem suporte nativo ao FMA. - + Faster FRSQRTE and FRECPE FRSQRTE e FRECPE mais rápido - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Essa opção melhora a velocidade de algumas funções aproximadas de pontos flutuantes ao usar aproximações nativas precisas. - + Faster ASIMD instructions (32 bits only) Instruções ASIMD mais rápidas (apenas 32 bits) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Essa opção melhora a velocidade de funções de pontos flutuantes de 32 bits ASIMD ao executá-las com modos de arredondamento incorretos. - + Inaccurate NaN handling Tratamento impreciso de NaN - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Esta opção melhora a velocidade ao remover a checagem NaN. Por favor, note que isso também reduzirá a precisão de certas instruções de ponto flutuante. - + Disable address space checks Desativar a verificação do espaço de endereços - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. Esta opção melhora a velocidade ao eliminar uma verificação de segurança antes de cada operação de memória. Desativá-la pode permitir a execução de código arbitrário. - + Ignore global monitor Ignorar monitor global - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Esta opção melhora a velocidade ao depender apenas das semânticas do cmpxchg pra garantir a segurança das instruções de acesso exclusivo. Por favor, note que isso pode resultar em travamentos e outras condições de execução. - + API: API: - + Changes the output graphics API. Vulkan is recommended. Altera a API gráfica de saída. O uso do Vulkan é recomendado. - + Device: Dispositivo: - + This setting selects the GPU to use (Vulkan only). Esta configuração seleciona a GPU a ser usada (apenas com Vulkan). - + Resolution: Resolução: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -561,27 +571,27 @@ Resoluções mais altas exigem mais VRAM e largura de banda. Opções abaixo de 1X podem causar artefatos. - + Window Adapting Filter: Filtro de adaptação de janela: - + FSR Sharpness: FSR Sharpness: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. Determina o quão nítida a imagem ficará usando o contraste dinâmico do FSR ou do SGSR. - + Anti-Aliasing Method: Método de Anti-Aliasing - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -590,22 +600,22 @@ SMAA oferece a melhor qualidade. FXAA pode produzir uma imagem mais estável em resoluções mais baixas. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Tela Cheia - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -614,12 +624,12 @@ Sem borda oferece a melhor compatibilidade com o teclado na tela que alguns jogo Tela cheia exclusiva pode oferecer melhor desempenho e melhor suporte a Freesync/Gsync. - + Aspect Ratio: Proporção do Ecrã: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -628,36 +638,36 @@ A maioria dos jogos suporta apenas 16:9, sendo necessárias modificações para Também controla a proporção das capturas de tela. - + Use persistent pipeline cache Usar cache persistente de pipeline - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Permite guardar os shaders para carregar os jogos nas execuções seguintes. Desabiltar essa opção só serve para propósitos de depuração. - + Use asynchronous GPU emulation Usar emulação assíncrona de GPU - + Uses an extra CPU thread for rendering. This option should always remain enabled. Usa uma thread de CPU extra para renderização. Esta opção deve estar sempre habilitada. - + NVDEC emulation: Emulação NVDEC: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -666,12 +676,12 @@ Tanto a CPU quanto a GPU podem ser utilizadas para decodificação, ou não deco Na maioria dos casos, a decodificação pela GPU fornece um melhor desempenho. - + ASTC Decoding Method: Método de Decodificação ASTC: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -684,76 +694,56 @@ CPU Assíncrona: Usa a CPU para decodificar texturas ASTC sob demanda. Elimina t mas pode apresentar artefatos visuais. - + ASTC Recompression Method: Método de Recompressão ASTC: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. A maioria das GPUs não suporta texturas ASTC e precisa descompactá-las para um formato intermediário: RGBA8.BC1/BC3: O formato intermediário será recomprimido para BC1 ou BC3, economizando VRAM mas degradando a qualidade da imagem. - + Frame Pacing Mode (Vulkan only) Modo de Ritmo de Quadros (apenas Vulkan) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. Controle como o emulador gerencia o ritmo de quadros para reduzir travamentos (engasgos) e deixar a taxa de quadros mais suave e consistente. - + VRAM Usage Mode: Modo de Uso da VRAM: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. Define se o emulador deve priorizar a economia de memória ou fazer o uso máximo da memória de vídeo disponível para melhorar o desempenho. O modo agressivo pode impactar a performance de outros aplicativos, como softwares de gravação. - + Skip CPU Inner Invalidation Ignorar invalidação interna da CPU - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. Ignora certas invalidações de cache durante atualizações de memória, reduzindo o uso da CPU e melhorando a latência. Isso pode causar travamentos leves. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: Modo de Sincronização vertical: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -764,12 +754,12 @@ Mailbox pode ter menor latência que FIFO e não apresenta cortes, mas pode perd Immediate (sem sincronização) exibe o que estiver disponível e pode apresentar cortes. - + Sync Memory Operations Sincronizar operações de memória - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. @@ -778,68 +768,68 @@ Esta opção corrige problemas em diversos jogos, mas pode reduzir o desempenho. Jogos baseados na Unreal Engine 4 costumam apresentar as mudanças mais significativas. - + Enable asynchronous presentation (Vulkan only) Ativar apresentação assíncrona (Somente Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. Melhora ligeiramente o desempenho ao mover a apresentação para uma thread de CPU separada. - + Force maximum clocks (Vulkan only) Forçar clock máximo (somente Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Executa trabalho em segundo plano aguardando pelos comandos gráficos para evitar a GPU de reduzir seu clock. - + Anisotropic Filtering: Filtro Anisotrópico: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. Controla a qualidade da renderização de texturas em ângulos oblíquos. Seguro definir em 16x na maioria das GPUs. - + GPU Mode: Modo da GPU: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: Precisão do DMA: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -848,44 +838,44 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation Ativar compilação assíncrona de shaders - + May reduce shader stutter. Pode reduzir travamentos de shaders. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. Acelera a decodificação de texturas 3D BCn usando processamento da GPU. Desative se ocorrerem travamentos ou falhas gráficas. - + GPU Unswizzle Max Texture Size Tamanho Máximo de Textura para GPU Unswizzle - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. @@ -894,48 +884,48 @@ A GPU é mais rápida para texturas médias e grandes, mas a CPU pode ser mais e Ajuste para encontrar o equilíbrio entre aceleração da GPU e sobrecarga da CPU. - + GPU Unswizzle Stream Size Tamanho do Fluxo de GPU Unswizzle - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. Define a quantidade máxima de dados de textura (em MiB) processados por quadro. Valores mais altos podem reduzir travamentos durante o carregamento de texturas, mas podem afetar a consistência dos quadros. - + GPU Unswizzle Chunk Size Tamanho do Bloco de GPU Unswizzle - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. Determina o número de fatias de profundidade processadas em uma única execução. Aumentar esse valor pode melhorar o desempenho em GPUs avançadas, mas pode causar TDR ou tempo limite do driver em hardwares mais fracos. - + Use Vulkan pipeline cache Utilizar cache de pipeline do Vulkan - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. Habilita o cache de pipeline da fabricante da GPU. Esta opção pode melhorar o tempo de carregamento de shaders significantemente em casos onde o driver Vulkan não armazena o cache de pipeline internamente. - + Enable Compute Pipelines (Intel Vulkan Only) Habilitar Pipeline de Computação (Somente Intel Vulkan) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. @@ -944,182 +934,182 @@ Esta configuração existe apenas para drivers proprietários da Intel e pode ca Pipelines de computação estão sempre habilitados em outros drivers. - + Enable Reactive Flushing Habilitar Flushing Reativo - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Usa flushing reativo ao invés de flushing preditivo, permitindo mais precisão na sincronização da memória. - + Sync to framerate of video playback Sincronizar com o framerate da reprodução de vídeo - + Run the game at normal speed during video playback, even when the framerate is unlocked. Executa o jogo na velocidade normal durante a reprodução de vídeo, mesmo se o framerate estiver desbloqueado. - + Barrier feedback loops Ciclos de feedback de barreira - + Improves rendering of transparency effects in specific games. Melhora a renderização de efeitos de transparência em jogos específicos. - + Enable buffer history Ativar histórico de buffer - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. Permite acesso a estados anteriores do buffer. Esta opção pode melhorar a qualidade de renderização e a consistência de desempenho em alguns jogos. - + Fix bloom effects Corrigir efeitos de bloom - + Removes bloom in Burnout. Remove o bloom no Burnout. - + Extended Dynamic State Estado Dinâmico Estendido - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. Controla o número de recursos que podem ser usados no Estado Dinâmico Estendido. Estados mais altos permitem mais recursos e podem aumentar o desempenho, mas também podem causar problemas gráficos adicionais. - + Vertex Input Dynamic State Estado Dinâmico de Entrada de Vértices - + Enables vertex input dynamic state feature for better quality and performance. Ativa o recurso de estado dinâmico de entrada de vértices para melhor qualidade e desempenho. - + Sample Shading Sombreamento por Amostragem - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. Permite que o shader de fragmento seja processado por cada amostra em fragmentos multiamostrados, em vez de uma única vez por fragmento. Melhora a qualidade gráfica ao custo de desempenho. Valores mais altos aumentam a qualidade, mas reduzem a performance. - + RNG Seed Semente de RNG - + Controls the seed of the random number generator. Mainly used for speedrunning. Controla a semente do gerador de números aleatórios. Usado principalmente em speedruns. - + Device Name Nome do Dispositivo - + The name of the console. O nome do console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: Data personalizada do RTC: - + This option allows to change the clock of the console. Can be used to manipulate time in games. Esta opção permite alterar o relógio do console. Pode ser usada para manipular o tempo nos jogos. - + The number of seconds from the current unix time Número de segundos a partir do tempo Unix atual - + Language: Idioma: - + This option can be overridden when region setting is auto-select Esta opção pode ser substituída quando a configuração de região estiver em seleção automática - + Region: Região: - + The region of the console. A região do console. - + Time Zone: Fuso Horário: - + The time zone of the console. O fuso horário do console. - + Sound Output Mode: Modo de saída de som - + Console Mode: Modo Console: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. @@ -1128,1026 +1118,1026 @@ Os jogos ajustarão resolução, detalhes e controladores suportados conforme es Definir como Portátil pode ajudar a melhorar o desempenho em sistemas mais fracos. - + Prompt for user profile on boot Solicitar perfil de usuário na inicialização - + Useful if multiple people use the same PC. Útil se várias pessoas usam o mesmo PC. - + Pause when not in focus Pausar quando não estiver em foco - + Pauses emulation when focusing on other windows. Pausa a emulação ao focar em outras janelas. - + Confirm before stopping emulation Confirmar antes de parar a emulação - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. Substitui as confirmações ao parar a emulação. Ao ativar, ignora esses avisos e encerra diretamente a emulação. - + Hide mouse on inactivity Esconder rato quando inactivo. - + Hides the mouse after 2.5s of inactivity. Oculta o mouse após 2,5s de inatividade. - + Check for updates Verificar atualizações - + Whether or not to check for updates upon startup. Define se deve verificar atualizações na inicialização. - + Enable Gamemode Habilitar Gamemode - + Force X11 as Graphics Backend Forçar X11 como backend gráfico - + Custom frontend Frontend customizado - + Real applet Applet real - - + + Disabled Desativado - + Never Nunca - + On Load Ao carregar - + Always Sempre - + CPU CPU - + GPU GPU - + CPU Asynchronous CPU Assíncrona - + Uncompressed (Best quality) Descompactado (Melhor Qualidade) - + BC1 (Low quality) BC1 (Baixa qualidade) - + BC3 (Medium quality) BC3 (Média qualidade) - - + + Auto Automático - + 30 FPS 30 FPS - + 60 FPS 60 FPS - + 90 FPS 90 FPS - + 120 FPS 120 FPS - + Conservative Conservador - + Aggressive Agressivo - + Vulkan Vulcano - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) OpenGL GLASM (Shaders em Assembly, apenas NVIDIA) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V (Experimental, apenas AMD/Mesa) - + Null Nenhum - + Fast Rápido - - - + + + Accurate Preciso - - - + + + Default Padrão - + Unsafe (fast) Inseguro (rápido) - + Safe (stable) Seguro (estável) - + Immediate - + Balanced Balanceado - + Unsafe Inseguro - + Paranoid (disables most optimizations) Paranoia (desativa a maioria das otimizações) - + Debugging Depuração - + Dynarmic Dynarmic - + NCE NCE - + Borderless Windowed Janela sem bordas - + Exclusive Fullscreen Tela cheia exclusiva - + No Video Output Sem saída de vídeo - + CPU Video Decoding Decodificação de vídeo pela CPU - + GPU Video Decoding (Default) Decodificação de vídeo pela GPU (Padrão) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [EXPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [EXPERIMENTAL] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [EXPERIMENTAL] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Vizinho mais próximo - + Bilinear Bilinear - + Bicubic Bicúbico - + Gaussian Gaussiano - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX Super Resolution - + Area Área - + MMPX MMPX - + Zero-Tangent Zero-Tangent - + B-Spline B-Spline - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Nenhum - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Padrão (16:9) - + Force 4:3 Forçar 4:3 - + Force 21:9 Forçar 21:9 - + Force 16:10 Forçar 16:10 - + Stretch to Window Esticar à Janela - + Automatic Automático - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Japonês (日本語) - + American English Inglês Americano - + French (français) Francês (français) - + German (Deutsch) Alemão (Deutsch) - + Italian (italiano) Italiano (italiano) - + Spanish (español) Espanhol (español) - + Chinese Chinês - + Korean (한국어) Coreano (한국어) - + Dutch (Nederlands) Holandês (Nederlands) - + Portuguese (português) Português (português) - + Russian (Русский) Russo (Русский) - + Taiwanese Taiwanês - + British English Inglês Britânico - + Canadian French Francês Canadense - + Latin American Spanish Espanhol Latino-Americano - + Simplified Chinese Chinês Simplificado - + Traditional Chinese (正體中文) Chinês Tradicional (正 體 中文) - + Brazilian Portuguese (português do Brasil) Português do Brasil (Brazilian Portuguese) - + Polish (polska) Polonês (polska) - + Thai (แบบไทย) Tailandês (แบบไทย) - - + + Japan Japão - + USA EUA - + Europe Europa - + Australia Austrália - + China China - + Korea Coreia - + Taiwan Taiwan - + Auto (%1) Auto select time zone Auto (%1) - + Default (%1) Default time zone Padrão (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Egito - + Eire Irlanda - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Irlanda - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Islândia - + Iran Irã - + Israel Israel - + Jamaica Jamaica - + Kwajalein Kwajalein - + Libya Líbia - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polônia - + Portugal Portugal - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapura - + Turkey Turquia - + UCT UCT - + Universal Universal - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Estéreo - + Surround Surround - + 4GB DRAM (Default) 4GB DRAM (Padrão) - + 6GB DRAM (Unsafe) 6GB DRAM (Não seguro) - + 8GB DRAM 8GB DRAM - + 10GB DRAM (Unsafe) 10GB DRAM (Inseguro) - + 12GB DRAM (Unsafe) 12GB DRAM (Inseguro) - + Docked Ancorado - + Handheld Portátil - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) Sempre perguntar (Padrão) - + Only if game specifies not to stop Somente se o jogo especificar para não parar - + Never ask Nunca perguntar - + Very Small (16 MB) Muito Pequeno (16 MB) - + Small (32 MB) Pequeno (32 MB) - + Normal (128 MB) Normal (128 MB) - + Large (256 MB) Grande (256 MB) - + Very Large (512 MB) Muito Grande (512 MB) - + Very Low (4 MB) Muito Baixo (4 MB) - + Low (8 MB) Baixo (8 MB) - + Normal (16 MB) Normal (16 MB) - + Medium (32 MB) Médio (32 MB) - + High (64 MB) Alto (64 MB) - + Very Low (32) Muito Baixo (32) - + Low (64) Baixo (64) - + Normal (128) Normal (128) - + Medium (256) Médio (256) - + High (512) Alto (512) - + ExtendedDynamicState 1 Estado Dinâmico Estendido 1 - + ExtendedDynamicState 2 Estado Dinâmico Estendido 2 - + ExtendedDynamicState 3 Estado Dinâmico Estendido 3 - + Tree View Visualização em Árvore - + Grid View Visualização em Grade @@ -6112,50 +6102,50 @@ Por favor vá para Configuração -> Sistema -> Rede e selecione. GRenderWindow - - + + OpenGL not available! OpenGL não está disponível! - + OpenGL shared contexts are not supported. Shared contexts do OpenGL não são suportados. - + Eden has not been compiled with OpenGL support. Eden não foi compilado com suporte a OpenGL. - - - + + + Error while initializing OpenGL! Erro ao inicializar OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. O seu GPU pode não suportar OpenGL, ou não tem os drivers gráficos mais recentes. - + Error while initializing OpenGL 4.6! Erro ao inicializar o OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 A sua GPU não tem suporte a OpenGL 4.6, talvez você não esteja usando os drivers gráficos mais atuais.<br><br>Renderizador GL:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Sua GPU pode não suportar uma ou mais extensões necessárias do OpenGL. Verifique se você possui a última versão dos drivers gráficos.<br><br>Renderizador GL:<br>%1<br><br>Extensões não suportadas:<br>%2 - + This build doesn't have OpenGL support. Essa build não suporte a OpenGL. @@ -6922,1133 +6912,1153 @@ Mensagem de Depuração: &Emulação - + + &Cheats + + + + &View &Exibir - + &Reset Window Size &Restaurar tamanho da janela - + &Debugging &Depurar - + &Game List Mode Modo Lista de &Jogos - + Game &Icon Size Tamanho do &Ícone do Jogo - + Reset Window Size to &720p Restaurar tamanho da janela para &720p - + Reset Window Size to 720p Restaurar tamanho da janela para 720p - + Reset Window Size to &900p Restaurar tamanho da janela para &900p - + Reset Window Size to 900p Restaurar tamanho da janela para 900p - + Reset Window Size to &1080p Restaurar tamanho da janela para &1080p - + Reset Window Size to 1080p Restaurar tamanho da janela para 1080p - + &Multiplayer &Multijogador - + &Tools &Ferramentas - + Am&iibo Am&iibo - + Launch &Applet Iniciar &Applet - + &TAS &TAS - + &Create Home Menu Shortcut &Criar atalho para o menu Home - + Install &Firmware Instalar &Firmware - + &Help &Ajuda - + &Install Files to NAND... &Instalar arquivos na NAND... - + L&oad File... C&arregar arquivo... - + Load &Folder... Carregar &pasta... - + E&xit &Sair - - + + &Pause &Pausa - + &Stop &Parar - + &Verify Installed Contents &Verificar conteúdo instalado - + &About Eden &Sobre o Eden - + Single &Window Mode Modo de &janela única - + Con&figure... Con&figurar... - + Ctrl+, Ctrl+, - + Enable Overlay Display Applet Habilitar a Sobreposição de Display do Applet - + Show &Filter Bar Mostrar Barra de &Filtros - + Show &Status Bar Mostrar Barra de &Estado - + Show Status Bar Mostrar Barra de Estado - + &Browse Public Game Lobby &Navegar no Lobby de Salas Públicas - + &Create Room &Criar Sala - + &Leave Room &Sair da Sala - + &Direct Connect to Room Conectar &Diretamente Numa Sala - + &Show Current Room Exibir &Sala Atual - + F&ullscreen T&ela cheia - + &Restart &Reiniciar - + Load/Remove &Amiibo... Carregar/Remover &Amiibo... - + Open &Mods Page Abrir Página de &Mods - + &User Handbook - + &Capture Screenshot &Captura de Tela - + &Album &Álbum - + &Set Nickname and Owner &Definir apelido e proprietário - + &Delete Game Data &Remover dados do jogo - + &Restore Amiibo &Recuperar Amiibo - + &Format Amiibo &Formatar Amiibo - + &Mii Editor &Editor de Mii - + &Configure TAS... &Configurar TAS - + Configure C&urrent Game... Configurar jogo atual... - - + + &Start &Começar - + &Reset &Restaurar - - + + R&ecord G&ravar - + Open &Controller Menu Menu Abrir &Controles - + Install Decryption &Keys Instalar Chaves de &Encriptação - + &Home Menu &Menu Home - + &Desktop &Área de Trabalho - + &Application Menu &Menu de Aplicativo - + &Root Data Folder &Pasta Raiz de Dados - + &NAND Folder &Pasta NAND - + &SDMC Folder &Pasta SDMC - + &Mod Folder &Pasta de Mods - + &Log Folder &Pasta de Logs - + From Folder Pela Pasta - + From ZIP Pelo ZIP - + &Eden Dependencies &Dependências do Eden - + &Data Manager &Gestor de Dados - + &Tree View &Visualização em Árvore - + &Grid View &Visualizar Grid - + Game Icon Size Tamanho do Ícone do jogo - - + + None Nenhum - + Show Game &Name Mostrar Nome de &Jogo - + Show &Performance Overlay Mostrar Sobreposição de &Desempenho - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) Pequeno (32x32) - + Standard (64x64) Padrão (64x64) - + Large (128x128) Grande (128x128) - + Full Size (256x256) Tamanho completo (256x256) - + Broken Vulkan Installation Detected Detectada Instalação Defeituosa do Vulkan - + Vulkan initialization failed during boot. Inicialização do Vulkan falhou durante o boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping Rodando um jogo - + Loading Web Applet... Carregando Applet Web... - - + + Disable Web Applet Desativar Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) Desativar o Applet Web pode problemas indefinidos e deverá apenas ser usando com o Super Mario 3D All-Stars. Você tem certeza que quer desativar o Applet Web? (Isso pode ser reativado nas Configurações de Depuração.) - + The amount of shaders currently being built A Quantidade total de Shaders está sendo atualmente construída - + The current selected resolution scaling multiplier. A atual multiplicação de escala de resolução selecionada. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Velocidade atual da emulação. Valores altos ou mais baixo que 100% indicam que o emulador está rodando mais rápido ou mais lento que um Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Quantos quadros por segundo o jogo está mostrando atualmente. Isto varia de jogo para jogo e de cena a cena. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory Selecionar Diretório - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory Abrir o Diretório da ROM extraída - + Invalid Directory Selected Diretório selecionado inválido - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo Amiibo - - + + The current amiibo has been removed O Amiibo atual foi removido - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8056,74 +8066,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/pt_PT.ts b/dist/languages/pt_PT.ts index eb9b0c12a4..b23b4da8d8 100644 --- a/dist/languages/pt_PT.ts +++ b/dist/languages/pt_PT.ts @@ -30,7 +30,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> @@ -399,196 +399,206 @@ Can help reduce stuttering at lower framerates. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Precisão: - + Change the accuracy of the emulated CPU (for debugging only). - - + + Backend: Backend: - + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) FMA inseguro (Melhorar performance no CPU sem FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Essa opção melhora a velocidade ao reduzir a precisão de instruções de fused-multiply-add em CPUs sem suporte nativo ao FMA. - + Faster FRSQRTE and FRECPE FRSQRTE e FRECPE mais rápido - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Essa opção melhora a velocidade de algumas funções aproximadas de pontos flutuantes ao usar aproximações nativas precisas. - + Faster ASIMD instructions (32 bits only) Instruções ASIMD mais rápidas (apenas 32 bits) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Essa opção melhora a velocidade de funções de pontos flutuantes de 32 bits ASIMD ao executá-las com modos de arredondamento incorretos. - + Inaccurate NaN handling Tratamento impreciso de NaN - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Esta opção melhora a velocidade ao remover a checagem NaN. Por favor, note que isso também reduzirá a precisão de certas instruções de ponto flutuante. - + Disable address space checks Desativar a verificação do espaço de endereços - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor Ignorar monitor global - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Esta opção melhora a velocidade ao depender apenas das semânticas do cmpxchg pra garantir a segurança das instruções de acesso exclusivo. Por favor, note que isso pode resultar em travamentos e outras condições de execução. - + API: API: - + Changes the output graphics API. Vulkan is recommended. - + Device: Dispositivo: - + This setting selects the GPU to use (Vulkan only). - + Resolution: Resolução: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: Filtro de adaptação de janela: - + FSR Sharpness: FSR Sharpness: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Método de Anti-Aliasing - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Tela Cheia - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -597,47 +607,47 @@ Sem borda oferece a melhor compatibilidade com o teclado na tela que alguns jogo Tela cheia exclusiva pode oferecer melhor performance e melhor suporte a Freesync/Gsync. - + Aspect Ratio: Proporção do Ecrã: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Permite guardar os shaders para carregar os jogos nas execuções seguintes. Desabiltar essa opção só serve para propósitos de depuração. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: Emulação NVDEC: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -646,12 +656,12 @@ Tanto a CPU quanto a GPU podem ser utilizadas para decodificação, ou não deco Na maioria dos casos, a decodificação pela GPU fornece uma melhor performance. - + ASTC Decoding Method: Método de Decodificação ASTC: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -660,75 +670,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: Método de Recompressão ASTC: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: Modo de Uso da VRAM: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: Modo de Sincronização vertical: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -736,79 +726,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) Ativar apresentação assíncrona (Somente Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. Melhora ligeiramente o desempenho ao mover a apresentação para uma thread de CPU separada. - + Force maximum clocks (Vulkan only) Forçar clock máximo (somente Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Executa trabalho em segundo plano aguardando pelos comandos gráficos para evitar a GPU de reduzir seu clock. - + Anisotropic Filtering: Filtro Anisotrópico: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -817,1291 +807,1291 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache Utilizar cache de pipeline do Vulkan - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. Habilita o cache de pipeline da fabricante da GPU. Esta opção pode melhorar o tempo de carregamento de shaders significantemente em casos onde o driver Vulkan não armazena o cache de pipeline internamente. - + Enable Compute Pipelines (Intel Vulkan Only) Habilitar Pipeline de Computação (Somente Intel Vulkan) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing Habilitar Flushing Reativo - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Usa flushing reativo ao invés de flushing preditivo, permitindo mais precisão na sincronização da memória. - + Sync to framerate of video playback Sincronizar com o framerate da reprodução de vídeo - + Run the game at normal speed during video playback, even when the framerate is unlocked. Executa o jogo na velocidade normal durante a reprodução de vídeo, mesmo se o framerate estiver desbloqueado. - + Barrier feedback loops Ciclos de feedback de barreira - + Improves rendering of transparency effects in specific games. Melhora a renderização de efeitos de transparência em jogos específicos. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed Semente de RNG - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name Nome do Dispositivo - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: Data personalizada do RTC: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: Idioma: - + This option can be overridden when region setting is auto-select - + Region: Região: - + The region of the console. - + Time Zone: Fuso Horário: - + The time zone of the console. - + Sound Output Mode: Modo de saída de som - + Console Mode: Modo Console: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation Confirmar antes de parar a emulação - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity Esconder rato quando inactivo. - + Hides the mouse after 2.5s of inactivity. - + Check for updates - + Whether or not to check for updates upon startup. - + Enable Gamemode Habilitar Gamemode - + Force X11 as Graphics Backend - + Custom frontend Frontend customizado - + Real applet Miniaplicativo real - - + + Disabled - + Never - + On Load - + Always - + CPU CPU - + GPU GPU - + CPU Asynchronous CPU Assíncrona - + Uncompressed (Best quality) Descompactado (Melhor Q - + BC1 (Low quality) BC1 (Baixa qualidade) - + BC3 (Medium quality) BC3 (Média qualidade) - - + + Auto Automático - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative Conservador - + Aggressive Agressivo - + Vulkan Vulcano - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null Nenhum (desativado) - + Fast - - - + + + Accurate Preciso - - - + + + Default Padrão - + Unsafe (fast) - + Safe (stable) - + Immediate - + Balanced - + Unsafe Inseguro - + Paranoid (disables most optimizations) Paranoia (desativa a maioria das otimizações) - + Debugging - + Dynarmic Dynarmic - + NCE NCE - + Borderless Windowed Janela sem bordas - + Exclusive Fullscreen Tela cheia exclusiva - + No Video Output Sem saída de vídeo - + CPU Video Decoding Decodificação de vídeo pela CPU - + GPU Video Decoding (Default) Decodificação de vídeo pela GPU (Padrão) - + 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [EXPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [EXPERIMENTAL] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [EXPERIMENTAL] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Vizinho mais próximo - + Bilinear Bilinear - + Bicubic Bicúbico - + Gaussian Gaussiano - + Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution - + Area - + MMPX - + Zero-Tangent - + B-Spline - + Mitchell - + Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Nenhum - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Padrão (16:9) - + Force 4:3 Forçar 4:3 - + Force 21:9 Forçar 21:9 - + Force 16:10 Forçar 16:10 - + Stretch to Window Esticar à Janela - + Automatic Automático - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Japonês (日本語) - + American English Inglês Americano - + French (français) Francês (français) - + German (Deutsch) Alemão (Deutsch) - + Italian (italiano) Italiano (italiano) - + Spanish (español) Espanhol (español) - + Chinese Chinês - + Korean (한국어) Coreano (한국어) - + Dutch (Nederlands) Holandês (Nederlands) - + Portuguese (português) Português (português) - + Russian (Русский) Russo (Русский) - + Taiwanese Taiwanês - + British English Inglês Britânico - + Canadian French Francês Canadense - + Latin American Spanish Espanhol Latino-Americano - + Simplified Chinese Chinês Simplificado - + Traditional Chinese (正體中文) Chinês Tradicional (正 體 中文) - + Brazilian Portuguese (português do Brasil) Português do Brasil (Brazilian Portuguese) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan Japão - + USA EUA - + Europe Europa - + Australia Austrália - + China China - + Korea Coreia - + Taiwan Taiwan - + Auto (%1) Auto select time zone Auto (%1) - + Default (%1) Default time zone Padrão (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Egipto - + Eire Irlanda - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Irlanda - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Islândia - + Iran Irão - + Israel Israel - + Jamaica Jamaica - + Kwajalein Kwajalein - + Libya Líbia - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polónia - + Portugal Portugal - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapura - + Turkey Turquia - + UCT UCT - + Universal Universal - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Estéreo - + Surround Surround - + 4GB DRAM (Default) 4GB DRAM (Padrão) - + 6GB DRAM (Unsafe) 6GB DRAM (Não seguro) - + 8GB DRAM - + 10GB DRAM (Unsafe) - + 12GB DRAM (Unsafe) - + Docked Ancorado - + Handheld Portátil - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) Sempre perguntar (Padrão) - + Only if game specifies not to stop Somente se o jogo especificar para não parar - + Never ask Nunca perguntar - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) - + High (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6046,50 +6036,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL não está disponível! - + OpenGL shared contexts are not supported. Shared contexts do OpenGL não são suportados. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! Erro ao inicializar OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. O seu GPU pode não suportar OpenGL, ou não tem os drivers gráficos mais recentes. - + Error while initializing OpenGL 4.6! Erro ao inicializar o OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 O teu GPU pode não suportar OpenGL 4.6, ou não tem os drivers gráficos mais recentes. - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Sua GPU pode não suportar uma ou mais extensões necessárias do OpenGL. Verifique se você possui a última versão dos drivers gráficos.<br><br>Renderizador GL:<br>%1<br><br>Extensões não suportadas:<br>%2 - + This build doesn't have OpenGL support. @@ -6855,1132 +6845,1152 @@ Debug Message: &Emulação - + + &Cheats + + + + &View &Vista - + &Reset Window Size &Restaurar tamanho da janela - + &Debugging &Depurar - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p Restaurar tamanho da janela para &720p - + Reset Window Size to 720p Restaurar tamanho da janela para 720p - + Reset Window Size to &900p Restaurar tamanho da janela para &900p - + Reset Window Size to 900p Restaurar tamanho da janela para 900p - + Reset Window Size to &1080p Restaurar tamanho da janela para &1080p - + Reset Window Size to 1080p Restaurar tamanho da janela para 1080p - + &Multiplayer &Multijogador - + &Tools &Ferramentas - + Am&iibo - + Launch &Applet - + &TAS &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help &Ajuda - + &Install Files to NAND... &Instalar arquivos na NAND... - + L&oad File... C&arregar arquivo... - + Load &Folder... Carregar &pasta... - + E&xit &Sair - - + + &Pause &Pausa - + &Stop &Parar - + &Verify Installed Contents &Verificar conteúdo instalado - + &About Eden - + Single &Window Mode Modo de &janela única - + Con&figure... Con&figurar... - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar Mostrar Barra de &Filtros - + Show &Status Bar Mostrar Barra de &Estado - + Show Status Bar Mostrar Barra de Estado - + &Browse Public Game Lobby &Navegar no Lobby de Salas Públicas - + &Create Room &Criar Sala - + &Leave Room &Sair da Sala - + &Direct Connect to Room Conectar &Diretamente Numa Sala - + &Show Current Room Exibir &Sala Atual - + F&ullscreen T&ela cheia - + &Restart &Reiniciar - + Load/Remove &Amiibo... Carregar/Remover &Amiibo... - + Open &Mods Page Abrir Página de &Mods - + &User Handbook - + &Capture Screenshot &Captura de Tela - + &Album - + &Set Nickname and Owner &Definir apelido e proprietário - + &Delete Game Data &Remover dados do jogo - + &Restore Amiibo &Recuperar Amiibo - + &Format Amiibo &Formatar Amiibo - + &Mii Editor - + &Configure TAS... &Configurar TAS - + Configure C&urrent Game... Configurar jogo atual... - - + + &Start &Começar - + &Reset &Restaurar - - + + R&ecord G&ravar - + Open &Controller Menu Menu Abrir &Controles - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -7988,74 +7998,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/ru_RU.ts b/dist/languages/ru_RU.ts index bb44335970..fb90b01bd3 100644 --- a/dist/languages/ru_RU.ts +++ b/dist/languages/ru_RU.ts @@ -37,8 +37,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;"> сайт</span></a>| <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;"> Исходный код</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;"> Контрибьюторы</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;"> Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;"> Stoat</span></a> |<a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;"> Twitter/X</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;"> Лицензия</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -411,50 +411,60 @@ Can help reduce stuttering at lower framerates. Может помочь уменьшить фризы при низкой частоте кадров. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Точность: - + Change the accuracy of the emulated CPU (for debugging only). Изменяет точность эмуляции процессора (только для отладки). - - + + Backend: Бэкэнд: - + CPU Clocks Частоты CPU - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. Увеличивает частоту, которую сообщает эмулируемый CPU, из-за чего могут быть убраны некоторые ограничители FPS. Слабые процессоры могут потерять производительность, а некоторые игры могут работать неправильно. - + Custom CPU Ticks Пользовательские тики CPU - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. Задает пользовательское значение тиков CPU. Более высокие значения могут повысить производительность, но могут вызвать взаимные блокировки. Рекомендуемый диапазон: 77–21000. - + Enable Host MMU Emulation (fastmem) Включить эмуляцию MMU хоста (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -463,98 +473,98 @@ Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) Отключить FMA (улучшает производительность на ЦП без FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Этот вариант улучшает скорость путем снижения точности инструкций слияния-умножения-сложения на процессорах без поддержки нативной FMA. - + Faster FRSQRTE and FRECPE Ускоренные FRSQRTE и FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Этот вариант улучшает скорость некоторых приближенных функций с плавающей запятой за счет использования менее точных встроенных приближений. - + Faster ASIMD instructions (32 bits only) Ускоренные инструкции ASIMD (только 32 бит) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Этот вариант улучшает скорость 32-битных функций с плавающей запятой ASIMD путем выполнения с неправильными режимами округления. - + Inaccurate NaN handling Неточная обработка NaN - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Этот вариант улучшает скорость отключая проверки на NaN. Обратите внимание, что это также снижает точность некоторых операций с плавающей запятой. - + Disable address space checks Отключить проверку адресного пространства - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. Эта опция повышает скорость за счет исключения проверки безопасности перед каждой операцией с памятью. Отключение может привести к выполнению произвольного кода. - + Ignore global monitor Игнорировать глобальный мониторинг - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Эта опция повышает скорость, полагаясь только на семантику cmpxchg для обеспечения безопасности инструкций исключительного доступа. Обратите внимание, что это может привести к дедлокам и race condition. - + API: API: - + Changes the output graphics API. Vulkan is recommended. Изменяет графический API вывода. Рекомендуется использовать Vulkan. - + Device: Устройство: - + This setting selects the GPU to use (Vulkan only). Этот параметр определяет используемый GPU (только Vulkan). - + Resolution: Разрешение: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -563,27 +573,27 @@ Options lower than 1X can cause artifacts. Опции ниже 1X могут вызывать артефакты. - + Window Adapting Filter: Фильтр масштабирования окна: - + FSR Sharpness: Резкость FSR: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. Определяет степень резкости изображения при использовании динамического контраста FSR или SGSR. - + Anti-Aliasing Method: Метод сглаживания: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -592,22 +602,22 @@ SMAA обеспечивает лучшее качество. FXAA может давать более стабильное изображение на низком разрешении. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Полноэкранный режим: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -616,12 +626,12 @@ Exclusive fullscreen may offer better performance and better Freesync/Gsync supp Эксклюзивный полноэкранный режим может иметь лучшую производительность и лучшую поддержку Freesync/G-Sync. - + Aspect Ratio: Соотношение сторон: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -630,35 +640,35 @@ Also controls the aspect ratio of captured screenshots. Также управляет соотношением сторон скриншотов. - + Use persistent pipeline cache Использовать постоянный кэш конвейера - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Позволяет сохранять шейдеры на диск для более быстрой загрузки при последующем запуске игры. Отключение этой функции предназначено только для отладки. - + Use asynchronous GPU emulation Использовать асинхронную эмуляцию GPU - + Uses an extra CPU thread for rendering. This option should always remain enabled. Использует дополнительный поток CPU для рендеринга. Эта опция всегда должна оставаться включенной. - + NVDEC emulation: Эмуляция NVDEC: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -667,12 +677,12 @@ In most cases, GPU decoding provides the best performance. В большинстве случаев декодирование с использованием ГП обеспечивает лучшую производительность. - + ASTC Decoding Method: Метод декодирования ASTC: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -684,12 +694,12 @@ GPU: использовать вычислительные шейдеры ГП Асинхронный CPU: использовать ЦП для декодирования текстур ASTC по мере необходимости. Устраняет фризы при декодировании ASTC, но может вызывать артефакты. - + ASTC Recompression Method: Метод пересжатия ASTC: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. @@ -697,64 +707,44 @@ BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, BC1/BC3: промежуточный формат будет перекодирован в BC1 или BC3, экономя видеопамять, но снижая качество изображения. - + Frame Pacing Mode (Vulkan only) Режим стабилизации кадров (только Vulkan) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. Определяет способ управления выводом кадров для уменьшения подергиваний и повышения плавности и стабильности частоты кадров. - + VRAM Usage Mode: Режим VRAM: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. Определяет, должен ли эмулятор экономить память или использовать всю доступную видеопамять для повышения производительности. Агрессивный режим может негативно сказаться на производительности других приложений, например программ записи. - + Skip CPU Inner Invalidation Пропуск внутренней инвалидизации CPU - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. Пропускает некоторые операции сброса кэша при обновлении памяти, снижая нагрузку на ЦП и уменьшая задержку. Может вызывать сбои в работе игр. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: Режим VSync: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -765,12 +755,12 @@ Mailbox может обеспечивать меньшую задержку, ч Immediate (без синхронизации) выводит все доступные кадры и может иметь разрывы. - + Sync Memory Operations Синхронизация операций памяти - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. @@ -779,56 +769,56 @@ Unreal Engine 4 games often see the most significant changes thereof. Игры на Unreal Engine 4 чаще всего демонстрируют заметные изменения. - + Enable asynchronous presentation (Vulkan only) Включить асинхронный вывод (только Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. Немного повышает производительность, перенося вывод кадра в отдельный поток CPU. - + Force maximum clocks (Vulkan only) Принудительно зафиксировать максимальную тактовую частоту (только для Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Выполняет фоновые операции во время ожидания графических команд, предотвращая снижение тактовой частоты GPU. - + Anisotropic Filtering: Анизотропная фильтрация: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. Управляет качеством отображения текстур под наклонными углами. На большинстве GPU безопасно использовать значение 16x. - + GPU Mode: Режим GPU: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. Управляет режимом эмуляции ГПУ. Большинство игр нормально отображаются в режиме Быстрый, но для некоторых требуется режим Точный. Частицы обычно корректно отображаются только в режиме Точный. - + DMA Accuracy: Точность DMA: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. @@ -837,12 +827,12 @@ Default follows the GPU Accuracy setting. По умолчанию соответствует настройке точности ГПУ. - + GPU Fence Behavior: Поведение барьеров ГПУ: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -851,44 +841,44 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation Включить асинхронную компиляцию шейдеров - + May reduce shader stutter. Может уменьшить фризы, вызванные компиляцией шейдеров. - + GPU Clocks Частоты GPU - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. Заставляет игру думать, что GPU завершает свою работу быстрее, чем на самом деле, чтобы она перестала подстраиваться под частоты Switch, понижать разрешение и дальность прорисовки. - + GPU Unswizzle GPU-десвиззлинг (GPU Unswizzle) - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. Ускоряет декодирование 3D-текстур BCn с использованием вычислений GPU. Отключите при возникновении сбоев или графических артефактов. - + GPU Unswizzle Max Texture Size Максимальный размер текстур для GPU-десвиззлинга - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. @@ -897,48 +887,48 @@ Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size Размер потока GPU-десвиззлинга - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. Задает максимальный объем данных текстур (в МиБ), обрабатываемый за кадр. Более высокие значения могут уменьшить подергивания при загрузке текстур, но это может повлиять на стабильность кадров. - + GPU Unswizzle Chunk Size Размер блока GPU-десвиззлинга - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. Определяет количество слоев глубины, обрабатываемых за один вызов. Увеличение этого значения может повысить пропускную способность на производительных GPU, но на слабом оборудовании способно вызвать TDR или тайм-ауты драйвера. - + Use Vulkan pipeline cache Использовать кэш конвейеров Vulkan - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. Включает кэш конвейеров, зависящий от производителя GPU. Эта опция может значительно ускорить загрузку шейдеров в тех случаях, когда драйвер Vulkan не сохраняет такие файлы кэша внутри себя. - + Enable Compute Pipelines (Intel Vulkan Only) Включить вычислительные конвейеры (только для Intel Vulkan) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. @@ -947,182 +937,182 @@ Compute pipelines are always enabled on all other drivers. На остальных драйверах вычислительные конвейеры всегда включены. - + Enable Reactive Flushing Включить реактивный сброс - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Использует реактивный сброс (Reactive Flushing) вместо прогнозирующего, обеспечивая более точную синхронизацию памяти. - + Sync to framerate of video playback Синхронизировать с частотой кадров видео - + Run the game at normal speed during video playback, even when the framerate is unlocked. Поддерживать нормальную скорость игры во время воспроизведения видео, даже если частота кадров разблокирована. - + Barrier feedback loops Циклы обратной связи барьеров - + Improves rendering of transparency effects in specific games. Улучшает отрисовку эффектов прозрачности в некоторых играх. - + Enable buffer history Включить историю буфера - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. Предоставляет доступ к предыдущим состояниям буфера. В некоторых играх может повысить качество рендеринга и стабильность производительности. - + Fix bloom effects Исправить эффекты bloom - + Removes bloom in Burnout. Удаляет эффект bloom в игре Burnout. - + Extended Dynamic State Расширенное динамическое состояние (Extended Dynamic State) - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. Определяет количество функций, доступных в Extended Dynamic State. Более высокие значения позволяют использовать больше функций и иногда повышают производительность, но могут вызвать дополнительные графические проблемы. - + Vertex Input Dynamic State Динамическое состояние ввода вершин (Vertex Input Dynamic State) - + Enables vertex input dynamic state feature for better quality and performance. Включает функцию динамического состояния ввода вершин для улучшения качества и производительности. - + Sample Shading Множественное затенение (Sample Shading) - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. Позволяет фрагментному шейдеру выполняться для каждого сэмпла в мультисемплированном фрагменте вместо одного раза. Повышает качество графики за счет снижения производительности. Более высокие значения повышают качество, но сильнее снижают производительность. - + RNG Seed Сид RNG - + Controls the seed of the random number generator. Mainly used for speedrunning. Задает начальное значение генератора случайных чисел. В основном используется для спидранов. - + Device Name Название устройства - + The name of the console. Имя консоли. - + Homebrew Args Аргументы Homebrew - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). Аргументы командной строки при запуске homebrew (например, -noglsl). - + Custom RTC Date: Пользовательская RTC-дата: - + This option allows to change the clock of the console. Can be used to manipulate time in games. Позволяет изменить системные часы консоли. Может использоваться для изменения времени в играх. - + The number of seconds from the current unix time Количество секунд от текущего UNIX-времени. - + Language: Язык: - + This option can be overridden when region setting is auto-select Эта настройка может быть переопределена при автоматическом выборе региона. - + Region: Регион: - + The region of the console. Регион консоли. - + Time Zone: Часовой пояс: - + The time zone of the console. Часовой пояс консоли. - + Sound Output Mode: Режим вывода звука: - + Console Mode: Консольный режим: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. @@ -1131,1026 +1121,1026 @@ Setting to Handheld can help improve performance for low end systems. Установка в портативный режим может повысить производительность на слабых системах. - + Prompt for user profile on boot Запрашивать профиль пользователя при запуске игры - + Useful if multiple people use the same PC. Полезно, если одним ПК пользуются несколько человек. - + Pause when not in focus Приостанавливать, если окно не активно - + Pauses emulation when focusing on other windows. Приостанавливает эмуляцию при переключении на другие окна. - + Confirm before stopping emulation Запрашивать подтверждение перед остановкой эмуляции - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. Убирает запросы на подтверждение остановки эмуляции. При включении этой настройки эмуляция завершается сразу, без подтверждения. - + Hide mouse on inactivity Скрывать курсор при бездействии - + Hides the mouse after 2.5s of inactivity. Скрывает курсор мыши после 2,5 секунд бездействия. - + Check for updates Проверять обновления - + Whether or not to check for updates upon startup. Проверять обновления при запуске. - + Enable Gamemode Включить режим игры - + Force X11 as Graphics Backend Принудительно использовать X11 как графический бэкенд - + Custom frontend Собственный интерфейс эмулятора - + Real applet Приложение из прошивки - - + + Disabled Отключено - + Never Никогда - + On Load При загрузке - + Always Всегда - + CPU CPU - + GPU GPU - + CPU Asynchronous Асинхронный CPU - + Uncompressed (Best quality) Без сжатия (наилучшее качество) - + BC1 (Low quality) BC1 (низкое качество) - + BC3 (Medium quality) BC3 (среднее качество) - - + + Auto Авто - + 30 FPS 30 FPS - + 60 FPS 60 FPS - + 90 FPS 90 FPS - + 120 FPS 120 FPS - + Conservative Консервативный - + Aggressive Агрессивный - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) OpenGL GLASM (ассемблерные шейдеры, только для NVIDIA) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V (экспериментальный, только для AMD/Mesa) - + Null Null - + Fast Производительность - - - + + + Accurate Точность - - - + + + Default По умолчанию - + Unsafe (fast) Небезопасно (быстро) - + Safe (stable) Безопасно (стабильно) - + Immediate Мгновенный - + Balanced Баланс - + Unsafe Небезопасно - + Paranoid (disables most optimizations) Параноик (отключает большинство оптимизаций) - + Debugging Отладка - + Dynarmic Dynarmic - + NCE NCE - + Borderless Windowed Безрамочный режим - + Exclusive Fullscreen Эксклюзивный полноэкранный - + No Video Output Отсутствие видеовыхода - + CPU Video Decoding Декодирование видео на CPU - + GPU Video Decoding (Default) Декодирование видео на GPU (По умолчанию) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [Экспериментально] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [Экспериментально] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [Экспериментально] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [ЭКПЕРИМЕНТАЛЬНО] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [Экспериментально] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Ближайший сосед (Nearest Neighbor) - + Bilinear Билинейный - + Bicubic Бикубический - + Gaussian По Гауссу - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX™️ Super Resolution - + Area Область (Area) - + MMPX MMPX - + Zero-Tangent Zero-Tangent - + B-Spline B-Spline - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir Snapdragon Game Super Resolution EdgeDir - + None Никакой - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Стандартное (16:9) - + Force 4:3 Принудительно 4:3 - + Force 21:9 Принудительно 21:9 - + Force 16:10 Принудительно 16:10 - + Stretch to Window Растянуть до окна - + Automatic Автоматически - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Японский (日本語) - + American English Американский английский - + French (français) Французский (français) - + German (Deutsch) Немецкий (Deutsch) - + Italian (italiano) Итальянский (italiano) - + Spanish (español) Испанский (español) - + Chinese Китайский - + Korean (한국어) Корейский (한국어) - + Dutch (Nederlands) Голландский (Nederlands) - + Portuguese (português) Португальский (português) - + Russian (Русский) Русский - + Taiwanese Тайваньский - + British English Британский английский - + Canadian French Канадский французский - + Latin American Spanish Латиноамериканский испанский - + Simplified Chinese Упрощённый китайский - + Traditional Chinese (正體中文) Традиционный китайский (正體中文) - + Brazilian Portuguese (português do Brasil) Бразильский португальский (português do Brasil) - + Polish (polska) Польский (polska) - + Thai (แบบไทย) Тайский (แบบไทย) - - + + Japan Япония - + USA США - + Europe Европа - + Australia Австралия - + China Китай - + Korea Корея - + Taiwan Тайвань - + Auto (%1) Auto select time zone Авто (%1) - + Default (%1) Default time zone По умолчанию (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Куба - + EET EET - + Egypt Египет - + Eire Эйре - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Эйре - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Гринвич - + Hongkong Гонконг - + HST HST - + Iceland Исландия - + Iran Иран - + Israel Израиль - + Jamaica Ямайка - + Kwajalein Кваджалейн - + Libya Ливия - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Навахо - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Польша - + Portugal Португалия - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Сингапур - + Turkey Турция - + UCT UCT - + Universal Универсальный - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Зулу - + Mono Моно - + Stereo Стерео - + Surround Объемный звук - + 4GB DRAM (Default) 4 ГБ ОЗУ (По умолчанию) - + 6GB DRAM (Unsafe) 6 ГБ ОЗУ (Небезопасно) - + 8GB DRAM 8 ГБ ОЗУ - + 10GB DRAM (Unsafe) 10 ГБ ОЗУ (Небезопасно) - + 12GB DRAM (Unsafe) 12 ГБ ОЗУ (Небезопасно) - + Docked В док-станции - + Handheld Портативный - - + + Normal Нормальная - - + + Boost Ускоренная - - + + Overclock Разгон - + Always ask (Default) Всегда спрашивать (По умолчанию) - + Only if game specifies not to stop Только если игра указывает не останавливать - + Never ask Никогда не спрашивать - + Very Small (16 MB) Очень маленький (16 МБ) - + Small (32 MB) Маленький (32 МБ) - + Normal (128 MB) Нормальный (128 МБ) - + Large (256 MB) Большой (256 МБ) - + Very Large (512 MB) Очень большой (512 МБ) - + Very Low (4 MB) Очень низкий (4 МБ) - + Low (8 MB) Низкий (8 МБ) - + Normal (16 MB) Нормальный (16 МБ) - + Medium (32 MB) Средний (32 МБ) - + High (64 MB) Высокий (64 МБ) - + Very Low (32) Очень низкий (32) - + Low (64) Низкий (64) - + Normal (128) Нормальный (128) - + Medium (256) Средний (256) - + High (512) Высокий (512) - + ExtendedDynamicState 1 ExtendedDynamicState 1 - + ExtendedDynamicState 2 ExtendedDynamicState 2 - + ExtendedDynamicState 3 ExtendedDynamicState 3 - + Tree View Древовидный - + Grid View Сетчатый @@ -6123,50 +6113,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL не доступен! - + OpenGL shared contexts are not supported. Общие контексты OpenGL не поддерживаются. - + Eden has not been compiled with OpenGL support. Eden не был скомпилирован с поддержкой OpenGL. - - - + + + Error while initializing OpenGL! Ошибка при инициализации OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Ваш ГП может не поддерживать OpenGL, или у вас установлен устаревший графический драйвер. - + Error while initializing OpenGL 4.6! Ошибка при инициализации OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Ваш ГП может не поддерживать OpenGL 4.6, или у вас установлен устаревший графический драйвер.<br><br>Рендерер GL:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Ваш ГП может не поддерживать одно или несколько требуемых расширений OpenGL. Пожалуйста, убедитесь в том, что у вас установлен последний графический драйвер.<br><br>Рендерер GL:<br>%1<br><br>Неподдерживаемые расширения:<br>%2 - + This build doesn't have OpenGL support. В этой сборке отсутствует поддержка OpenGL. @@ -6933,800 +6923,820 @@ Debug Message: &Эмуляция - + + &Cheats + + + + &View &Вид - + &Reset Window Size &Сбросить размер окна - + &Debugging Отла&дка - + &Game List Mode &Вид списка игр - + Game &Icon Size Размер &иконок - + Reset Window Size to &720p Сбросить размер окна до &720p - + Reset Window Size to 720p Сбросить размер окна до 720p - + Reset Window Size to &900p Сбросить размер окна до &900p - + Reset Window Size to 900p Сбросить размер окна до 900p - + Reset Window Size to &1080p Сбросить размер окна до &1080p - + Reset Window Size to 1080p Сбросить размер окна до 1080p - + &Multiplayer &Мультиплеер - + &Tools &Инструменты - + Am&iibo Amiibo - + Launch &Applet &Апплеты - + &TAS &TAS - + &Create Home Menu Shortcut Создать &ярлык Home Menu - + Install &Firmware Установить &прошивку - + &Help &Помощь - + &Install Files to NAND... &Установить файлы в NAND... - + L&oad File... Загрузить &файл... - + Load &Folder... Загрузить &папку... - + E&xit &Выход - - + + &Pause &Пауза - + &Stop &Стоп - + &Verify Installed Contents Провер&ить установленное содержимое - + &About Eden &О Eden - + Single &Window Mode &Режим одного окна - + Con&figure... Параметр&ы... - + Ctrl+, Ctrl+, - + Enable Overlay Display Applet Включить отображение апплета оверлея - + Show &Filter Bar Показать п&анель поиска - + Show &Status Bar Показать панель с&татуса - + Show Status Bar Показать панель статуса - + &Browse Public Game Lobby &Просмотреть публичные игровые лобби - + &Create Room &Создать комнату - + &Leave Room Покинуть &комнату - + &Direct Connect to Room П&рямое подключение к комнате - + &Show Current Room Показать &текущую комнату - + F&ullscreen &Полноэкранный - + &Restart П&ерезапустить - + Load/Remove &Amiibo... &Загрузить/Удалить Amiibo... - + Open &Mods Page Открыть страницу &модов - + &User Handbook - + &Capture Screenshot &Сделать скриншот - + &Album Открыть &Альбом - + &Set Nickname and Owner Установить &никнейм и владельца - + &Delete Game Data &Удалить данные игры - + &Restore Amiibo &Восстановить Amiibo - + &Format Amiibo &Форматировать Amiibo - + &Mii Editor Открыт&ь Mii Editor - + &Configure TAS... &Настройка TAS... - + Configure C&urrent Game... &Настроить текущую игру... - - + + &Start &Запустить - + &Reset &Сбросить - - + + R&ecord З&апись - + Open &Controller Menu Открыть &Меню контроллеров - + Install Decryption &Keys &Установить ключи дешифровки - + &Home Menu Отк&рыть Home Menu - + &Desktop &Рабочий стол - + &Application Menu &Меню приложений - + &Root Data Folder &Корневая папка - + &NAND Folder П&апка NAND - + &SDMC Folder Па&пка SDMC - + &Mod Folder Папка &модов - + &Log Folder Папка &журнала - + From Folder Из &папки - + From ZIP &Из ZIP - + &Eden Dependencies &Зависимости Eden - + &Data Manager Упра&вление данными - + &Tree View &Древовидный - + &Grid View &Сетчатый - + Game Icon Size Размер иконки игры - - + + None Никакой - + Show Game &Name Показать игру - + Show &Performance Overlay &Оверлей производительности - + Post-Processing &Shaders... - + &Carousel View &В Виде Карусели - + Small (32x32) Маленький (32х32) - + Standard (64x64) Стандартный (64х64) - + Large (128x128) Большой (128х128) - + Full Size (256x256) Полноразмерный (256х256) - + Broken Vulkan Installation Detected Обнаружена поврежденная установка Vulkan - + Vulkan initialization failed during boot. Не удалось выполнить инициализацию Vulkan во время загрузки. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping Запущена игра - + Loading Web Applet... Загрузка веб-апплета... - - + + Disable Web Applet Отключить веб-апплет - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) Отключение веб-апплета может привести к неожиданному поведению и должно использоваться только, если вы хотите запустить Super Mario 3D All-Stars. Вы уверены, что хотите отключить веб-апплет? (Его можно снова включить в настройках отладки.) - + The amount of shaders currently being built Количество создаваемых шейдеров на данный момент - + The current selected resolution scaling multiplier. Текущий выбранный множитель масштабирования разрешения. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Текущая скорость эмуляции. Значения выше или ниже 100% указывают на то, что эмуляция идет быстрее или медленнее, чем на Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Количество кадров в секунду в данный момент. Значение будет различаться между играми и сценами. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Время, которое нужно для эмуляции одного кадра Switch, не принимая во внимание ограничение FPS или вертикальную синхронизацию. Для эмуляции в полной скорости значение должно быть не больше 16,67 мс. - + Unmute Включить звук - + Mute Выключить звук - + Reset Volume Сбросить громкость - + Configure Effects... - + &Clear Recent Files &Очистить недавние файлы - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue &Продолжить - + Warning: Outdated Game Format Предупреждение: устаревший формат игры - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. Для этой игры вы используете разархивированный формат ROM'а, который является устаревшим и был заменен другими, такими как NCA, NAX, XCI или NSP. В разархивированных каталогах ROM'а отсутствуют иконки, метаданные и поддержка обновлений.<br><br>Для получения информации о различных форматах Switch, поддерживаемых Eden, ознакомьтесь с руководством пользователя. Это сообщение больше не будет отображаться. - - + + Error while loading ROM! Ошибка при загрузке ROM'а! - + The ROM format is not supported. Формат ROM'а не поддерживается. - + An error occurred initializing the video core. Произошла ошибка при инициализации видеоядра. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. Ошибка при загрузке ROM'а! %1 - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. %1<br>Пожалуйста, пересоздайте дампы ваших файлов или обратитесь за помощью в Discord/Stoat. - + An unknown error occurred. Please see the log for more details. Произошла неизвестная ошибка. Пожалуйста, проверьте журнал для подробностей. - - + + (64-bit) (64-bit) - - + + (32-bit) (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - + Closing software... Закрываем программу... - + Save Data Сохранения - + Mod Data Данные модов - + Error Opening %1 Folder Ошибка при открытии папки %1 - - + + Folder does not exist! Папка не существует! - + Remove Installed Game Contents? Удалить установленное содержимое игр? - + Remove Installed Game Update? Удалить установленное обновление игры? - + Remove Installed Game DLC? Удалить установленные DLC игры? - + Remove Entry Удалить запись - + Delete OpenGL Transferable Shader Cache? Удалить переносной кэш шейдеров OpenGL? - + Delete Vulkan Transferable Shader Cache? Удалить переносной кэш шейдеров Vulkan? - + Delete All Transferable Shader Caches? Удалить весь переносной кэш шейдеров? - + Remove Custom Game Configuration? Удалить пользовательскую настройку игры? - + Remove Cache Storage? Удалить кэш-хранилище? - + Remove File Удалить файл - + Remove Play Time Data Удалить данные игрового времени - + Reset play time? Сбросить время игры? - - + + RomFS Extraction Failed! Не удалось извлечь RomFS! - + There was an error copying the RomFS files or the user cancelled the operation. Произошла ошибка при копировании файлов RomFS или пользователь отменил операцию. - + Full Полный - + Skeleton Скелет - + Select RomFS Dump Mode Выберите режим дампа RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Пожалуйста, выберите, как вы хотите выполнить дамп RomFS. <br>Полный скопирует все файлы в новую папку, в то время как <br>скелет создаст только структуру папок. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root В %1 недостаточно свободного места для извлечения RomFS. Пожалуйста, освободите место или выберите другую папку для дампа в Эмуляция > Параметры > Система > Файловая система > Корень дампа - + Extracting RomFS... Извлечение RomFS... - - + + Cancel Отмена - + RomFS Extraction Succeeded! Извлечение RomFS прошло успешно! - + The operation completed successfully. Операция выполнена успешно. - + Error Opening %1 Ошибка при открытии %1 - + Select Directory Выбрать папку - + Properties Свойства - + The game properties could not be loaded. Не удалось загрузить свойства игры. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Исполняемый файл Switch (%1);;Все файлы (*.*) - + Load File Загрузить файл - + Open Extracted ROM Directory Открыть папку извлеченного ROM'а - + Invalid Directory Selected Выбрана недопустимая папка - + The directory you have selected does not contain a 'main' file. Папка, которую вы выбрали, не содержит файла 'main'. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - Устанавливаемый файл Switch (*.nca *.nsp *.xci);;Архив контента Nintendo (*.nca);;Пакет подачи Nintendo (*.nsp);;Образ картриджа NX (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) + - + Install Files Установить файлы - + %n file(s) remaining %n файл(ов) осталось%n файл(ов) осталось%n файл(ов) осталось%n файл(ов) осталось - + Installing file "%1"... Установка "%1"... - - + + Install Results Результаты - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Чтобы избежать возможных конфликтов, мы не рекомендуем пользователям устанавливать игры в NAND. Пожалуйста, используйте эту функцию только для установки обновлений и DLC. - + %n file(s) were newly installed %n файл(ов) были установлены недавно @@ -7736,7 +7746,7 @@ Please, only use this feature to install updates and DLC. - + %n file(s) were overwritten %n файл(ов) были перезаписаны @@ -7746,7 +7756,7 @@ Please, only use this feature to install updates and DLC. - + %n file(s) failed to install %n файл(ов) не удалось установить @@ -7756,324 +7766,324 @@ Please, only use this feature to install updates and DLC. - + System Application Системное приложение - + System Archive Системный архив - + System Application Update Обновление системного приложения - + Firmware Package (Type A) Пакет прошивки (Тип А) - + Firmware Package (Type B) Пакет прошивки (Тип Б) - + Game Игра - + Game Update Обновление игры - + Game DLC DLC игры - + Delta Title Дельта-титул - + Select NCA Install Type... Выберите тип установки NCA... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Пожалуйста, выберите тип приложения, который вы хотите установить для этого NCA: (В большинстве случаев, подходит стандартный выбор «Игра».) - + Failed to Install Ошибка установки - + The title type you selected for the NCA is invalid. Тип приложения, который вы выбрали для NCA, недействителен. - + File not found Файл не найден - + File "%1" not found Файл "%1" не найден - + OK ОК - + Function Disabled Функция отключена - + Compatibility list reporting is currently disabled. Check back later! Отправка отчетов о совместимости временно отключена. Доступ будет восстановлен позднее! - + Error opening URL Ошибка при открытии URL - + Unable to open the URL "%1". Не удалось открыть URL: "%1". - + TAS Recording Запись TAS - + Overwrite file of player 1? Перезаписать файл игрока 1? - + Invalid config detected Обнаружена недопустимая конфигурация - + Handheld controller can't be used on docked mode. Pro controller will be selected. Портативный контроллер не может быть использован в режиме док-станции. Будет выбран контроллер Pro. - - + + Amiibo Amiibo - - + + The current amiibo has been removed Текущий amiibo был удален - + Error Ошибка - - + + The current game is not looking for amiibos Текущая игра не ищет amiibo - + Amiibo File (%1);; All Files (*.*) Файл Amiibo (%1);; Все Файлы (*.*) - + Load Amiibo Загрузить Amiibo - + Error loading Amiibo data Ошибка загрузки данных Amiibo - + The selected file is not a valid amiibo Выбранный файл не является допустимым amiibo - + The selected file is already on use Выбранный файл уже используется - + An unknown error occurred Произошла неизвестная ошибка - + No firmware available Прошивка недоступна - + Firmware Corrupted Прошивка повреждена - + Unknown applet Неизвестный апплет - + Applet doesn't map to a known value. Апплет не соответствует ни одному известному значению. - + Record not found Запись не найдена - + Applet not found. Please reinstall firmware. Апплет не найден. Пожалуйста, переустановите прошивку. - + Capture Screenshot Сделать скриншот - + PNG Image (*.png) Изображение PNG (*.png) - + TAS state: Running %1/%2 Состояние TAS: Выполняется %1/%2 - + TAS state: Recording %1 Состояние TAS: Записывается %1 - + TAS state: Idle %1/%2 Состояние TAS: Простой %1/%2 - + TAS State: Invalid Состояние TAS: Неверное - + &Stop Running &Остановка - + Stop R&ecording &Закончить запись - + Building: %n shader(s) Компиляция %n шейдер(ов)Компиляция %n шейдер(ов)Компиляция %n шейдер(ов)Компиляция %n шейдер(ов) - + Scale: %1x %1 is the resolution scaling factor Масштаб: %1x - + Speed: %1% / %2% Скорость: %1% / %2% - + Speed: %1% Скорость: %1% - + Game: %1 FPS Игра: %1 FPS - + Frame: %1 ms Кадр: %1 мс - + NO AA БЕЗ СГЛАЖИВАНИЯ - + NO FX - + FX - + VOLUME: MUTE ГРОМКОСТЬ: ЗАГЛУШЕНА - + VOLUME: %1% Volume percentage (e.g. 50%) ГРОМКОСТЬ: %1% - + Derivation Components Missing Отсутствуют необходимые компоненты - + Decryption keys are missing. Install them now? Ключи дешифрования отсутствуют. Хотите установить их? - + Wayland Detected! Обнаружен Wayland! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8084,74 +8094,74 @@ Would you like to force it for future launches? Хотите включить X11 для последующих запусков? - + Use X11 Использовать X11 - + Continue with Wayland Продолжить с Wayland - + Don't show again Больше не показывать - + Restart Required Требуется перезапуск - + Restart Eden to apply the X11 backend. Перезапустите Eden, чтобы применить X11. - + Slow Замедлено - + Turbo Турбо - + Unlocked Разблокировано - + Select RomFS Dump Target Выбор цели для дампа RomFS - + Please select which RomFS you would like to dump. Выберите RomFS, который вы хотите извлечь. - + Are you sure you want to close Eden? Вы уверены, что хотите закрыть Eden? - - - + + + Eden Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Вы уверены, что хотите остановить эмуляцию? Любой несохраненный прогресс будет потерян. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/sv.ts b/dist/languages/sv.ts index 818a84cbe1..e1a9555848 100644 --- a/dist/languages/sv.ts +++ b/dist/languages/sv.ts @@ -37,13 +37,13 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Webbplats</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Källkod</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Bidragsgivare</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licens</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><span style=" font-size:7pt;">&quot;Nintendo Switch&quot; is a trademark of Nintendo. Eden is not affiliated with Nintendo in any way.</span></p></body></html> - <html><head/><body><p><span style=" font-size:7pt;">&quot;Nintendo Switch&quot; är ett varumärke som tillhör Nintendo. Eden har ingen anknytning till Nintendo..</span></p></body></html> + <html><head/><body><p><span style=" font-size:7pt;">&quot;Nintendo Switch&quot; är ett varumärke som tillhör Nintendo. Eden har ingen anknytning till Nintendo.</span></p></body></html> @@ -411,50 +411,60 @@ Can help reduce stuttering at lower framerates. Kan bidra till att minska hackande vid lägre bildfrekvenser. - + + Enable cheats by default + Aktivera fuskkoder som standard + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + Aktiverar vanliga fuskkoder när ett spel startar. Master Code-poster är alltid aktiverade. Enskilda fuskkoder kan fortfarande växlas via Fuskkoder i menyraden medan spelet körs. + + + Accuracy: Noggrannhet: - + Change the accuracy of the emulated CPU (for debugging only). Ändra noggrannheten för den emulerade CPU:n (endast för felsökning). - - + + Backend: Bakände: - + CPU Clocks CPU-klockfrekvenser - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. Höjer den klockfrekvens som den emulerade processorn rapporterar, vilket tar bort vissa FPS-begränsare. Svagare processorer kan få sämre prestanda och vissa spel kan fungera felaktigt. - + Custom CPU Ticks Anpassade CPU-ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. Ange ett anpassat värde för CPU-ticks. Högre värden kan öka prestandan, men kan orsaka deadlocks. Ett intervall på 77 till 21000 rekommenderas. - + Enable Host MMU Emulation (fastmem) Aktivera värd-MMU-emulering (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -463,100 +473,100 @@ Om den aktiveras sker läsning/skrivning av gästminnet direkt i minnet och anv Om den inaktiveras tvingas all minnesåtkomst att använda programvaru-MMU-emulering. - + Unfuse FMA (improve performance on CPUs without FMA) Unfuse FMA (förbättrar prestanda på CPU:er utan FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Detta alternativ förbättrar hastigheten genom att minska noggrannheten i fused-multiply-add-instruktioner på processorer utan inbyggt FMA-stöd. - + Faster FRSQRTE and FRECPE Snabbare FRSQRTE och FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Detta alternativ förbättrar hastigheten för vissa approximativa flyttalsfunktioner genom att använda mindre exakta inbyggda approximationer. - + Faster ASIMD instructions (32 bits only) Snabbare ASIMD-instruktioner (endast 32 bitar) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Detta alternativ förbättrar hastigheten för 32-bitars ASIMD flyttalsfunktioner genom att köra med felaktiga avrundningslägen. - + Inaccurate NaN handling Felaktig NaN-hantering - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Detta alternativ förbättrar hastigheten genom att ta bort NaN-kontrollen. Observera att detta också minskar noggrannheten för vissa instruktioner för flyttal. - + Disable address space checks Inaktivera kontroller av adressutrymme - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. Det här alternativet förbättrar hastigheten genom att eliminera en säkerhetskontroll före varje minnesoperation. Om du inaktiverar det kan det bli möjligt att köra godtycklig kod. - + Ignore global monitor Ignorera global monitor - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Detta alternativ förbättrar hastigheten genom att endast förlita sig på semantiken i cmpxchg för att garantera säkerheten för instruktioner med exklusiv åtkomst. Observera att detta kan leda till deadlocks och andra tävlingsförhållanden. - + API: API: - + Changes the output graphics API. Vulkan is recommended. Ändrar grafik-API:et för utdata. Vulkan rekommenderas. - + Device: Enhet: - + This setting selects the GPU to use (Vulkan only). Denna inställning väljer vilken GPU som ska användas (endast Vulkan). - + Resolution: Status: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -565,27 +575,27 @@ Högre upplösningar kräver mer VRAM och bandbredd. Alternativ lägre än 1X kan orsaka artefakter. - + Window Adapting Filter: Fönsteranpassande filter: - + FSR Sharpness: FSR-skärpa: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. Avgör hur skarp bilden ser ut med FSR:s eller SGSR:s dynamiska kontrast. - + Anti-Aliasing Method: Metod för kantutjämning: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -594,22 +604,22 @@ SMAA erbjuder den bästa kvaliteten. FXAA kan ge en stabilare bild i lägre upplösningar. - + Enable post-processing effects Aktivera efterbehandlingseffekter - + Applies post-processing effects to the final image. Tillämpar efterbehandlingseffekter på den slutliga bilden. - + Fullscreen Mode: Helskärmsläge: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -618,12 +628,12 @@ Borderless ger bäst kompatibilitet med skärmtangentbordet som vissa spel kräv Exklusiv helskärm kan ge bättre prestanda och bättre stöd för Freesync/Gsync. - + Aspect Ratio: Bildförhållande: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -632,36 +642,36 @@ De flesta spel stöder endast 16:9, så modifieringar krävs för att få andra Kontrollerar även bildförhållandet för tagna skärmdumpar. - + Use persistent pipeline cache Använd permanent pipeline-cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Gör det möjligt att spara shaders i lagringsutrymmet för snabbare laddning vid nästa spelstart. Att inaktivera detta är endast avsett för felsökning. - + Use asynchronous GPU emulation Använd asynkron GPU-emulering - + Uses an extra CPU thread for rendering. This option should always remain enabled. Använder en extra CPU-tråd för rendering. Detta alternativ bör alltid vara aktiverat. - + NVDEC emulation: NVDEC-emulering: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -670,12 +680,12 @@ Den kan antingen använda CPU eller GPU för avkodning, eller inte utföra någo I de flesta fall ger GPU-avkodning bäst prestanda. - + ASTC Decoding Method: ASTC-avkodningsmetod: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -688,12 +698,12 @@ CPU asynkront: Använd CPU:n för att avkoda ASTC-texturer vid behov. Eliminerar men kan ge artefakter. - + ASTC Recompression Method: ASTC-återkomprimeringsmetod: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. @@ -702,64 +712,44 @@ BC1/BC3: Det mellanliggande formatet kommer att komprimeras om till BC1- eller B vilket sparar VRAM men försämrar bildkvaliteten. - + Frame Pacing Mode (Vulkan only) Frame Pacing Mode (endast Vulkan) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. Styr hur emulatorn hanterar bildhastigheten för att minska hackighet och göra bildfrekvensen jämnare och mer konsekvent. - + VRAM Usage Mode: VRAM-användningsläge: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. Väljer om emulatorn ska prioritera att spara minne eller utnyttja tillgängligt videominne maximalt för prestanda. Aggressivt läge kan påverka prestandan hos andra program, till exempel inspelningsprogram. - + Skip CPU Inner Invalidation Hoppa över CPU:ns interna ogiltigförklaring - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. Hoppar över vissa cache-ogiltigförklaringar under minnesuppdateringar, vilket minskar CPU-användningen och förbättrar latensen. Detta kan orsaka mjuka krascher. - - GPU Readback Before NCE Invalidation - GPU-återläsning före NCE-ogiltigförklaring - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - Skriver tillbaka GPU-buffertdata till gästens minne innan NCE ogiltigförklarar hela gästsidan, så att data bevaras medan CPU-lagringen fortsätter. - - - - Patch Runtime NROs for NCE - Korrigera NRO:er under körning för NCE - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - Tillämpar NCE-korrigeringar på NRO-moduler som läses in under körning. Det krävs för att vissa spel ska fungera korrekt. - - - + VSync Mode: VSync-läge: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -770,12 +760,12 @@ Mailbox kan ha lägre latens än FIFO och uppvisar inte tearing, men kan tappa b Immediate (ingen synkronisering) visar allt som är tillgängligt och kan uppvisa tearing. - + Sync Memory Operations Synkronisera minnesoperationer - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. @@ -784,44 +774,44 @@ Det här alternativet åtgärdar problem i spel, men kan försämra prestandan. Unreal Engine 4-spel upplever ofta de mest betydande förändringarna av detta. - + Enable asynchronous presentation (Vulkan only) Aktivera asynkron presentation (endast Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. Förbättrar prestandan något genom att flytta presentationen till en separat CPU-tråd. - + Force maximum clocks (Vulkan only) Tvinga fram maximal klockfrekvens (endast Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Körs i bakgrunden i väntan på grafikkommandon för att förhindra att GPU:n sänker sin klockhastighet. - + Anisotropic Filtering: Anisotropisk filtrering: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. Kontrollerar kvaliteten på texturrendering vid sneda vinklar. Det går att ställa in 16× på de flesta GPU:er. - + GPU Mode: GPU-läge: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. @@ -830,12 +820,12 @@ De flesta spel återges bra med Snabb, men Exakt krävs fortfarande för vissa. Partiklar återges ofta korrekt endast i läget Exakt. - + DMA Accuracy: DMA-noggrannhet: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. @@ -844,12 +834,12 @@ Osäker är snabbare, medan Säker är stabilare och kan lösa problem i vissa s Standard följer inställningen för GPU-noggrannhet. - + GPU Fence Behavior: Beteende för GPU-staket: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -862,44 +852,44 @@ Exakt förbättrar kompatibiliteten ytterligare, men på bekostnad av viss prest Standard följer inställningen för GPU-läge. - + Enable asynchronous shader compilation Aktivera asynkron shaderkompilering - + May reduce shader stutter. Kan minska shader-hackighet. - + GPU Clocks GPU-klockfrekvenser - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. Får spelet att tro att GPU-arbetet avslutas snabbare än det gör, så att det slutar sänka upplösning och ritaravstånd för att passa Switch-klockfrekvenserna. - + GPU Unswizzle GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. Accelererar avkodning av BCn 3D-texturer med hjälp av GPU-beräkningar. Inaktivera om du upplever krascher eller grafiska fel. - + GPU Unswizzle Max Texture Size Maximal texturstorlek för GPU Unswizzle - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. @@ -908,48 +898,48 @@ GPU är snabbare för medelstora och stora texturer, men CPU kan vara effektivar Justera detta för att hitta balansen mellan GPU-acceleration och CPU-överbelastning. - + GPU Unswizzle Stream Size Strömstorlek för GPU Unswizzle - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. Ställer in den maximala mängden texturdata (i MiB) som bearbetas per bildruta. Högre värden kan minska hackighet under texturinläsning men kan påverka bildrutans konsistens. - + GPU Unswizzle Chunk Size Chunk-storlek för GPU Unswizzle - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. Bestämmer antalet djupskivor som bearbetas i en enda sändning. Att öka detta kan förbättra genomströmningen på avancerade GPU:er, men kan orsaka TDR eller drivrutinstidsgränser på svagare hårdvara. - + Use Vulkan pipeline cache Använda Vulkan pipeline-cache - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. Aktiverar GPU-leverantörsspecifik pipeline-cache. Det här alternativet kan förbättra laddningstiden för shaders avsevärt i fall där Vulkan-drivrutinen inte lagrar pipeline-cache-filer internt. - + Enable Compute Pipelines (Intel Vulkan Only) Aktivera compute pipelines (endast Intel Vulkan) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. @@ -958,182 +948,182 @@ Denna inställning finns endast för Intels egna drivrutiner och kan orsaka kras Beräkningspipelines är alltid aktiverade på alla andra drivrutiner. - + Enable Reactive Flushing Aktivera Reactive Flushing - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Använder reaktiv rensning i stället för prediktiv rensning, vilket ger mer exakt minnessynkning. - + Sync to framerate of video playback Synkronisera med bildfrekvensen för videouppspelning - + Run the game at normal speed during video playback, even when the framerate is unlocked. Kör spelet i normal hastighet under videouppspelning, även när bildfrekvensen är upplåst. - + Barrier feedback loops Återkopplingsloopar för barriärer - + Improves rendering of transparency effects in specific games. Förbättrar renderingen av transparenseffekter i vissa spel. - + Enable buffer history Aktivera bufferthistorik - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. Aktiverar åtkomst till tidigare bufferttillstånd. Det här alternativet kan förbättra renderingskvaliteten och prestandakonsistensen i vissa spel. - + Fix bloom effects Korrigera bloom-effekter - + Removes bloom in Burnout. Tar bort bloom i Burnout. - + Extended Dynamic State Utökad dynamisk status - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. Kontrollerar antalet funktioner som kan användas i utökat dynamiskt tillstånd. Högre tillstånd möjliggör fler funktioner och kan öka prestandan, men kan orsaka ytterligare grafiska problem. - + Vertex Input Dynamic State Dynamiskt tillstånd för vertexinmatning - + Enables vertex input dynamic state feature for better quality and performance. Aktiverar funktionen för dynamiskt tillstånd för vertexinmatning för bättre kvalitet och prestanda. - + Sample Shading Provskuggning - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. Tillåter fragment-shadern att exekveras per prov i ett multisamplade fragment istället för en gång per fragment. Förbättrar grafikens kvalitet på bekostnad av prestanda. Högre värden förbättrar kvaliteten men försämrar prestandan. - + RNG Seed RNG-frö - + Controls the seed of the random number generator. Mainly used for speedrunning. Att kontrollera fröet till slumptalsgeneratorn. Används främst för speedrunning. - + Device Name Enhetsnamn - + The name of the console. Konsolens namn. - + Homebrew Args Homebrew-argument - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). Kommandoradsargument som skickas till homebrew vid start (t.ex. -noglsl). - + Custom RTC Date: Anpassat RTC-datum: - + This option allows to change the clock of the console. Can be used to manipulate time in games. Med det här alternativet kan du ändra klockan på konsolen. Kan användas för att manipulera tiden i spel. - + The number of seconds from the current unix time Antalet sekunder från aktuell Unix-tid - + Language: Språk: - + This option can be overridden when region setting is auto-select Det här alternativet kan åsidosättas när regioninställningen är automatiskt vald - + Region: Region: - + The region of the console. Konsolens region. - + Time Zone: Tidszon: - + The time zone of the console. Konsolens tidszon. - + Sound Output Mode: Ljudutmatningsläge: - + Console Mode: Konsolläge: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. @@ -1142,1026 +1132,1026 @@ Spel ändrar upplösning, detaljer och stödda kontroller beroende på denna ins Inställningen Handhållen kan förbättra prestandan för enklare system. - + Prompt for user profile on boot Fråga efter användarprofil vid uppstart - + Useful if multiple people use the same PC. Användbart om flera personer använder samma dator. - + Pause when not in focus Pausa när inte i fokus - + Pauses emulation when focusing on other windows. Pausar emulering när fokus är på andra fönster. - + Confirm before stopping emulation Bekräfta innan emuleringen stoppas - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. Åsidosätter frågor om att bekräfta att emuleringen ska avslutas. Om du aktiverar den hoppar du över sådana uppmaningar och avslutar emuleringen direkt. - + Hide mouse on inactivity Dölj musen vid inaktivitet - + Hides the mouse after 2.5s of inactivity. Döljer musen efter 2,5 sekunders inaktivitet. - + Check for updates Leta efter uppdateringar - + Whether or not to check for updates upon startup. Om uppdateringar ska sökas vid start eller inte. - + Enable Gamemode Aktivera Gamemode - + Force X11 as Graphics Backend Tvinga X11 som grafikbackend - + Custom frontend Anpassad frontend - + Real applet Verklig applet - - + + Disabled Inaktiverad - + Never Aldrig - + On Load Vid inläsning - + Always Alltid - + CPU CPU - + GPU GPU - + CPU Asynchronous CPU asynkron - + Uncompressed (Best quality) Okomprimerad (bästa kvalitet) - + BC1 (Low quality) BC1 (låg kvalitet) - + BC3 (Medium quality) BC3 (medelhög kvalitet) - - + + Auto Auto - + 30 FPS 30 bilder/s - + 60 FPS 60 bilder/s - + 90 FPS 90 bilder/s - + 120 FPS 120 bilder/s - + Conservative Konservativ - + Aggressive Aggressiv - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) OpenGL GLASM (Assembly Shaders, endast NVIDIA) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V (Experimentell, endast AMD/Mesa) - + Null Null - + Fast Snabb - - - + + + Accurate Exakt - - - + + + Default Standard - + Unsafe (fast) Osäker (snabb) - + Safe (stable) Säker (stabil) - + Immediate Omedelbar - + Balanced Balanserad - + Unsafe Inte säker - + Paranoid (disables most optimizations) Paranoid (inaktiverar de flesta optimeringar) - + Debugging Felsökning - + Dynarmic Dynarmisk - + NCE NCE - + Borderless Windowed Ramlöst fönsterläge - + Exclusive Fullscreen Exklusiv helskärm - + No Video Output Ingen videoutgång - + CPU Video Decoding CPU-videoavkodning - + GPU Video Decoding (Default) GPU videoavkodning (standard) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [EXPERIMENTELL] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [EXPERIMENTELL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [EXPERIMENTELL] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [EXPERIMENTELL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [EXPERIMENTELL] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Närmsta granne - + Bilinear Bilinjär - + Bicubic Bikubisk - + Gaussian Gaussisk - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX Super Resolution - + Area Område - + MMPX MMPX - + Zero-Tangent Zero-Tangent - + B-Spline B-Spline - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir Snapdragon Game Super Resolution EdgeDir - + None Ingen - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Standard (16:9) - + Force 4:3 Tvinga 4:3 - + Force 21:9 Tvinga 21:9 - + Force 16:10 Tvinga 16:10 - + Stretch to Window Sträck ut till fönster - + Automatic Automatiskt - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Japanska (日本語) - + American English Amerikansk engelska - + French (français) Franska (français) - + German (Deutsch) Tyska (Deutsch) - + Italian (italiano) Italienska (italiano) - + Spanish (español) Spanska (español) - + Chinese Kinesiska - + Korean (한국어) Koreanska (한국어) - + Dutch (Nederlands) Nederländska (Nederlands) - + Portuguese (português) Portugisiska (português) - + Russian (Русский) Ryska (Русский) - + Taiwanese Taiwanesiska - + British English Brittisk engelska - + Canadian French Kanadensisk franska - + Latin American Spanish Latinamerikansk spanska - + Simplified Chinese Förenklad kinesiska - + Traditional Chinese (正體中文) Traditionell kinesiska (正體中文) - + Brazilian Portuguese (português do Brasil) Brasiliansk portugisiska (português do Brasil) - + Polish (polska) Polska (polska) - + Thai (แบบไทย) Thai (แบบไทย) - - + + Japan Japan - + USA USA - + Europe Europa - + Australia Australien - + China Kina - + Korea Korea - + Taiwan Taiwan - + Auto (%1) Auto select time zone Auto (%1) - + Default (%1) Default time zone Standard (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Kuba - + EET EET - + Egypt Egypten - + Eire Irland - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Irland - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hongkong - + HST HST - + Iceland Island - + Iran Iran - + Israel Israel - + Jamaica Jamaica - + Kwajalein Kwajalein - + Libya Libyen - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Polen - + Portugal Portugal - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapore - + Turkey Turkiet - + UCT UCT - + Universal Universal - + UTC UTC - + W-SU W-SU - + WET VÅT - + Zulu Zulu - + Mono Mono - + Stereo Stereo - + Surround Surround - + 4GB DRAM (Default) 4 GB DRAM (standard) - + 6GB DRAM (Unsafe) 6 GB DRAM (osäker) - + 8GB DRAM 8 GB DRAM - + 10GB DRAM (Unsafe) 10 GB DRAM (osäker) - + 12GB DRAM (Unsafe) 12 GB DRAM (osäker) - + Docked Dockad - + Handheld Handhållen - - + + Normal Normal - - + + Boost Förstärk - - + + Overclock Överklocka - + Always ask (Default) Fråga alltid (standard) - + Only if game specifies not to stop Endast om spelet anger att det inte ska stoppas - + Never ask Fråga aldrig - + Very Small (16 MB) Mycket liten (16 MB) - + Small (32 MB) Liten (32 MB) - + Normal (128 MB) Normal (128 MB) - + Large (256 MB) Stor (256 MB) - + Very Large (512 MB) Mycket stor (512 MB) - + Very Low (4 MB) Mycket låg (4 MB) - + Low (8 MB) Låg (8 MB) - + Normal (16 MB) Normal (16 MB) - + Medium (32 MB) Medium (32 MB) - + High (64 MB) Hög (64 MB) - + Very Low (32) Mycket låg (32) - + Low (64) Låg (64) - + Normal (128) Normal (128) - + Medium (256) Medium (256) - + High (512) Hög (512) - + ExtendedDynamicState 1 ExtendedDynamicState 1 - + ExtendedDynamicState 2 ExtendedDynamicState 2 - + ExtendedDynamicState 3 ExtendedDynamicState 3 - + Tree View Trädvy - + Grid View Rutnätsvy @@ -6134,50 +6124,50 @@ Gå till Konfigurera -> System -> Nätverk och gör ett val. GRenderWindow - - + + OpenGL not available! OpenGL är inte tillgängligt! - + OpenGL shared contexts are not supported. Delade OpenGL-kontexter stöds inte. - + Eden has not been compiled with OpenGL support. Eden har inte kompilerats med OpenGL-stöd. - - - + + + Error while initializing OpenGL! Fel vid initiering av OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Din GPU kanske inte stöder OpenGL, eller så har du inte den senaste grafikdrivrutinen. - + Error while initializing OpenGL 4.6! Fel vid initiering av OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Din GPU kanske inte stöder OpenGL 4.6, eller så har du inte den senaste grafikdrivrutinen.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Din GPU kanske inte stöder ett eller flera av de nödvändiga OpenGL-tilläggen. Se till att du har den senaste grafikdrivrutinen.<br><br>GL Renderer:<br>%1<br><br>Tillägg som inte stöds:<br>%2 - + This build doesn't have OpenGL support. Den här versionen saknar stöd för OpenGL. @@ -6944,800 +6934,820 @@ Felsökningsmeddelande: &Emulering - + + &Cheats + &Fuskkoder + + + &View &Visa - + &Reset Window Size Å&terställ fönsterstorlek - + &Debugging &Felsökning - + &Game List Mode Läge för s&pellista - + Game &Icon Size Storlek för spel&ikon - + Reset Window Size to &720p Återställ fönsterstorlek till &720p - + Reset Window Size to 720p Återställ fönsterstorlek till 720p - + Reset Window Size to &900p Återställ fönsterstorlek till &900p - + Reset Window Size to 900p Återställ fönsterstorleken till 900p - + Reset Window Size to &1080p Återställ fönsterstorlek till &1080p - + Reset Window Size to 1080p Återställ fönsterstorleken till 1080p - + &Multiplayer &Flera spelare - + &Tools Ver&ktyg - + Am&iibo Am&iibo - + Launch &Applet Starta &applet - + &TAS &TAS - + &Create Home Menu Shortcut S&kapa genväg till startmenyn - + Install &Firmware Installera &firmware - + &Help &Hjälp - + &Install Files to NAND... &Installera filer till NAND… - + L&oad File... Läs &in fil… - + Load &Folder... Läs in &mapp… - + E&xit A&vsluta - - + + &Pause &Paus - + &Stop &Stoppa - + &Verify Installed Contents &Verifiera installerat innehåll - + &About Eden &Om Eden - + Single &Window Mode Enkelt &fönsterläge - + Con&figure... Kon&figurera… - + Ctrl+, Ctrl+, - + Enable Overlay Display Applet Aktivera applet för överläggsvisning - + Show &Filter Bar Visa &filterfält - + Show &Status Bar Visa &statusrad - + Show Status Bar Visa statusrad - + &Browse Public Game Lobby &Bläddra i offentlig spellobby - + &Create Room &Skapa rum - + &Leave Room &Lämna rummet - + &Direct Connect to Room &Direkt anslutning till rum - + &Show Current Room &Visa aktuellt rum - + F&ullscreen H&elskärm - + &Restart Starta o&m - + Load/Remove &Amiibo... Läs in/ta bort &Amiibo… - + Open &Mods Page Öppna &Mods-sidan - + &User Handbook &Användarhandbok - + &Capture Screenshot &Ta skärmdump - + &Album &Album - + &Set Nickname and Owner &Ange smeknamn och ägare - + &Delete Game Data &Radera speldata - + &Restore Amiibo Å&terställ Amiibo - + &Format Amiibo &Formatera Amiibo - + &Mii Editor &Mii-redigerare - + &Configure TAS... &Konfigurera TAS… - + Configure C&urrent Game... Konfigurera a&ktuellt spel… - - + + &Start &Starta - + &Reset Starta &om - - + + R&ecord Spela &in - + Open &Controller Menu Öppna &kontrollermenyn - + Install Decryption &Keys Installera avkrypteringsn&ycklar - + &Home Menu &Hemmeny - + &Desktop S&krivbord - + &Application Menu &Applikationsmeny - + &Root Data Folder &Rotdatamapp - + &NAND Folder &NAND-mapp - + &SDMC Folder &SDMC-mapp - + &Mod Folder &Mod-mapp - + &Log Folder &Loggmapp - + From Folder Från mapp - + From ZIP Från ZIP - + &Eden Dependencies &Edens beroenden - + &Data Manager &Datahanterare - + &Tree View &Trädvy - + &Grid View &Rutnätsvy - + Game Icon Size Storlek för spelikon - - + + None Ingen - + Show Game &Name Visa spel&namn - + Show &Performance Overlay Visa &prestandaöverlägg - + Post-Processing &Shaders... Efterbearbetning och &skuggning… - + &Carousel View &Karusellvy - + Small (32x32) Liten (32x32) - + Standard (64x64) Standard (64x64) - + Large (128x128) Stor (128x128) - + Full Size (256x256) Full storlek (256x256) - + Broken Vulkan Installation Detected Felaktig Vulkan-installation upptäcktes - + Vulkan initialization failed during boot. Vulkan-initialiseringen misslyckades under uppstarten. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping Kör ett spel - + Loading Web Applet... Läser in webbapplet… - - + + Disable Web Applet Inaktivera webbapplet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) Att inaktivera webbappletten kan leda till odefinierat beteende och bör endast användas med Super Mario 3D All-Stars. Är du säker på att du vill inaktivera webbappletten? (Detta kan återaktiveras i felsökningsinställningarna.) - + The amount of shaders currently being built Antalet shaders som för närvarande byggs - + The current selected resolution scaling multiplier. Den aktuella valda multiplikatorn för upplösningsskalning. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Aktuell emuleringshastighet. Värden högre eller lägre än 100 % indikerar att emuleringen körs snabbare eller långsammare än en Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Hur många bildrutor per sekund spelet för närvarande visar. Detta varierar från spel till spel och från scen till scen. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tid som krävs för att emulera en Switch-bildruta, exklusive bildbegränsning eller v-synkronisering. För emulering i full hastighet bör detta vara högst 16,67 ms. - + Unmute Aktivera ljud - + Mute Tyst - + Reset Volume Återställ volym - + Configure Effects... Konfigurera effekter… - + &Clear Recent Files &Töm tidigare filer - + + Disable All Cheats + Inaktivera alla fuskkoder + + + + Enable All Cheats + Aktivera alla fuskkoder + + + + Unnamed Cheat + Namnlös fuskkod + + + &Continue &Fortsätt - + Warning: Outdated Game Format Varning: Föråldrat spelformat - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. Du använder det dekonstruerade ROM-katalogformatet för detta spel, vilket är ett föråldrat format som har ersatts av andra format såsom NCA, NAX, XCI eller NSP. Dekonstruerade ROM-kataloger saknar ikoner, metadata och uppdateringsstöd.<br> För en förklaring av de olika Switch-format som Eden har stöd för, se vår användarhandbok. Detta meddelande kommer inte att visas igen. - - + + Error while loading ROM! Fel vid inläsning av ROM! - + The ROM format is not supported. ROM-formatet stöds inte. - + An error occurred initializing the video core. Ett fel uppstod vid initialiseringen av videokärnan. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. Detta orsakas vanligtvis av inaktuella grafikdrivrutiner. Se loggen för mer information. Se: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>Så här kommer du åt loggfiler</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. Fel vid inläsning av ROM! %1 - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. %1<br>Dumpa dina filer igen eller fråga på Discord/Stoat för hjälp. - + An unknown error occurred. Please see the log for more details. Ett okänt fel har uppstått. Se loggen för mer information. - - + + (64-bit) (64-bitar) - - + + (32-bit) (32-bitar) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - + Closing software... Stänger programvara… - + Save Data Sparat data - + Mod Data Mod-data - + Error Opening %1 Folder Fel vid öppning av mappen %1 - - + + Folder does not exist! Mappen finns inte! - + Remove Installed Game Contents? Ta bort installerat spelinnehåll? - + Remove Installed Game Update? Ta bort installerad speluppdatering? - + Remove Installed Game DLC? Ta bort installerat spel-DLC? - + Remove Entry Ta bort post - + Delete OpenGL Transferable Shader Cache? Ta bort OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? Ta bort Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? Ta bort alla Transferable Shader Caches? - + Remove Custom Game Configuration? Ta bort anpassad spelkonfiguration? - + Remove Cache Storage? Ta bort cachelagring? - + Remove File Ta bort fil - + Remove Play Time Data Ta bort data om speltid - + Reset play time? Nollställ speltid? - - + + RomFS Extraction Failed! Extrahering av RomFS misslyckades! - + There was an error copying the RomFS files or the user cancelled the operation. Det uppstod ett fel vid kopieringen av RomFS-filerna eller så avbröt användaren åtgärden. - + Full Fullständigt - + Skeleton Skelett - + Select RomFS Dump Mode Välj dumpläge för RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Välj hur du vill att RomFS ska dumpas. <br>Fullständigt kopierar alla filer till den nya katalogen, medan <br>skelett endast skapar katalogstrukturen. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root Det finns inte tillräckligt med ledigt utrymme på %1 för att extrahera RomFS. Frigör utrymme eller välj en annan dumpkatalog under Emulering > Konfigurera > System > Filsystem > Dumprot - + Extracting RomFS... Extraherar RomFS… - - + + Cancel Avbryt - + RomFS Extraction Succeeded! Extrahering av RomFS lyckades! - + The operation completed successfully. Operationen slutfördes. - + Error Opening %1 Fel vid öppning av %1 - + Select Directory Välj katalog - + Properties Egenskaper - + The game properties could not be loaded. Spelegenskaperna kunde inte läsas in. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Körbar Switch-fil (%1);;Alla filer (*.*) - + Load File Läs in fil - + Open Extracted ROM Directory Öppna katalog för extraherad ROM - + Invalid Directory Selected Ogiltig katalog valdes - + The directory you have selected does not contain a 'main' file. Den katalog du har valt innehåller ingen ”main”-fil. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - Installerbar Switch-fil (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) + Installerbar Switch-fil(*.nca*.nsp*.nsz*.xci*.xcz);;Nintendo Content Archive(*.nca);;Nintendo Submission Package(*.nsp*.nsz);;NX Cartridge Image(*.xci*.xcz); - + Install Files Installera filer - + %n file(s) remaining %n fil återstår%n filer återstår - + Installing file "%1"... Installerar filen "%1"… - - + + Install Results Installationsresultat - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. För att undvika eventuella konflikter avråder vi användare från att installera basspel på NAND. Använd endast denna funktion för att installera uppdateringar och DLC. - + %n file(s) were newly installed %n ny fil installerades @@ -7745,7 +7755,7 @@ Använd endast denna funktion för att installera uppdateringar och DLC. - + %n file(s) were overwritten %n fil skrevs över @@ -7753,7 +7763,7 @@ Använd endast denna funktion för att installera uppdateringar och DLC. - + %n file(s) failed to install %n fil gick inte att installera @@ -7761,324 +7771,324 @@ Använd endast denna funktion för att installera uppdateringar och DLC. - + System Application Systemapplikation - + System Archive Systemarkiv - + System Application Update Uppdatering för systemapplikation - + Firmware Package (Type A) Firmware-paket (Type A) - + Firmware Package (Type B) Firmware-paket (Type B) - + Game Spel - + Game Update Speluppdatering - + Game DLC DLC för spel - + Delta Title Deltatitel - + Select NCA Install Type... Välj NCA-installationstyp… - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Välj vilken typ av titel du vill installera denna NCA som: (I de flesta fall är standardinställningen ”Spel” tillräcklig.) - + Failed to Install Misslyckades med att installera - + The title type you selected for the NCA is invalid. Den titeltypen du valt för NCA är ogiltig. - + File not found Filen hittades inte - + File "%1" not found Filen "%1" hittades inte - + OK Ok - + Function Disabled Funktion inaktiverad - + Compatibility list reporting is currently disabled. Check back later! Rapportering till kompatibilitetslistan är för närvarande inaktiverad. Kom tillbaka senare! - + Error opening URL Fel vid öppning av URL - + Unable to open the URL "%1". Det går inte att öppna URL:en ”%1”. - + TAS Recording TAS-inspelning - + Overwrite file of player 1? Skriv över fil för spelare 1? - + Invalid config detected Ogiltig konfiguration upptäcktes - + Handheld controller can't be used on docked mode. Pro controller will be selected. Handhållen kontroller kan inte användas i dockat läge. Pro-kontrollern kommer att väljas. - - + + Amiibo Amiibo - - + + The current amiibo has been removed Den aktuella amiibo har tagits bort - + Error Fel - - + + The current game is not looking for amiibos Det aktuella spelet letar inte efter amiibos - + Amiibo File (%1);; All Files (*.*) Amiibo-fil (%1);; Alla filer (*.*) - + Load Amiibo Läs in Amiibo - + Error loading Amiibo data Fel vid läsning av Amiibo-data - + The selected file is not a valid amiibo Den valda filen är inte en giltig amiibo - + The selected file is already on use Den valda filen används redan - + An unknown error occurred Ett okänt fel uppstod - + No firmware available Ingen firmware tillgänglig - + Firmware Corrupted Firmware är skadat - + Unknown applet Okänd applet - + Applet doesn't map to a known value. Appleten mappar inte till ett känt värde. - + Record not found Posten hittades inte - + Applet not found. Please reinstall firmware. Appleten hittades inte. Installera om fast programvara. - + Capture Screenshot Ta skärmbild - + PNG Image (*.png) PNG-bild (*.png) - + TAS state: Running %1/%2 TAS-tillstånd: Kör %1/%2 - + TAS state: Recording %1 TAS-tillstånd: Spelar in %1 - + TAS state: Idle %1/%2 TAS-tillstånd: Overksam %1/%2 - + TAS State: Invalid TAS-tillstånd: Ogiltig - + &Stop Running &Stoppa körning - + Stop R&ecording Stoppa i&nspelning - + Building: %n shader(s) Bygger: %n shaderBygger: %n shaders - + Scale: %1x %1 is the resolution scaling factor Skala: %1x - + Speed: %1% / %2% Hastighet: %1 % / %2 % - + Speed: %1% Hastighet: %1 % - + Game: %1 FPS Spel: %1 bilder/s - + Frame: %1 ms Bildruta: %1 ms - + NO AA NO AA - + NO FX INGA FX - + FX FX - + VOLUME: MUTE VOLYM: TYST - + VOLUME: %1% Volume percentage (e.g. 50%) VOLYM: %1 % - + Derivation Components Missing Deriveringskomponenter saknas - + Decryption keys are missing. Install them now? Avkrypteringsnycklar saknas. Installera dem nu? - + Wayland Detected! Wayland upptäcktes! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8089,74 +8099,74 @@ Det rekommenderas att använda X11 istället. Vill du tvinga det för framtida starter? - + Use X11 Använd X11 - + Continue with Wayland Fortsätt med Wayland - + Don't show again Visa inte igen - + Restart Required Omstart krävs - + Restart Eden to apply the X11 backend. Starta om Eden för att tillämpa X11-backend. - + Slow Långsam - + Turbo Turbo - + Unlocked Upplåst - + Select RomFS Dump Target Välj RomFS-dumpmål - + Please select which RomFS you would like to dump. Välj vilken RomFS du vill dumpa. - + Are you sure you want to close Eden? Är du säker på att du vill stänga Eden? - - - + + + Eden Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Är du säker på att du vill stoppa emuleringen? Alla osparade framsteg kommer att gå förlorade. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/tr_TR.ts b/dist/languages/tr_TR.ts index b63445c3fb..e1385eb8a6 100644 --- a/dist/languages/tr_TR.ts +++ b/dist/languages/tr_TR.ts @@ -37,8 +37,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Web Sitesi</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Kaynak Kodu</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Katkıda Bulunanlar</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Lisans</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -410,49 +410,59 @@ Can help reduce stuttering at lower framerates. Düşük kare hızlarında takılmaları azaltmaya yardımcı olabilir. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Doğruluk: - + Change the accuracy of the emulated CPU (for debugging only). Öykünülen, yani emüle edilen CPU'nun doğruluk seviyesini değiştirir (yalnızca hata ayıklama için). - - + + Backend: Arkayüz: - + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks Özel İşlemci Döngüleri - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. İşlemci/CPU tick hızı için özel bir değer belirleyin. Daha yüksek değerler performansı artırabilir, ancak kilitlenmelere de neden olabilir. 77-21000 aralığı tavsiye edilir. - + Enable Host MMU Emulation (fastmem) Ana Bilgisayar MMU Emülasyonunu Etkinleştir (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -461,158 +471,158 @@ Bunu etkinleştirmek, misafir bellek okuma/yazma işlemlerinin doğrudan belleğ Bunu devre dışı bırakmak, tüm bellek erişimlerinin, Yazılımsal MMU Emülasyonu kullanmaya zorlamasına neden olur. - + Unfuse FMA (improve performance on CPUs without FMA) FMA'yı Ayır (FMA olmayan CPU'larda performansı artırır) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Bu seçenek, gömülü/yerel FMA desteği olmayan CPU'larda, FMA komutlarının doğruluğunu/hassasiyetini düşürerek hızı artırır. - + Faster FRSQRTE and FRECPE Daha hızlı FRSQRTE ve FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Bu seçenek, daha az doğru olan gömülü/yerel yaklaşıklıkları kullanarak, bazı yaklaşık floating-point işlevlerinin hızını artırır. - + Faster ASIMD instructions (32 bits only) Daha hızlı ASIMD komutları (yalnızca 32 bit) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Bu seçenek, incorrect durumdaki rounding mode'ları ile çalıştırarak 32 bit ASIMD floating-point işlevlerinin hızını artırır. - + Inaccurate NaN handling Uygunsuz NaN kullanımı - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Bu seçenek, NaN denetimini kaldırarak hızı artırır. Lütfen unutmayın, bu aynı zamanda bazı floating-point işlemlerinin doğruluğunu azaltır. - + Disable address space checks Adres boşluğu kontrolünü kapatır. - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. Bu seçenek, her bellek işleminden önce bir güvenlik kontrolünü kaldırarak hızı artırır. Devre dışı bırakılması, rastgele kod yürütülmesine izin verebilir. - + Ignore global monitor Global monitörü görmezden gel - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Bu seçenek, özel erişim talimatlarının güvenliğini sağlamak için yalnızca cmpxchg semantiğine güvenerek hızı artırır. Lütfen bunun kilitlenmelere ve diğer yarış durumlarına neden olabileceğini unutmayın. - + API: API: - + Changes the output graphics API. Vulkan is recommended. Çıkış grafik API'sini değiştirir. Vulkan önerilir. - + Device: Cihaz: - + This setting selects the GPU to use (Vulkan only). Bu ayar, kullanılacak GPU'yu seçer (yalnızca Vulkan). - + Resolution: Çözünürlük: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. Farklı bir çözünürlükte işleme yapmaya zorlar. Yüksek çözünürlükler daha fazla VRAM ve bant genişliği gerektirir. 1X'ten düşük seçenekler yapay bozulmalara neden olabilir. - + Window Adapting Filter: Pencereye Uyarlı Filtre: - + FSR Sharpness: FSR Keskinliği: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Kenar Yumuşatma Yöntemi: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. Kullanılacak kenar yumuşatma yöntemi. SMAA en iyi kaliteyi sunar. FXAA, düşük çözünürlüklerde daha kararlı bir görüntü oluşturabilir. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Tam Ekran Modu: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. Pencereyi tam ekranda işlemek için kullanılan yöntem. Sınırsız, bazı oyunların giriş için istediği ekran klavyesi ile en iyi uyumluluğu sunar. Özel tam ekran, daha iyi performans ve daha iyi Freesync/Gsync desteği sağlayabilir. - + Aspect Ratio: En-Boy Oranı: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -621,46 +631,46 @@ Also controls the aspect ratio of captured screenshots. Ayrıca, yakalanan ekran görüntülerinin en-boy oranını da kontrol eder. - + Use persistent pipeline cache Kalıcı işlem hattı önbelleğini kullan - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Gölgelendiriclerin sonraki oyun açılışlarında daha hızlı yüklenmesi için depolama alanına kaydedilmesine olanak tanır. Devre dışı bırakılması yalnızca hata ayıklama amaçlıdır. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: NVDEC emülasyonu: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. Videoların nasıl çözüleceğini belirtir. Kod çözme için CPU veya GPU kullanabilir veya hiç kod çözme işlemi yapmayabilir (videolarda siyah ekran). Çoğu durumda GPU ile kod çözme en iyi performansı sağlar. - + ASTC Decoding Method: ASTC Kod Çözme Yöntemi - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -669,75 +679,55 @@ stuttering but may present artifacts. Bu seçenek ASTC dokularının nasıl çözüleceğini kontrol eder. CPU: Kod çözme için işlemciyi kullanır. GPU: ASTC dokularını çözmek için GPU'nun hesaplama gölgelendiricilerini kullanır (önerilir). CPU Asenkron: ASTC dokularını talep üzerine çözmek için işlemciyi kullanır. ASTC kod çözme kaynaklı takılmaları giderir ancak görsel bozulmalara neden olabilir. - + ASTC Recompression Method: ASTC Yeniden Sıkıştırma Yöntemi - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. Çoğu GPU, ASTC dokuları için doğrudan desteğe sahip değildir ve bir ara formata (RGBA8) açılmalıdır. BC1/BC3: Ara format BC1 veya BC3 formatında yeniden sıkıştırılarak VRAM tasarrufu sağlar ancak görüntü kalitesini düşürür. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: VRAM Kullanım Modu - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. Emülatörün belleği korumayı mı yoksa performans için mevcut video belleğini maksimum düzeyde kullanmayı mı tercih edeceğini seçer. Agresif mod, kayıt yazılımları gibi diğer uygulamaların performansını etkileyebilir. - + Skip CPU Inner Invalidation CPU Geçersiz Kılma'yı Atla - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. Bellek güncellemeleri sırasında belirli önbellek geçersiz kılma işlemlerini atlayarak işlemci kullanımını azaltır ve gecikmeyi iyileştirir. Bu, hafif çökmelere neden olabilir. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: VSync Modu: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -745,79 +735,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te FIFO (VSync) kare düşürmez veya yırtılma göstermez ancak ekran yenileme hızıyla sınırlıdır. FIFO Relaxed, yavaşlamadan toparlanırken yırtılmaya izin verir. Mailbox, FIFO'dan daha düşük gecikmeye sahip olabilir ve yırtılma yapmaz ancak kare düşürebilir. Immediate (senkronizasyon yok), mevcut olanı anında sunar ve yırtılmalara neden olabilir. - + Sync Memory Operations Bellek İşlemlerini Senkronize Et - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. Hesaplama ve bellek işlemleri arasında veri tutarlılığı sağlar. Bu seçenek oyunlardaki sorunları giderir ancak performansı düşürebilir. Unreal Engine 4 oyunları genellikle bundan en önemli ölçüde etkilenenlerdir. - + Enable asynchronous presentation (Vulkan only) Asenkron sunumu etkinleştir (Yalnızca Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. Sunum işlemini ayrı bir işlemci iş parçacığına taşıyarak performansı biraz artırır. - + Force maximum clocks (Vulkan only) En yüksek hızı zorla (Yalnızca Vulkan için) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Grafik komutlarını beklerken GPU'nun hızının düşmesini engellemek için arka planda görev yürütür - + Anisotropic Filtering: Anisotropic Filtering: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. Eğik açılardaki doku oluşturma kalitesini kontrol eder. Çoğu grafik kartında 16x olarak ayarlanması güvenlidir. - + GPU Mode: Grafik Kartı Modu - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: DMA Doğruluğu: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -826,1291 +816,1291 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation Asenkron gölgelendirici derlemeyi etkinleştir - + May reduce shader stutter. Gölgelendirici/shader takılmalarını azaltabilir. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache Vulkan pipeline önbelleği kullan - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. Grafik kartı üreticisine özel işlem hattı önbelleğini etkinleştirir. Bu seçenek, Vulkan sürücüsünün işlem hattı önbellek dosyalarını dahili olarak saklamadığı durumlarda gölgelendirici yükleme süresini önemli ölçüde iyileştirebilir. - + Enable Compute Pipelines (Intel Vulkan Only) Hesaplama İşlem Hatlarını Etkinleştir (Yalnızca Intel Vulkan) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. Bazı oyunlar için gereklidir. Bu ayar yalnızca Intel'in tescilli sürücüleri için mevcuttur ve etkinleştirilirse çökmeye neden olabilir. Hesaplama işlem hatları diğer tüm sürücülerde her zaman etkindir. - + Enable Reactive Flushing Reaktif Temizlemeyi Etkinleştir - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Tahminli temizleme yerine reaktif temizleme kullanarak daha doğru bellek senkronizasyonu sağlar. - + Sync to framerate of video playback Video oynatma kare hızına senkronize et - + Run the game at normal speed during video playback, even when the framerate is unlocked. Kare hızı kilidi açık olsa bile video oynatımı sırasında oyunu normal hızda çalıştırır. - + Barrier feedback loops Bariyer geri besleme döngüleri - + Improves rendering of transparency effects in specific games. Belirli oyunlarda şeffaflık efektlerinin oluşturulmasını iyileştirir. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State Genişletilmiş Dinamik Durum - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. Genişletilmiş Dinamik Durumda kullanılabilecek özelliklerin sayısını kontrol eder. Daha yüksek durumlar daha fazla özelliğe izin verir ve performansı artırabilir, ancak ek grafik sorunlarına neden olabilir. - + Vertex Input Dynamic State Vertex Dinamik Durumu - + Enables vertex input dynamic state feature for better quality and performance. Daha iyi kalite ve performans için Vertex dinamik durum özelliğini etkinleştirir. - + Sample Shading Örnek Gölgelendirme - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. Parça gölgelendiricinin, her parça için bir kez yerine çoklu örneklenmiş bir parçadaki her örnek için yürütülmesine olanak tanır. Performans pahasına grafik kalitesini artırır. Daha yüksek değerler kaliteyi artırır ancak performansı düşürür. - + RNG Seed RNG çekirdeği - + Controls the seed of the random number generator. Mainly used for speedrunning. Rastgele sayı üretecinin tohumunu kontrol eder. Esas olarak hızlı bitirme denemeleri için kullanılır. - + Device Name Cihaz İsmi - + The name of the console. Konsolun adı - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: Özel RTC Tarihi - + This option allows to change the clock of the console. Can be used to manipulate time in games. Bu seçenek konsolun saatini değiştirmeye olanak tanır. Oyunlarda zamanı manipüle etmek için kullanılabilir. - + The number of seconds from the current unix time Mevcut unix zamanından itibaren saniye sayısı - + Language: Dil: - + This option can be overridden when region setting is auto-select Bölge ayarı otomatik seçim olduğunda bu seçenek geçersiz kılınabilir. - + Region: Bölge: - + The region of the console. Konsolun bölgesi - + Time Zone: Saat Dilimi: - + The time zone of the console. Konsolun saat dilimi - + Sound Output Mode: Ses Çıkış Modu: - + Console Mode: Konsol Modu: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. Konsolun Yerleşik veya El Modunda olup olmadığını seçer. Oyunlar bu ayara bağlı olarak çözünürlüklerini, detaylarını ve desteklenen kontrolcülerini değiştirecektir. El Moduna ayarlamak, düşük seviyeli sistemler için performansı artırmaya yardımcı olabilir. - + Prompt for user profile on boot Açılışta kullanıcı profili için sor - + Useful if multiple people use the same PC. Aynı bilgisayarı birden fazla kişi kullanıyorsa yararlıdır. - + Pause when not in focus Odaklı değilken duraklat - + Pauses emulation when focusing on other windows. Diğer pencerelere odaklanıldığında emülasyonu duraklatır. - + Confirm before stopping emulation Emülasyonu durdurmadan önce onayla - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. Emülasyonu durdurma onayı isteklerini/istemlerini geçersiz kılar. Etkinleştirildiğinde, bu tür istekleri/istemleri atlar ve emülasyonu doğrudan/dirket olarak kapatır. - + Hide mouse on inactivity Hareketsizlik durumunda imleci gizle - + Hides the mouse after 2.5s of inactivity. 2,5 saniye hareketsizlikten sonra fareyi gizler. - + Check for updates Güncellemeleri Kontrol Et - + Whether or not to check for updates upon startup. Başlangıçta güncellemelerin kontrol edilip edilmeyeceği. - + Enable Gamemode Oyun Modunu/Gamemode Etkinleştir - + Force X11 as Graphics Backend Grafik arka ucu olarak X11'i zorla - + Custom frontend Özel ön yüz - + Real applet Gerçek aplikasyon - - + + Disabled Devre Dışı - + Never Asla - + On Load Yüklemede - + Always Her zaman - + CPU CPU - + GPU GPU - + CPU Asynchronous Asenkron CPU - + Uncompressed (Best quality) Sıkıştırılmamış (En iyi kalite) - + BC1 (Low quality) BC1 (Düşük kalite) - + BC3 (Medium quality) BC3 (Orta kalite) - - + + Auto Otomatik - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative Muhafazakar - + Aggressive Agresif - + Vulkan Vulkan - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null Boş - + Fast Hızlı - - - + + + Accurate Doğru - - - + + + Default Varsayılan - + Unsafe (fast) Güvenli Değil (hızlı) - + Safe (stable) Güvenli (Stabil) - + Immediate - + Balanced Dengeli - + Unsafe Güvensiz - + Paranoid (disables most optimizations) Paranoya (çoğu optimizasyonu kapatır) - + Debugging Hata ayıklama - + Dynarmic Dinamik - + NCE NCE - + Borderless Windowed Kenarlıksız Tam Ekran - + Exclusive Fullscreen Ayrılmış Tam Ekran - + No Video Output Video Çıkışı Yok - + CPU Video Decoding CPU Video Decoding - + GPU Video Decoding (Default) GPU Video Decoding (Varsayılan) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [DENEYSEL] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [DENEYSEL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [DENEYSEL] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [DENEYSEL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [DENEYSEL] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor En Yakın Komşu Algoritması - + Bilinear Bilinear - + Bicubic Bicubic - + Gaussian Gausyen - + Lanczos Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX Süper Çözünürlük - + Area Area - + MMPX MMPX - + Zero-Tangent Zero-Tangent - + B-Spline B-Spline - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Yok - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Varsayılan (16:9) - + Force 4:3 4:3'e Zorla - + Force 21:9 21:9'a Zorla - + Force 16:10 16:10'a Zorla - + Stretch to Window Ekrana Sığdır - + Automatic Otomatik - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Japonca (日本語) - + American English Amerikan İngilizcesi - + French (français) Fransızca (français) - + German (Deutsch) Almanca (Deutsch) - + Italian (italiano) İtalyanca (italiano) - + Spanish (español) İspanyolca (español) - + Chinese Çince - + Korean (한국어) Korece (한국어) - + Dutch (Nederlands) Flemenkçe (Nederlands) - + Portuguese (português) Portekizce (português) - + Russian (Русский) Rusça (Русский) - + Taiwanese Tayvanca - + British English İngiliz İngilizcesi - + Canadian French Kanada Fransızcası - + Latin American Spanish Latin Amerika İspanyolcası - + Simplified Chinese Basitleştirilmiş Çince - + Traditional Chinese (正體中文) Geleneksel Çince (正體中文) - + Brazilian Portuguese (português do Brasil) Brezilya Portekizcesi (português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan Japonya - + USA ABD - + Europe Avrupa - + Australia Avustralya - + China Çin - + Korea Kore - + Taiwan Tayvan - + Auto (%1) Auto select time zone Otomatik (%1) - + Default (%1) Default time zone Varsayılan (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Küba - + EET EET - + Egypt Mısır - + Eire İrlanda - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-İrlanda - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 MT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hong Kong - + HST HST - + Iceland İzlanda - + Iran İran - + Israel İsrail - + Jamaica Jamaika - + Kwajalein Kwajalein - + Libya Libya - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navaho - + NZ Yeni Zelanda - + NZ-CHAT Chatham Adaları - + Poland Polonya - + Portugal Portekiz - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapur - + Turkey Türkiye - + UCT UCT - + Universal Evrensel - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Stereo - + Surround Surround - + 4GB DRAM (Default) 4GB DRAM (Varsayılan) - + 6GB DRAM (Unsafe) 6GB DRAM (Güvenli Değil) - + 8GB DRAM 8GB DRAM - + 10GB DRAM (Unsafe) 10GB DRAM (Güvenli Değil) - + 12GB DRAM (Unsafe) 12GB DRAM (Güvenli Değil) - + Docked Dock Modu Aktif - + Handheld Taşınabilir - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) Her zaman sor (Varsayılan) - + Only if game specifies not to stop Sadece oyun durdurulmamasını belirtirse - + Never ask Asla sorma - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) Orta (256) - + High (512) Yüksek (512) - + ExtendedDynamicState 1 Genişletilmiş Dinamik Durum 1 - + ExtendedDynamicState 2 Genişletilmiş Dinamik Durum 2 - + ExtendedDynamicState 3 Genişletilmiş Dinamik Durum 3 - + Tree View - + Grid View @@ -6073,50 +6063,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL kullanıma uygun değil! - + OpenGL shared contexts are not supported. OpenGL paylaşılan bağlam desteklenmiyor. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! OpenGl başlatılırken bir hata oluştu! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. GPU'nuz OpenGL desteklemiyor veya güncel bir grafik sürücüsüne sahip değilsiniz. - + Error while initializing OpenGL 4.6! OpenGl 4.6 başlatılırken bir hata oluştu! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 GPU'nuz OpenGL 4.6'yı desteklemiyor veya güncel bir grafik sürücüsüne sahip değilsiniz.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 GPU'nuz gereken bir yada daha fazla OpenGL eklentisini desteklemiyor Lütfen güncel bir grafik sürücüsüne sahip olduğunuzdan emin olun.<br><br>GL Renderer:<br>%1<br><br> Desteklenmeyen Eklentiler:<br>%2 - + This build doesn't have OpenGL support. @@ -6882,1132 +6872,1152 @@ Debug Message: &Emülasyon - + + &Cheats + + + + &View &Görünüm - + &Reset Window Size &Pencere Boyutunu Sıfırla - + &Debugging &Hata Ayıklama - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p Pencere Boyutunu &720p'ye Sıfırla - + Reset Window Size to 720p Pencere Boyutunu 720p'ye Sıfırla - + Reset Window Size to &900p Pencere Boyutunu &900p'ye Sıfırla - + Reset Window Size to 900p Pencere Boyutunu 900p'ye Sıfırla - + Reset Window Size to &1080p Pencere Boyutunu &1080p'ye Sıfırla - + Reset Window Size to 1080p Pencere Boyutunu 1080p'ye Sıfırla - + &Multiplayer &Çok Oyunculu - + &Tools &Aletler - + Am&iibo - + Launch &Applet - + &TAS &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help &Yardım - + &Install Files to NAND... &NAND'e Dosya Kur... - + L&oad File... &Dosyayı Yükle... - + Load &Folder... &Klasörü Yükle... - + E&xit &Çıkış - - + + &Pause &Duraklat - + &Stop Du&rdur - + &Verify Installed Contents &Kurulu İçerikleri Onayla - + &About Eden - + Single &Window Mode &Tek Pencere Modu - + Con&figure... &Yapılandır... - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar &Filtre Çubuğu'nu Göster - + Show &Status Bar &Durum Çubuğu'nu Göster - + Show Status Bar Durum Çubuğunu Göster - + &Browse Public Game Lobby &Herkese Açık Oyun Lobilerine Göz At - + &Create Room &Oda Oluştur - + &Leave Room &Odadan Ayrıl - + &Direct Connect to Room &Odaya Direkt Bağlan - + &Show Current Room &Şu Anki Odayı Göster - + F&ullscreen &Tam Ekran - + &Restart &Yeniden Başlat - + Load/Remove &Amiibo... &Amiibo Yükle/Kaldır - + Open &Mods Page &Mod Sayfasını Aç - + &User Handbook - + &Capture Screenshot &Ekran Görüntüsü Al - + &Album - + &Set Nickname and Owner - + &Delete Game Data - + &Restore Amiibo - + &Format Amiibo - + &Mii Editor - + &Configure TAS... &TAS'i Ayarla... - + Configure C&urrent Game... &Geçerli Oyunu Yapılandır... - - + + &Start B&aşlat - + &Reset &Sıfırla - - + + R&ecord K&aydet - + Open &Controller Menu - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected Bozuk Vulkan Kurulumu Algılandı - + Vulkan initialization failed during boot. Açılış sırasında Vulkan başlatma işlemi başarısız oldu. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping Bir oyun çalıştırılıyor - + Loading Web Applet... Web Uygulaması Yükleniyor... - - + + Disable Web Applet Web Uygulamasını Devre Dışı Bırak - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute Sesi aç - + Mute Sessize al - + Reset Volume Sesi Sıfırla - + Configure Effects... - + &Clear Recent Files &Son Dosyaları Temizle - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL URL açılırken hata oluştu - + Unable to open the URL "%1". - + TAS Recording TAS İşlemi Kaydı - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo Amiibo - - + + The current amiibo has been removed Mevcut Amiibo kaldırıldı - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted Donanım Yazılımı/Firmware Bozuk - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 TAS durumu: %1/%2 Çalışıyor - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor Ölçek: %1x - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8015,74 +8025,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/uk.ts b/dist/languages/uk.ts index fd166bc4f9..f29d550b84 100644 --- a/dist/languages/uk.ts +++ b/dist/languages/uk.ts @@ -37,8 +37,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Вебсайт</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Вихідний код</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Автори</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Ліцензія</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -411,50 +411,60 @@ Can help reduce stuttering at lower framerates. Може зменшити затримки при низькій частоті кадрів. - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: Точність: - + Change the accuracy of the emulated CPU (for debugging only). Змінює точність емульованого ЦП (лише для зневадження) - - + + Backend: Бекенд: - + CPU Clocks Тактові частоти ЦП - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. Збільшує тактову частоту, про яку повідомляє емульований ЦП, завдяки чому прибираються деякі обмеження частоти кадрів. На слабших ЦП це може спричинити зменшення продуктивності, а деякі ігри можуть неправильно відтворюватися. - + Custom CPU Ticks Користувацькі такти ЦП - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. Налаштування власного значення тактів ЦП. Більші значення можуть збільшити продуктивність, але також можуть спричинити блокування. Рекомендовані значення в діапазоні 77–21000. - + Enable Host MMU Emulation (fastmem) Увімкнути емуляцію MMU хоста (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -463,100 +473,100 @@ Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) Не використовувати FMA (покращує продуктивність на ЦП без FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. Це налаштування покращує швидкість завдяки зменшенню точності виконання операцій множення й складання з окрегленням на ЦП без вбудованої підтримки FMA. - + Faster FRSQRTE and FRECPE Швидші FRSQRTE та FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. Це налаштування покращує швидкість виконання деяких приблизних функцій із рухомою комою завдяки використанню менш точних вбудованих приближеннях. - + Faster ASIMD instructions (32 bits only) Швидші інструкції ASIMD (лише 32 біти) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. Це налаштування покращує швидкість виконання 32 бітових функцій ASIMD із рухомою комою завдяки використанню неправильних режиміс округлення. - + Inaccurate NaN handling Неточна обробка NaN - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. Це налаштування покращує швидкість завдяки вилученню перевірки NaN. Зверніть увагу, що також це зменшує точність виконання певних інструкцій із рухомою комою. - + Disable address space checks Вимкнути перевірки адресного простору - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. Це налаштування покращує швидкість завдяки вимкненню перевірок безпеки перед операціями з пам’яттю. Вимкнення може дозволити грі виконувати довільний код. - + Ignore global monitor Ігнорувати глобальний моніторинг - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. Це налаштування покращує швидкість завдяки покладанню лише на семантику cmpxchg, щоб забезпечити безпеку інструкцій ексклюзивного доступу. Зверніть увагу, що це може спричинити взаємне блокування або інші умови змагання даних. - + API: API: - + Changes the output graphics API. Vulkan is recommended. Змінює API виведення графіки. Рекомендовано використовувати Vulkan. - + Device: Пристрій: - + This setting selects the GPU to use (Vulkan only). Це налаштування вибирає ГП для використання (лише Vulkan). - + Resolution: Роздільність: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -565,27 +575,27 @@ Options lower than 1X can cause artifacts. Варіанти нище ніж 1X можуть спричинити проблеми з візуалізацією. - + Window Adapting Filter: Фільтр адаптації вікна: - + FSR Sharpness: Різкість FSR: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. Визначає, наскільки різким буде виглядати зображення при використанні динамічного контрасту FSR або SGSR. - + Anti-Aliasing Method: Метод згладжування: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -594,22 +604,22 @@ SMAA забезпечує найкращу якість. FXAA може створювати стабільніше зображення при низьких роздільностях. - + Enable post-processing effects Увімкнути ефекти постобробки - + Applies post-processing effects to the final image. Застосовує ефекти постобробки до фінального зображення. - + Fullscreen Mode: Повноекранний режим: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -618,12 +628,12 @@ Exclusive fullscreen may offer better performance and better Freesync/Gsync supp «Ексклюзивний повноекранний» може надати кращі продуктивність і підтримку Freesync/Gsync. - + Aspect Ratio: Співвідношення сторін: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -632,36 +642,36 @@ Also controls the aspect ratio of captured screenshots. Також керує співвідношеням сторін знімків екрана. - + Use persistent pipeline cache Використовувати стійкий кеш конвеєра - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. Дозволяє зберігати шейдери на накопичувачі для швидшого завантаження під час наступних запусків гри. Вимкнення цього налаштування задумане лише для зневадження. - + Use asynchronous GPU emulation Використовувати асинхронну емуляцію ГП - + Uses an extra CPU thread for rendering. This option should always remain enabled. Використовує додатковий потік ЦП для візуалізації. Це налаштування повинно завжди залишатися увімкненим. - + NVDEC emulation: Емуляція NVDEC: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -670,12 +680,12 @@ In most cases, GPU decoding provides the best performance. У більшості випадків декодування за допомогою ГП забезпечує найкращу продуктивність. - + ASTC Decoding Method: Метод декодування ASTC: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -687,12 +697,12 @@ stuttering but may present artifacts. Асинхронно ЦП: Використання ЦП для декодування ASTC-текстур по мірі їх викликів. Повністю усуває затримки декодування ASTC ціною проблем з візуалізацією, поки текстури декодуються. - + ASTC Recompression Method: Метод перестиснення ASTC: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. @@ -700,64 +710,44 @@ BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, BC1/BC3: Проміжний формат буде перепаковано у формат BC1 або BC3 для збереження відеопам’яті, але це негатривно вплине на якість зображення. - + Frame Pacing Mode (Vulkan only) Режим виведення кадрів (лише Vulkan) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. Керує тим, як емулятор виконує виведення кадрів, щоб зменшити затримки й забезпечити плавнішу й стабільнішу частоту кадрів. - + VRAM Usage Mode: Режим використання відеопам’яті: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. Це налаштування вибирає, чи повинен емулятор надавати перевагу заощадженню пам’яті, чи по максимуму використовувати доступну відеопам’ять задля продуктивності. Режим «Агресивно» може вплинути на продуктивність інших застосунків, як-от засоби запису. - + Skip CPU Inner Invalidation Пропускати внутрішнє анулювання ЦП - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. Пропускає деякі анулювання кешу під час оновлень пам’яті, зменшуючи використання ЦП й виправляючи затримки. Це може спричинити збої. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: Режим вертикальної синхронізації: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -768,12 +758,12 @@ Mailbox може мати меншу затримку, ніж FIFO, і не ма Immediate (без синхронізації) показує всі кадри й може створювати розриви. - + Sync Memory Operations Синхронізувати операції з пам’яттю - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. @@ -782,44 +772,44 @@ Unreal Engine 4 games often see the most significant changes thereof. Ігри на Unreal Engine 4 часто зазнають найзначніших змін. - + Enable asynchronous presentation (Vulkan only) Увімкнути асинхронне подання (лише Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. Трохи покращує продуктивність завдяки переміщенню подання на окремий потік ЦП. - + Force maximum clocks (Vulkan only) Примусово максимальна тактова частота (лише Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Виконує роботу у фоновому режимі в очікуванні графічних команд, не даючи змоги ГП знижувати тактову частоту. - + Anisotropic Filtering: Анізотропна фільтрація: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. Керує якістю візуалізації текстур під непрямими кутами. Для більшості ГП можна вільно вибирати 16x. - + GPU Mode: Режим ГП: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. @@ -828,24 +818,24 @@ Particles tend to only render correctly with Accurate mode. Частинки зазвичай правильно візуалізуються лише з режимом «Точно». - + DMA Accuracy: Точність DMA: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -854,44 +844,44 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation Увімкнути асинхронну компіляцію шейдерів - + May reduce shader stutter. Може зменшити шейдерні затримки. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle Розпакування за допомогою ГП - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. Прискорює декодування 3D-текстур BCn застосовуючи обчислення за допомогою ГП. Вимкніть у разі збоїв або проблем із графікою. - + GPU Unswizzle Max Texture Size Максимальний розмір текстур для розпакування за допомогою ГП - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. @@ -900,48 +890,48 @@ Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size Розмір потоку розпакування за допомогою ГП - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. Встановлює максимальний обсяг даних текстур (у МіБ) для обробки на кадр. Вищі значення здатні зменшити затримки під час завантаження текстур, але можуть вплинути на стабільність кадрів. - + GPU Unswizzle Chunk Size Розмір блоків розпакування за допомогою ГП - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. Визначає кількість зрізів глибини, оброблених за одне відправлення. Збільшення здатне покращити пропускну здатність на потужних ГП, але може призвести до TDR або затримок драйвера зі слабшим устаткуванням. - + Use Vulkan pipeline cache Використовувати кеш конвеєра Vulkan - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. Вмикає особливий для різних виробників ГП кеш конвеєра. Це налаштування може значно зменшити час завантаження шейдерів у випадках, коли драйвер Vulkan не зберігає власний кеш конвеєра. - + Enable Compute Pipelines (Intel Vulkan Only) Увімкнути обчислювальні конвеєри (лише Intel Vulkan) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. @@ -950,182 +940,182 @@ Compute pipelines are always enabled on all other drivers. Обчислювальні конвеєри завжди увімкнені у всіх інших драйверах. - + Enable Reactive Flushing Увімкнути реактивне очищення - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. Використовує реактивне очищення замість прогнозованого, забезпечуючи точнішу синхронізацію пам’яті. - + Sync to framerate of video playback Синхронізувати частоту кадрів з відтворенням відео - + Run the game at normal speed during video playback, even when the framerate is unlocked. Відтворювати гру з нормальною швидкістю під час відтворення відео навіть при розблокованій частоті кадрів. - + Barrier feedback loops Бар’єрні цикли відгуку - + Improves rendering of transparency effects in specific games. Покращує візуалізацію ефектів прозорості в деяких іграх. - + Enable buffer history Увімкнути історію буфера - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. Вмикає доступ до попередніх станів буфера. Цей параметр може покращити якість візуалізації та стабільну продуктивність у деяких іграх. - + Fix bloom effects Виправити ефекти світіння - + Removes bloom in Burnout. Прибирає світіння в Burnout. - + Extended Dynamic State Розширений динамічний стан - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. Керує кількістю функцій, які можна використовувати в «Розширеному динамічному стані». Вищі значення допускають більше функцій і можуть збільшити продуктивність, але можуть спричинити додаткові проблеми з графікою. - + Vertex Input Dynamic State Динамічний стан введення вершин - + Enables vertex input dynamic state feature for better quality and performance. Вмикає можливість динамічного стану введення вершин для кращих якості й продуктивності. - + Sample Shading Шейдинг зразків - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. Дозволяє виконувати фрагмент шейдера для кожного зразка в багатозразковому фрагменті замість одного разу для кожного фрагмента. Покращує якість графікі ціною втрати продуктивності. Вищі значення покращують якість, але погіршують продуктивність. - + RNG Seed Початкове значення RNG - + Controls the seed of the random number generator. Mainly used for speedrunning. Керує початковим значення генератора випадкових чисел. Зазвичай використовується в спідранах. - + Device Name Назва пристрою - + The name of the console. Назва консолі. - + Homebrew Args Параметри запуску Homebrew - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). Параметри командного рядка, що передаються Homebrew при запуску (як-от noglsl). - + Custom RTC Date: Користувацька дата RTC: - + This option allows to change the clock of the console. Can be used to manipulate time in games. Це налаштування дозволяє змінити час годинника консолі. Можна використовувати для маніпуляцій із часом в іграх. - + The number of seconds from the current unix time Кількість секунд від поточного unix-часу. - + Language: Мова: - + This option can be overridden when region setting is auto-select Це налаштування може перевизначитися, якщо налаштування регіону вибирається автоматично - + Region: Регіон: - + The region of the console. Регіон консолі. - + Time Zone: Часовий пояс: - + The time zone of the console. Часовий пояс консолі. - + Sound Output Mode: Режим виведення звуку: - + Console Mode: Режим консолі: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. @@ -1134,1026 +1124,1026 @@ Setting to Handheld can help improve performance for low end systems. Налаштування «Портативний» може покращити продуктивність на слабких системах. - + Prompt for user profile on boot Запитувати профіль користувача під час запуску - + Useful if multiple people use the same PC. Корисно, якщо одним комп’ютером користуються кілька користувачів. - + Pause when not in focus Призупиняти, якщо не у фокусі - + Pauses emulation when focusing on other windows. Призупиняє емуляцію при фокусування на інших вікнах. - + Confirm before stopping emulation Підтверджувати зупинку емуляції - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. Перевизначає запити на підтвердження зупинки емуляції. Увімкнення обходить такі запити й одразу зупиняє емуляцію. - + Hide mouse on inactivity Приховувати курсор миші при бездіяльності - + Hides the mouse after 2.5s of inactivity. Приховує курсор миші після 2,5 с її бездіяльності. - + Check for updates Перевіряти оновлення - + Whether or not to check for updates upon startup. Чи перевіряти оновлення при запуску. - + Enable Gamemode Увімкнути ігровий режим - + Force X11 as Graphics Backend Примусово використовувати X11 як графічний бекенд - + Custom frontend Користувацький фронтенд - + Real applet Справжній аплет - - + + Disabled Вимкнено - + Never Ніколи - + On Load При завантаженні - + Always Завжди - + CPU ЦП - + GPU ГП - + CPU Asynchronous Асинхронно ЦП - + Uncompressed (Best quality) Без стиснення (Найкраща якість) - + BC1 (Low quality) ВС1 (Низька якість) - + BC3 (Medium quality) ВС3 (Середня якість) - - + + Auto Автоматично - + 30 FPS 30 к/с - + 60 FPS 60 к/с - + 90 FPS 90 к/с - + 120 FPS 120 к/с - + Conservative Заощадження - + Aggressive Агресивно - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) OpenGL GLASM (асемблерні шейдери, лише NVIDIA) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V (експериментально, лише AMD/Mesa) - + Null Нічого - + Fast Швидко - - - + + + Accurate Точно - - - + + + Default Стандартно - + Unsafe (fast) Небезпечно (швидко) - + Safe (stable) Безпечно (стабільно) - + Immediate - + Balanced Збалансовано - + Unsafe Небезпечно - + Paranoid (disables most optimizations) Параноїк (вимикає більшість оптимізацій) - + Debugging Зневадження - + Dynarmic Динамічно - + NCE NCE - + Borderless Windowed Безрамкове вікно - + Exclusive Fullscreen Ексклюзивний повноекранний - + No Video Output Виведення відео відсутнє - + CPU Video Decoding Декодування відео на ЦП - + GPU Video Decoding (Default) Декодування відео на ГП (стандатно) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [ЕКСПЕРИМЕНТАЛЬНО] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [ЕКСПЕРИМЕНТАЛЬНО] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [ЕКСПЕРИМЕНТАЛЬНО] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [ЕКСПЕРИМЕНТАЛЬНО] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [ЕКСПЕРИМЕНТАЛЬНО] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Найближчий сусід - + Bilinear Білінійний - + Bicubic Бікубічний - + Gaussian Ґаусса - + Lanczos Ланцоша - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution AMD FidelityFX Super Resolution - + Area Області - + MMPX MMPX - + Zero-Tangent Нульовий тангенс - + B-Spline B-Spline - + Mitchell Мітчелла - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir Snapdragon Game Super Resolution EdgeDir - + None Немає - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Стандартно (16:9) - + Force 4:3 Примусово 4:3 - + Force 21:9 Примусово 21:9 - + Force 16:10 Примусово 16:10 - + Stretch to Window Розтягнути до вікна - + Automatic Автоматично - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Японська (日本語) - + American English Американська англійська - + French (français) Французька (français) - + German (Deutsch) Німецька (Deutsch) - + Italian (italiano) Італійська (italiano) - + Spanish (español) Іспанська (español) - + Chinese Китайська - + Korean (한국어) Корейська (한국어) - + Dutch (Nederlands) Нідерландська (Nederlands) - + Portuguese (português) Португальська (português) - + Russian (Русский) Російська (Русский) - + Taiwanese Тайванська - + British English Британська англійська - + Canadian French Канадська французька - + Latin American Spanish Латиноамериканська іспанська - + Simplified Chinese Спрощена китайська - + Traditional Chinese (正體中文) Традиційна китайська (正體中文) - + Brazilian Portuguese (português do Brasil) Бразильська португальська (português do Brasil) - + Polish (polska) Польська (polska) - + Thai (แบบไทย) Тайська (แบบไทย) - - + + Japan Японія - + USA США - + Europe Європа - + Australia Австралія - + China Китай - + Korea Корея - + Taiwan Тайвань - + Auto (%1) Auto select time zone Автоматично (%1) - + Default (%1) Default time zone Стандартно (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Куба - + EET EET - + Egypt Єгипет - + Eire Ейре - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Гринвіч - + Hongkong Гонконг - + HST HST - + Iceland Ісландія - + Iran Іран - + Israel Ізраїль - + Jamaica Ямайка - + Kwajalein Кваджалейн - + Libya Лівія - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Навахо - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Польща - + Portugal Португалія - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Сінгапур - + Turkey Туреччина - + UCT UCT - + Universal Універсальний - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Зулу - + Mono Моно - + Stereo Стерео - + Surround Об’ємний - + 4GB DRAM (Default) 4GB DRAM (стандартно) - + 6GB DRAM (Unsafe) 6GB DRAM (небезпечно) - + 8GB DRAM 8GB DRAM - + 10GB DRAM (Unsafe) 10GB DRAM (небезпечно) - + 12GB DRAM (Unsafe) 12GB DRAM (небезпечно) - + Docked У докстанції - + Handheld Портативний - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) Завжди запитувати (стандартно) - + Only if game specifies not to stop Лише якщо гра вказує не зупиняти - + Never ask Ніколи не запитувати - + Very Small (16 MB) Дуже малий (16 МБ) - + Small (32 MB) Малий (32 МБ) - + Normal (128 MB) Нормальний (128 МБ) - + Large (256 MB) Великий (256 МБ) - + Very Large (512 MB) Дуже великий (512 МБ) - + Very Low (4 MB) Дуже низький (4 МБ) - + Low (8 MB) Низький (8 МБ) - + Normal (16 MB) Нормальний (16 МБ) - + Medium (32 MB) Середній (32 МБ) - + High (64 MB) Високий (64 МБ) - + Very Low (32) Дуже низький (32) - + Low (64) Низький (64) - + Normal (128) Нормальний (128) - + Medium (256) Середньо (256) - + High (512) Високо (512) - + ExtendedDynamicState 1 Розширений динамічний стан 1 - + ExtendedDynamicState 2 Розширений динамічний стан 2 - + ExtendedDynamicState 3 Розширений динамічний стан 3 - + Tree View Дерево вибору - + Grid View Таблиця @@ -6125,50 +6115,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL недоступний! - + OpenGL shared contexts are not supported. Спільні контексти OpenGL не підтримуються. - + Eden has not been compiled with OpenGL support. Eden не скомпільовано з підтримкою OpenGL. - - - + + + Error while initializing OpenGL! Помилка під час ініціалізації OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. Ваш ГП може не підтримувати OpenGL або у вас встановлено застарілий графічний драйвер. - + Error while initializing OpenGL 4.6! Помилка під час ініціалізації OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 Ваш ГП може не підтримувати OpenGL 4.6 або у вас встановлено застарілий графічний драйвер.<br><br>Візуалізатор GL:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 Ваш ГП може не підтримувати одне або кілька розширень, необхідних для OpenGL. Переконайтеся, що у вас встановлено останній графічний драйвер.<br><br>Візуалізатор GL:<br>%1<br><br>Непідтримувані розширення:<br>%2 - + This build doesn't have OpenGL support. Ця збірка не підтримує OpenGL. @@ -6935,800 +6925,820 @@ Debug Message: [&E] Емуляція - + + &Cheats + + + + &View [&V] Вигляд - + &Reset Window Size [&R] Скинути розмір вікна - + &Debugging [&D] Зневадження - + &Game List Mode [&G] Режим переліку ігор - + Game &Icon Size [&I] Розмір значків ігор - + Reset Window Size to &720p [&7] Скинути розмір вікна до 720p - + Reset Window Size to 720p Скинути розмір вікна до 720p - + Reset Window Size to &900p [&9] Скинути розмір вікна до 900p - + Reset Window Size to 900p Скинути розмір вікна до 900p - + Reset Window Size to &1080p [&1] Скинути розмір вікна до 1080p - + Reset Window Size to 1080p Скинути розмір вікна до 1080p - + &Multiplayer [&M] Багатоосібна гра - + &Tools [&T] Інструменти - + Am&iibo [&I] Amiibo - + Launch &Applet [&A] Запустити аплет - + &TAS [&T] TAS - + &Create Home Menu Shortcut [&C] Створити ярлик меню-домівки - + Install &Firmware [&F] Встановити прошивку - + &Help [&H] Допомога - + &Install Files to NAND... [&I] Встановити файли до NAND... - + L&oad File... [&O] Завантажити файл... - + Load &Folder... [&F] Завантажити теку... - + E&xit [&X] Вийти - - + + &Pause [&P] Призупинити - + &Stop [&S] Зупинити - + &Verify Installed Contents [&V] Перевірити встановлений вміст - + &About Eden [&A] Про Eden - + Single &Window Mode [&W] Одновіконний режим - + Con&figure... [&F] Налаштувати... - + Ctrl+, Ctrl+, - + Enable Overlay Display Applet Увімкнути аплет показу оверлея - + Show &Filter Bar [&F] Показати панель фільтрування - + Show &Status Bar [&S] Показати панель стану - + Show Status Bar Показати панель стану - + &Browse Public Game Lobby [&B] Переглянути публічні ігрові лобі - + &Create Room [&C] Створити кімнату - + &Leave Room [&L] Покинути кімнату - + &Direct Connect to Room [&D] Пряме з’єднання з кімнатою - + &Show Current Room [&S] Показати поточну кімнату - + F&ullscreen [&U] Повноекранний - + &Restart [&R] Перезапустити - + Load/Remove &Amiibo... [&A] Завантажити/вилучити amiibo... - + Open &Mods Page [&M] Відкрити сторінку модів - + &User Handbook - + &Capture Screenshot [&C] Зробити знімок екрана - + &Album [&A] Альбом - + &Set Nickname and Owner [&S] Указати псевдонім і власника - + &Delete Game Data [&D] Видалити дані гри - + &Restore Amiibo [&R] Відновити amiibo - + &Format Amiibo [&F] Форматувати amiibo - + &Mii Editor [&M] Редактор Mii - + &Configure TAS... [&C] Налаштувати TAS... - + Configure C&urrent Game... [&U] Налаштувати поточну гру... - - + + &Start [&S] Запустити - + &Reset [&S] Скинути - - + + R&ecord [&E] Запис - + Open &Controller Menu [&C] Відкрити меню контролерів - + Install Decryption &Keys [&K] Встановити ключі дешифрування - + &Home Menu [&H] Меню-домівка - + &Desktop [&D] Стільниця - + &Application Menu [&A] Меню застосунків - + &Root Data Folder [&R] Коренева тека даних - + &NAND Folder [&N] Тека NAND - + &SDMC Folder [&S] Тека SDMC - + &Mod Folder [&M] Тека модів - + &Log Folder [&L] Тека журналу - + From Folder З теки - + From ZIP Із ZIP - + &Eden Dependencies [&E] Залежності Eden - + &Data Manager [&D] Керування даними - + &Tree View [&T] Дерево вибору - + &Grid View [&G] Таблиця - + Game Icon Size Розмір значків ігор - - + + None Жодного - + Show Game &Name [&N] Показати назву гри - + Show &Performance Overlay [&P] Показати оверлей продуктивності - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) Маленький (32х32) - + Standard (64x64) Стандартний (64х64) - + Large (128x128) Великий (128х128) - + Full Size (256x256) Повнорозмірний (256х256) - + Broken Vulkan Installation Detected Виявлено пошкоджене встановлення Vulkan - + Vulkan initialization failed during boot. Не вдалося ініціалізувати Vulkan під час запуску. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping Запущено гру - + Loading Web Applet... Завантаження вебаплета... - - + + Disable Web Applet Вимкнути вебаплет - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) Вимкнення вебапплета може призвести до несподіваної поведінки, і це слід робити лише для Super Mario 3D All-Stars. Ви впевнені, що хочете вимкнути вебапплет? (Його можна знову увімкнути в налаштуваннях зневадження.) - + The amount of shaders currently being built Кількість наразі створених шейдерів - + The current selected resolution scaling multiplier. Наразі вибраний множник масштабування роздільності. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. Поточна швидкість емуляції. Значення вище або нижче 100% вказують на те, що емуляція йде швидше або повільніше, ніж на Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Частота кадрів, яку наразі показує гра. Значення змінюватиметься залежно від гри та з кожною сценою. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Час, потрібний для емуляції 1 кадру Switch, не враховуючи обмеження частоти кадрів або вертикальну синхронізацію. Для повношвидкісної емуляції значення повинно бути не вище 16,67 мс. - + Unmute Увімкнути звук - + Mute Вимкнути звук - + Reset Volume Скинути гучність - + Configure Effects... - + &Clear Recent Files [&C] Очистити нещодавні файли - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue [&C] Продовжити - + Warning: Outdated Game Format Увага: Застарілий формат гри - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. Для цієї гри ви використовуєте формат теки з деконструйованим ROM, який є застарілим форматом, заміненим на інші, як-от NCA, NAX, XCI, або NSP. У тек із деконструйованими ROM немає значків, метаданих, а також вони не підтримують оновлення.<br>Для подробиць стосовно різноманітних форматів Switch, які підтримує Eden, ознайомтеся з нашим посібником користувача. Це повідомлення не буде показано знову. - - + + Error while loading ROM! Помилка під час завантаження ROM! - + The ROM format is not supported. Непідтримуваний формат ROM. - + An error occurred initializing the video core. Сталася помилка під час ініціалізації відеоядра. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. Помилка під час завантаження ROM! %1 - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. %1<br>Створіть новий дамп файлів або зверніться по допомогу в Discord/Stoat. - + An unknown error occurred. Please see the log for more details. Сталася невідома помилка. Ознайомтеся з журналом, щоб дізнатися подробиці. - - + + (64-bit) (64-бітовий) - - + + (32-bit) (32-бітовий) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - + Closing software... Закриття програмного засобу... - + Save Data Дані збережень - + Mod Data Дані модів - + Error Opening %1 Folder Помилка під час відкриття теки «%1» - - + + Folder does not exist! Теки не існує! - + Remove Installed Game Contents? Вилучити встановлений вміст гри? - + Remove Installed Game Update? Вилучити встановлені оновлення гри? - + Remove Installed Game DLC? Вилучити встановлені доповнення гри? - + Remove Entry Вилучити запис - + Delete OpenGL Transferable Shader Cache? Видалити переміщуваний кеш шейдерів OpenGL? - + Delete Vulkan Transferable Shader Cache? Видалити переміщуваний кеш шейдерів Vulkan? - + Delete All Transferable Shader Caches? Видалити весь переміщуваний кеш шейдерів? - + Remove Custom Game Configuration? Вилучити користувацькі налаштування гри? - + Remove Cache Storage? Вилучити сховище кешу? - + Remove File Вилучити файл - + Remove Play Time Data Вилучити дані награного часу - + Reset play time? Скинути награний час? - - + + RomFS Extraction Failed! Не вдалося видобути RomFS! - + There was an error copying the RomFS files or the user cancelled the operation. Під час копіювання файлів RomFS сталася помилка або користувач скасував операцію. - + Full Повний - + Skeleton Скелет - + Select RomFS Dump Mode Виберіть режим створення дампу RomFS - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. Виберіть, як ви хочете виконати дамп RomFS <br>Повний скопіює всі файли до нової теки, тоді як <br>скелет створить лише структуру тек. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root За адресою «%1» недостатньо вільного місця для видобування RomFS. Звільніть місце або виберіть іншу теку для створення дампу в «Емуляція» → «Налаштувати» → «Система» → «Файлова система» → «Коренева тека дампів». - + Extracting RomFS... Видобування RomFS... - - + + Cancel Скасувати - + RomFS Extraction Succeeded! RomFS видобуто успішно! - + The operation completed successfully. Операцію успішно виконано. - + Error Opening %1 Помилка під час відкриття «%1» - + Select Directory Вибрати теку - + Properties Властивості - + The game properties could not be loaded. Неможливо завантажити властивості гри. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Виконуваний файл Switch (%1);;Усі файли (*.*) - + Load File Завантажити файл - + Open Extracted ROM Directory Відкрити теку видобутого ROM - + Invalid Directory Selected Вибрано неправильну теку - + The directory you have selected does not contain a 'main' file. Вибрана тека не містить файлу «main». - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - Встановлюваний файл Switch (*.nca, *.nsp, *.xci);;Архів вмісту Nintendo (*.nca);;Пакет подання Nintendo (*.nsp);;Образ картриджа NX (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) + - + Install Files Встановити файли - + %n file(s) remaining Лишився 1 файлЛишилося %n файлиЛишилося %n файлівЛишилося %n файлів - + Installing file "%1"... Встановлення файлу «%1»... - - + + Install Results Результати встановлення - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. Щоб уникнути можливих конфліктів, ми не радимо користувачам встановлювати ігри в NAND. Користуйтеся цією функцією лише для встановлення оновлень і доповнень. - + %n file(s) were newly installed Щойно встановлено %n файл @@ -7738,7 +7748,7 @@ Please, only use this feature to install updates and DLC. - + %n file(s) were overwritten Перезаписано %n файл @@ -7748,7 +7758,7 @@ Please, only use this feature to install updates and DLC. - + %n file(s) failed to install Не вдалося встановити %n файл @@ -7758,324 +7768,324 @@ Please, only use this feature to install updates and DLC. - + System Application Системний застосунок - + System Archive Системний архів - + System Application Update Оновлення системного застосунку - + Firmware Package (Type A) Пакет прошивки (Тип А) - + Firmware Package (Type B) Пакет прошивки (Тип Б) - + Game Гра - + Game Update Оновлення гри - + Game DLC Доповнення гри - + Delta Title Проєкт «Дельта» - + Select NCA Install Type... Виберіть тип встановлення NCA... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) Виберіть тип проєкту, який ви хочете встановити для цього NCA: (У більшості випадків підходить стандартний вибір «Гра».) - + Failed to Install Не вдалося встановити - + The title type you selected for the NCA is invalid. Тип проєкту, який ви вибрали для NCA, неправильний. - + File not found Файл не виявлено - + File "%1" not found Файл «%1» не виявлено - + OK Гаразд - + Function Disabled Функцію вимкнену - + Compatibility list reporting is currently disabled. Check back later! Звітування для переліку сумісності наразі вимкнено. Зазирніть пізніше! - + Error opening URL Помилка під час відкриття URL - + Unable to open the URL "%1". Не вдалося відкрити URL: «%1». - + TAS Recording Записування TAS - + Overwrite file of player 1? Перезаписати файл гравця 1? - + Invalid config detected Виявлено неправильне налаштування - + Handheld controller can't be used on docked mode. Pro controller will be selected. Портативний контролер неможливо використовувати в режимі докстанції. Буде вибрано контролер Pro. - - + + Amiibo Amiibo - - + + The current amiibo has been removed Поточний amiibo вилучено - + Error Помилка - - + + The current game is not looking for amiibos Поточна гра не очікує amiibo - + Amiibo File (%1);; All Files (*.*) Файл amiibo (%1);; Усі файли (*.*) - + Load Amiibo Завантажити amiibo - + Error loading Amiibo data Помилка під час завантаження даних amiibo - + The selected file is not a valid amiibo Вибраний файл не є дійсним amiibo - + The selected file is already on use Вибраний файл уже використовується - + An unknown error occurred Сталася невідома помилка - + No firmware available Немає доступних прошивок - + Firmware Corrupted Прошивка пошкоджена - + Unknown applet Невідомий аплет - + Applet doesn't map to a known value. Аплет не призначено до відомого значення. - + Record not found Запис не виявлено - + Applet not found. Please reinstall firmware. Аплет не виявлено. Перевстановіть прошивку. - + Capture Screenshot Зробити знімок екрана - + PNG Image (*.png) Зображення PNG (*.png) - + TAS state: Running %1/%2 Стан TAS: Працює %1/%2 - + TAS state: Recording %1 Стан TAS: Триває запис %1 - + TAS state: Idle %1/%2 Стан TAS: Бездіяльність %1/%2 - + TAS State: Invalid Стан TAS: Неправильний - + &Stop Running [&S] Зупинити - + Stop R&ecording [&E] Зупинити запис - + Building: %n shader(s) Компіляція: %n шейдерКомпіляція: %n шейдериКомпіляція: %n шейдерівКомпіляція: %n шейдерів - + Scale: %1x %1 is the resolution scaling factor Масштаб: %1x - + Speed: %1% / %2% Швидкість: %1% / %2% - + Speed: %1% Швидкість: %1% - + Game: %1 FPS Гра: %1 к/с - + Frame: %1 ms Кадр: %1 мс - + NO AA БЕЗ ЗГЛАДЖУВАННЯ - + NO FX - + FX - + VOLUME: MUTE ГУЧНІСТЬ: ВИМКНЕНО - + VOLUME: %1% Volume percentage (e.g. 50%) ГУЧНІСТЬ: %1% - + Derivation Components Missing Відсутні компоненти виведення - + Decryption keys are missing. Install them now? Відсутні ключі шифрування. Встановити їх зараз? - + Wayland Detected! Виявлено Wayland! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8086,74 +8096,74 @@ Would you like to force it for future launches? Хочете примусово увімкнути його для наступних запусків? - + Use X11 Використовувати X11 - + Continue with Wayland Продовжити з Wayland - + Don't show again Не показувати знову - + Restart Required Потрібен перезапуск - + Restart Eden to apply the X11 backend. Перезапуск Eden для застосування бекенду X11. - + Slow Сповільнення - + Turbo Прискорення - + Unlocked Розблоковано - + Select RomFS Dump Target Виберіть розташування для створення дампу RomFS - + Please select which RomFS you would like to dump. Виберіть, який дамп RomFS ви хочете створити. - + Are you sure you want to close Eden? Ви впевнені, що хочете закрити Eden? - - - + + + Eden Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. Ви впевнені, що хочете зупинити емуляцію? Увесь незбережений поступ буде втрачено. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/vi.ts b/dist/languages/vi.ts index f0a7e591bd..5fbedcf11a 100644 --- a/dist/languages/vi.ts +++ b/dist/languages/vi.ts @@ -30,7 +30,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> @@ -399,252 +399,262 @@ Can help reduce stuttering at lower framerates. - - Accuracy: - Độ chính xác: - - - - Change the accuracy of the emulated CPU (for debugging only). + + Enable cheats by default - - - Backend: + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + Accuracy: + Độ chính xác: + + + + Change the accuracy of the emulated CPU (for debugging only). + + + + + + Backend: + + + + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) Không dùng FMA (tăng hiệu suất cho các dòng CPU không hỗ trợ FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. - + Faster FRSQRTE and FRECPE FRSQRTE và FRECPE nhanh hơn - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. - + Faster ASIMD instructions (32 bits only) Các chỉ thị ASIMD nhanh hơn (chỉ cho 32 bit) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. - + Inaccurate NaN handling Xử lí NaN không chính xác - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. - + Disable address space checks Tắt kiểm tra không gian địa chỉ - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor Bỏ qua màn hình chung - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. - + API: API: - + Changes the output graphics API. Vulkan is recommended. - + Device: Thiết bị: - + This setting selects the GPU to use (Vulkan only). - + Resolution: Độ phân giải: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: Bộ lọc điều chỉnh cửa sổ: - + FSR Sharpness: Độ nét FSR: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Phương pháp khử răng cưa: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Chế độ toàn màn hình: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. - + Aspect Ratio: Tỉ lệ khung hình: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: Giả lập NVDEC: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. - + ASTC Decoding Method: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -653,75 +663,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: Chế độ Vsync: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -729,79 +719,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) Bật hiển thị bất đồng bộ (chỉ cho Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. - + Force maximum clocks (Vulkan only) Buộc chạy ở xung nhịp tối đa (chỉ cho Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Chạy các công việc trong nền trong khi đang chờ lệnh đồ họa để giữ cho GPU không giảm xung nhịp. - + Anisotropic Filtering: Lọc bất đẳng hướng: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -810,1290 +800,1290 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache Dùng bộ nhớ đệm pipeline Vulkan - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. - + Enable Compute Pipelines (Intel Vulkan Only) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing Bật xả tương ứng - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. - + Sync to framerate of video playback Đồng bộ hóa với tốc độ khung hình khi phát video - + Run the game at normal speed during video playback, even when the framerate is unlocked. Chạy game với tốc độ bình thường trong quá trình phát video, ngay cả khi tốc độ khung hình được mở khóa. - + Barrier feedback loops Vòng lặp phản hồi rào cản - + Improves rendering of transparency effects in specific games. Cải thiện hiệu quả kết xuất của hiệu ứng trong suốt trong một số game. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed Hạt giống RNG - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name Tên thiết bị - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: - + This option can be overridden when region setting is auto-select - + Region: Vùng: - + The region of the console. - + Time Zone: Múi giờ: - + The time zone of the console. - + Sound Output Mode: Chế độ đầu ra âm thanh: - + Console Mode: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity Ẩn con trỏ chuột khi không dùng - + Hides the mouse after 2.5s of inactivity. - + Check for updates - + Whether or not to check for updates upon startup. - + Enable Gamemode - + Force X11 as Graphics Backend - + Custom frontend - + Real applet - - + + Disabled - + Never - + On Load - + Always - + CPU CPU - + GPU - + CPU Asynchronous - + Uncompressed (Best quality) Không nén (Chất lượng tốt nhất) - + BC1 (Low quality) BC1 (Chất lượng thấp) - + BC3 (Medium quality) BC3 (Chất lượng trung bình) - - + + Auto Tự động - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative - + Aggressive - + Vulkan Vulkan - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null Null - + Fast - - - + + + Accurate Chính xác - - - + + + Default Mặc định - + Unsafe (fast) - + Safe (stable) - + Immediate - + Balanced - + Unsafe Không an toàn - + Paranoid (disables most optimizations) Paranoid (vô hiệu hoá hầu hết sự tối ưu) - + Debugging - + Dynarmic - + NCE - + Borderless Windowed Cửa sổ không viền - + Exclusive Fullscreen Toàn màn hình - + No Video Output Không có đầu ra video - + CPU Video Decoding Giải mã video bằng CPU - + GPU Video Decoding (Default) Giải mã video bằng GPU (Mặc định) - + 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [THỬ NGHIỆM] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [THỬ NGHIỆM] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Nearest Neighbor - + Bilinear Bilinear - + Bicubic Bicubic - + Gaussian Gaussian - + Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution - + Area - + MMPX - + Zero-Tangent - + B-Spline - + Mitchell - + Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Không có - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Mặc định (16:9) - + Force 4:3 Dùng 4:3 - + Force 21:9 Dùng 21:9 - + Force 16:10 Dùng 16:10 - + Stretch to Window Mở rộng đến cửa sổ - + Automatic Tự động - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Tiếng Nhật (日本語) - + American English Tiếng Anh Mỹ - + French (français) Tiếng Pháp (French) - + German (Deutsch) Tiếng Đức (Deutsch) - + Italian (italiano) Tiếng Ý (italiano) - + Spanish (español) Tiếng Tây Ban Nha (Español) - + Chinese Tiếng Trung - + Korean (한국어) Tiếng Hàn (한국어) - + Dutch (Nederlands) Tiếng Hà Lan (Nederlands) - + Portuguese (português) Tiếng Bồ Đào Nha (Portuguese) - + Russian (Русский) Tiếng Nga (Русский) - + Taiwanese Tiếng Đài Loan - + British English Tiếng Anh Anh - + Canadian French Tiếng Pháp Canada - + Latin American Spanish Tiếng Tây Ban Nha Mỹ Latinh - + Simplified Chinese Tiếng Trung giản thể - + Traditional Chinese (正體中文) Tiếng Trung phồn thể (正體中文) - + Brazilian Portuguese (português do Brasil) Tiếng Bồ Đào Nha Brasil (Português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan Nhật Bản - + USA Hoa Kỳ - + Europe Châu Âu - + Australia Úc - + China Trung Quốc - + Korea Hàn Quốc - + Taiwan Đài Loan - + Auto (%1) Auto select time zone Tự động (%1) - + Default (%1) Default time zone Mặc định (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Ai Cập - + Eire Eire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hồng Kông - + HST HST - + Iceland Iceland - + Iran Iran - + Israel Israel - + Jamaica Jamaica - + Kwajalein Kwajalein - + Libya Libya - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Ba Lan - + Portugal Bồ Đào Nha - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapore - + Turkey Thổ Nhĩ Kỳ - + UCT UCT - + Universal Quốc tế - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Stereo - + Surround Surround - + 4GB DRAM (Default) - + 6GB DRAM (Unsafe) - + 8GB DRAM - + 10GB DRAM (Unsafe) - + 12GB DRAM (Unsafe) - + Docked Docked - + Handheld Handheld - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) - + Only if game specifies not to stop - + Never ask - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) - + High (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6046,50 +6036,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL không khả dụng! - + OpenGL shared contexts are not supported. Các ngữ cảnh OpenGL chung không được hỗ trợ. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! Lỗi khi khởi tạo OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. GPU của bạn có thể không hỗ trợ OpenGL, hoặc bạn không có driver đồ hoạ mới nhất. - + Error while initializing OpenGL 4.6! Lỗi khi khởi tạo OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 GPU của bạn có thể không hỗ trợ OpenGL 4.6, hoặc bạn không có driver đồ hoạ mới nhất.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 GPU của bạn có thể không hỗ trợ một hoặc nhiều tiện ích OpenGL cần thiết. Vui lòng đảm bảo bạn có driver đồ hoạ mới nhất.<br><br>GL Renderer:<br>%1<br><br>Tiện ích không hỗ trợ:<br>%2 - + This build doesn't have OpenGL support. @@ -6855,1132 +6845,1152 @@ Debug Message: &Giả lập - + + &Cheats + + + + &View &Xem - + &Reset Window Size &Đặt lại kích thước cửa sổ - + &Debugging &Gỡ lỗi - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p Đặt lại kích thước cửa sổ về &720p - + Reset Window Size to 720p Đặt lại kích thước cửa sổ về 720p - + Reset Window Size to &900p Đặt lại kích thước cửa sổ về &900p - + Reset Window Size to 900p Đặt lại kích thước cửa sổ về 900p - + Reset Window Size to &1080p Đặt lại kích thước cửa sổ về &1080p - + Reset Window Size to 1080p Đặt lại kích thước cửa sổ về 1080p - + &Multiplayer &Nhiều người chơi - + &Tools &Công cụ - + Am&iibo - + Launch &Applet - + &TAS &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help &Trợ giúp - + &Install Files to NAND... &Cài đặt tập tin vào NAND... - + L&oad File... N&ạp tập tin... - + Load &Folder... Nạp &thư mục... - + E&xit T&hoát - - + + &Pause &Tạm dừng - + &Stop &Dừng - + &Verify Installed Contents - + &About Eden - + Single &Window Mode Chế độ &cửa sổ đơn - + Con&figure... Cấu &hình... - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar Hiện thanh &lọc - + Show &Status Bar Hiện thanh &trạng thái - + Show Status Bar Hiện thanh trạng thái - + &Browse Public Game Lobby &Duyệt phòng game công khai - + &Create Room &Tạo phòng - + &Leave Room &Rời phòng - + &Direct Connect to Room &Kết nối trực tiếp tới phòng - + &Show Current Room &Hiện phòng hiện tại - + F&ullscreen T&oàn màn hình - + &Restart &Khởi động lại - + Load/Remove &Amiibo... Nạp/Loại bỏ &Amiibo... - + Open &Mods Page Mở trang &mods - + &User Handbook - + &Capture Screenshot &Chụp ảnh màn hình - + &Album - + &Set Nickname and Owner - + &Delete Game Data - + &Restore Amiibo - + &Format Amiibo - + &Mii Editor - + &Configure TAS... &Cấu hình TAS... - + Configure C&urrent Game... Cấu hình game h&iện tại... - - + + &Start &Bắt đầu - + &Reset &Đặt lại - - + + R&ecord G&hi lại - + Open &Controller Menu - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -7988,74 +7998,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/vi_VN.ts b/dist/languages/vi_VN.ts index 51156ca9c8..c4f1a5311b 100644 --- a/dist/languages/vi_VN.ts +++ b/dist/languages/vi_VN.ts @@ -30,7 +30,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> @@ -399,252 +399,262 @@ Can help reduce stuttering at lower framerates. - - Accuracy: - Độ chính xác - - - - Change the accuracy of the emulated CPU (for debugging only). + + Enable cheats by default - - - Backend: + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + Accuracy: + Độ chính xác + + + + Change the accuracy of the emulated CPU (for debugging only). + + + + + + Backend: + + + + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - + Enable Host MMU Emulation (fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) Không dùng FMA (tăng hiệu suất cho các dòng CPU không hỗ trợ FMA) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. - + Faster FRSQRTE and FRECPE Chạy FRSQRTE và FRECPE nhanh hơn - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. - + Faster ASIMD instructions (32 bits only) Các lệnh ASIMD nhanh hơn (chỉ áp dụng cho 32 bit) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. - + Inaccurate NaN handling Xử lí NaN gặp lỗi - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. - + Disable address space checks Tắt kiểm tra không gian địa chỉ - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. - + Ignore global monitor Bỏ qua màn hình chung - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. - + API: API đồ hoạ: - + Changes the output graphics API. Vulkan is recommended. - + Device: Thiết bị đồ hoạ: - + This setting selects the GPU to use (Vulkan only). - + Resolution: Độ phân giải: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. - + Window Adapting Filter: Bộ lọc điều chỉnh cửa sổ: - + FSR Sharpness: Độ sắc nét FSR: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: Phương pháp khử răng cưa: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: Chế độ Toàn màn hình: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. - + Aspect Ratio: Tỉ lệ khung hình: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: Giả lập NVDEC - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. - + ASTC Decoding Method: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -653,75 +663,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: Chế độ Vsync: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -729,79 +719,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) Bật hiển thị bất đồng bộ (chỉ dành cho Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. - + Force maximum clocks (Vulkan only) Buộc chạy ở xung nhịp tối đa (chỉ Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. Chạy các công việc trong nền trong khi đang chờ lệnh đồ họa để giữ cho GPU không giảm xung nhịp. - + Anisotropic Filtering: Bộ lọc góc nghiêng: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -810,1290 +800,1290 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache Dùng Vulkan pipeline cache - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. - + Enable Compute Pipelines (Intel Vulkan Only) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing Bật xả tương ứng - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. - + Sync to framerate of video playback Đồng bộ hóa với tốc độ khung hình khi phát video - + Run the game at normal speed during video playback, even when the framerate is unlocked. Chạy game với tốc độ bình thường trong quá trình phát video, ngay cả khi tốc độ khung hình được mở khóa. - + Barrier feedback loops Vòng lặp phản hồi rào cản - + Improves rendering of transparency effects in specific games. Cải thiện hiệu quả hiển thị của hiệu ứng trong suốt trong một số trò chơi. - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed Hạt giống RNG - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name Tên thiết bị - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: - + This option can be overridden when region setting is auto-select - + Region: Vùng: - + The region of the console. - + Time Zone: Múi giờ: - + The time zone of the console. - + Sound Output Mode: Chế độ đầu ra âm thanh - + Console Mode: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity Ẩn con trỏ chuột khi không dùng - + Hides the mouse after 2.5s of inactivity. - + Check for updates - + Whether or not to check for updates upon startup. - + Enable Gamemode - + Force X11 as Graphics Backend - + Custom frontend - + Real applet - - + + Disabled - + Never - + On Load - + Always - + CPU CPU - + GPU - + CPU Asynchronous - + Uncompressed (Best quality) Không nén (Chất lượng tốt nhất) - + BC1 (Low quality) BC1 (Chất lượng thấp) - + BC3 (Medium quality) BC3 (Chất lượng trung bình) - - + + Auto Tự động - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative - + Aggressive - + Vulkan Vulkan - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null Null - + Fast - - - + + + Accurate Tuyệt đối - - - + + + Default Mặc định - + Unsafe (fast) - + Safe (stable) - + Immediate - + Balanced - + Unsafe Tương đối - + Paranoid (disables most optimizations) Paranoid (vô hiệu hoá hầu hết sự tối ưu) - + Debugging - + Dynarmic - + NCE - + Borderless Windowed Cửa sổ không viền - + Exclusive Fullscreen Toàn màn hình - + No Video Output Không Video Đầu Ra - + CPU Video Decoding Giải mã video bằng CPU - + GPU Video Decoding (Default) Giải mã video bằng GPU (Mặc định) - + 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [THỬ NGHIỆM] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [THỬ NGHIỆM] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor Nearest Neighbor - + Bilinear Bilinear - + Bicubic Bicubic - + Gaussian ScaleForce - + Lanczos - + ScaleForce ScaleForce - + AMD FidelityFX Super Resolution - + Area - + MMPX - + Zero-Tangent - + B-Spline - + Mitchell - + Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None Trống - + FXAA FXAA - + SMAA SMAA - + Default (16:9) Mặc định (16:9) - + Force 4:3 Dùng 4:3 - + Force 21:9 Dùng 21:9 - + Force 16:10 Dung 16:10 - + Stretch to Window Kéo dãn đến cửa sổ phần mềm - + Automatic Tự động - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) Tiếng Nhật (日本語) - + American English Tiếng Anh Mỹ - + French (français) Tiếng Pháp (French) - + German (Deutsch) Tiếng Đức (Deutsch) - + Italian (italiano) Tiếng Ý (italiano) - + Spanish (español) Tiếng Tây Ban Nha (Spanish) - + Chinese Tiếng Trung - + Korean (한국어) Tiếng Hàn (한국어) - + Dutch (Nederlands) Tiếng Hà Lan (Dutch) - + Portuguese (português) Tiếng Bồ Đào Nha (Portuguese) - + Russian (Русский) Tiếng Nga (Русский) - + Taiwanese Tiếng Đài Loan - + British English Tiếng Anh UK (British English) - + Canadian French Tiếng Pháp Canada - + Latin American Spanish Tiếng Mỹ La-tinh - + Simplified Chinese Tiếng Trung giản thể - + Traditional Chinese (正體中文) Tiếng Trung phồn thể (正體中文) - + Brazilian Portuguese (português do Brasil) Tiếng Bồ Đào Nha của người Brazil (Português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan Nhật Bản - + USA Hoa Kỳ - + Europe Châu Âu - + Australia Châu Úc - + China Trung Quốc - + Korea Hàn Quốc - + Taiwan Đài Loan - + Auto (%1) Auto select time zone Tự động (%1) - + Default (%1) Default time zone Mặc định (%1) - + CET CET - + CST6CDT CST6CDT - + Cuba Cuba - + EET EET - + Egypt Ai Cập - + Eire Eire - + EST EST - + EST5EDT EST5EDT - + GB GB - + GB-Eire GB-Eire - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich Greenwich - + Hongkong Hồng Kông - + HST HST - + Iceland Iceland - + Iran Iran - + Israel Israel - + Jamaica Jamaica - + Kwajalein Kwajalein - + Libya Libya - + MET MET - + MST MST - + MST7MDT MST7MDT - + Navajo Navajo - + NZ NZ - + NZ-CHAT NZ-CHAT - + Poland Ba Lan - + Portugal Bồ Đào Nha - + PRC PRC - + PST8PDT PST8PDT - + ROC ROC - + ROK ROK - + Singapore Singapore - + Turkey Thổ Nhĩ Kỳ - + UCT UCT - + Universal Quốc tế - + UTC UTC - + W-SU W-SU - + WET WET - + Zulu Zulu - + Mono Mono - + Stereo Stereo - + Surround Surround - + 4GB DRAM (Default) - + 6GB DRAM (Unsafe) - + 8GB DRAM - + 10GB DRAM (Unsafe) - + 12GB DRAM (Unsafe) - + Docked Chế độ cắm TV - + Handheld Cầm tay - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) - + Only if game specifies not to stop - + Never ask - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) - + High (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6046,50 +6036,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! Không có sẵn OpenGL! - + OpenGL shared contexts are not supported. Các ngữ cảnh OpenGL chung không được hỗ trợ. - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! Đã xảy ra lỗi khi khởi tạo OpenGL! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. GPU của bạn có thể không hỗ trợ OpenGL, hoặc bạn không có driver đồ hoạ mới nhất. - + Error while initializing OpenGL 4.6! Lỗi khi khởi tạo OpenGL 4.6! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 GPU của bạn có thể không hỗ trợ OpenGL 4.6, hoặc bạn không có driver đồ hoạ mới nhất.<br><br>GL Renderer:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 GPU của bạn có thể không hỗ trợ một hoặc nhiều tiện ích OpenGL cần thiết. Vui lòng đảm bảo bạn có driver đồ hoạ mới nhất.<br><br>GL Renderer:<br>%1<br><br>Tiện ích không hỗ trợ:<br>%2 - + This build doesn't have OpenGL support. @@ -6855,1132 +6845,1152 @@ Debug Message: &Giả lập - + + &Cheats + + + + &View &Xem - + &Reset Window Size &Đặt lại kích thước cửa sổ - + &Debugging &Gỡ lỗi - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p Đặt lại kích thước cửa sổ về &720p - + Reset Window Size to 720p Đặt lại kích thước cửa sổ về 720p - + Reset Window Size to &900p Đặt lại kích thước cửa sổ về &900p - + Reset Window Size to 900p Đặt lại kích thước cửa sổ về 900p - + Reset Window Size to &1080p Đặt lại kích thước cửa sổ về &1080p - + Reset Window Size to 1080p Đặt lại kích thước cửa sổ về 1080p - + &Multiplayer &Nhiều người chơi - + &Tools &Công cụ - + Am&iibo - + Launch &Applet - + &TAS &TAS - + &Create Home Menu Shortcut - + Install &Firmware - + &Help &Trợ giúp - + &Install Files to NAND... &Cài đặt tập tin vào NAND... - + L&oad File... N&ạp tập tin... - + Load &Folder... Nạp &Thư mục - + E&xit Th&oát - - + + &Pause &Tạm dừng - + &Stop &Dừng - + &Verify Installed Contents - + &About Eden - + Single &Window Mode &Chế độ cửa sổ đơn - + Con&figure... Cấu& hình - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar Hiện thanh &lọc - + Show &Status Bar Hiện thanh &trạng thái - + Show Status Bar Hiển thị thanh trạng thái - + &Browse Public Game Lobby &Duyệt phòng game công khai - + &Create Room &Tạo phòng - + &Leave Room &Rời phòng - + &Direct Connect to Room &Kết nối trực tiếp tới phòng - + &Show Current Room &Hiện phòng hiện tại - + F&ullscreen T&oàn màn hình - + &Restart &Khởi động lại - + Load/Remove &Amiibo... Tải/Loại bỏ &Amiibo - + Open &Mods Page Mở trang &mods - + &User Handbook - + &Capture Screenshot &Chụp ảnh màn hình - + &Album - + &Set Nickname and Owner - + &Delete Game Data - + &Restore Amiibo - + &Format Amiibo - + &Mii Editor - + &Configure TAS... &Cấu hình TAS... - + Configure C&urrent Game... Cấu hình game hiện tại... - - + + &Start &Bắt đầu - + &Reset &Đặt lại - - + + R&ecord G&hi - + Open &Controller Menu - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -7988,74 +7998,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/languages/zh_CN.ts b/dist/languages/zh_CN.ts index 2b86a73843..6a630afbb2 100644 --- a/dist/languages/zh_CN.ts +++ b/dist/languages/zh_CN.ts @@ -33,12 +33,12 @@ hr { height: 1px; border-width: 0; } li.unchecked::marker { content: "\2610"; } li.checked::marker { content: "\2612"; } </style></head><body style=" font-family:'Noto Sans'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">Eden 是一个实验性的开源任天堂 Switch 模拟器,以 GPLv3.0+ 许可证授权。本项目基于 yuzu 模拟器开发(后者已于 2024 年 3 月终止)。<br /><br />请勿使用此软件运行非法获得的游戏。</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">Eden 是一个以 GPLv3.0+ 许可证授权的实验性开源任天堂 Switch 模拟器。本项目基于已于 2024 年 3 月终止的 yuzu 模拟器开发。<br /><br />请勿使用此软件运行非法获得的游戏。</span></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">主页</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">源码</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">贡献者</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">许可证</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -61,12 +61,12 @@ li.checked::marker { content: "\2612"; } Touch the top left corner <br>of your touchpad. - 触摸你的触摸板<br>的左上角。 + 触摸您的触摸板<br>的左上角。 Now touch the bottom right corner <br>of your touchpad. - 触摸你的触摸板<br>的右下角。 + 触摸您的触摸板<br>的右下角。 @@ -140,7 +140,7 @@ li.checked::marker { content: "\2612"; } When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? - 屏蔽玩家后,你将无法收到他们的聊天消息。<br><br>您确定要屏蔽 %1 吗? + 屏蔽玩家后,您将无法收到他们的聊天消息。<br><br>您确定要屏蔽 %1 吗? @@ -396,7 +396,7 @@ Disabling it means unlocking the framerate to the maximum your PC can reach. When the Slow Speed hotkey is pressed, the speed will be limited to this percentage. - 当按下 减速模式 快捷键时,速度会被限制在这个百分比。 + 当按下减速模式快捷键时,速度会被限制在这个百分比。 @@ -411,50 +411,60 @@ Can help reduce stuttering at lower framerates. 可以帮助在较低帧率下减少卡顿。 - + + Enable cheats by default + 默认开启作弊 + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + 在游戏启动时启用常规作弊码。总是开启主作弊码。游戏运行时,仍然可以在菜单栏的作弊选项中单独切换各个作弊码。 + + + Accuracy: 精度: - + Change the accuracy of the emulated CPU (for debugging only). 更改模拟 CPU 的精度(仅供调试使用)。 - - + + Backend: 后端: - + CPU Clocks CPU 时钟频率 - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. 提高模拟 CPU 报告的时钟频率,从而消除部分帧率限制。 性能较弱的 CPU 可能会出现可见性能下降,甚至会导致某些游戏运行异常。 - + Custom CPU Ticks 自定义 CPU 时钟周期 - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. - 设置自定义的 CPU 时钟周期。较高的数值可能提升性能,但也可能导致游戏卡死。推荐范围:77–21000。 + 设置自定义的 CPU 时钟周期。较高的数值可能提升性能,但也可能导致游戏卡死。推荐范围:77-21000。 - + Enable Host MMU Emulation (fastmem) 启用主机 MMU 模拟(快速内存存取) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -463,100 +473,100 @@ Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) 低精度 FMA (在 CPU 不支持 FMA 指令集的情况下提高性能) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. 该选项通过降低积和熔加运算的精度来提高模拟器在不支持 FMA 指令集 CPU 上的运行速度。 - + Faster FRSQRTE and FRECPE 快速 FRSQRTE 和 FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. 该选项通过使用精度较低的近似值来提高某些浮点函数的运算速度。 - + Faster ASIMD instructions (32 bits only) 加速 ASIMD 指令执行(仅限 32 位) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. 该选项通过不正确的舍入模式来提高 32 位 ASIMD 浮点函数的运行速度。 - + Inaccurate NaN handling 低精度非数处理 - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. 该选项通过取消非数检查来提高速度。 请注意,这也会降低某些浮点指令的精确度。 - + Disable address space checks 禁用地址空间检查 - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. 此选项通过在每次内存操作前取消安全检查来提高速度。 禁用它可能允许执行任意代码。 - + Ignore global monitor 忽略全局监视器 - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. 此选项仅通过 cmpxchg 指令来提高速度,以确保独占访问指令的安全性。 请注意,这可能会导致死锁和其他问题。 - + API: API: - + Changes the output graphics API. Vulkan is recommended. 更改图形输出的 API。 推荐使用 Vulkan。 - + Device: 设备: - + This setting selects the GPU to use (Vulkan only). - 设置Vulkan下使用的GPU。 + 此设置将选定要使用的 GPU (仅 Vulkan)。 - + Resolution: 分辨率: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -565,27 +575,27 @@ Options lower than 1X can cause artifacts. 低于 1X 的选项可能造成渲染问题。 - + Window Adapting Filter: 窗口滤镜: - + FSR Sharpness: FSR 锐化度: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. 确定使用 FSR 或 SGSR 的动态对比度时图像看起来有多锐利。 - + Anti-Aliasing Method: 抗锯齿方式: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -594,22 +604,22 @@ SMAA 提供最佳质量。 FXAA 可以在较低分辨率下产生更稳定的画面。 - + Enable post-processing effects 开启后处理效果 - + Applies post-processing effects to the final image. 给最终图像加上后处理效果。 - + Fullscreen Mode: 全屏模式: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -618,12 +628,12 @@ Exclusive fullscreen may offer better performance and better Freesync/Gsync supp 独占全屏提供更好的性能和 Freesync/Gsync 支持。 - + Aspect Ratio: 屏幕纵横比: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. @@ -632,36 +642,36 @@ Also controls the aspect ratio of captured screenshots. 此设置同时控制捕获截图的高宽比。 - + Use persistent pipeline cache 使用持久管道缓存 - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. 将生成的着色器保存到硬盘,提高后续游戏过程中的着色器加载速度。 请仅在调试时禁用此项。 - + Use asynchronous GPU emulation 使用异步 GPU 模拟 - + Uses an extra CPU thread for rendering. This option should always remain enabled. 使用额外的 CPU 线程进行渲染。 此选项应始终保持启用状态。 - + NVDEC emulation: NVDEC 模拟方式: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -670,12 +680,12 @@ In most cases, GPU decoding provides the best performance. 大多数情况下,使用 GPU 解码将提供最好的性能。 - + ASTC Decoding Method: ASTC 纹理解码方式: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -688,12 +698,12 @@ CPU 异步模拟:使用 CPU 在 ASTC 纹理到达时对其进行解码。 消除 ASTC 解码带来的卡顿,但在解码时可能出现渲染问题。 - + ASTC Recompression Method: ASTC 纹理重压缩方式: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. @@ -702,64 +712,44 @@ BC1/BC3: 中间格式将被重新压缩为 BC1 或 BC3 格式,从而节省显存 但会降低图像质量。 - + Frame Pacing Mode (Vulkan only) 帧同步模式 (仅限 Vulkan) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. 控制模拟器如何管理帧同步,以减少卡顿,使帧率表现更加平稳顺滑。 - + VRAM Usage Mode: VRAM 使用模式: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. 选择模拟器是应优先节省内存还是最大限度地使用可用视频内存以提高性能。 激进模式可能会影响诸如录屏软件等其他应用程序的性能,。 - + Skip CPU Inner Invalidation 跳过 CPU 内部失效处理 - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. 在内存更新期间跳过某些缓存失效,从而降低 CPU 使用率并改善延迟。这可能导致软件崩溃。 - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: 垂直同步模式: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -770,12 +760,12 @@ Mailbox 的延迟可能比 FIFO 低且不会导致撕裂,但可能会丢帧。 Immediate (不同步) 会呈现全部可用内容,并可能出现撕裂。 - + Sync Memory Operations 同步内存操作 - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. @@ -784,44 +774,44 @@ Unreal Engine 4 games often see the most significant changes thereof. 虚幻 4 引擎的游戏通常会看到最显著的变化。 - + Enable asynchronous presentation (Vulkan only) 启用异步帧提交 (仅限 Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. 将帧提交移动到单独的 CPU 线程,略微提高性能。 - + Force maximum clocks (Vulkan only) 强制最大时钟 (仅限 Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. 在后台运行的同时等待图形命令,以防止 GPU 降低时钟速度。 - + Anisotropic Filtering: 各向异性过滤: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. 控制在斜角下纹理渲染的质量。 大多数 GPU 上设置为 16 倍是安全的。 - + GPU Mode: GPU 模式: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. @@ -829,12 +819,12 @@ Particles tend to only render correctly with Accurate mode. 大多数游戏在“快速”模式下渲染效果良好,但有些游戏仍需使用“精确”模式。而粒子效果通常只有在“精确”模式下才能正确渲染。 - + DMA Accuracy: DMA 精度: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. @@ -843,57 +833,61 @@ Default follows the GPU Accuracy setting. 默认使用 GPU 精度设置。 - + GPU Fence Behavior: GPU 围栏行为: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. Accurate further improves compatibility at the cost of some performance. Default follows the GPU Mode setting. - + 控制 GPU 围栏同步行为。 +即时是最快的选项,但可能会引入一些问题。 +平衡提供更好的兼容性,并可能修复某些游戏中的问题。 +精确在牺牲一些性能的情况下进一步提高兼容性。 +默认则遵循 GPU 模式设置。 - + Enable asynchronous shader compilation 开启异步着色器编译 - + May reduce shader stutter. 可能减少着色器卡顿。 - + GPU Clocks GPU 时钟频率 - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. 通过让游戏误以为 GPU 的处理速度比实际更快,以避免游戏为了适应 Switch 的时钟频率而降低分辨率和渲染距离。 - + GPU Unswizzle GPU 还原 - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. 利用 GPU 计算来加速 BCn 格式 3D 纹理的解码。如果遇到崩溃或画面花屏,请禁用此项。 - + GPU Unswizzle Max Texture Size GPU 还原最大纹理尺寸 - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. @@ -902,48 +896,48 @@ Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size GPU 还原流大小 - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - 设置每帧处理的纹理数据最大量(单位:MiB)。 -较高的数值可以减少纹理加载时的卡顿,但可能会影响帧率的稳定性(即造成帧时间波动)。 + 设置每帧处理的纹理数据最大量 (单位:MiB)。 +较高的数值可以减少纹理加载时的卡顿,但可能会影响帧率的稳定性,即造成帧时间波动。 - + GPU Unswizzle Chunk Size GPU 还原块大小 - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. 确定在单次调度(Dispatch)中处理的深度切片(Depth Slices)数量。 增加此数值可以提高高端 GPU 的吞吐量(处理效率),但在性能较弱的硬件上可能会引发 TDR(驱动程序重置)或驱动超时。 - + Use Vulkan pipeline cache 启用 Vulkan 管线缓存 - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. 启用 GPU 供应商专用的管线缓存。 在 Vulkan 驱动程序内部不存储管线缓存的情况下,此选项可显著提高着色器加载速度。 - + Enable Compute Pipelines (Intel Vulkan Only) 启用计算管线 (仅限 Intel 显卡 Vulkan 模式) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. @@ -952,181 +946,181 @@ Compute pipelines are always enabled on all other drivers. 在所有其他驱动程序上始终启用计算管线。 - + Enable Reactive Flushing 启用反应性刷新 - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. 使用反应性刷新取代预测性刷新,从而更精确地同步内存。 - + Sync to framerate of video playback 播放视频时帧率同步 - + Run the game at normal speed during video playback, even when the framerate is unlocked. 在视频播放期间以正常速度运行游戏,即使帧率未锁定。 - + Barrier feedback loops 屏障反馈环路 - + Improves rendering of transparency effects in specific games. 改进某些游戏中透明效果的渲染。 - + Enable buffer history 启用缓冲区历史 - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. 允许访问之前的缓冲状态。 这个选项可能会提升某些游戏的渲染质量和性能一致性。 - + Fix bloom effects 修复泛光效果 - + Removes bloom in Burnout. 去除《火爆狂飙》中的泛光特效。 - + Extended Dynamic State 扩展动态状态 - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. 控制在扩展动态状态中可使用的函数数量。更高的数值允许启用更多功能,并可能提升性能,但同时也可能导致额外的图形问题。 - + Vertex Input Dynamic State 顶点输入动态状态 - + Enables vertex input dynamic state feature for better quality and performance. 开启顶点输入动态状态功能来获得更好的质量和性能。 - + Sample Shading 采样着色 - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. 允许片段着色器在多重采样的片段中每个样本执行一次而不是每个片段执行一次。可以提高图形质量,但会降低性能。 更高的值可以提高质量但会降低性能。 - + RNG Seed 随机数生成器种子 - + Controls the seed of the random number generator. Mainly used for speedrunning. 控制随机数生成器的种子。 主要用于竞速游戏。 - + Device Name 设备名称 - + The name of the console. 主机的数量。 - + Homebrew Args 自制软件参数 - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). 启动 homebrew 时需要传递的命令行参数 (例如 -noglsl)。 - + Custom RTC Date: 自定义系统时间: - + This option allows to change the clock of the console. Can be used to manipulate time in games. 此选项允许更改控制台的时钟。 可用于操纵游戏中的时间。 - + The number of seconds from the current unix time 来自当前 unix 时间的秒数。 - + Language: 语言: - + This option can be overridden when region setting is auto-select 当区域设置为自动选择时可以使用此选项替代。 - + Region: 地区: - + The region of the console. 主机的区域。 - + Time Zone: 时区: - + The time zone of the console. 主机的时区。 - + Sound Output Mode: 声音输出模式: - + Console Mode: 控制台模式: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. @@ -1135,1026 +1129,1026 @@ Setting to Handheld can help improve performance for low end systems. 将设置为掌机模式可以帮助低端系统提高性能。 - + Prompt for user profile on boot 启动时提示选择用户账户 - + Useful if multiple people use the same PC. 在多人使用相同的 PC 时有效。 - + Pause when not in focus 在丢失焦点时暂停 - + Pauses emulation when focusing on other windows. 当焦点位于其它窗口时暂停模拟器。 - + Confirm before stopping emulation 停止模拟时需要确认 - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. 替代提示以确认停止模拟。 启用它将绕过此类提示并直接退出模拟。 - + Hide mouse on inactivity 自动隐藏鼠标光标 - + Hides the mouse after 2.5s of inactivity. 在 2.5 秒无活动后隐藏鼠标。 - + Check for updates 检查更新 - + Whether or not to check for updates upon startup. 在启动时是否检查更新。 - + Enable Gamemode 启用游戏模式 - + Force X11 as Graphics Backend 强制使用 X11 作为图形后端 - + Custom frontend 自定义前端 - + Real applet 真实的小程序 - - + + Disabled 禁用 - + Never 永不 - + On Load 加载时 - + Always 总是 - + CPU CPU - + GPU GPU - + CPU Asynchronous CPU 异步模拟 - + Uncompressed (Best quality) 不压缩 (最高质量) - + BC1 (Low quality) BC1 (低质量) - + BC3 (Medium quality) BC3 (中等质量) - - + + Auto 自动 - + 30 FPS 30 FPS - + 60 FPS 60 FPS - + 90 FPS 90 FPS - + 120 FPS 120 FPS - + Conservative 保守模式 - + Aggressive 激进模式 - + Vulkan Vulkan - + OpenGL GLSL OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) OpenGL GLASM (汇编着色器,仅限 NVIDIA 显卡) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) OpenGL SPIR-V (实验性,仅限 AMD/Mesa) - + Null 无 - + Fast 高速 - - - + + + Accurate 高精度 - - - + + + Default 系统默认 - + Unsafe (fast) 不安全(快速) - + Safe (stable) 安全(稳定) - + Immediate 即时 - + Balanced 平衡 - + Unsafe 低精度 - + Paranoid (disables most optimizations) 偏执模式 (禁用绝大多数优化项) - + Debugging 调试 - + Dynarmic 动态编译 - + NCE 本机代码执行 - + Borderless Windowed 无边框窗口 - + Exclusive Fullscreen 独占全屏 - + No Video Output 无视频输出 - + CPU Video Decoding CPU 视频解码 - + GPU Video Decoding (Default) GPU 视频解码 (默认) - + 0.25X (180p/270p) [EXPERIMENTAL] 0.25X (180p/270p) [实验性] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [实验性] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [实验性] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] 1.25X (900p/1350p) [实验性] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [实验性] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor 近邻取样 - + Bilinear 双线性过滤 - + Bicubic 双三线过滤 - + Gaussian 高斯模糊 - + Lanczos Lanczos - + ScaleForce 强制缩放 - + AMD FidelityFX Super Resolution AMD FidelityFX 超级分辨率 - + Area 区域 - + MMPX MMPX - + Zero-Tangent 零切线 - + B-Spline B-Spline - + Mitchell Mitchell - + Spline-1 Spline-1 - + Snapdragon Game Super Resolution 骁龙游戏超级分辨率 - + Snapdragon Game Super Resolution EdgeDir 骁龙游戏超级分辨率 EdgeDir - + None 无 - + FXAA 快速近似抗锯齿 - + SMAA 子像素形态学抗锯齿 - + Default (16:9) 默认 (16:9) - + Force 4:3 强制 4:3 - + Force 21:9 强制 21:9 - + Force 16:10 强制 16:10 - + Stretch to Window 拉伸窗口 - + Automatic 自动 - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) 日语 (日本語) - + American English 美式英语 - + French (français) 法语 (français) - + German (Deutsch) 德语 (Deutsch) - + Italian (italiano) 意大利语 (italiano) - + Spanish (español) 西班牙语 (español) - + Chinese 中文 - + Korean (한국어) 韩语 (한국어) - + Dutch (Nederlands) 荷兰语 (Nederlands) - + Portuguese (português) 葡萄牙语 (português) - + Russian (Русский) 俄语 (Русский) - + Taiwanese 台湾中文 - + British English 英式英语 - + Canadian French 加拿大法语 - + Latin American Spanish 拉美西班牙语 - + Simplified Chinese 简体中文 - + Traditional Chinese (正體中文) 繁体中文 (正體中文) - + Brazilian Portuguese (português do Brasil) 巴西-葡萄牙语 (português do Brasil) - + Polish (polska) - 波兰语(波兰语) + 波兰语 (polska) + + + + Thai (แบบไทย) + 泰语 (แบบไทย) - Thai (แบบไทย) - 泰语 - - - - + Japan 日本 - + USA 美国 - + Europe 欧洲 - + Australia 澳大利亚 - + China 中国 - + Korea 韩国 - + Taiwan 台湾地区 - + Auto (%1) Auto select time zone 自动 (%1) - + Default (%1) Default time zone 默认 (%1) - + CET 欧洲中部时间 - + CST6CDT 古巴标准时间&古巴夏令时 - + Cuba 古巴 - + EET 东欧时间 - + Egypt 埃及 - + Eire 爱尔兰 - + EST 东部标准时间 - + EST5EDT 东部标准时间&东部夏令时 - + GB 英国 - + GB-Eire 英国-爱尔兰时间 - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich 格林威治 - + Hongkong 香港 - + HST 美国夏威夷时间 - + Iceland 冰岛 - + Iran 伊朗 - + Israel 以色列 - + Jamaica 牙买加 - + Kwajalein 夸贾林环礁 - + Libya 利比亚 - + MET 中欧时间 - + MST 山区标准时间 (北美) - + MST7MDT 山区标准时间&山区夏令时 (北美) - + Navajo 纳瓦霍 - + NZ 新西兰时间 - + NZ-CHAT NZ-CHAT - + Poland 波兰 - + Portugal 葡萄牙 - + PRC 中国标准时间 - + PST8PDT 太平洋标准时间&太平洋夏令时 - + ROC 台湾时间 - + ROK 韩国时间 - + Singapore 新加坡 - + Turkey 土耳其 - + UCT UCT - + Universal 世界时间 - + UTC 协调世界时 - + W-SU 欧洲-莫斯科时间 - + WET 西欧时间 - + Zulu 祖鲁 - + Mono 单声道 - + Stereo 立体声 - + Surround 环绕声 - + 4GB DRAM (Default) 4GB DRAM (默认) - + 6GB DRAM (Unsafe) 6GB DRAM (不安全) - + 8GB DRAM 8GB DRAM - + 10GB DRAM (Unsafe) 10GB DRAM (不安全) - + 12GB DRAM (Unsafe) 12GB DRAM (不安全) - + Docked 主机模式 - + Handheld 掌机模式 - - + + Normal 正常 - - + + Boost 升频 - - + + Overclock 超频 - + Always ask (Default) 总是询问 (默认) - + Only if game specifies not to stop 仅当游戏不希望停止时 - + Never ask 从不询问 - + Very Small (16 MB) 很小 (16 MB) - + Small (32 MB) 较小 (32 MB) - + Normal (128 MB) 正常 (128 MB) - + Large (256 MB) 较大 (256 MB) - + Very Large (512 MB) 很大 (512 MB) - + Very Low (4 MB) 很低 (4 MB) - + Low (8 MB) 低 (8 MB) - + Normal (16 MB) 正常 (16 MB) - + Medium (32 MB) 中 (32 MB) - + High (64 MB) 高 (64 MB) - + Very Low (32) 很低 (32) - + Low (64) 低 (64) - + Normal (128) 正常 (128) - + Medium (256) 中(256) - + High (512) 高(512) - + ExtendedDynamicState 1 扩展动态状态 1 - + ExtendedDynamicState 2 扩展动态状态 2 - + ExtendedDynamicState 3 扩展动态状态 3 - + Tree View 树景视图 - + Grid View 网格视图 @@ -5120,12 +5114,12 @@ Once deleted, these can NOT be recovered. Are you 100% sure you want to delete t &Edit - 编辑 (&E) + 编辑(&E) &Delete - 删除 (&D) + 删除(&D) @@ -5378,7 +5372,7 @@ UUID: %2 Select TAS Load Directory... - 选择 TAS 载入目录... + 选择 TAS 加载目录... @@ -5620,12 +5614,12 @@ Drag points to change position, or double-click table cells to edit values. Row 1 Text: - 第一行: + 第 1 行: Row 2 Text: - 第二行: + 第 2 行: @@ -5836,7 +5830,7 @@ Drag points to change position, or double-click table cells to edit values. &Controller P1 - 控制器 P1 (&C) + 控制器 P1(&C) @@ -6113,50 +6107,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! OpenGL 模式不可用! - + OpenGL shared contexts are not supported. 不支持 OpenGL 共享上下文。 - + Eden has not been compiled with OpenGL support. Eden 尚未编译为支持 OpenGL。 - - - + + + Error while initializing OpenGL! 初始化 OpenGL 时出错! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. 您的 GPU 可能不支持 OpenGL ,或者您没有安装最新的显卡驱动。 - + Error while initializing OpenGL 4.6! 初始化 OpenGL 4.6 时出错! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 您的 GPU 可能不支持 OpenGL 4.6 ,或者您没有安装最新的显卡驱动。<br><br>GL 渲染器:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 您的 GPU 可能不支持某些必需的 OpenGL 扩展。请确保您已经安装最新的显卡驱动。<br><br>GL 渲染器:<br>%1<br><br>不支持的扩展:<br>%2 - + This build doesn't have OpenGL support. 此版本不支持 OpenGL。 @@ -6166,7 +6160,7 @@ Please go to Configure -> System -> Network and make a selection. &Add New Game Directory - 添加新游戏目录 (&A) + 添加新游戏目录(&A) @@ -6439,7 +6433,7 @@ Please go to Configure -> System -> Network and make a selection. %1 of %n result(s) - %n个结果中的第%1个 + %n 个结果中的第 %1 个 @@ -6531,7 +6525,8 @@ Please go to Configure -> System -> Network and make a selection. Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Eden account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: - + 无法向公共大厅公开房间。要公开托管房间,您必须在模拟 -> 配置 -> Web 中配置有效的 Eden 帐户。如果您不想在公共大厅发布房间,则请选择"未列出"。 +调试信息: @@ -6904,12 +6899,12 @@ Debug Message: &File - 文件 (&F) + 文件(&F) &Recent Files - 最近文件 (&R) + 最近文件(&R) @@ -6919,1140 +6914,1160 @@ Debug Message: &Emulation - 模拟 (&E) + 模拟(&E) - + + &Cheats + 作弊(&C) + + + &View - 视图 (&V) + 视图(&V) - + &Reset Window Size - 重置窗口大小 (&R) + 重置窗口大小(&R) - + &Debugging - 调试 (&D) - - - - &Game List Mode - 游戏列表模式 (&G) + 调试(&D) - Game &Icon Size - 游戏图标大小 (&I) - - - - Reset Window Size to &720p - 重置窗口大小为720p (&7) + &Game List Mode + 游戏列表模式(&G) + Game &Icon Size + 游戏图标大小(&I) + + + + Reset Window Size to &720p + 重置窗口大小为 &720p + + + Reset Window Size to 720p 重置窗口大小为720p - + Reset Window Size to &900p - 重置窗口大小为900p (&9) + 重置窗口大小为 &900p - + Reset Window Size to 900p 重置窗口大小为900p - + Reset Window Size to &1080p - 重置窗口大小为1080p (&1) + 重置窗口大小为 &1080p - + Reset Window Size to 1080p 重置窗口大小为1080p - + &Multiplayer - 多人游戏 (&M) + 多人游戏(&M) - + &Tools - 工具 (&T) + 工具(&T) - + Am&iibo Am&iibo - + Launch &Applet - 启动小程序 (&A) + 启动小程序(&A) - + &TAS - TAS (&T) + &TAS - + &Create Home Menu Shortcut 创建主页菜单快捷方式(&C) - + Install &Firmware 安装固件(&F) - + &Help - 帮助 (&H) + 帮助(&H) - + &Install Files to NAND... 安装文件到 NAND... (&I) - + L&oad File... 加载文件... (&O) - + Load &Folder... 加载文件夹... (&F) - + E&xit - 退出 (&X) + 退出(&X) - - + + &Pause - 暂停 (&P) + 暂停(&P) - + &Stop - 停止 (&S) + 停止(&S) - + &Verify Installed Contents - 验证已安装内容的完整性 (&V) + 验证已安装内容的完整性(&V) - + &About Eden 关于 Eden(&A) - + Single &Window Mode - 单窗口模式 (&W) + 单窗口模式(&W) - + Con&figure... 设置... (&F) - + Ctrl+, Ctrl+, - + Enable Overlay Display Applet 开启覆盖层显示小程序 - + Show &Filter Bar - 显示搜索栏 (&F) + 显示搜索栏(&F) - + Show &Status Bar - 显示状态栏 (&S) + 显示状态栏(&S) - + Show Status Bar 显示状态栏 - + &Browse Public Game Lobby - 浏览公共游戏大厅 (&B) + 浏览公共游戏大厅(&B) - + &Create Room - 创建房间 (&C) + 创建房间(&C) - + &Leave Room - 离开房间 (&L) + 离开房间(&L) - + &Direct Connect to Room - 直接连接到房间 (&D) + 直接连接到房间(&D) - + &Show Current Room - 显示当前房间 (&S) + 显示当前房间(&S) - + F&ullscreen - 全屏 (&U) + 全屏(&U) - + &Restart - 重新启动 (&R) + 重新启动(&R) - + Load/Remove &Amiibo... - 加载/移除 Amiibo... (&A) + 加载/移除 &Amiibo... - + Open &Mods Page - 打开 Mod 页面 (&M) + 打开 &Mod 页面 - + &User Handbook 用户手册(&U) - + &Capture Screenshot - 捕获截图 (&C) + 捕获截图(&C) - + &Album - 相册 (&A) + 相册(&A) - + &Set Nickname and Owner - 设置昵称及所有者 (&S) + 设置昵称及所有者(&S) - + &Delete Game Data - 删除游戏数据 (&D) + 删除游戏数据(&D) - + &Restore Amiibo - 重置 Amiibo (&R) + 重置 Amiibo(&R) - + &Format Amiibo - 格式化 Amiibo (&F) + 格式化 Amiibo(&F) - + &Mii Editor - Mii 编辑器 (&M) + &Mii 编辑器 - + &Configure TAS... - 配置 TAS... (&C) + 配置 TAS...(&C) - + Configure C&urrent Game... - 配置当前游戏... (&U) + 配置当前游戏...(&U) - - + + &Start - 开始 (&S) + 开始(&S) - + &Reset - 重置 (&R) + 重置(&R) - - + + R&ecord - 录制 (&E) + 录制(&E) - + Open &Controller Menu - 打开控制器菜单 (&C) + 打开控制器菜单(&C) - + Install Decryption &Keys 安装解密密钥(&K) - + &Home Menu - 主页 (&H) + 主页(&H) - + &Desktop 桌面(&D) - + &Application Menu 应用程序菜单(&A) - + &Root Data Folder 根数据文件夹(&R) - + &NAND Folder &NAND 文件夹 - + &SDMC Folder &SDMC 文件夹 - + &Mod Folder &Mod 文件夹 - + &Log Folder &Log 文件夹 - + From Folder 从文件夹 - + From ZIP 从 ZIP - + &Eden Dependencies &Eden 依赖项 - + &Data Manager 数据管理器(&D) - + &Tree View - 树景视图 (&T) + 树状视图(&T) - + &Grid View - 网格视图 (&G) + 网格视图(&G) - + Game Icon Size 游戏图标大小 - - + + None 无 - + Show Game &Name - 显示游戏名称 (&N) + 显示游戏名称(&N) - + Show &Performance Overlay 显示性能覆盖层 - + Post-Processing &Shaders... 后处理效果着色器(&S)... - + &Carousel View 轮播视图(&C) - + Small (32x32) 小 (32x32) - + Standard (64x64) 标准 (64x64) - + Large (128x128) 大 (128x128) - + Full Size (256x256) 最大 (256x256) - + Broken Vulkan Installation Detected 检测到损坏的 Vulkan 安装 - + Vulkan initialization failed during boot. 在启动时初始化 Vulkan 失败。 - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping 运行游戏 - + Loading Web Applet... 正在加载 Web 小程序... - - + + Disable Web Applet 禁用 Web 小程序 - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) 禁用网页小程序可能会导致未定义的行为并且应仅在 超级马里奥 3D 全明星中使用。您确定要禁用网页小程序吗? (这可以在调试设置中重新启用。) - + The amount of shaders currently being built 当前正在构建的着色器数量 - + The current selected resolution scaling multiplier. 当前选择的分辨率缩放倍数。 - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. 当前模拟速度。高于或低于 100% 的数值表示模拟运行比 Switch 快或慢。 - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. 游戏当前显示的每秒帧数。这个数值会因游戏和场景的不同而有所变化。 - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 模拟 Switch 一帧所需的时间,不包括帧限制或垂直同步。为了全速模拟这个时间最多应为 16.67 毫秒。 - + Unmute 取消静音 - + Mute 静音 - + Reset Volume 重置音量 - + Configure Effects... 配置效果... - + &Clear Recent Files 清除最近的文件(&C) - + + Disable All Cheats + 关闭所有作弊 + + + + Enable All Cheats + 开启所有作弊 + + + + Unnamed Cheat + 未命名的作弊 + + + &Continue 继续(&C) - + Warning: Outdated Game Format 警告: 游戏格式过时 - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. 您正在为此游戏使用解包 ROM 目录格式,这是一种已过时的格式,它已被 NCA、NAX、XCI 或 NSP 等其他格式取代。解包 ROM 目录缺少图标、元数据和更新支持。<br>有关 Eden 支持的各种 Switch 格式的说明请查阅我们的用户手册。此消息将不再显示。 - - + + Error while loading ROM! 加载 ROM 时出错! - + The ROM format is not supported. 不支持该 ROM 格式。 - + An error occurred initializing the video core. 初始化视频核心时发生错误。 - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. 这通常是因为过时的 GPU 驱动所导致的。具体情况请查看日志。请查阅: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>如何访问日志文件</a>。 - + Error while loading ROM! %1 %1 signifies a numeric error code. 加载 ROM 时出错! %1 - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. %1<br>请重新导出您的文件,或在 Discord/Stoat 上寻求帮助。 - + An unknown error occurred. Please see the log for more details. 发生未知错误。请查看日志以获取更多详情。 - - + + (64-bit) (64 位) - - + + (32-bit) (32 位) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit %1 %2 - + Closing software... 正在关闭软件... - + Save Data 存档数据 - + Mod Data Mod 数据 - + Error Opening %1 Folder 打开 %1 文件夹出错 - - + + Folder does not exist! 文件夹不存在! - + Remove Installed Game Contents? 是否移除已安装的游戏内容? - + Remove Installed Game Update? 是否移除已安装的游戏更新? - + Remove Installed Game DLC? 是否移除已安装的游戏 DLC? - + Remove Entry 删除条目 - + Delete OpenGL Transferable Shader Cache? 要删除 OpenGL 可传输着色器缓存吗? - + Delete Vulkan Transferable Shader Cache? 要删除 Vulkan 可传输着色器缓存吗? - + Delete All Transferable Shader Caches? 删除所有可传输的着色器缓存? - + Remove Custom Game Configuration? 是否移除自定义游戏配置? - + Remove Cache Storage? 要清除缓存存储吗? - + Remove File 删除文件 - + Remove Play Time Data 删除游戏时间数据 - + Reset play time? 要重置播放时间吗? - - + + RomFS Extraction Failed! RomFS 提取失败! - + There was an error copying the RomFS files or the user cancelled the operation. 复制 RomFS 文件时出错或用户取消了操作。 - + Full 完整 - + Skeleton 结构 - + Select RomFS Dump Mode 选择 RomFS 转储模式 - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. 请选择您希望如何导出 RomFS。<br>&quot;完整&quot; 将把所有文件复制到新的目录中,而<br>&quot;结构&quot; 仅会创建目录结构。</br></br> - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root %1 的可用空间不足,无法提取 RomFS。请释放空间或在模拟 > 配置 > 系统 > 文件系统 > 转储根目录,中选择其它目录 - + Extracting RomFS... 正在提取 RomFS... - - + + Cancel 取消 - + RomFS Extraction Succeeded! RomFS 提取成功! - + The operation completed successfully. 操作已成功完成。 - + Error Opening %1 打开 %1 时出错 - + Select Directory 选择目录 - + Properties 属性 - + The game properties could not be loaded. 无法加载游戏属性。 - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. Switch 可执行文件 (%1);;所有文件 (*.*) - + Load File 加载文件 - + Open Extracted ROM Directory 打开已提取的 ROM 目录 - + Invalid Directory Selected 选择的目录无效 - + The directory you have selected does not contain a 'main' file. 您选择的目录不包含 'main' 文件。 - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) - 可安装的 Switch 文件 (*.nca *.nsp *.xci);;任天堂内容档案 (*.nca);;任天堂提交包 (*.nsp);;NX 卡带镜像 (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) + 可安装的 Switch 文件 (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo 内容档案 (*.nca);;Nintendo 提交包 (*.nsp *.nsz);;NX 卡带映像 (*.xci *.xcz) - + Install Files 安装文件 - + %n file(s) remaining 剩余 %n 个文件 - + Installing file "%1"... 正在安装文件 "%1"... - - + + Install Results 安装结果 - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. 为了避免可能的冲突,我们不鼓励用户将基础游戏安装到 NAND。 请仅使用此功能来安装更新和 DLC。 - + %n file(s) were newly installed 已新安装 %n 个文件 - + %n file(s) were overwritten 已覆盖了 %n 个文件 - + %n file(s) failed to install %n 个文件安装失败 - + System Application 系统应用 - + System Archive 系统档案 - + System Application Update 系统应用更新 - + Firmware Package (Type A) 固件包 (类型 A) - + Firmware Package (Type B) 固件包 (类型 B) - + Game 游戏 - + Game Update 游戏更新 - + Game DLC 游戏可下载内容 - + Delta Title Delta 标题 - + Select NCA Install Type... 选择 NCA 安装类型... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) 请选择您希望将此 NCA 安装为的标题类型: (在大多数情况下,默认的 '游戏' 就可以。) - + Failed to Install 安装失败 - + The title type you selected for the NCA is invalid. 您为 NCA 选择的标题类型无效。 - + File not found 找不到文件 - + File "%1" not found 未找到文件 "%1" - + OK 确定 - + Function Disabled 功能已被关闭 - + Compatibility list reporting is currently disabled. Check back later! 兼容性列表报告目前已被禁用。请稍后再查看! - + Error opening URL 打开网址出错 - + Unable to open the URL "%1". 无法打开 URL "%1"。 - + TAS Recording TAS 录像 - + Overwrite file of player 1? 要覆盖玩家 1 的文件吗? - + Invalid config detected 检测到无效配置 - + Handheld controller can't be used on docked mode. Pro controller will be selected. 手柄在主机模式下无法使用。将选择 Pro 手柄。 - - + + Amiibo Amiibo - - + + The current amiibo has been removed 当前的 amiibo 已被移除 - + Error 错误 - - + + The current game is not looking for amiibos 当前游戏不支持寻找 amiibo - + Amiibo File (%1);; All Files (*.*) Amiibo 文件 (%1);; 所有文件 (*.*) - + Load Amiibo 读取 Amiibo - + Error loading Amiibo data 加载 Amiibo 数据出错 - + The selected file is not a valid amiibo 所选文件不是有效的 amiibo - + The selected file is already on use 所选文件正在使用中 - + An unknown error occurred 发生未知错误 - + No firmware available 没有可用的固件 - + Firmware Corrupted 固件已损坏 - + Unknown applet 未知小程序 - + Applet doesn't map to a known value. 无法识别该小程序对应的值。 - + Record not found 找不到记录程序 - + Applet not found. Please reinstall firmware. 找不到小程序。请重新安装固件。 - + Capture Screenshot 截取屏幕截图 - + PNG Image (*.png) PNG 图像 (*.png) - + TAS state: Running %1/%2 TAS 状态: 正在运行 %1/%2 - + TAS state: Recording %1 TAS 状态: 正在录制 %1 - + TAS state: Idle %1/%2 TAS 状态: 空闲 %1/%2 - + TAS State: Invalid TAS 状态: 无效 - + &Stop Running 停止运行(&S) - + Stop R&ecording 停止录制(&A) - + Building: %n shader(s) 正在编译:%n 个着色器 - + Scale: %1x %1 is the resolution scaling factor 缩放: %1x - + Speed: %1% / %2% 速度: %1% / %2% - + Speed: %1% 速度: %1% - + Game: %1 FPS 游戏: %1 FPS - + Frame: %1 ms 帧: %1 ms - + NO AA 无 AA - + NO FX 无 FX - + FX FX - + VOLUME: MUTE 音量: 静音 - + VOLUME: %1% Volume percentage (e.g. 50%) 音量: %1% - + Derivation Components Missing 缺少派生组件 - + Decryption keys are missing. Install them now? 缺少解密密钥。现在安装吗? - + Wayland Detected! 检测到 Wayland! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8063,74 +8078,74 @@ Would you like to force it for future launches? 您想要在未来的启动中强制执行吗? - + Use X11 使用 X11 - + Continue with Wayland 继续使用 Wayland - + Don't show again 不再显示 - + Restart Required 需要重新启动 - + Restart Eden to apply the X11 backend. 重新启动 Eden 以应用 X11 后端。 - + Slow 慢速 - + Turbo 加速 - + Unlocked 解锁 - + Select RomFS Dump Target 选择 RomFS 转储目标 - + Please select which RomFS you would like to dump. 请选择您想要转储的 RomFS。 - + Are you sure you want to close Eden? 您确实要关闭 Eden 吗? - - - + + + Eden Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. 您确定要停止模拟吗?任何未保存的进度将会丢失。 - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? @@ -10110,7 +10125,7 @@ Do not uncheck unless you know what you're doing. Keeps the old data directory. This is recommended if you aren't space-constrained and want to keep separate data for the old emulator. - 保留旧的数据目录。如果你的存储空间充足,并且想为旧 + 保留旧的数据目录。如果您的存储空间充足,并且想为旧 模拟器保留独立的数据,这是推荐做法。 @@ -10209,7 +10224,7 @@ This is recommended if you want to share data between emulators. Dual Joycons - 双 Joycons 手柄 + 双 Joycon 手柄 @@ -10410,7 +10425,7 @@ This is recommended if you want to share data between emulators. Sega Genesis - 世嘉创世纪 + 世嘉 Genesis @@ -10489,7 +10504,7 @@ Please try again or contact the developer of the software. Who will receive the points? - 谁将获得黄金点数? + 谁将获得点数? diff --git a/dist/languages/zh_TW.ts b/dist/languages/zh_TW.ts index 463d7fa2ed..cf681917cd 100644 --- a/dist/languages/zh_TW.ts +++ b/dist/languages/zh_TW.ts @@ -37,8 +37,8 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">網站</span></a>|<a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">原始碼</span></a>|<a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">貢獻者</span></a>|<a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a>|<a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a>|<a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a>|<a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">許可證</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + @@ -410,49 +410,59 @@ Can help reduce stuttering at lower framerates. 可在較低FPS時減少卡頓的情況 - + + Enable cheats by default + + + + + Enables regular cheats when a game starts. Master Code entries are always enabled. Individual cheats can still be toggled from Cheats in the menu bar while the game is running. + + + + Accuracy: 準確度: - + Change the accuracy of the emulated CPU (for debugging only). 改變模擬CPU的準確度(僅限偵錯用) - - + + Backend: 後端: - + CPU Clocks - + Raises the clock the emulated CPU reports, which removes some FPS limiters. Weaker CPUs may see reduced performance, and certain games may behave improperly. - + Custom CPU Ticks 自訂CPU時脈 - + Set a custom value of CPU ticks. Higher values can increase performance, but may cause deadlocks. A range of 77-21000 is recommended. 自訂CPU時脈。更高的值可能提高效能,但也可能導致遊戲卡死。建議範圍為77-21000。 - + Enable Host MMU Emulation (fastmem) 啟用主機 MMU 模擬(fastmem) - + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU. Disabling this forces all memory accesses to use Software MMU Emulation. @@ -461,100 +471,100 @@ Disabling this forces all memory accesses to use Software MMU Emulation. - + Unfuse FMA (improve performance on CPUs without FMA) 解除融合FMA(能讓不支援 FMA 指令集的 CPU 提高效能) - + This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support. 透過降低積和熔加運算的準確度來提高模擬器在不支援FMA指令集CPU上的運行速度 - + Faster FRSQRTE and FRECPE 更快的 FRSQRTE 和 FRECPE - + This option improves the speed of some approximate floating-point functions by using less accurate native approximations. 透過使用準確度較低的近似值來提高某些浮點函數的運算速度 - + Faster ASIMD instructions (32 bits only) 快速 ASIMD 指令(僅限 32 位元) - + This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes. 透過使用不準確的捨入模式來提高32位元ASIMD浮點函數的運算速度 - + Inaccurate NaN handling 低準確度NaN處理 - + This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions. 透過取消NaN檢查來提高速度。 請注意,啟用後會降低些浮點指令的準確度 - + Disable address space checks 停用位址空間檢查 - + This option improves speed by eliminating a safety check before every memory operation. Disabling it may allow arbitrary code execution. 透過省略在每次記憶體操作前執行的安全檢查來提高速度 停用此功能可能會允許任意程式碼執行 - + Ignore global monitor 忽略全局監視器 - + This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions. 透過僅依賴cmpxchg指令來確保獨佔存取指令的安全性並提高速度。 請注意,這可能會導致死鎖或其它問題 - + API: API: - + Changes the output graphics API. Vulkan is recommended. 更改使用的圖形API 推薦使用Vulkan - + Device: 裝置: - + This setting selects the GPU to use (Vulkan only). 選擇要使用的GPU(僅限Vulkan) - + Resolution: 解析度: - + Forces to render at a different resolution. Higher resolutions require more VRAM and bandwidth. Options lower than 1X can cause artifacts. @@ -563,27 +573,27 @@ Options lower than 1X can cause artifacts. 選擇低於1X的解析度可能會導致畫面異常 - + Window Adapting Filter: 視窗適應過濾器: - + FSR Sharpness: FSR 銳化度: - + Determines how sharpened the image will look using FSR's or SGSR's dynamic contrast. - + Anti-Aliasing Method: 抗鋸齒: - + The anti-aliasing method to use. SMAA offers the best quality. FXAA can produce a more stable picture in lower resolutions. @@ -592,22 +602,22 @@ SMAA的品質最佳 FXAA在低解析度下可以產生較穩定的畫面 - + Enable post-processing effects - + Applies post-processing effects to the final image. - + Fullscreen Mode: 全螢幕模式: - + The method used to render the window in fullscreen. Borderless offers the best compatibility with the on-screen keyboard that some games request for input. Exclusive fullscreen may offer better performance and better Freesync/Gsync support. @@ -616,47 +626,47 @@ Exclusive fullscreen may offer better performance and better Freesync/Gsync supp 獨佔全螢幕將提供更好的性能以及更佳的FreeSync/G-Sync支援 - + Aspect Ratio: 長寬比: - + Stretches the renderer to fit the specified aspect ratio. Most games only support 16:9, so modifications are required to get other ratios. Also controls the aspect ratio of captured screenshots. - + Use persistent pipeline cache - + Allows saving shaders to storage for faster loading on following game boots. Disabling it is only intended for debugging. 將產生的著色器快取儲存至硬碟,讓遊戲在後續過程中不需再次產生以提高速度 建議僅在偵錯時才停用此選項 - + Use asynchronous GPU emulation - + Uses an extra CPU thread for rendering. This option should always remain enabled. - + NVDEC emulation: NVDEC 模擬: - + Specifies how videos should be decoded. It can either use the CPU or the GPU for decoding, or perform no decoding at all (black screen on videos). In most cases, GPU decoding provides the best performance. @@ -665,12 +675,12 @@ In most cases, GPU decoding provides the best performance. GPU解碼在大多數情況下提供最好的性能 - + ASTC Decoding Method: ASTC解碼方式: - + This option controls how ASTC textures should be decoded. CPU: Use the CPU for decoding. GPU: Use the GPU's compute shaders to decode ASTC textures (recommended). @@ -679,75 +689,55 @@ stuttering but may present artifacts. - + ASTC Recompression Method: ASTC重新壓縮方式: - + Most GPUs lack support for ASTC textures and must decompress to anintermediate format: RGBA8. BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format, saving VRAM but degrading image quality. - + Frame Pacing Mode (Vulkan only) - + Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. - + VRAM Usage Mode: VRAM 使用模式: - + Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance. Aggressive mode may impact performance of other applications such as recording software. - + Skip CPU Inner Invalidation 跳過CPU內部失效處理 - + Skips certain cache invalidations during memory updates, reducing CPU usage and improving latency. This may cause soft-crashes. - - GPU Readback Before NCE Invalidation - - - - - Flushes GPU buffer data back to guest memory before NCE invalidates the whole guest page, preserving it while the CPU store proceeds. - - - - - Patch Runtime NROs for NCE - - - - - Applies NCE code patches to runtime-loaded NRO modules.This is required for some games to run correctly. - - - - + VSync Mode: 垂直同步: - + FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. FIFO Relaxed allows tearing as it recovers from a slow down. Mailbox can have lower latency than FIFO and does not tear but may drop frames. @@ -755,79 +745,79 @@ Immediate (no synchronization) presents whatever is available and can exhibit te - + Sync Memory Operations 同步記憶體操作 - + Ensures data consistency between compute and memory operations. This option fixes issues in games, but may degrade performance. Unreal Engine 4 games often see the most significant changes thereof. - + Enable asynchronous presentation (Vulkan only) 啟用非同步顯示(僅限Vulkan) - + Slightly improves performance by moving presentation to a separate CPU thread. 透過將畫面顯示移至獨立的CPU執行緒來略微提升性能。 - + Force maximum clocks (Vulkan only) 強制使用最大時脈(僅限Vulkan) - + Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed. 在等待圖形命令時於背景執行任務以防GPU降低時脈 - + Anisotropic Filtering: 各向異性過濾: - + Controls the quality of texture rendering at oblique angles. Safe to set at 16x on most GPUs. - + GPU Mode: - + Controls the GPU emulation mode. Most games render fine with Fast, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. - + DMA Accuracy: - + Controls the DMA read mode. Unsafe is faster, while Safe is more stable and can fix issues in some games. Default follows the GPU Accuracy setting. - + GPU Fence Behavior: - + Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. @@ -836,1291 +826,1291 @@ Default follows the GPU Mode setting. - + Enable asynchronous shader compilation - + May reduce shader stutter. - + GPU Clocks - + Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch's clocks. - + GPU Unswizzle - + Accelerates BCn 3D texture decoding using GPU compute. Disable if experiencing crashes or graphical glitches. - + GPU Unswizzle Max Texture Size - + Sets the maximum size (MiB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead. - + GPU Unswizzle Stream Size - + Sets the maximum amount of texture data (in MiB) processed per frame. Higher values can reduce stutter during texture loading but may impact frame consistency. - + GPU Unswizzle Chunk Size - + Determines the number of depth slices processed in a single dispatch. Increasing this can improve throughput on high-end GPUs but may cause TDR or driver timeouts on weaker hardware. - + Use Vulkan pipeline cache 启用 Vulkan 管线缓存 - + Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally. 启用 GPU 供应商专用的管线缓存。 在 Vulkan 驱动程序内部不存储管线缓存的情况下,此选项可显著提高着色器加载速度。 - + Enable Compute Pipelines (Intel Vulkan Only) 启用计算管线 (仅限 Intel 显卡 Vulkan 模式) - + Required by some games. This setting only exists for Intel proprietary drivers and may crash if enabled. Compute pipelines are always enabled on all other drivers. - + Enable Reactive Flushing 启用反应性刷新 - + Uses reactive flushing instead of predictive flushing, allowing more accurate memory syncing. 使用反应性刷新取代预测性刷新,从而更精确地同步内存。 - + Sync to framerate of video playback 播放视频时帧率同步 - + Run the game at normal speed during video playback, even when the framerate is unlocked. 在视频播放期间以正常速度运行游戏,即使帧率未锁定。 - + Barrier feedback loops 屏障反馈循环 - + Improves rendering of transparency effects in specific games. 改进某些游戏中透明效果的渲染。 - + Enable buffer history - + Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. - + Fix bloom effects - + Removes bloom in Burnout. - + Extended Dynamic State - + Controls the number of features that can be used in Extended Dynamic State. Higher states allow for more features and can increase performance, but may cause additional graphical issues. - + Vertex Input Dynamic State - + Enables vertex input dynamic state feature for better quality and performance. - + Sample Shading - + Allows the fragment shader to execute per sample in a multi-sampled fragment instead of once per fragment. Improves graphics quality at the cost of performance. Higher values improve quality but degrade performance. - + RNG Seed 隨機種子 - + Controls the seed of the random number generator. Mainly used for speedrunning. - + Device Name 裝置名稱 - + The name of the console. - + Homebrew Args - + Command-line arguments passed to homebrew at launch (e.g. -noglsl). - + Custom RTC Date: 自定义系统时间: - + This option allows to change the clock of the console. Can be used to manipulate time in games. - + The number of seconds from the current unix time - + Language: 语言: - + This option can be overridden when region setting is auto-select - + Region: 區域: - + The region of the console. - + Time Zone: 時區: - + The time zone of the console. - + Sound Output Mode: 音訊輸出模式: - + Console Mode: 控制台模式: - + Selects if the console is in Docked or Handheld mode. Games will change their resolution, details and supported controllers and depending on this setting. Setting to Handheld can help improve performance for low end systems. - + Prompt for user profile on boot - + Useful if multiple people use the same PC. - + Pause when not in focus - + Pauses emulation when focusing on other windows. - + Confirm before stopping emulation 停止模拟时需要确认 - + Overrides prompts asking to confirm stopping the emulation. Enabling it bypasses such prompts and directly exits the emulation. - + Hide mouse on inactivity 滑鼠閒置時自動隱藏 - + Hides the mouse after 2.5s of inactivity. - + Check for updates - + Whether or not to check for updates upon startup. - + Enable Gamemode 启用游戏模式 - + Force X11 as Graphics Backend - + Custom frontend 自定义前端 - + Real applet 真实的小程序 - - + + Disabled - + Never - + On Load - + Always - + CPU CPU - + GPU GPU - + CPU Asynchronous CPU 异步模拟 - + Uncompressed (Best quality) 不壓縮 (最高品質) - + BC1 (Low quality) BC1 (低品質) - + BC3 (Medium quality) BC3 (中品質) - - + + Auto 自動 - + 30 FPS - + 60 FPS - + 90 FPS - + 120 FPS - + Conservative 保守模式(节省 VRAM) - + Aggressive 激进模式 - + Vulkan Vulkan - + OpenGL GLSL - + OpenGL GLASM (Assembly Shaders, NVIDIA Only) - + OpenGL SPIR-V (Experimental, AMD/Mesa Only) - + Null 無 - + Fast - - - + + + Accurate 高精度 - - - + + + Default 預設 - + Unsafe (fast) - + Safe (stable) - + Immediate - + Balanced - + Unsafe 低精度 - + Paranoid (disables most optimizations) 偏执模式 (禁用绝大多数优化项) - + Debugging - + Dynarmic Dynarmic - + NCE NCE - + Borderless Windowed 無邊框視窗 - + Exclusive Fullscreen 全螢幕獨占 - + No Video Output 無視訊輸出 - + CPU Video Decoding CPU 視訊解碼 - + GPU Video Decoding (Default) GPU 視訊解碼(預設) - + 0.25X (180p/270p) [EXPERIMENTAL] - + 0.5X (360p/540p) [EXPERIMENTAL] 0.5X (360p/540p) [实验性] - + 0.75X (540p/810p) [EXPERIMENTAL] 0.75X (540p/810p) [實驗性] - + 1X (720p/1080p) 1X (720p/1080p) - + 1.25X (900p/1350p) [EXPERIMENTAL] - + 1.5X (1080p/1620p) [EXPERIMENTAL] 1.5X (1080p/1620p) [實驗性] - + 2X (1440p/2160p) 2X (1440p/2160p) - + 3X (2160p/3240p) 3X (2160p/3240p) - + 4X (2880p/4320p) 4X (2880p/4320p) - + 5X (3600p/5400p) 5X (3600p/5400p) - + 6X (4320p/6480p) 6X (4320p/6480p) - + 7X (5040p/7560p) 7X (5040p/7560p) - + 8X (5760p/8640p) 8X (5760p/8640p) - + Nearest Neighbor 最近鄰 - + Bilinear 雙線性 - + Bicubic 雙立方 - + Gaussian 高斯 - + Lanczos - + ScaleForce 強制縮放 - + AMD FidelityFX Super Resolution - + Area - + MMPX - + Zero-Tangent - + B-Spline - + Mitchell - + Spline-1 - + Snapdragon Game Super Resolution - + Snapdragon Game Super Resolution EdgeDir - + None 無 - + FXAA FXAA - + SMAA SMAA - + Default (16:9) 預設 (16:9) - + Force 4:3 強制 4:3 - + Force 21:9 強制 21:9 - + Force 16:10 強制 16:10 - + Stretch to Window 延伸視窗 - + Automatic 自動 - + 2x 2x - + 4x 4x - + 8x 8x - + 16x 16x - + Japanese (日本語) 日文 (日本語) - + American English 美式英语 - + French (français) 法文 (français) - + German (Deutsch) 德文 (Deutsch) - + Italian (italiano) 義大利文 (italiano) - + Spanish (español) 西班牙文 (español) - + Chinese 中文 - + Korean (한국어) 韓文 (한국어) - + Dutch (Nederlands) 荷蘭文 (Nederlands) - + Portuguese (português) 葡萄牙文 (português) - + Russian (Русский) 俄文 (Русский) - + Taiwanese 台灣中文 - + British English 英式英文 - + Canadian French 加拿大法文 - + Latin American Spanish 拉丁美洲西班牙文 - + Simplified Chinese 簡體中文 - + Traditional Chinese (正體中文) 正體中文 (正體中文) - + Brazilian Portuguese (português do Brasil) 巴西-葡萄牙語 (português do Brasil) - + Polish (polska) - + Thai (แบบไทย) - - + + Japan 日本 - + USA 美國 - + Europe 歐洲 - + Australia 澳洲 - + China 中國 - + Korea 南韓 - + Taiwan 台灣 - + Auto (%1) Auto select time zone 自動 (%1) - + Default (%1) Default time zone 預設 (%1) - + CET 中歐 - + CST6CDT CST6CDT - + Cuba 古巴 - + EET EET - + Egypt 埃及 - + Eire 愛爾蘭 - + EST 北美東部 - + EST5EDT EST5EDT - + GB GB - + GB-Eire 英國-愛爾蘭 - + GMT GMT - + GMT+0 GMT+0 - + GMT-0 GMT-0 - + GMT0 GMT0 - + Greenwich 格林威治 - + Hongkong 香港 - + HST 夏威夷 - + Iceland 冰島 - + Iran 伊朗 - + Israel 以色列 - + Jamaica 牙買加 - + Kwajalein 瓜加林環礁 - + Libya 利比亞 - + MET 中歐 - + MST 北美山區 - + MST7MDT MST7MDT - + Navajo 納瓦霍 - + NZ 紐西蘭 - + NZ-CHAT 紐西蘭-查塔姆群島 - + Poland 波蘭 - + Portugal 葡萄牙 - + PRC 中國 - + PST8PDT 太平洋 - + ROC 臺灣 - + ROK 韓國 - + Singapore 新加坡 - + Turkey 土耳其 - + UCT UCT - + Universal 世界 - + UTC UTC - + W-SU 莫斯科 - + WET 西歐 - + Zulu 協調世界時 - + Mono 單聲道 - + Stereo 立體聲 - + Surround 環繞音效 - + 4GB DRAM (Default) 4GB DRAM (默认) - + 6GB DRAM (Unsafe) 6GB DRAM (不安全) - + 8GB DRAM - + 10GB DRAM (Unsafe) - + 12GB DRAM (Unsafe) - + Docked TV - + Handheld 掌機模式 - - + + Normal - - + + Boost - - + + Overclock - + Always ask (Default) 总是询问 (默认) - + Only if game specifies not to stop 仅当游戏不希望停止时 - + Never ask 从不询问 - + Very Small (16 MB) - + Small (32 MB) - + Normal (128 MB) - + Large (256 MB) - + Very Large (512 MB) - + Very Low (4 MB) - + Low (8 MB) - + Normal (16 MB) - + Medium (32 MB) - + High (64 MB) - + Very Low (32) - + Low (64) - + Normal (128) - + Medium (256) - + High (512) - + ExtendedDynamicState 1 - + ExtendedDynamicState 2 - + ExtendedDynamicState 3 - + Tree View - + Grid View @@ -6072,50 +6062,50 @@ Please go to Configure -> System -> Network and make a selection. GRenderWindow - - + + OpenGL not available! 無法使用 OpenGL 模式! - + OpenGL shared contexts are not supported. 不支援 OpenGL 共用的上下文。 - + Eden has not been compiled with OpenGL support. - - - + + + Error while initializing OpenGL! 初始化 OpenGL 時發生錯誤! - + Your GPU may not support OpenGL, or you do not have the latest graphics driver. 您的 GPU 可能不支援 OpenGL,或是未安裝最新的圖形驅動程式 - + Error while initializing OpenGL 4.6! 初始化 OpenGL 4.6 時發生錯誤! - + Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1 您的 GPU 可能不支援 OpenGL 4.6,或是未安裝最新的圖形驅動程式<br><br>GL 渲染器:<br>%1 - + Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2 您的 GPU 可能不支援某些必需的 OpenGL 功能。請確保您已安裝最新的圖形驅動程式。<br><br>GL 渲染器:<br>%1<br><br>不支援的功能:<br>%2 - + This build doesn't have OpenGL support. @@ -6880,1132 +6870,1152 @@ Debug Message: 模擬 (&E) - + + &Cheats + + + + &View 檢視 (&V) - + &Reset Window Size 重設視窗大小(&R) - + &Debugging 偵錯 (&D) - + &Game List Mode - + Game &Icon Size - + Reset Window Size to &720p 重設視窗大小為 &720p - + Reset Window Size to 720p 重設視窗大小為 720p - + Reset Window Size to &900p 重設視窗大小為 &900p - + Reset Window Size to 900p 重設視窗大小為 900p - + Reset Window Size to &1080p 重設視窗大小為 &1080p - + Reset Window Size to 1080p 重設視窗大小為 1080p - + &Multiplayer 多人遊戲 (&M) - + &Tools 工具 (&T) - + Am&iibo - + Launch &Applet - + &TAS TAS (&T) - + &Create Home Menu Shortcut - + Install &Firmware - + &Help 說明 (&H) - + &Install Files to NAND... &安裝檔案至內部儲存空間 - + L&oad File... 開啟檔案(&O)... - + Load &Folder... 開啟資料夾(&F)... - + E&xit 結束(&X) - - + + &Pause 暫停(&P) - + &Stop 停止(&S) - + &Verify Installed Contents 驗證已安裝內容的完整性 (&V) - + &About Eden - + Single &Window Mode 單一視窗模式(&W) - + Con&figure... 設定 (&F) - + Ctrl+, - + Enable Overlay Display Applet - + Show &Filter Bar 顯示搜尋列(&F) - + Show &Status Bar 顯示狀態列(&S) - + Show Status Bar 顯示狀態列 - + &Browse Public Game Lobby 瀏覽公用遊戲大廳 (&B) - + &Create Room 建立房間 (&C) - + &Leave Room 離開房間 (&L) - + &Direct Connect to Room 直接連線到房間 (&D) - + &Show Current Room 顯示目前的房間 (&S) - + F&ullscreen 全螢幕(&U) - + &Restart 重新啟動(&R) - + Load/Remove &Amiibo... 載入/移除 Amiibo... (&A) - + Open &Mods Page 模組資訊 (&M) - + &User Handbook - + &Capture Screenshot 截圖 (&C) - + &Album - + &Set Nickname and Owner 登錄持有者和暱稱 (&S) - + &Delete Game Data 清除遊戲資料 (&D) - + &Restore Amiibo 復原資料 (&R) - + &Format Amiibo 初始化 Amiibo (&F) - + &Mii Editor - + &Configure TAS... 設定 &TAS… - + Configure C&urrent Game... 目前遊戲設定...(&U) - - + + &Start 開始(&S) - + &Reset 重設 (&R) - - + + R&ecord 錄製 (&E) - + Open &Controller Menu 打开控制器菜单 (&C) - + Install Decryption &Keys - + &Home Menu - + &Desktop - + &Application Menu - + &Root Data Folder - + &NAND Folder - + &SDMC Folder - + &Mod Folder - + &Log Folder - + From Folder - + From ZIP - + &Eden Dependencies - + &Data Manager - + &Tree View - + &Grid View - + Game Icon Size - - + + None - + Show Game &Name - + Show &Performance Overlay - + Post-Processing &Shaders... - + &Carousel View - + Small (32x32) - + Standard (64x64) - + Large (128x128) - + Full Size (256x256) - + Broken Vulkan Installation Detected - + Vulkan initialization failed during boot. - + Running a game TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping - + Loading Web Applet... - - + + Disable Web Applet - + Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? (This can be re-enabled in the Debug settings.) - + The amount of shaders currently being built - + The current selected resolution scaling multiplier. - + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch. - + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - + Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - + Unmute - + Mute - + Reset Volume - + Configure Effects... - + &Clear Recent Files - + + Disable All Cheats + + + + + Enable All Cheats + + + + + Unnamed Cheat + + + + &Continue - + Warning: Outdated Game Format - + You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.<br>For an explanation of the various Switch formats Eden supports, out our user handbook. This message will not be shown again. - - + + Error while loading ROM! - + The ROM format is not supported. - + An error occurred initializing the video core. - + This is usually caused by outdated GPU drivers. Please see the log for more details. See: <a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>How to access log files</a>. - + Error while loading ROM! %1 %1 signifies a numeric error code. - + %1<br>Please redump your files or ask on Discord/Stoat for help. %1 signifies an error string. - + An unknown error occurred. Please see the log for more details. - - + + (64-bit) - - + + (32-bit) - - + + %1 %2 %1 is the title name. %2 indicates if the title is 64-bit or 32-bit - + Closing software... - + Save Data - + Mod Data - + Error Opening %1 Folder - - + + Folder does not exist! - + Remove Installed Game Contents? - + Remove Installed Game Update? - + Remove Installed Game DLC? - + Remove Entry - + Delete OpenGL Transferable Shader Cache? - + Delete Vulkan Transferable Shader Cache? - + Delete All Transferable Shader Caches? - + Remove Custom Game Configuration? - + Remove Cache Storage? - + Remove File - + Remove Play Time Data - + Reset play time? - - + + RomFS Extraction Failed! - + There was an error copying the RomFS files or the user cancelled the operation. - + Full - + Skeleton - + Select RomFS Dump Mode - + Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure. - + There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation > Configure > System > Filesystem > Dump Root - + Extracting RomFS... - - + + Cancel - + RomFS Extraction Succeeded! - + The operation completed successfully. - + Error Opening %1 - + Select Directory - + Properties - + The game properties could not be loaded. - + Switch Executable (%1);;All Files (*.*) %1 is an identifier for the Switch executable file extensions. - + Load File - + Open Extracted ROM Directory - + Invalid Directory Selected - + The directory you have selected does not contain a 'main' file. - - Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci) + + Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge Image (*.xci *.xcz) - + Install Files - + %n file(s) remaining - + Installing file "%1"... - - + + Install Results - + To avoid possible conflicts, we discourage users from installing base games to the NAND. Please, only use this feature to install updates and DLC. - + %n file(s) were newly installed - + %n file(s) were overwritten - + %n file(s) failed to install - + System Application - + System Archive - + System Application Update - + Firmware Package (Type A) - + Firmware Package (Type B) - + Game - + Game Update - + Game DLC - + Delta Title - + Select NCA Install Type... - + Please select the type of title you would like to install this NCA as: (In most instances, the default 'Game' is fine.) - + Failed to Install - + The title type you selected for the NCA is invalid. - + File not found - + File "%1" not found - + OK - + Function Disabled - + Compatibility list reporting is currently disabled. Check back later! - + Error opening URL - + Unable to open the URL "%1". - + TAS Recording - + Overwrite file of player 1? - + Invalid config detected - + Handheld controller can't be used on docked mode. Pro controller will be selected. - - + + Amiibo - - + + The current amiibo has been removed - + Error - - + + The current game is not looking for amiibos - + Amiibo File (%1);; All Files (*.*) - + Load Amiibo - + Error loading Amiibo data - + The selected file is not a valid amiibo - + The selected file is already on use - + An unknown error occurred - + No firmware available - + Firmware Corrupted - + Unknown applet - + Applet doesn't map to a known value. - + Record not found - + Applet not found. Please reinstall firmware. - + Capture Screenshot - + PNG Image (*.png) - + TAS state: Running %1/%2 - + TAS state: Recording %1 - + TAS state: Idle %1/%2 - + TAS State: Invalid - + &Stop Running - + Stop R&ecording - + Building: %n shader(s) - + Scale: %1x %1 is the resolution scaling factor - + Speed: %1% / %2% - + Speed: %1% - + Game: %1 FPS - + Frame: %1 ms - + NO AA - + NO FX - + FX - + VOLUME: MUTE - + VOLUME: %1% Volume percentage (e.g. 50%) - + Derivation Components Missing - + Decryption keys are missing. Install them now? - + Wayland Detected! - + Wayland is known to have significant performance issues and mysterious bugs. It's recommended to use X11 instead. @@ -8013,74 +8023,74 @@ Would you like to force it for future launches? - + Use X11 - + Continue with Wayland - + Don't show again - + Restart Required - + Restart Eden to apply the X11 backend. - + Slow - + Turbo - + Unlocked - + Select RomFS Dump Target - + Please select which RomFS you would like to dump. - + Are you sure you want to close Eden? - - - + + + Eden - + Are you sure you want to stop the emulation? Any unsaved progress will be lost. - + The currently running application has requested Eden to not exit. Would you like to bypass this and exit anyway? diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss index f968ad18b7..17d5dfef1c 100644 --- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss +++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss @@ -375,7 +375,9 @@ QMenuBar::item { } QMenuBar::item:selected { - background: transparent; + /* A hovered menu stays readable */ + background-color: #1464A0; + color: #F0F0F0; border: 0px solid #32414B; } diff --git a/docs/CrossCompile.md b/docs/CrossCompile.md index 06bac5d9db..d635c90b8e 100644 --- a/docs/CrossCompile.md +++ b/docs/CrossCompile.md @@ -6,10 +6,31 @@ General guide for cross compiling. A painless guide for cross compilation (or to test NCE) from a x86_64 system without polluting your main. -- Install QEMU: `sudo pkg install qemu` -- Download Debian 13: `wget https://cdimage.debian.org/debian-cd/current/arm64/iso-cd/debian-13.0.0-arm64-netinst.iso` -- Create a system disk: `qemu-img create -f qcow2 debian-13-arm64-ci.qcow2 30G` -- Run the VM: `qemu-system-aarch64 -M virt -m 2G -cpu max -bios /usr/local/share/qemu/edk2-aarch64-code.fd -drive if=none,file=debian-13.0.0-arm64-netinst.iso,format=raw,id=cdrom -device scsi-cd,drive=cdrom -drive if=none,file=debian-13-arm64-ci.qcow2,id=hd0,format=qcow2 -device virtio-blk-device,drive=hd0 -device virtio-gpu-pci -device usb-ehci -device usb-kbd -device intel-hda -device hda-output -nic user,model=virtio-net-pci` +```sh +#!/bin/sh +ISO_FILE="debian-13.0.0-arm64-netinst.iso" +DISK_FILE="debian-13-arm64-ci.qcow2" +which -- qemu-system-aarch64 || sudo pkg install qemu +[ -f "$ISO_FILE" ] || wget https://cdimage.debian.org/debian-cd/current/arm64/iso-cd/$ISO_FILE +[ -f "$DISK_FILE" ] || qemu-img create -f qcow2 "$DISK_FILE" 30G +QEMU_FLAGS=( + -M virt + -m 2G + -cpu max + -bios /usr/local/share/qemu/edk2-aarch64-code.fd + -drive if=none,file=$ISO_FILE,format=raw,id=cdrom + -drive if=none,file=$DISK_FILE,id=hd0,format=qcow2 + -device scsi-cd,drive=cdrom + -device virtio-blk-device,drive=hd0 + -device virtio-gpu-pci + -device usb-ehci + -device usb-kbd + -device intel-hda + -device hda-output + -nic user,model=virtio-net-pci +) +qemu-system-aarch64 "${QEMU_FLAGS[@]}" +``` ## Gentoo diff --git a/docs/Deps.md b/docs/Deps.md index 2b73ecb4ac..4f293b9642 100644 --- a/docs/Deps.md +++ b/docs/Deps.md @@ -25,7 +25,7 @@ The following additional tools are also required: * `tools/windows/install-vulkan-sdk.ps1` (for PowerShell 5+) * `tools/windows/install-vulkan-sdk.sh` (for Git Bash, etc) -If you are on desktop and plan to use the Qt frontend, you *must* install Qt 6, and optionally Qt Creator (the **RECOMMENDED** IDE for building) +If you are on desktop and plan to use the Qt frontend, you *must* install Qt >=6.6, and optionally Qt Creator (the **RECOMMENDED** IDE for building) * On Linux, *BSD and macOS, this can be done by the package manager * If you wish to use Qt Creator, append `qtcreator` or `qt-creator` to the commands seen below. diff --git a/docs/Development.md b/docs/Development.md index ddffb0cbb4..03870919b0 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -24,25 +24,6 @@ If the work is licensed/vendored from other people or projects, you may omit the For more information on the license header script, run `.ci/license-header.sh -h`. -## Pull Requests - -Pull requests are only to be merged by core developers when properly tested and discussions conclude on Discord or other communication channels. Labels are recommended but not required. However, all PRs MUST be namespaced and optionally typed: - -```txt -[cmake] refactor: CPM over submodules -[desktop] feat: implement firmware install from ZIP -[hle] stub fw20 functions -[core] test: raise maximum CPU cores to 6 -[cmake, core] Unbreak FreeBSD Building Process -``` - -- The level of namespacing is generally left to the committer's choice. -- However, we never recommend going more than two levels *except* in `hle`, in which case you may go as many as four levels depending on the specificity of your changes. -- Ocassionally, up to two additional namespaces may be provided for more clarity. - - Changes that affect the entire project (sans CMake changes) should be namespaced as `meta`. -- Maintainers are permitted to change namespaces at will. -- Commits within PRs are not required to be namespaced, but it is highly recommended. - ## Adding new settings When adding new settings, use `tr("Setting:")` if the setting is meant to be a field, otherwise use `tr("Setting")` if the setting is meant to be a Yes/No or checkmark type of setting, see [this short style guide](https://learn.microsoft.com/en-us/style-guide/punctuation/colons#in-ui). diff --git a/docs/README.md b/docs/README.md index f7568e16f3..16d1748f7e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -28,7 +28,7 @@ This contains documentation created by developers, build instructions, guideline Policies and information on development. -- **[AI and LLM Usage](./policies/AI.md)** +- **[AI and LLM Usage](./CONTRIBUTING.md#policies)** - **[Coding guidelines](./policies/Coding.md)** - **[Contributing](../CONTRIBUTING.md)** diff --git a/docs/build/Android.md b/docs/build/Android.md index 60ec31a678..add7fb90c7 100644 --- a/docs/build/Android.md +++ b/docs/build/Android.md @@ -33,10 +33,9 @@ Eden by default will be cloned into: ## Building with Terminal 1. Download the SDK and NDK from Android Studio. -2. Navigate to SDK and NDK paths. -3. Then set ANDROID_SDK_ROOT and ANDROID_NDK_ROOT in terminal via -`export ANDROID_SDK_ROOT=path/to/sdk` -`export ANDROID_NDK_ROOT=path/to/ndk`. +2. Navigate to SDK path. +3. Then set ANDROID_HOME in terminal via +`export ANDROID_HOME=path/to/sdk` 4. Navigate to `eden/src/android`. 5. Then Build with `./gradlew assembleRelWithDebInfo`. 6. To build the optimised build use `./gradlew assembleGenshinSpoofRelWithDebInfo`. diff --git a/docs/dynarmic/Fastmem.svg b/docs/dynarmic/Fastmem.svg index a3ed0bb68b..3da3480965 100644 --- a/docs/dynarmic/Fastmem.svg +++ b/docs/dynarmic/Fastmem.svg @@ -1,4 +1 @@ - - - -
Emulator
Address Space
Guest Address Space
SIGSEGV Trap
Fastmem
Only needs to linearly offset from fastmem arena
Less codegen (SIGSEGV traps)
Is fast only if SIGSEGV handlers are sufficiently fast
\ No newline at end of file +
Emulator
Address Space
Guest Address Space
SIGSEGV Trap
Fastmem
Only needs to linearly offset from fastmem arena
Less codegen (SIGSEGV traps)
Is fast only if SIGSEGV handlers are sufficiently fast
\ No newline at end of file diff --git a/docs/dynarmic/HostToGuest.svg b/docs/dynarmic/HostToGuest.svg index 6a15a44b46..bfb94aa302 100644 --- a/docs/dynarmic/HostToGuest.svg +++ b/docs/dynarmic/HostToGuest.svg @@ -1,4 +1 @@ - - - -
Emulator
Address Space
Guest Address Space
Resolver
Host to Guest translation
Looks up correct PTE
Translates each address 
Is slow
\ No newline at end of file +
Emulator
Address Space
Guest Address Space
Resolver
Host to Guest translation
Looks up correct PTE
Translates each address
Is slow
\ No newline at end of file diff --git a/docs/img/creator-1.png b/docs/img/creator-1.png index 3e43ee7eca..d7f30897c6 100644 Binary files a/docs/img/creator-1.png and b/docs/img/creator-1.png differ diff --git a/docs/policies/AI.md b/docs/policies/AI.md deleted file mode 100644 index dd4b4a7fb2..0000000000 --- a/docs/policies/AI.md +++ /dev/null @@ -1,203 +0,0 @@ -# AI Policy - -> [!WARNING] -> We are trialing a slightly relaxed AI policy to allow high-quality contributors to use AI *responsibly*. -> This policy is subject to change at any point in time, so check back frequently. -> -> This banner will be removed once we have finalized our revised policy. - -- [AI Policy](#ai-policy) - - [TL;DR](#tldr) - - [Definitions](#definitions) - - [Scope](#scope) - - [Introduction](#introduction) - - [Requirements](#requirements) - - [Sign-off, Authorship, and Copyright](#sign-off-authorship-and-copyright) - - [Permitted Usage](#permitted-usage) - - [Recommended Prior Discussion](#recommended-prior-discussion) - - [Forbidden Usage](#forbidden-usage) - - [Human Effort Denial of Service](#human-effort-denial-of-service) - - [Disclosure](#disclosure) - - [Codebase Ingestion](#codebase-ingestion) - - [Enforcement](#enforcement) - - [Addendum: AI Commit Messages](#addendum-ai-commit-messages) - - [References](#references) - -## TL;DR - -AI-assisted contributions are welcome, provided you take responsibility for them. - -- You **must** disclose any AI or LLM usage in your pull request description *and* commit message. -- You **must** be able to explain, defend, and revise every line of code you submit. -- Commit messages, PR descriptions, issues, and comments **must** be written by you. Verbatim AI output is not acceptable. -- Undisclosed AI usage will result in your contribution being rejected. -- Low-quality contributions, disclosed or not, will be reworked or rejected. -- Spamming automated PRs, comments, or issues is treated as a Denial of Service (DoS) attack on our reviewers; see [Human Effort Denial of Service](#human-effort-denial-of-service). - -## Definitions - -An *AI or LLM-based tool* is any piece of software that generates code, text, or other content through machine learning models. This includes, but is not limited to: chat assistants, agentic coding tools/harnesses, inline code completion suggestions you have accepted into the code, and AI-driven explanation/refactoring features. - -For the purposes of this policy, basic deterministic/static development tools (such as clang-tidy, git, compilers, etc.) are not considered AI tools. - -Terms such as "substantially", "large-scale", "majority", and "low-quality" are intentionally left vague, and will be interpreted at the maintainers' discretion. When in doubt, ask first. - -## Scope - -This policy applies to all code contributions, alongside issues and pull requests surrounding this codebase. This includes: - -- Commit messages -- PR descriptions -- Code review comments -- Issue/PR comments -- Patches submitted via e-mail - -Areas that are not directly related to code--such as our surrounding communities--are not covered by the terms of this policy. Additionally, spelling/grammar checking via AI or LLM-based tools is not covered under this document. - -## Introduction - -In the right hands, AI and LLM-based tools are incredibly useful for getting features and bugfixes out the door as fast as possible. At the same time, reviewer bandwidth is a scarce resource. We are therefore open to AI-assisted contributions, provided they are produced and disclosed properly. - -The goal of this document is *not* to set arbitrary restrictions, but rather to keep our development healthy and stable, while still allowing contributors to use the tools they find helpful. A contribution must be worth more to the project than the time it takes to review it. - -Throughout this document, **must** and **must not** are inflexible, binding requirements. Refusal to follow these is treated as a violation of the terms outlined in this document. - -## Requirements - -These apply to all contributions, whether AI-assisted or not. AI-assisted contributions also carry additional disclosure requirements as outlined in [Disclosure](#disclosure). - -1. *Disclosure*. Any and all usage of AI or LLM-based tools within any contribution **must** be explicitly marked and disclosed as appropriate. -2. *Responsibility*. The human submitter of any contribution is held wholly responsible for the accuracy, completeness, and intent of what is submitted. You **must** be able to explain, defend, and revise your code during review. -3. *Review*. All code **must** be thoroughly reviewed by the author before opening a PR or marking it ready for review. -4. *Testing*. All code changes **must** be tested directly by the human author. -5. *Quality*. All submitted code is held to a strict standard of excellence. Low-quality AI-generated content does not uphold this standard. -6. *Licensing*. All code **must** be compatible with the GPLv3 or later. You **must** warrant that you have the right to submit it under those terms, and that it was not copied from work published under an incompatible license. - -## Sign-off, Authorship, and Copyright - -AI agents **must not** add `Signed-off-by:` tags. The human submitter **must** sign off on all changes. - -Similarly, AI agents cannot hold authorship or copyright over code, and **must not** add `Co-authored-by:` or `Co-developed-by:` tags. The human submitter **must** author all changes. - -## Permitted Usage - -This is a non-exhaustive list of permitted uses of AI and LLM-based tools, provided they are disclosed properly. - -- Drafting issues and pull requests, provided the final text and submitted code are substantially your own. -- Debugging issues, bugs, glitches, and crashes, whether pre-existing or introduced by your own changes. -- Reviewing your own changes before submitting a PR. -- Research, brainstorming, and codebase searching/understanding. -- Applying tedious but not particularly large changes, such as mass-migrating specific classes to polyfills or abstractions. - -## Recommended Prior Discussion - -Some usage cases are not necessarily forbidden nor permitted. These should be discussed with maintainers in an issue or e-mail *before* submission. Maintainers and reviewers may also comment on this during the review/submission phase. - -- Generating boilerplate/scaffolding for new code. -- Writing unit tests. -- Large-scale refactors primarily driven by an AI agent. -- Any contribution where an AI agent or model was responsible for the majority of the implementation. - -## Forbidden Usage - -This is a non-exhaustive list of strictly forbidden uses of AI and LLM-based tools. - -- Vibecoding, or changes entirely authored by AI agents without human intervention or understanding. - - If you don't choose to put in the necessary effort to understand every line of code you submitted, neither will we. -- Fully AI-generated commit messages, PR descriptions, issues, or comments. See [Addendum: AI Commit Messages](#addendum-ai-commit-messages). -- Submission of AI-assisted work that is not disclosed per the [Disclosure](#disclosure) requirements. -- Low-quality submissions that fail to satisfy our standard of code excellence. -- Submitting secrets, credentials, private user data, or unpublished security reports to third-party AI services. - - This includes console keys, encryption material, and private vulnerability disclosures. -- Verbatim AI code reviews (e.g. Codex/Copilot reviews). - -## Human Effort Denial of Service - -Using automated tools and AI to submit PRs, issues, and comments that we have to carefully review and handle is considered a [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack) on our human effort. - -It takes very little effort on your side (an LLM prompt) to generate a large amount of effort on ours (careful and thorough code review). Please respect our time and don't do that. - -## Disclosure - -How you disclose AI usage is up to you. However, it **must** be explicit, easy to identify, and placed both within the commit message *and* the surrounding PR description. For patches submitted by e-mail, the cover letter counts as the PR description. We recommend an `Assisted-by:` footer: - -```txt -Assisted-by: () -``` - -For instance: - -```txt -Assisted-by: Claude Opus 5.5 (initial draft and code review) -``` - -Contributions without a commit message (e.g. issues/comments) should instead use a plain sentence in the text body such as `I used to help with `. PRs and commit messages may opt to use this format as well. - -Multi-commit series/squashes **must** maintain the trailer. Maintainers will handle this for merges to master, but you are responsible for ensuring the disclosure survives into the final commit/PR body of squashes within your branches. - -Regardless, what matters is that reviewers can tell *at a glance* where and how AI was involved in your contribution. - -## Codebase Ingestion - -Ingestion of this codebase by LLMs for any purpose--such as training or prompt context--is permitted *for now*. This may change at any point as litigation and court rulings around AI and code copyright proceed. - -AI models may have ingested AGPLv3 or otherwise copyleft-incompatible code and may regurgitate it. You remain responsible for ensuring that all code you submit is compatible with the GPLv3 or later. - -## Enforcement - -- If we suspect undisclosed AI usage in a contribution, we will ask for disclosure. -- Refusal to provide disclosure will result in rejection of the contribution, and your PR or issue will be closed. Maintainers may choose to rework it themselves if the change is worth having. -- Accounts that spam us with repeated automated PRs or comments will be blocked or permanently suspended from our Git instance. -- Maintainers reserve the right to close your issues and pull requests if you don't follow the guidelines and procedures outlined in this document, and refuse or fail to make changes as necessary to comply. -- Repeated failures to comply may result in loss of contribution privileges. - -## Addendum: AI Commit Messages - -The patchset for pull request [#3422](https://git.eden-emu.dev/eden-emu/eden/pulls/3422) was fed into a dedicated code AI model, and it produced the following: - -```txt -profile_manager: Refactor user deletion to use index instead of UUID - -This commit improves the user profile deletion flow in the following ways: - -1. **UI layer (ConfigureProfileManager)**: - - Replaces UUID-based deletion with index-based deletion - - Passes the selected row index from the tree view to the confirmation dialog - - Emits deleteUser(int index) signal from ConfigureProfileManagerDeleteDialog - - Removes lambda capture and std::function callback in favor of direct signal/slot connection - -2. **Delete dialog**: - - Changes SetInfo() signature to accept index instead of accept callback - - Stores index internally and emits it via deleteUser signal on acceptance - -3. **Core ProfileManager**: - - Refactors RemoveUser(UUID) → RemoveProfileAtIndex(index) - - Removes duplicated stable_partition + save logic from RemoveUser() - - Centralizes profile removal and save-file writing in RemoveProfileAtIndex() - -4. **Minor follow-up**: - - Adds profile_manager.ResetUserSaveFile() call in PopulateUserList() to ensure consistent state when refreshing the user list - -These changes eliminate redundant code, reduce the risk of UUID → index mismatch bugs, and make the deletion path more straightforward and maintainable. - -Fixes: potential inconsistency when user order changes between UI and backend -``` - -This: - -- Is needlessly verbose (nobody cares about most of these details) -- Doesn't address the actual purpose of the PR (fixing a double-deletion bug in the profile manager) -- Has unicode arrows (this is bad for command-line editors) -- Uses corporate and word-salad language that pads out the message to make it look like a lot changed - -A good commit message should be concise, descriptive, and convey the *intent* behind the change, such as the bug being fixed or the feature being added. It should *not* be a detailed changelog of every individual byte that's changed. - -## References - -This policy document has been adapted from the AI policies of numerous other free and open-source projects, whether restrictive or permissive. - -- [Gitea](https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md#ai-contribution-policy) -- The [Linux kernel](https://kernel.org/doc/html/next/process/coding-assistants.html) -- [Gentoo Linux](https://wiki.gentoo.org/wiki/Project:Council/AI_policy) -- [cURL](https://curl.se/dev/contribute.html#on-ai-use-in-curl) -- [FastAPI](https://tiangolo.com/open-source/contributing/#automated-code-and-ai) diff --git a/docs/user/UsingCheats.md b/docs/user/UsingCheats.md index d6ad7b634a..a89a29d50f 100644 --- a/docs/user/UsingCheats.md +++ b/docs/user/UsingCheats.md @@ -45,12 +45,13 @@ Another option would be to launch the game in Eden and close it - then go into t ***INFO***: Make sure you select the correct directory or it will not work, the screen should show the **cheats** sub-directory. -2. You should now see the cheat appear in the **Add-ons** screen. -3. Launch the game and confirm that the cheat is applied. + +9. You should now see the cheat appear in the **Add-ons** screen. +10. Launch the game and confirm that the cheat is applied. ### Step 2: Multiple Cheats -In order to install multiple cheats, you must repeat the steps above with the new cheat, creating a new directory with the name of the cheat and cheats directory. You **cannot** install multiple cheats with a single file. +In order to install multiple cheats, you must repeat the steps above with the new cheat, creating a new directory with the name of the cheat and cheats directory. Community Member [Ninjistix](https://github.com/Ninjistix) created a utility (Windows or anything that can run Python) that can take a file with multiple cheats and create the files/structure for you with a provided Build ID. To download and run it, see the [GitHub Project](https://github.com/Ninjistix/nxCheat_Splitter) page. @@ -122,7 +123,7 @@ Another option would be to launch the game in Eden and close it - then go into t ### Step 2: Multiple Cheats -In order to install multiple cheats, you must repeat the steps above with the new cheat, creating a new directory with the name of the cheat and cheats directory. You **cannot** install multiple cheats with a single file. +In order to install multiple cheats, you must repeat the steps above with the new cheat, creating a new directory with the name of the cheat and cheats directory. Community Member [Ninjistix](https://github.com/Ninjistix) created a utility (Windows or anything that can run Python) that can take a file with multiple cheats and create the files/structure for you with a provided Build ID. To download and run it, see the [GitHub Project](https://github.com/Ninjistix/nxCheat_Splitter) page. @@ -154,3 +155,11 @@ Cheats are enabled by default, but can be disabled so they don't affect gameplay 3. *Select/Deselect* the name of the cheat you wish to enable/disable. 4. Click **OK** to close the window. 5. Launch the game to confirm the cheat is/is not active. + +### Runtime Cheat Controls + +* While a game is running, open **Cheats** from the menu bar to toggle individual entries from the loaded cheat files. The menu stays open while toggling entries and is hidden when the running game has no cheats. Runtime changes apply to the current game session only. + +* Use **Configure > System > Core > Enable cheats by default** to choose whether regular cheats start enabled. The setting can also be overridden for an individual game from its **System** settings. + +* Master Code entries (`{}` blocks) are always enabled and appear as disabled and checked items in the runtime menu. diff --git a/externals/cmake-modules/DetectArchitecture.cmake b/externals/cmake-modules/DetectArchitecture.cmake index 105963c8c2..c572be51e3 100644 --- a/externals/cmake-modules/DetectArchitecture.cmake +++ b/externals/cmake-modules/DetectArchitecture.cmake @@ -101,6 +101,11 @@ endfunction() # ia64 exists # the rest exist, but are probably less popular than ia64 +detect_architecture_symbols( + ARCH wasm + SYMBOLS + "__EMSCRIPTEN__") + detect_architecture_symbols( ARCH arm64 SYMBOLS @@ -203,11 +208,6 @@ detect_architecture_symbols( "__loongarch__" "__loongarch64") -detect_architecture_symbols( - ARCH wasm - SYMBOLS - "__EMSCRIPTEN__") - # "generic" target # If you have reached this point, you're on some as-of-yet unsupported architecture. # See the docs up above for known unsupported architectures diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index 77222884c6..de3477e8b0 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt @@ -34,6 +34,13 @@ import org.yuzu.yuzu_emu.applets.web.WebBrowser * with the native side of the Yuzu code. */ object NativeLibrary { + @Keep + class RuntimeCheat( + val id: Int, + val name: String, + val enabled: Boolean, + val isMaster: Boolean + ) @Keep data class UpdateResult( var tag: String = "", @@ -197,6 +204,9 @@ object NativeLibrary { */ external fun isPaused(): Boolean + external fun getRuntimeCheats(): Array + external fun setRuntimeCheatEnabled(id: Int, enabled: Boolean): Boolean + /** * Returns the performance stats for the current game */ diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 0548004cf5..2d1909a36f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -13,10 +13,10 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { FASTMEM("cpuopt_fastmem"), FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives"), CORE_SYNC_CORE_SPEED("sync_core_speed"), + ENABLE_CHEATS_BY_DEFAULT("enable_cheats_by_default"), RENDERER_USE_SPEED_LIMIT("use_speed_limit"), USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"), SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"), - NCE_INVALIDATION_GPU_READBACK("nce_invalidation_gpu_readback"), FIX_BLOOM_EFFECTS("fix_bloom_effects"), EMULATE_BGR565("emulate_bgr565"), RESCALE_HACK("rescale_hack"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 690c746628..9e38be12c0 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -316,6 +316,13 @@ abstract class SettingsItem( descriptionId = R.string.use_sync_core_description ) ) + put( + SwitchSetting( + BooleanSetting.ENABLE_CHEATS_BY_DEFAULT, + titleId = R.string.enable_cheats_by_default, + descriptionId = R.string.enable_cheats_by_default_description + ) + ) put( SingleChoiceSetting( IntSetting.REGION_INDEX, @@ -859,13 +866,6 @@ abstract class SettingsItem( descriptionId = R.string.skip_cpu_inner_invalidation_description ) ) - put( - SwitchSetting( - BooleanSetting.NCE_INVALIDATION_GPU_READBACK, - titleId = R.string.nce_invalidation_gpu_readback, - descriptionId = R.string.nce_invalidation_gpu_readback_description - ) - ) put( SwitchSetting( BooleanSetting.FIX_BLOOM_EFFECTS, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index f9185e39e6..82d66db16f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -510,6 +510,7 @@ class SettingsFragmentPresenter( add(IntSetting.FAST_CPU_TIME.key) add(IntSetting.FAST_GPU_TIME.key) add(BooleanSetting.CORE_SYNC_CORE_SPEED.key) + add(BooleanSetting.ENABLE_CHEATS_BY_DEFAULT.key) add(IntSetting.MEMORY_LAYOUT.key) add(BooleanSetting.USE_CUSTOM_CPU_TICKS.key) @@ -554,7 +555,6 @@ class SettingsFragmentPresenter( add(HeaderSetting(R.string.hacks)) add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key) - add(BooleanSetting.NCE_INVALIDATION_GPU_READBACK.key) add(BooleanSetting.FIX_BLOOM_EFFECTS.key) add(BooleanSetting.EMULATE_BGR565.key) add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt index eacc64a63e..8d1fcb4fd4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt @@ -79,9 +79,8 @@ class DriverFetcherFragment : Fragment() { IntRange(100, 599) to "Unsupported", IntRange(600, 639) to "Mr. Purple EOL-24.3.4", IntRange(640, 699) to "Mr. Purple T19", - IntRange(700, 710) to "KIMCHI 25.2.0_r5", - IntRange(711, 799) to "Mr. Purple T23", - IntRange(800, 899) to "GameHub Adreno 8xx", + IntRange(700, 710) to "Mr. Purple T29", + IntRange(711, 899) to "Mr. Purple T30", IntRange(900, Int.MAX_VALUE) to "Unsupported" ) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 3323b3cf9a..65043ec8d2 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -734,6 +734,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { binding.inGameMenu.menu.findItem(R.id.menu_quick_settings)?.isVisible = BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean() + binding.inGameMenu.menu.findItem(R.id.menu_cheats)?.isVisible = false binding.pausedIcon.setOnClickListener { if (this::emulationState.isInitialized && emulationState.isPaused) { @@ -817,6 +818,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { R.id.menu_load_amiibo -> handleLoadAmiiboSelection() + R.id.menu_cheats -> { + binding.drawerLayout.closeDrawer(binding.inGameMenu) + showRuntimeCheatDialog() + true + } + R.id.menu_controls -> { val action = HomeNavigationDirections.actionGlobalSettingsActivity( null, @@ -962,6 +969,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { emulationState.updateSurface() + binding.inGameMenu.menu.findItem(R.id.menu_cheats)?.isVisible = + NativeLibrary.getRuntimeCheats().isNotEmpty() updateShowStatsOverlay() updateSocOverlay() @@ -987,6 +996,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) { if (it) { + binding.inGameMenu.menu.findItem(R.id.menu_cheats)?.isVisible = false binding.loadingText.setText(R.string.shutting_down) ViewUtils.showView(binding.loadingIndicator) ViewUtils.hideView(binding.inputContainer) @@ -1119,6 +1129,45 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { NativePostProcessing.persist() } + private fun showRuntimeCheatDialog() { + val cheats = NativeLibrary.getRuntimeCheats() + if (cheats.isEmpty()) return + + val names = cheats.map { it.name.ifEmpty { getString(R.string.unnamed_cheat) } }.toTypedArray() + lateinit var dialog: androidx.appcompat.app.AlertDialog + dialog = MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.cheats) + .setMultiChoiceItems(names, cheats.map { it.enabled }.toBooleanArray()) { _, which, enabled -> + if (cheats[which].isMaster) { + dialog.listView.setItemChecked(which, true) + } else if (!NativeLibrary.setRuntimeCheatEnabled(cheats[which].id, enabled)) { + dialog.listView.setItemChecked(which, !enabled) + } + } + .setNegativeButton(R.string.disable_all_cheats) { _, _ -> + cheats.forEach { + if (!it.isMaster) NativeLibrary.setRuntimeCheatEnabled(it.id, false) + } + } + .setNeutralButton(R.string.enable_all_cheats) { _, _ -> + cheats.forEach { + if (!it.isMaster) NativeLibrary.setRuntimeCheatEnabled(it.id, true) + } + } + .setPositiveButton(R.string.done, null) + .create() + dialog.setOnShowListener { + val listView = dialog.listView + fun updateMasterVisuals() = repeat(listView.childCount) { index -> + listView.getChildAt(index).alpha = + if (cheats[listView.firstVisiblePosition + index].isMaster) 0.38f else 1f + } + listView.setOnScrollChangeListener { _, _, _, _, _ -> updateMasterVisuals() } + updateMasterVisuals() + } + dialog.show() + } + private fun addQuickSettings() { binding.quickSettingsSheet.apply { val container = binding.quickSettingsSheet.findViewById(R.id.quick_settings_container) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt index 6717894c93..f5f0cda0e9 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt @@ -100,7 +100,7 @@ class Game( companion object { val extensions: Set = HashSet( - listOf("xci", "nsp", "nca", "nro") + listOf("xci", "nsp", "nca", "nro", "nsz", "xcz") ) } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt index 411b764e36..bb2337a310 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt @@ -109,7 +109,7 @@ object GameHelper { // File extensions considered as external content, buuut should // be done better imo. - private val externalContentExtensions = setOf("nsp", "xci") + private val externalContentExtensions = setOf("nsp", "xci", "nsz", "xcz") private fun scanContentContainersRecursive( files: Array, diff --git a/src/android/app/src/main/jni/game_metadata.cpp b/src/android/app/src/main/jni/game_metadata.cpp index 49d92bca75..9b6cd44e9f 100644 --- a/src/android/app/src/main/jni/game_metadata.cpp +++ b/src/android/app/src/main/jni/game_metadata.cpp @@ -76,7 +76,9 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobj auto const file_type = loader->GetFileType(); if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) return false; - if ((file_type == Loader::FileType::NSP || file_type == Loader::FileType::XCI) && !Loader::IsBootableGameContainer(file, file_type)) + if ((file_type == Loader::FileType::NSP || file_type == Loader::FileType::XCI || + file_type == Loader::FileType::NSZ || file_type == Loader::FileType::XCZ) && + !Loader::IsBootableGameContainer(file, file_type)) return false; u64 program_id = 0; return loader->ReadProgramId(program_id) == Loader::ResultStatus::Success; diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index d4f7689934..51d0085c6f 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -67,6 +67,7 @@ extern "C" { #include "core/file_sys/submission_package.h" #include "core/file_sys/vfs/vfs.h" #include "core/file_sys/vfs/vfs_real.h" +#include "core/memory/dmnt_cheat_types.h" #include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/controller.h" #include "core/frontend/applets/error.h" @@ -946,6 +947,31 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused(JNIEnv* env, jclass claz return static_cast(EmulationSession::GetInstance().IsPaused()); } +jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getRuntimeCheats(JNIEnv* env, jclass clazz) { + const auto cheats = EmulationSession::GetInstance().System().GetRuntimeCheats(); + const auto runtime_cheat_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary$RuntimeCheat"); + const auto constructor = env->GetMethodID(runtime_cheat_class, "", "(ILjava/lang/String;ZZ)V"); + auto result = env->NewObjectArray(static_cast(cheats.size()), runtime_cheat_class, nullptr); + for (jsize i = 0; i < static_cast(cheats.size()); ++i) { + const auto& cheat = cheats[i]; + const auto name = Common::Android::ToJString(env, cheat.name); + const auto item = env->NewObject(runtime_cheat_class, constructor, static_cast(cheat.id), name, + static_cast(cheat.enabled), + static_cast(cheat.is_master)); + env->SetObjectArrayElement(result, i, item); + env->DeleteLocalRef(name); + env->DeleteLocalRef(item); + } + env->DeleteLocalRef(runtime_cheat_class); + return result; +} + +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setRuntimeCheatEnabled(JNIEnv* env, jclass clazz, + jint id, jboolean enabled) { + return static_cast(EmulationSession::GetInstance().System().SetCheatEnabled( + static_cast(id), static_cast(enabled))); +} + jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletCaptureBuffer(JNIEnv* env, jclass clazz) { using namespace VideoCore::Capture; diff --git a/src/android/app/src/main/res/drawable/ic_forgejo.xml b/src/android/app/src/main/res/drawable/ic_forgejo.xml new file mode 100644 index 0000000000..c16033a6a5 --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_forgejo.xml @@ -0,0 +1,30 @@ + + + + + + + + + diff --git a/src/android/app/src/main/res/drawable/ic_github.xml b/src/android/app/src/main/res/drawable/ic_github.xml deleted file mode 100644 index c2ee43803d..0000000000 --- a/src/android/app/src/main/res/drawable/ic_github.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/src/android/app/src/main/res/drawable/ic_yuzu.png b/src/android/app/src/main/res/drawable/ic_yuzu.png index fce02afa1f..a9c95fa73b 100644 Binary files a/src/android/app/src/main/res/drawable/ic_yuzu.png and b/src/android/app/src/main/res/drawable/ic_yuzu.png differ diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml index cc8d26dd58..b3512041b1 100644 --- a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml +++ b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml @@ -250,7 +250,7 @@ style="@style/EdenButton.Secondary" android:layout_width="56dp" android:layout_height="56dp" - app:icon="@drawable/ic_github" + app:icon="@drawable/ic_forgejo" app:iconGravity="textStart" app:iconSize="24dp" app:iconPadding="0dp" /> diff --git a/src/android/app/src/main/res/layout/fragment_about.xml b/src/android/app/src/main/res/layout/fragment_about.xml index b1b896f169..3bc73699dc 100644 --- a/src/android/app/src/main/res/layout/fragment_about.xml +++ b/src/android/app/src/main/res/layout/fragment_about.xml @@ -259,7 +259,7 @@ android:layout_height="56dp" android:layout_weight="1" android:layout_marginStart="8dp" - app:icon="@drawable/ic_github" + app:icon="@drawable/ic_forgejo" app:iconSize="24dp" app:iconGravity="textStart" app:iconPadding="0dp" diff --git a/src/android/app/src/main/res/menu/menu_in_game.xml b/src/android/app/src/main/res/menu/menu_in_game.xml index c1d8147f84..d9ef158d5e 100644 --- a/src/android/app/src/main/res/menu/menu_in_game.xml +++ b/src/android/app/src/main/res/menu/menu_in_game.xml @@ -43,6 +43,10 @@ android:icon="@drawable/ic_nfc" android:title="@string/load_amiibo" /> + غير مدعوم (لا يتوفر نموذج ذاكرة Vulkan أو float16) Lossless Scaling قم بتوفير نسختك الخاصة من ملف Lossless.dll لتفعيل توليد الإطارات - مثبت + تم التثبيت غير مثبت استبدل إزالة @@ -501,9 +501,9 @@ يحدد سرعة المحاكاة بنسبة مئوية محددة من السرعة العادية. نسبة الحد الأقصى للسرعة يحدد النسبة المئوية للحد من سرعة المحاكاة. %100 هي السرعة الطبيعية. القيم الأعلى أو الأقل ستزيد أو تقلل من الحد الأقصى للسرعة. - سرعة تيربو + السرعة الفائقة عند تفعيل وضع التيربو، سيتم تشغيل المحاكاة بهذه السرعة. - سرعة بطيئة + السرعة البطيئة عند تفعيل الوضع البطيء، سيتم تشغيل المحاكاة بهذه السرعة. خلفية وحدة المعالجة المركزية دقة وحدة المعالجة المركزية @@ -514,7 +514,7 @@ اسم الجهاز - وضع الإرساء + وضع المنصة يزيد الدقة ويقلل الأداء. يتم استخدام الوضع المحمول عند تعطيله، مما يقلل الدقة ويزيد الأداء. المنطقة التي تمت محاكاتها لغة المحاكاة @@ -543,7 +543,7 @@ الشبكة - الدقة (الإرساء/محمول) + الدقة (المنصة/محمول) VSync وضع مرشح ملائم للنافذة حدة FSR/SGSR @@ -587,10 +587,8 @@ يجعل اللعبة تعتقد أن عمل وحدة معالجة الرسومات ينتهي بشكل أسرع مما هو عليه في الواقع، لذلك تتوقف عن خفض الدقة ومسافة العرض لتتناسب مع سرعات جهاز Switch. تخطي إبطال صلاحية وحدة المعالجة المركزية الداخلية يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة من جانب وحدة المعالجة المركزية أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسن أداءها. قد يتسبب ذلك في حدوث أعطال أو تعطل في بعض الألعاب. - إعادة قراءة وحدة معالجة الرسومات قبل إبطال صلاحية NCE - إصلاح مؤقت. يعالج مشكلة تعطل لعبة Ender Magnolia (وغيرها من ألعاب UE). قد يؤدي إلى انخفاض في الأداء. يجري العمل على تحسينه. إصلاح تأثيرات التوهج - يقلل من ضبابية التوهج في LA/EOW (Adreno A6XX - A7XX/ Turnip)، ويزيل التوهج في Burnout. تحذير: قد يسبب تشوهات رسومية في ألعاب أخرى. + يزيل تأثير التوهج في لعبة Burnout. محاكاة BGR565 يُصلح مشاكل انعكاس الألوان في الألعاب أو ظهور تشوهات غريبة أو ظلال غريبة. تفعيل ميزة إعادة التحجيم القديمة @@ -696,7 +694,7 @@ عصا التحكم العصا اليمنى عصا-C - مضغوط + ضغط العصا النطاق المنطقة الميتة معدل @@ -823,10 +821,16 @@ الإعدادات النظام - وضع الإرساء، المنطقة، اللغة + وضع المنصة، المنطقة، اللغة الرسومات مستوى دقة المحاكاة، الدقة، ذاكرة التخزين المؤقتة للتظليل الإعدادات السريعة + رموز الغش + تفعيل جميع رموز الغش + تعطيل جميع رموز الغش + رمز الغش بدون اسم + تفعيل رموز الغش بشكل افتراضي + تفعيل رموز الغش الاعتيادية عند بدء اللعبة تفعيل الإعدادات السريعة السماح بالوصول إلى قائمة الإعدادات السريعة عن طريق التمرير و زر القائمة الصوت @@ -871,12 +875,12 @@ نسخ التفاصيل الإضافات تفعيل/تعطيل التعديلات، التحديثات، المحتوى القابل للتنزيل - زمن اللعب: - مسح زمن اللعب - إعادة تعيين زمن اللعب للعبة الحالية إلى 0 ثانية - سيؤدي هذا إلى مسح بيانات زمن اللعب الحالية للعبة. هل أنت متأكد؟ - تمت إعادة تعيين زمن اللعب - تعديل زمن اللعب + وقت اللعب: + مسح وقت اللعب + إعادة تعيين وقت لعب اللعبة الحالية إلى 0 ثانية + سيؤدي هذا إلى مسح بيانات وقت اللعب للعبة الحالية. هل أنت متأكد؟ + تمت إعادة تعيين وقت اللعب + تعديل وقت اللعب ساعات دقائق س @@ -885,7 +889,7 @@ يجب أن تكون الساعات بين 0 و 9999 يجب أن تكون الدقائق بين 0 و 59 يجب أن تكون الثواني بين 0 و 59 - تم تحديث زمن اللعب بنجاح + تم تحديث وقت اللعب بنجاح مسح ذاكرة التخزين المؤقتة للتظليل يزيل جميع التظليلات التي تم إنشاؤها أثناء لعب هذه اللعبة ستواجه المزيد من التقطع مع إعادة إنشاء ذاكرة التخزين المؤقتة للتظلل diff --git a/src/android/app/src/main/res/values-es/strings.xml b/src/android/app/src/main/res/values-es/strings.xml index 05135b515e..0633299105 100644 --- a/src/android/app/src/main/res/values-es/strings.xml +++ b/src/android/app/src/main/res/values-es/strings.xml @@ -531,7 +531,6 @@ Omitir invalidación interna de la CPU Omite ciertas invalidaciones de caché de la CPU durante las actualizaciones de memoria, lo que reduce el uso de la CPU y mejora su rendimiento. Esto puede causar fallos o bloqueos en algunos juegos. Arreglar los efectos de resplandor - Reduce el efecto de resplandor en LA/EOW (Adreno A6XX - A7XX/ Turnip), elimina el resplandor en Burnout. Advertencia: puede causar artefactos gráficos en otros juegos. Emular BGR565 Soluciona problemas con colores invertidos en juegos, artefactos o sombras extrañas. Activar la pasada de reescalado heredada diff --git a/src/android/app/src/main/res/values-ru/strings.xml b/src/android/app/src/main/res/values-ru/strings.xml index c291a9276b..f50c5c329c 100644 --- a/src/android/app/src/main/res/values-ru/strings.xml +++ b/src/android/app/src/main/res/values-ru/strings.xml @@ -577,7 +577,6 @@ Пропустить внутреннюю инвалидацию ЦП Пропускает некоторые инвалидации кэша на стороне ЦП при обновлениях памяти, уменьшая нагрузку на процессор и повышая производительность. Может вызывать сбои в некоторых играх. Исправить эффекты размытия - Частично убирает размытие в LA/EOW (Adreno A6XX - A7XX/ Turnip), полностью отключает его в Burnout. Внимание: может вызывать графические артефакты в других играх. Эмулировать BGR565 Исправляет проблемы с инвертированными цветами в играх, а также со странными артефактами или некорректными тенями. Включить старый метод изменения разрешения diff --git a/src/android/app/src/main/res/values-uk/strings.xml b/src/android/app/src/main/res/values-uk/strings.xml index b49e320806..92bcbb5a41 100644 --- a/src/android/app/src/main/res/values-uk/strings.xml +++ b/src/android/app/src/main/res/values-uk/strings.xml @@ -493,7 +493,6 @@ Пропустити внутрішнє інвалідування CPU Пропускає деякі інвалідації кешу на стороні CPU під час оновлення пам\'яті, зменшуючи навантаження на процесор і покращуючи продуктивність. Може спричинити збої в деяких іграх. Виправити ефекти світіння - Зменшує розмиття світіння в LA/EOW (Adreno A6XX–A7XX / Turnip), прибирає світіння в Burnout. Увага: може спричинити графічні артефакти в інших іграх. Емулювати BGR565 Виправляє проблеми з інвертованими кольорами в іграх або дивними артефактами чи тінями. Увімкнути застаріле масштабування diff --git a/src/android/app/src/main/res/values-zh-rCN/strings.xml b/src/android/app/src/main/res/values-zh-rCN/strings.xml index 6ae0f102b2..33c780943c 100644 --- a/src/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/android/app/src/main/res/values-zh-rCN/strings.xml @@ -578,7 +578,7 @@ 跳过CPU内部无效化 在更新内存时跳过某些 CPU 端的缓存失效操作,从而降低 CPU 占用率并提升性能。可能会在某些游戏中引发故障点或崩溃。 修复 Bloom 效果 - 减少《智慧的再现》和《众神的三角力量2》(Adreno A6XX - A7XX/ Turnip)中的 bloom 模糊,并移除《Burnout》中的 bloom 效果。警告:可能会导致在其他游戏中出现图形异常。 + 去除《火爆狂飙》中的泛光特效。 模拟 BGR565 修复游戏中的颜色反转或是异常的画面瑕疵或阴影问题 启用旧版缩放处理 @@ -815,6 +815,12 @@ 图形 精度等级、分辨率及着色器缓存 快速设置 + 作弊 + 开启所有作弊 + 关闭所有作弊 + 未命名的作弊 + 默认开启作弊 + 在游戏启动时启用常规作弊 启用快速设置 允许通过滑动和菜单按钮访问快速设置菜单 声音 diff --git a/src/android/app/src/main/res/values-zh-rTW/strings.xml b/src/android/app/src/main/res/values-zh-rTW/strings.xml index 3f0c6d9215..e5dcde98dd 100644 --- a/src/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/android/app/src/main/res/values-zh-rTW/strings.xml @@ -36,7 +36,7 @@ 虛擬按鍵設定 調整虛擬按鍵的位置與顯示設定 - 編輯虛擬按鍵 + 調整虛擬按鍵 調整虛擬按鍵的位置和大小 @@ -253,8 +253,8 @@ 跳過安裝韌體? 設定模擬器資料 模擬器需要金鑰才能正常執行,同時建議安裝韌體以啟動 QLaunch 小程式 - 授予權限 - 授予權限以使用模擬器的特定功能 + 授予通知權限 + 授予 Eden 傳送通知的權限以使用模擬器的特定功能 許多遊戲需要韌體才能正常運作 https://yuzu-mirror.github.io/help/quickstart/#guide-introduction 通知 @@ -268,8 +268,8 @@ 製造商 型號 型號代碼 - 安卓版本 - 安卓安全性修補程式等級 + Android 版本 + Android 安全性修補程式等級 版本號碼 基本資訊 硬體 @@ -287,7 +287,7 @@ 跳過 取消 安裝 Amiibo 金鑰 - 需要先安裝才能在遊戲中使用 Amiibo + 安裝 Amiibo 以在日後遊玩時使用 GPU 驅動程式下載器 GPU 驅動程式管理員 安裝替代驅動程式以取得潛在的更佳效能或準確度 @@ -417,17 +417,17 @@ 您的裝置不支援自訂驅動程式 此裝置不支援注入自訂驅動程式\n請以後再來查看是否已新增支援! 管理 Eden 資料 - 安裝韌體、金鑰,導入/導出使用者資料及安裝其它項目! + 安裝韌體、金鑰,匯入/匯出使用者資料及安裝其它項目! 遊戲資料夾 深度掃描 新增遊戲資料夾 這個資料夾已經新增過了! 遊戲資料夾設定 - %d 個存檔導入失敗 + %d 個存檔匯入失敗 - 成功導入 %d 個存檔 + 成功匯入 %d 個存檔 找不到儲存資料 驗證已安裝內容的完整性 @@ -451,7 +451,7 @@ Qlaunch - 從 Switch 系統主畫面啟動應用程式(目前僅支援英文) + 從 Switch 系統主畫面啟動應用程式(目前模擬區域尚不支援臺灣、澳洲、中國、南韓啟動 Qlaunch) 小程式啟動器 使用已安裝的韌體啟動系統小程式 未安裝韌體 @@ -577,10 +577,8 @@ 讓遊戲誤以為 GPU 工作能更快完成,避免遊戲為了配合 Switch 的時脈而降低解析度與渲染距離 跳過 CPU 內部失效處理 在記憶體更新期間跳過某些 CPU 端快取的失效處理,減少 CPU 使用率並提高其性能。可能會導致某些遊戲出現故障或當機 - 在 NCE 無效化前進行 GPU 回讀 - (暫時性功能)修復 \"終結者瑪格諾莉亞:霧中綻放\" 及其它使用虛幻引擎之遊戲中的當機問題,可能會降低效能。此功能正在改善中 修正光暈特效 - 在 \"薩爾達傳說:織夢島\" 和 \"薩爾達傳說:智慧的再現\" 中減少光暈模糊的問題並移除 \"橫衝直撞:狂飆樂園重製版\" 中的光暈效果(適用於 Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常 + 移除《橫衝直撞:狂飆樂園重製版》中的光暈效果 模擬 BGR565 修正遊戲中出現的色彩反轉、圖形異常或陰影異常 啟用舊版重新縮放處理 @@ -603,7 +601,7 @@ 擴充功能 擴展動態狀態 - 控制擴展動態狀態中可使用的功能數量,較高的數值可根據驅動程式支援的動態狀態減少管線編譯的次數 + 控制 Vulkan 擴展動態狀態中可使用的功能數量,較高的數值可根據驅動程式支援的動態狀態減少管線編譯的次數 停用 頂點輸入動態狀態 啟用此功能可提供更彈性的頂點輸入處理方式,並可能減少頂點/緩衝區的管線編譯時間 @@ -808,7 +806,7 @@ 推薦驅動程式: GPU 型號 不支援的 GPU - 您的 GPU 不支援驅動程式注入,不建議嘗試設定自訂驅動程式 + 您的 GPU 不支援驅動程式注入,不建議嘗試安裝自訂驅動程式 設定 @@ -817,6 +815,12 @@ 圖形 準確度層級、解析度及著色器快取 快捷設定 + 金手指 + 啟用所有金手指 + 停用所有金手指 + 未命名的金手指 + 預設啟用金手指 + 在遊戲啟動時啟用一般金手指 啟用快捷設定 允許透過滑動和選單按鈕存取快捷設定選單 音訊 @@ -833,9 +837,9 @@ 遊戲儲存資料路徑 設定遊戲儲存資料的自訂路徑 重設為預設值 - 遷移儲存資料 + 移動儲存資料 您要將現有的儲存資料移至新位置嗎? - 成功遷移儲存資料 + 儲存資料遷移成功 儲存資料遷移失敗 存檔目錄設定完成 所選取的位置已有儲存資料,是否要取代該檔案? @@ -891,10 +895,10 @@ 儲存資料已成功刪除 內容類型 更新及 DLC - 模組及金手指 - 重要的˙附加元件通知 + Mod 和金手指 + 注意! - 若要安裝模組及金手指,您必須選擇一個包含 cheats/、romfs/ 或 exefs/ 的目錄。我們無法驗證這些內容是否與您的遊戲相容,所以請謹慎安裝! + 若要安裝 Mod 和金手指,您必須選擇一個包含 cheats/、romfs/ 或 exefs/ 的目錄。我們無法驗證這些內容是否與您的遊戲相容,所以請謹慎安裝! 無效的目錄 請確保您選取的目錄包含 cheats/、romfs/ 或 exefs/ 資料夾,然後再試一次 @@ -981,7 +985,7 @@ 暫停模擬 繼續模擬 疊加層/虛擬按鍵設定 - 導入 Amiibo + 匯入 Amiibo 觸控螢幕 鎖定側邊選單 解鎖側邊選單 @@ -1128,6 +1132,16 @@ 全部清除 Freedreno 設定已儲存 已清除所有 Freedreno 變數 + 變數 %1$s 已新增 + 設定檔 \"%1$s\" 已套用 + 變數名稱不可空白 + 變數設定失敗 + 關於 Freedreno 設定 + 透過調整 Freedreno/Turnip GPU 驅動程式的設定來偵錯、分析和最佳化效能,會自動儲存變更。詳情請參閱 https://docs.mesa3d.org/drivers/freedreno.html + Freedreno 設定 + 調整此遊戲的 GPU 驅動程式設定 + Freedreno 設定已儲存 + 方向鍵 左搖桿 @@ -1136,14 +1150,17 @@ 螢幕截圖 - 正在建置著色器 + 正在編譯著色器 變更應用程式主題 預設 - 質感設計3 - Eden介面設定 + Material You + Eden 介面設定 主題和顏色 + 全螢幕模式 + 在使用 Eden 時隱藏 Android 系統的導覽列,在直向時從螢幕底部往上滑以暫時顯示它們;橫向時則從螢幕側邊往內滑動 + 變更主題模式 跟隨系統 @@ -1152,18 +1169,26 @@ 黑色背景 - 使用深色主題時,套用黑色背景。 + 使用深色主題時套用黑色背景 + + + 遊戲資料夾 + 在 Eden 首頁顯示新增遊戲資料夾的按鈕 + QLaunch + 在 Eden 首頁顯示 QLaunch 按鈕 語言 - 選擇Eden顯示的語言 + 選擇 Eden 顯示的語言 跟隨系統 主題色彩 + Eden 紫色 藍色 青色 紅色 + 綠色 黃色 橘色 粉紅色 @@ -1185,14 +1210,28 @@ 更改小程式前端和設定 自訂前端 - Switch小程式 + Switch 小程式 軟體鍵盤 飛航模式 - 將飛航模式傳遞給Switch作業系統 + 將飛航模式傳遞給 Switch 作業系統 + 啟用小程式虛擬按鍵 + 啟用 Horizon OS 內建的小程式虛擬按鍵,長按 Home 鍵 1 秒以顯示虛擬按鍵 + + + 使用者管理 + 更改使用者名稱、圖片及新增或刪除使用者 + 新增使用者 + 新增使用者 + 編輯使用者資料 + 編輯 + 刪除 + 使用者名稱 + 使用者 ID (通用唯一辨識碼) + 這是此使用者設定檔的唯一識別碼,建立後就無法進行更改 授權 來自 AMD 的升級圖像品質 - \ No newline at end of file + diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 191506c818..f4b1cc1389 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -498,7 +498,7 @@ Make sure the user data folders are at the root of the zip folder and contain a config file at config/config.ini and try again. https://discord.gg/HstXbPch7X https://stt.gg/qKgFEAbH - https://nitter.poast.org/edenemuofficial + https://x.com/edenemuofficial https://eden-emu.dev https://git.eden-emu.dev/eden-emu @@ -593,10 +593,8 @@ Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch\'s clocks. Skip CPU Inner Invalidation Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games. - GPU Readback Before NCE Invalidation - Temporary. Fix Ender Magnolia (and other UE titles) crashes. May reduce performance. Improvement in progress. Fix Bloom Effects - Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games. + Removes bloom in Burnout. Emulate BGR565 Fixes problems with inverted colors in games or strange artifacts or strange shadows. Enable Legacy Rescale Pass @@ -842,6 +840,12 @@ Graphics Accuracy level, resolution, shader cache Quick Settings + Cheats + Enable All Cheats + Disable All Cheats + Unnamed Cheat + Enable cheats by default + Enable regular cheats when a game starts Enable Quick Settings Allow access to quick settings menu via swipe and menu button Audio diff --git a/src/common/controller_console_state.h b/src/common/controller_console_state.h new file mode 100644 index 0000000000..5a01cd122b --- /dev/null +++ b/src/common/controller_console_state.h @@ -0,0 +1,125 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/settings.h" + +namespace Common { + +/// State shared between the console-mode engine (in the main window) and the Controllers tab: +/// the UI reads and requests, the engine applies on its next tick. +struct ControllerConsoleState { + std::mutex mutex; + /// Live pads as (display name, identity): possible handheld controls first + std::vector> pads; + /// How many of `pads` could be a handheld's controls (the first ones) + std::size_t builtin_pads = 0; + /// Set by the Identify button: capture the next pad that has a button pressed + bool identify_armed = false; + std::chrono::steady_clock::time_point identify_armed_at{}; + + /// One assigned player, as the Controllers tab lists it + struct PlayerRow { + int player; ///< 0-based player index + std::string name; + bool active; ///< the pad has an input held (or was just tapped) + bool leaving; ///< the controller left and nothing took its place: shown red, then gone + int flash; ///< 0 none, 1 green (a controller took the player), 2 red (one left) + long long flash_since; ///< ms since epoch; the flash blinks for 1.5 seconds from here + std::string profile; ///< the input profile the player's controller carries ("" none) + /// Turn Off: 0 not Bluetooth, 1 not yet (identical ones not told apart), 2 yes + int turn_off = 0; + /// The player its controller started as (-1: this one); a reconnect's guessed player + int origin = -1; + bool guessed = false; + /// The name given to its controller ("" none): `name` is then "Name (Xbox)" + std::string custom_name; + /// Battery percent (-1 unknown), charging, wired + int battery = -1; + bool charging = false; + bool wired = false; + }; + /// True while an automatic assignment mode runs (the engine owns the players) + bool engine_active = false; + /// The players the engine assigned, in player order + std::vector players; + /// The handheld's own pad: its name ("" when not identified) and whether it holds a player + std::string handheld_name; + bool handheld_has_player = false; + /// The Controllers tab asked to remove the handheld's controller (its ✕) + bool builtin_remove_request = false; + /// The removed controller auto-detect leaves alone, by name ("" when not connected) + std::string handheld_blocked_name; + /// Swaps requested from the settings and the overlay, for this session only + std::vector> swap_requests; + /// Players whose Bluetooth controller is to be turned off; the player is freed + std::vector remove_requests; + /// Names given to players' controllers from the Controllers tab ("" takes it off) + std::vector> rename_requests; + /// Players whose controller the Controllers tab asked to rumble (a click on its row) + std::vector rumble_requests; + /// An input profile picked for a player, put on its controller's set. No name takes it off + /// (`restore`: the set's mappings from before this session's first profile come back). + struct ProfileRequest { + int player; + std::string name; + bool restore = false; + }; + std::vector profile_requests; + /// Bypass Steam Input took effect at startup: SDL opens the real controllers + std::atomic steam_bypassed{false}; + /// Whether Steam's virtual pads are around, and the models Steam hid that Eden opened again + /// for their motion (vendor << 16 | product) + std::atomic steam_pads_present{false}; + std::set steam_hidden_models; + /// Bumped when the engine reloads the emulated controllers: the player tabs refresh + unsigned long long generation = 0; + /// Use Any Controller as Joy-Cons: each player playing as a single Joy-Con (0 no, 1 held + /// sideways, 2 upright). Its mapping is the engine's then: the player tab can't edit it. + std::array joycon_held{}; +}; + +[[nodiscard]] inline ControllerConsoleState& GetControllerConsoleState() { + static ControllerConsoleState instance; + return instance; +} + +/// True when Eden was launched through Steam: Steam Input then wraps the controllers in +/// virtual ones +[[nodiscard]] inline bool RunningUnderSteam() { + static const bool launched = + std::getenv("SteamGameId") != nullptr || std::getenv("SteamAppId") != nullptr; + return launched; +} + +/// True when Steam Input's virtual pads are the players: under Steam, not bypassed, with +/// Steam's pads around. Otherwise the real controllers are, as outside Steam. +[[nodiscard]] inline bool SteamPadsInUse() { + const auto& state = GetControllerConsoleState(); + return RunningUnderSteam() && !state.steam_bypassed && state.steam_pads_present; +} + +/// True for a controller model Steam hid that Eden opened again for its motion (never a player) +[[nodiscard]] inline bool SteamHidModel(unsigned vendor, unsigned product) { + auto& state = GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + return state.steam_hidden_models.contains(vendor << 16 | product); +} + +/// Debug Probes: detailed controller traces in the log, for bug reports +[[nodiscard]] inline bool ControllerProbes() { + return Settings::values.console_debug_probes.GetValue(); +} + +} // namespace Common diff --git a/src/common/fs/file.cpp b/src/common/fs/file.cpp index 461a5eee35..7a0f69a84d 100644 --- a/src/common/fs/file.cpp +++ b/src/common/fs/file.cpp @@ -7,18 +7,25 @@ #include #include "common/assert.h" +#include "common/bit_util.h" #include "common/fs/file.h" #include "common/fs/fs.h" +#include "common/fs/fs_types.h" #ifdef __ANDROID__ #include "common/fs/fs_android.h" #endif #include "common/logging.h" +#include "common/literals.h" #ifdef _WIN32 #include #include +#include #else #include +#include +#include +#include #endif #ifdef _MSC_VER @@ -36,13 +43,13 @@ namespace { #ifdef _WIN32 /** - * Converts the file access mode and file type enums to a file access mode wide string. - * - * @param mode File access mode - * @param type File type - * - * @returns A pointer to a wide string representing the file access mode. - */ +* Converts the file access mode and file type enums to a file access mode wide string. +* +* @param mode File access mode +* @param type File type +* +* @returns A pointer to a wide string representing the file access mode. +*/ [[nodiscard]] constexpr const wchar_t* AccessModeToWStr(FileAccessMode mode, FileType type) { switch (type) { case FileType::BinaryFile: @@ -79,12 +86,12 @@ namespace { } /** - * Converts the file-share access flag enum to a Windows defined file-share access flag. - * - * @param flag File-share access flag - * - * @returns Windows defined file-share access flag. - */ +* Converts the file-share access flag enum to a Windows defined file-share access flag. +* +* @param flag File-share access flag +* +* @returns Windows defined file-share access flag. +*/ [[nodiscard]] constexpr int ToWindowsFileShareFlag(FileShareFlag flag) { switch (flag) { case FileShareFlag::ShareNone: @@ -102,13 +109,13 @@ namespace { #else /** - * Converts the file access mode and file type enums to a file access mode string. - * - * @param mode File access mode - * @param type File type - * - * @returns A pointer to a string representing the file access mode. - */ +* Converts the file access mode and file type enums to a file access mode string. +* +* @param mode File access mode +* @param type File type +* +* @returns A pointer to a string representing the file access mode. +*/ [[nodiscard]] constexpr const char* AccessModeToStr(FileAccessMode mode, FileType type) { switch (type) { case FileType::BinaryFile: @@ -147,12 +154,12 @@ namespace { #endif /** - * Converts the seek origin enum to a seek origin integer. - * - * @param origin Seek origin - * - * @returns Seek origin integer. - */ +* Converts the seek origin enum to a seek origin integer. +* +* @param origin Seek origin +* +* @returns Seek origin integer. +*/ [[nodiscard]] constexpr int ToSeekOrigin(SeekOrigin origin) { switch (origin) { case SeekOrigin::SetOrigin: @@ -178,7 +185,7 @@ std::string ReadStringFromFile(const std::filesystem::path& path, FileType type) } size_t WriteStringToFile(const std::filesystem::path& path, FileType type, - std::string_view string) { + std::string_view string) { if (Exists(path) && !IsFile(path)) { return 0; } @@ -189,7 +196,7 @@ size_t WriteStringToFile(const std::filesystem::path& path, FileType type, } size_t AppendStringToFile(const std::filesystem::path& path, FileType type, - std::string_view string) { + std::string_view string) { if (Exists(path) && !IsFile(path)) { return 0; } @@ -244,69 +251,189 @@ FileType IOFile::GetType() const { return file_type; } +#if defined(__unix__) +static int PlatformMapReadOnly(IOFile& io, const char* path) { + io.mmap_fd = open(path, O_RDONLY); + if (io.mmap_fd > 0) { + struct stat st; + fstat(io.mmap_fd, &st); + io.mmap_size = st.st_size; + + int map_flags = MAP_PRIVATE; +#ifdef MAP_PREFAULT_READ + // Prefaults reads so the final resulting pagetable from this big stupid mmap() + // isn't comically lazily loaded, we just coalesce everything in-place for our + // lovely mmap flags; if we didn't prefault the reads the page table will be + // constructed in-place (i.e on a read-by-read basis) causing lovely soft-faults + // which would nuke any performance gains. + // + // This of course incurs a cost in the initial mmap(2) call, but that is fine. + map_flags |= MAP_PREFAULT_READ; +#endif +#ifdef MAP_NOSYNC + // This causes physical media to not be synched to our file/memory + // This means that if the read-only file is written to, we won't see changes + // or we may see changes which are just funnily scattered, in any case + // this presumes the files won't be changed during execution + // + // Do not ever use this on write files (if we ever support that); this will create + // a fun amount of fragmentation on the disk. + map_flags |= MAP_NOSYNC; +#endif +#if defined(NDEBUG) && defined(MAP_NOCORE) + map_flags |= MAP_NOCORE; +#endif +#ifdef MAP_HUGE_2MB + map_flags |= MAP_HUGE_2MB; //2mb pages +#elif defined(MAP_ALIGNED) + // File must be big enough that it's worth to super align. We can't just super-align every + // file otherwise we will run out of alignments for actually important files :) + // System doesn't guarantee a super alignment, but if it's available it will delete + // about 3 layers(?) of the TLB tree for each read/write. + // Again the cost of faults may make this negligible gains, but hey, we gotta work + // what we gotta work with. + map_flags |= MAP_ALIGNED(21); //2^21 = 2mb use 2MB pages +#endif + io.mmap_base = (u8*)mmap(nullptr, io.mmap_size, PROT_READ, map_flags, io.mmap_fd, 0); + if (io.mmap_base == MAP_FAILED) { + close(io.mmap_fd); + io.mmap_fd = -1; + } else { + using namespace Common::Literals; + // For small files it is acceptable to use a full readahead + // See https://github.com/torvalds/linux/blob/e80d033851b3bc94c3d254ac66660ddd0a49d72c/include/linux/pagemap.h#L1392 + if (u64(st.st_size) >= 256_MiB) { + posix_madvise(io.mmap_base, io.mmap_size, POSIX_MADV_RANDOM); + } else { + posix_madvise(io.mmap_base, io.mmap_size, POSIX_MADV_SEQUENTIAL); + } + } + } + return io.mmap_fd; +} +static void PlatformUnmap(IOFile& io) { + if (io.mmap_fd != -1) { + munmap(io.mmap_base, io.mmap_size); + close(io.mmap_fd); + io.mmap_fd = -1; + } +} +#elif defined(__APPLE__) +// NO IMPLEMENTATION YET +#else +static int PlatformMapReadOnly(IOFile& io, const wchar_t* path) { + io.file_handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); + if (HANDLE(io.file_handle) != INVALID_HANDLE_VALUE) { + io.mapping_handle = CreateFileMappingW(HANDLE(io.file_handle), nullptr, PAGE_READONLY, 0, 0, nullptr); + if (io.mapping_handle) { + io.mmap_base = (u8*)MapViewOfFile(HANDLE(io.mapping_handle), FILE_MAP_READ, 0, 0, 0); + if (io.mmap_base) { + _LARGE_INTEGER pvalue; + GetFileSizeEx(io.file_handle, &pvalue); + io.mmap_size = uint32_t(pvalue.QuadPart); + } else { + CloseHandle(io.mapping_handle); + CloseHandle(io.file_handle); + return -1; + } + } else { + CloseHandle(io.file_handle); + return -1; + } + } + return 0; +} +static void PlatformUnmap(IOFile& io) { + if(io.mapping_handle) { + if(io.mmap_base) + UnmapViewOfFile(HANDLE(io.mmap_base)); + CloseHandle(HANDLE(io.mapping_handle)); + } + if(io.file_handle != INVALID_HANDLE_VALUE) + CloseHandle(HANDLE(io.file_handle)); +} +#endif + void IOFile::Open(const fs::path& path, FileAccessMode mode, FileType type, FileShareFlag flag) { Close(); - file_path = path; file_access_mode = mode; file_type = type; - errno = 0; - #ifdef _WIN32 - if (flag != FileShareFlag::ShareNone) { - file = _wfsopen(path.c_str(), AccessModeToWStr(mode, type), ToWindowsFileShareFlag(flag)); - } else { - _wfopen_s(&file, path.c_str(), AccessModeToWStr(mode, type)); + // TODO: this probably can use better logic but oh well I'm not a windowser + file_handle = nullptr; + if (type == FileType::BinaryFile && mode == FileAccessMode::Read) { + if (PlatformMapReadOnly(*this, path.c_str()) == -1) { + LOG_ERROR(Common_Filesystem, "Error mmap'ing file"); //: {}", path.c_str()); + } + } + if (file_handle == nullptr) { + if (flag != FileShareFlag::ShareNone) { + file = _wfsopen(path.c_str(), AccessModeToWStr(mode, type), ToWindowsFileShareFlag(flag)); + } else { + _wfopen_s(&file, path.c_str(), AccessModeToWStr(mode, type)); + } } #elif __ANDROID__ if (Android::IsContentUri(path)) { ASSERT_MSG(mode == FileAccessMode::Read, "Content URI file access is for read-only!"); - const auto fd = Android::OpenContentUri(path, Android::OpenMode::Read); - if (fd != -1) { - file = fdopen(fd, "r"); - const auto error_num = errno; - if (error_num != 0 && file == nullptr) { - LOG_ERROR(Common_Filesystem, "Error opening file: {}, error: {}", path.c_str(), - strerror(error_num)); + if (PlatformMapReadOnly(*this, path.c_str()) == -1) { + LOG_ERROR(Common_Filesystem, "Error mmap'ing file: {}", path.c_str()); + int const fd = Android::OpenContentUri(path, Android::OpenMode::Read); + if (fd != -1) { + file = fdopen(fd, "r"); + if (errno != 0 && file == nullptr) + LOG_ERROR(Common_Filesystem, "Error opening file: {}, error: {}", path.c_str(), strerror(errno)); + } else { + LOG_ERROR(Common_Filesystem, "Error opening file: {}", path.c_str()); } - } else { - LOG_ERROR(Common_Filesystem, "Error opening file: {}", path.c_str()); } } else { file = std::fopen(path.c_str(), AccessModeToStr(mode, type)); } +#elif defined(__HAIKU__) || defined(__managarm__) || defined(__OPENORBIS__) || defined(__APPLE__) + file = std::fopen(path.c_str(), AccessModeToStr(mode, type)); +#elif defined(__unix__) + if (type == FileType::BinaryFile && mode == FileAccessMode::Read) { + if (PlatformMapReadOnly(*this, path.c_str()) == -1) { + LOG_ERROR(Common_Filesystem, "Error mmap'ing file: {}", path.c_str()); + } + } + if (mmap_fd == -1) { + file = std::fopen(path.c_str(), AccessModeToStr(mode, type)); // mmap(2) failed or simply we can't use it + } #else + // Some other fancy OS (ahem fucking Darwin/Mac OSX) file = std::fopen(path.c_str(), AccessModeToStr(mode, type)); #endif - if (!IsOpen()) { const auto ec = std::error_code{errno, std::generic_category()}; LOG_ERROR(Common_Filesystem, "Failed to open the file at path={}, ec_message={}", - PathToUTF8String(file_path), ec.message()); + PathToUTF8String(file_path), ec.message()); } } void IOFile::Close() { - if (!IsOpen()) { - return; +#if defined(__APPLE__) + // NO IMPLEMENTATION YET +#else + PlatformUnmap(*this); +#endif + if (file) { + errno = 0; + const auto close_result = std::fclose(file) == 0; + if (!close_result) { + const auto ec = std::error_code{errno, std::generic_category()}; + LOG_ERROR(Common_Filesystem, "Failed to close the file at path={}, ec_message={}", + PathToUTF8String(file_path), ec.message()); + } + file = nullptr; } - - errno = 0; - - const auto close_result = std::fclose(file) == 0; - - if (!close_result) { - const auto ec = std::error_code{errno, std::generic_category()}; - LOG_ERROR(Common_Filesystem, "Failed to close the file at path={}, ec_message={}", - PathToUTF8String(file_path), ec.message()); - } - - file = nullptr; } bool IOFile::IsOpen() const { - return file != nullptr; + return file != nullptr || IsMappedFile(); } std::string IOFile::ReadString(size_t length) const { @@ -323,137 +450,132 @@ size_t IOFile::WriteString(std::span string) const { } bool IOFile::Flush() const { - if (!IsOpen()) { - return false; + ASSERT(!IsMappedFile()); + if (file) { + errno = 0; + auto const flush_result = std::fflush(file) == 0; + if (!flush_result) { + const auto ec = std::error_code{errno, std::generic_category()}; + LOG_ERROR(Common_Filesystem, "Failed to flush the file at path={}, ec_message={}", + PathToUTF8String(file_path), ec.message()); + } + return flush_result; } - - errno = 0; - -#ifdef _WIN32 - const auto flush_result = std::fflush(file) == 0; -#else - const auto flush_result = std::fflush(file) == 0; -#endif - - if (!flush_result) { - const auto ec = std::error_code{errno, std::generic_category()}; - LOG_ERROR(Common_Filesystem, "Failed to flush the file at path={}, ec_message={}", - PathToUTF8String(file_path), ec.message()); - } - - return flush_result; + return false; } bool IOFile::Commit() const { - if (!IsOpen()) { - return false; - } - - errno = 0; - + ASSERT(!IsMappedFile()); + if (file) { + errno = 0; #ifdef _WIN32 - const auto commit_result = std::fflush(file) == 0 && _commit(fileno(file)) == 0; + const auto commit_result = std::fflush(file) == 0 && _commit(fileno(file)) == 0; #else - const auto commit_result = std::fflush(file) == 0 && fsync(fileno(file)) == 0; + const auto commit_result = std::fflush(file) == 0 && fsync(fileno(file)) == 0; #endif - - if (!commit_result) { - const auto ec = std::error_code{errno, std::generic_category()}; - LOG_ERROR(Common_Filesystem, "Failed to commit the file at path={}, ec_message={}", - PathToUTF8String(file_path), ec.message()); + if (!commit_result) { + const auto ec = std::error_code{errno, std::generic_category()}; + LOG_ERROR(Common_Filesystem, "Failed to commit the file at path={}, ec_message={}", + PathToUTF8String(file_path), ec.message()); + } + return commit_result; } - - return commit_result; + return false; } bool IOFile::SetSize(u64 size) const { - if (!IsOpen()) { - return false; - } - - errno = 0; - + ASSERT(!IsMappedFile()); + if (file) { + errno = 0; #ifdef _WIN32 - const auto set_size_result = _chsize_s(fileno(file), static_cast(size)) == 0; + const auto set_size_result = _chsize_s(fileno(file), s64(size)) == 0; #else - const auto set_size_result = ftruncate(fileno(file), static_cast(size)) == 0; + const auto set_size_result = ftruncate(fileno(file), s64(size)) == 0; #endif - - if (!set_size_result) { - const auto ec = std::error_code{errno, std::generic_category()}; - LOG_ERROR(Common_Filesystem, "Failed to resize the file at path={}, size={}, ec_message={}", - PathToUTF8String(file_path), size, ec.message()); + if (!set_size_result) { + const auto ec = std::error_code{errno, std::generic_category()}; + LOG_ERROR(Common_Filesystem, "Failed to resize the file at path={}, size={}, ec_message={}", + PathToUTF8String(file_path), size, ec.message()); + } + return set_size_result; } - - return set_size_result; + return false; } u64 IOFile::GetSize() const { - if (!IsOpen()) { - return 0; - } + if (IsMappedFile()) + return mmap_size; + if (file) { + // Flush any unwritten buffered data into the file prior to retrieving the file mmap_size. + std::fflush(file); +#if __ANDROID__ + u64 file_size = 0; + if (Android::IsContentUri(file_path)) { + file_size = Android::GetSize(file_path); + } else { + std::error_code ec; - // Flush any unwritten buffered data into the file prior to retrieving the file size. - std::fflush(file); + file_size = fs::file_size(file_path, ec); -#ifdef __ANDROID__ - u64 file_size = 0; - if (Android::IsContentUri(file_path)) { - file_size = Android::GetSize(file_path); - } else { + if (ec) { + LOG_ERROR(Common_Filesystem, "Failed to retrieve the file mmap_size of path={}, ec_message={}", + PathToUTF8String(file_path), ec.message()); + return 0; + } + } +#else std::error_code ec; - - file_size = fs::file_size(file_path, ec); - + auto const file_size = fs::file_size(file_path, ec); if (ec) { - LOG_ERROR(Common_Filesystem, - "Failed to retrieve the file size of path={}, ec_message={}", - PathToUTF8String(file_path), ec.message()); + LOG_ERROR(Common_Filesystem, "Failed to retrieve the file mmap_size of path={}, ec_message={}", + PathToUTF8String(file_path), ec.message()); return 0; } - } -#else - std::error_code ec; - - const auto file_size = fs::file_size(file_path, ec); - - if (ec) { - LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}", - PathToUTF8String(file_path), ec.message()); - return 0; - } #endif - - return file_size; + return file_size; + } + return 0; } bool IOFile::Seek(s64 offset, SeekOrigin origin) const { - if (!IsOpen()) { - return false; + if (IsMappedFile()) { + // fuck you to whoever made this method const + switch (origin) { + case SeekOrigin::SetOrigin: + mmap_offset = s64(offset); + break; + case SeekOrigin::CurrentPosition: + mmap_offset += s64(offset); + break; + case SeekOrigin::End: + mmap_offset = s64(mmap_size) + s64(offset); + break; + } + return true; } - - errno = 0; - - const auto seek_result = fseeko(file, offset, ToSeekOrigin(origin)) == 0; - - if (!seek_result) { - const auto ec = std::error_code{errno, std::generic_category()}; - LOG_ERROR(Common_Filesystem, - "Failed to seek the file at path={}, offset={}, origin={}, ec_message={}", - PathToUTF8String(file_path), offset, origin, ec.message()); + if (file) { + errno = 0; + const auto seek_result = fseeko(file, offset, ToSeekOrigin(origin)) == 0; + if (!seek_result) { + const auto ec = std::error_code{errno, std::generic_category()}; + LOG_ERROR(Common_Filesystem, "Failed to seek the file at path={}, offset={}, origin={}, ec_message={}", + PathToUTF8String(file_path), offset, origin, ec.message()); + } + return seek_result; } - - return seek_result; + return false; } s64 IOFile::Tell() const { - if (!IsOpen()) { - return 0; + if (IsMappedFile()) { + errno = 0; + return s64(mmap_offset); } - - errno = 0; - - return ftello(file); + if (file) { + errno = 0; + return ftello(file); + } + return 0; } } // namespace Common::FS diff --git a/src/common/fs/file.h b/src/common/fs/file.h index b1ccfbd18a..b7e65fca62 100644 --- a/src/common/fs/file.h +++ b/src/common/fs/file.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include #include @@ -24,12 +25,12 @@ enum class SeekOrigin { }; /** - * Opens a file stream at path with the specified open mode. - * - * @param file_stream Reference to file stream - * @param path Filesystem path - * @param open_mode File stream open mode - */ +* Opens a file stream at path with the specified open mode. +* +* @param file_stream Reference to file stream +* @param path Filesystem path +* @param open_mode File stream open mode +*/ template void OpenFileStream(FileStream& file_stream, const std::filesystem::path& path, std::ios_base::openmode open_mode) { @@ -48,14 +49,14 @@ void OpenFileStream(FileStream& file_stream, const Path& path, std::ios_base::op #endif /** - * Reads an entire file at path and returns a string of the contents read from the file. - * If the filesystem object at path is not a regular file, this function returns an empty string. - * - * @param path Filesystem path - * @param type File type - * - * @returns A string of the contents read from the file. - */ +* Reads an entire file at path and returns a string of the contents read from the file. +* If the filesystem object at path is not a regular file, this function returns an empty string. +* +* @param path Filesystem path +* @param type File type +* +* @returns A string of the contents read from the file. +*/ [[nodiscard]] std::string ReadStringFromFile(const std::filesystem::path& path, FileType type); #ifdef _WIN32 @@ -70,18 +71,18 @@ template #endif /** - * Writes a string to a file at path and returns the number of characters successfully written. - * If a file already exists at path, its contents will be erased. - * If a file does not exist at path, it creates and opens a new empty file for writing. - * If the filesystem object at path exists and is not a regular file, this function returns 0. - * - * @param path Filesystem path - * @param type File type - * - * @returns Number of characters successfully written. - */ +* Writes a string to a file at path and returns the number of characters successfully written. +* If a file already exists at path, its contents will be erased. +* If a file does not exist at path, it creates and opens a new empty file for writing. +* If the filesystem object at path exists and is not a regular file, this function returns 0. +* +* @param path Filesystem path +* @param type File type +* +* @returns Number of characters successfully written. +*/ [[nodiscard]] size_t WriteStringToFile(const std::filesystem::path& path, FileType type, - std::string_view string); + std::string_view string); #ifdef _WIN32 template @@ -95,15 +96,15 @@ template #endif /** - * Appends a string to a file at path and returns the number of characters successfully written. - * If a file does not exist at path, it creates and opens a new empty file for appending. - * If the filesystem object at path exists and is not a regular file, this function returns 0. - * - * @param path Filesystem path - * @param type File type - * - * @returns Number of characters successfully written. - */ +* Appends a string to a file at path and returns the number of characters successfully written. +* If a file does not exist at path, it creates and opens a new empty file for appending. +* If the filesystem object at path exists and is not a regular file, this function returns 0. +* +* @param path Filesystem path +* @param type File type +* +* @returns Number of characters successfully written. +*/ [[nodiscard]] size_t AppendStringToFile(const std::filesystem::path& path, FileType type, std::string_view string); @@ -131,14 +132,14 @@ public: FileShareFlag flag = FileShareFlag::ShareReadOnly); /** - * An IOFile is a lightweight wrapper on C Library file operations. - * Automatically closes an open file on the destruction of an IOFile object. - * - * @param path Filesystem path - * @param mode File access mode - * @param type File type, default is BinaryFile. Use TextFile to open the file as a text file - * @param flag (Windows only) File-share access flag, default is ShareReadOnly - */ + * An IOFile is a lightweight wrapper on C Library file operations. + * Automatically closes an open file on the destruction of an IOFile object. + * + * @param path Filesystem path + * @param mode File access mode + * @param type File type, default is BinaryFile. Use TextFile to open the file as a text file + * @param flag (Windows only) File-share access flag, default is ShareReadOnly + */ explicit IOFile(const std::filesystem::path& path, FileAccessMode mode, FileType type = FileType::BinaryFile, FileShareFlag flag = FileShareFlag::ShareReadOnly); @@ -152,84 +153,70 @@ public: IOFile& operator=(IOFile&& other) noexcept; /** - * Gets the path of the file. - * - * @returns The path of the file. - */ + * Gets the path of the file. + * + * @returns The path of the file. + */ [[nodiscard]] std::filesystem::path GetPath() const; /** - * Gets the access mode of the file. - * - * @returns The access mode of the file. - */ + * Gets the access mode of the file. + * + * @returns The access mode of the file. + */ [[nodiscard]] FileAccessMode GetAccessMode() const; /** - * Gets the type of the file. - * - * @returns The type of the file. - */ + * Gets the type of the file. + * + * @returns The type of the file. + */ [[nodiscard]] FileType GetType() const; /** - * Opens a file at path with the specified file access mode. - * This function behaves differently depending on the FileAccessMode. - * These behaviors are documented in each enum value of FileAccessMode. - * - * @param path Filesystem path - * @param mode File access mode - * @param type File type, default is BinaryFile. Use TextFile to open the file as a text file - * @param flag (Windows only) File-share access flag, default is ShareReadOnly - */ + * Opens a file at path with the specified file access mode. + * This function behaves differently depending on the FileAccessMode. + * These behaviors are documented in each enum value of FileAccessMode. + * + * @param path Filesystem path + * @param mode File access mode + * @param type File type, default is BinaryFile. Use TextFile to open the file as a text file + * @param flag (Windows only) File-share access flag, default is ShareReadOnly + */ void Open(const std::filesystem::path& path, FileAccessMode mode, - FileType type = FileType::BinaryFile, - FileShareFlag flag = FileShareFlag::ShareReadOnly); - -// #ifdef _WIN32 -// template -// void Open(const Path& path, FileAccessMode mode, FileType type = FileType::BinaryFile, -// FileShareFlag flag = FileShareFlag::ShareReadOnly) { -// using ValueType = typename Path::value_type; -// if constexpr (IsChar) { -// Open(ToU8String(path), mode, type, flag); -// } else { -// Open(std::filesystem::path{path}, mode, type, flag); -// } -// } -// #endif + FileType type = FileType::BinaryFile, + FileShareFlag flag = FileShareFlag::ShareReadOnly); /// Closes the file if it is opened. void Close(); /** - * Checks whether the file is open. - * Use this to check whether the calls to Open() or Close() succeeded. - * - * @returns True if the file is open, false otherwise. - */ + * Checks whether the file is open. + * Use this to check whether the calls to Open() or Close() succeeded. + * + * @returns True if the file is open, false otherwise. + */ [[nodiscard]] bool IsOpen() const; /** - * Helper function which deduces the value type of a contiguous STL container used in ReadSpan. - * If T is not a contiguous container as defined by the concept IsContiguousContainer, this - * calls ReadObject and T must be a trivially copyable object. - * - * See ReadSpan for more details if T is a contiguous container. - * See ReadObject for more details if T is a trivially copyable object. - * - * @tparam T Contiguous container or trivially copyable object - * - * @param data Container of T::value_type data or reference to object - * - * @returns Count of T::value_type data or objects successfully read. - */ + * Helper function which deduces the value type of a contiguous STL container used in ReadSpan. + * If T is not a contiguous container as defined by the concept IsContiguousContainer, this + * calls ReadObject and T must be a trivially copyable object. + * + * See ReadSpan for more details if T is a contiguous container. + * See ReadObject for more details if T is a trivially copyable object. + * + * @tparam T Contiguous container or trivially copyable object + * + * @param data Container of T::value_type data or reference to object + * + * @returns Count of T::value_type data or objects successfully read. + */ template [[nodiscard]] size_t Read(T& data) const { if constexpr (IsContiguousContainer) { using ContiguousType = typename T::value_type; - static_assert(std::is_trivially_copyable_v, - "Data type must be trivially copyable."); + static_assert(std::is_trivially_copyable_v, "Data type must be trivially copyable."); return ReadSpan(data); } else { return ReadObject(data) ? 1 : 0; @@ -237,25 +224,24 @@ public: } /** - * Helper function which deduces the value type of a contiguous STL container used in WriteSpan. - * If T is not a contiguous STL container as defined by the concept IsContiguousContainer, this - * calls WriteObject and T must be a trivially copyable object. - * - * See WriteSpan for more details if T is a contiguous container. - * See WriteObject for more details if T is a trivially copyable object. - * - * @tparam T Contiguous container or trivially copyable object - * - * @param data Container of T::value_type data or const reference to object - * - * @returns Count of T::value_type data or objects successfully written. - */ + * Helper function which deduces the value type of a contiguous STL container used in WriteSpan. + * If T is not a contiguous STL container as defined by the concept IsContiguousContainer, this + * calls WriteObject and T must be a trivially copyable object. + * + * See WriteSpan for more details if T is a contiguous container. + * See WriteObject for more details if T is a trivially copyable object. + * + * @tparam T Contiguous container or trivially copyable object + * + * @param data Container of T::value_type data or const reference to object + * + * @returns Count of T::value_type data or objects successfully written. + */ template [[nodiscard]] size_t Write(const T& data) const { if constexpr (IsContiguousContainer) { using ContiguousType = typename T::value_type; - static_assert(std::is_trivially_copyable_v, - "Data type must be trivially copyable."); + static_assert(std::is_trivially_copyable_v, "Data type must be trivially copyable."); return WriteSpan(data); } else { static_assert(std::is_trivially_copyable_v, "Data type must be trivially copyable."); @@ -264,197 +250,219 @@ public: } /** - * Reads a span of T data from a file sequentially. - * This function reads from the current position of the file pointer and - * advances it by the (count of T * sizeof(T)) bytes successfully read. - * - * Failures occur when: - * - The file is not open - * - The opened file lacks read permissions - * - Attempting to read beyond the end-of-file - * - * @tparam T Data type - * - * @param data Span of T data - * - * @returns Count of T data successfully read. - */ + * Reads a span of T data from a file sequentially. + * This function reads from the current position of the file pointer and + * advances it by the (count of T * sizeof(T)) bytes successfully read. + * + * Failures occur when: + * - The file is not open + * - The opened file lacks read permissions + * - Attempting to read beyond the end-of-file + * + * @tparam T Data type + * + * @param data Span of T data + * + * @returns Count of T data successfully read. + */ template requires std::is_trivially_copyable_v [[nodiscard]] size_t ReadSpan(std::span data) const { - if (!IsOpen()) { - return 0; + if (IsMappedFile()) { + std::memcpy(data.data(), mmap_base + mmap_offset, sizeof(T) * data.size()); + return data.size(); } - return std::fread(data.data(), sizeof(T), data.size(), file); + return IsOpen() ? std::fread(data.data(), sizeof(T), data.size(), file) : 0; } /** - * Writes a span of T data to a file sequentially. - * This function writes from the current position of the file pointer and - * advances it by the (count of T * sizeof(T)) bytes successfully written. - * - * Failures occur when: - * - The file is not open - * - The opened file lacks write permissions - * - * @tparam T Data type - * - * @param data Span of T data - * - * @returns Count of T data successfully written. - */ + * Writes a span of T data to a file sequentially. + * This function writes from the current position of the file pointer and + * advances it by the (count of T * sizeof(T)) bytes successfully written. + * + * Failures occur when: + * - The file is not open + * - The opened file lacks write permissions + * + * @tparam T Data type + * + * @param data Span of T data + * + * @returns Count of T data successfully written. + */ template [[nodiscard]] size_t WriteSpan(std::span data) const { static_assert(std::is_trivially_copyable_v, "Data type must be trivially copyable."); - - if (!IsOpen()) { - return 0; + if (IsMappedFile()) { + std::memcpy(mmap_base + mmap_offset, data.data(), sizeof(T) * data.size()); + return data.size(); } - - return std::fwrite(data.data(), sizeof(T), data.size(), file); + return IsOpen() ? std::fwrite(data.data(), sizeof(T), data.size(), file) : 0; } /** - * Reads a T object from a file sequentially. - * This function reads from the current position of the file pointer and - * advances it by the sizeof(T) bytes successfully read. - * - * Failures occur when: - * - The file is not open - * - The opened file lacks read permissions - * - Attempting to read beyond the end-of-file - * - * @tparam T Data type - * - * @param object Reference to object - * - * @returns True if the object is successfully read from the file, false otherwise. - */ + * Reads a T object from a file sequentially. + * This function reads from the current position of the file pointer and + * advances it by the sizeof(T) bytes successfully read. + * + * Failures occur when: + * - The file is not open + * - The opened file lacks read permissions + * - Attempting to read beyond the end-of-file + * + * @tparam T Data type + * + * @param object Reference to object + * + * @returns True if the object is successfully read from the file, false otherwise. + */ template [[nodiscard]] bool ReadObject(T& object) const { static_assert(std::is_trivially_copyable_v, "Data type must be trivially copyable."); static_assert(!std::is_pointer_v, "T must not be a pointer to an object."); - - if (!IsOpen()) { - return false; + if (IsMappedFile()) { + std::memcpy(&object, mmap_base + mmap_offset, sizeof(T)); +#ifdef _WIN32 + return bool(sizeof(T)); +#else + return sizeof(T); +#endif } - - return std::fread(&object, sizeof(T), 1, file) == 1; + return IsOpen() ? std::fread(&object, sizeof(T), 1, file) == 1 : false; } /** - * Writes a T object to a file sequentially. - * This function writes from the current position of the file pointer and - * advances it by the sizeof(T) bytes successfully written. - * - * Failures occur when: - * - The file is not open - * - The opened file lacks write permissions - * - * @tparam T Data type - * - * @param object Const reference to object - * - * @returns True if the object is successfully written to the file, false otherwise. - */ + * Writes a T object to a file sequentially. + * This function writes from the current position of the file pointer and + * advances it by the sizeof(T) bytes successfully written. + * + * Failures occur when: + * - The file is not open + * - The opened file lacks write permissions + * + * @tparam T Data type + * + * @param object Const reference to object + * + * @returns True if the object is successfully written to the file, false otherwise. + */ template [[nodiscard]] bool WriteObject(const T& object) const { static_assert(std::is_trivially_copyable_v, "Data type must be trivially copyable."); static_assert(!std::is_pointer_v, "T must not be a pointer to an object."); - - if (!IsOpen()) { - return false; + if (IsMappedFile()) { + std::memcpy(mmap_base + mmap_offset, &object, sizeof(T)); +#ifdef _WIN32 + return sizeof(T) != 0; +#else + return sizeof(T); +#endif } - - return std::fwrite(&object, sizeof(T), 1, file) == 1; + return IsOpen() ? std::fwrite(&object, sizeof(T), 1, file) == 1 : false; } /** - * Specialized function to read a string of a given length from a file sequentially. - * This function writes from the current position of the file pointer and - * advances it by the number of characters successfully read. - * The size of the returned string may not match length if not all bytes are successfully read. - * - * @param length Length of the string - * - * @returns A string read from the file. - */ + * Specialized function to read a string of a given length from a file sequentially. + * This function writes from the current position of the file pointer and + * advances it by the number of characters successfully read. + * The size of the returned string may not match length if not all bytes are successfully read. + * + * @param length Length of the string + * + * @returns A string read from the file. + */ [[nodiscard]] std::string ReadString(size_t length) const; /** - * Specialized function to write a string to a file sequentially. - * This function writes from the current position of the file pointer and - * advances it by the number of characters successfully written. - * - * @param string Span of const char backed std::string or std::string_view - * - * @returns Number of characters successfully written. - */ + * Specialized function to write a string to a file sequentially. + * This function writes from the current position of the file pointer and + * advances it by the number of characters successfully written. + * + * @param string Span of const char backed std::string or std::string_view + * + * @returns Number of characters successfully written. + */ [[nodiscard]] size_t WriteString(std::span string) const; /** - * Attempts to flush any unwritten buffered data into the file. - * - * @returns True if the flush was successful, false otherwise. - */ + * Attempts to flush any unwritten buffered data into the file. + * + * @returns True if the flush was successful, false otherwise. + */ bool Flush() const; /** - * Attempts to commit the file into the disk. - * Note that this is an expensive operation as this forces the operating system to write - * the contents of the file associated with the file descriptor into the disk. - * - * @returns True if the commit was successful, false otherwise. - */ + * Attempts to commit the file into the disk. + * Note that this is an expensive operation as this forces the operating system to write + * the contents of the file associated with the file descriptor into the disk. + * + * @returns True if the commit was successful, false otherwise. + */ bool Commit() const; /** - * Resizes the file to a given size. - * If the file is resized to a smaller size, the remainder of the file is discarded. - * If the file is resized to a larger size, the new area appears as if zero-filled. - * - * Failures occur when: - * - The file is not open - * - * @param size File size in bytes - * - * @returns True if the file resize succeeded, false otherwise. - */ + * Resizes the file to a given size. + * If the file is resized to a smaller size, the remainder of the file is discarded. + * If the file is resized to a larger size, the new area appears as if zero-filled. + * + * Failures occur when: + * - The file is not open + * + * @param size File size in bytes + * + * @returns True if the file resize succeeded, false otherwise. + */ [[nodiscard]] bool SetSize(u64 size) const; /** - * Gets the size of the file. - * - * Failures occur when: - * - The file is not open - * - * @returns The file size in bytes of the file. Returns 0 on failure. - */ + * Gets the size of the file. + * + * Failures occur when: + * - The file is not open + * + * @returns The file size in bytes of the file. Returns 0 on failure. + */ [[nodiscard]] u64 GetSize() const; /** - * Moves the current position of the file pointer with the specified offset and seek origin. - * - * @param offset Offset from seek origin - * @param origin Seek origin - * - * @returns True if the file pointer has moved to the specified offset, false otherwise. - */ + * Moves the current position of the file pointer with the specified offset and seek origin. + * + * @param offset Offset from seek origin + * @param origin Seek origin + * + * @returns True if the file pointer has moved to the specified offset, false otherwise. + */ [[nodiscard]] bool Seek(s64 offset, SeekOrigin origin = SeekOrigin::SetOrigin) const; /** - * Gets the current position of the file pointer. - * - * @returns The current position of the file pointer. - */ + * Gets the current position of the file pointer. + * + * @returns The current position of the file pointer. + */ [[nodiscard]] s64 Tell() const; -private: +#ifdef _WIN32 + inline bool IsMappedFile() const noexcept { return mapping_handle != nullptr; } +#else // POSIX + inline bool IsMappedFile() const noexcept { return mmap_fd != -1; } +#endif + std::filesystem::path file_path; FileAccessMode file_access_mode{}; FileType file_type{}; - std::FILE* file = nullptr; + // Any decent system should have mmap() for files + // Systems with artifical mmap() limitations should simply change the logic within file.cpp + // and reduce the threshold for which the mmap() is set to +#ifdef _WIN32 + void *mapping_handle = nullptr; + void *file_handle = nullptr; +#else // POSIX + int mmap_fd = -1; +#endif + u8* mmap_base = nullptr; + size_t mmap_size = 0; + mutable s64 mmap_offset = 0; // fuck you }; } // namespace Common::FS diff --git a/src/common/logging.cpp b/src/common/logging.cpp index ed12d52532..88f92837de 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -418,6 +418,10 @@ void SetGlobalFilter(const Filter& filter) { logging_instance->filter = filter; } +bool IsMessageEnabled(Class log_class, Level log_level) { + return logging_instance && logging_instance->filter.CheckMessage(log_class, log_level); +} + void SetColorConsoleBackendEnabled(bool enabled) { if (logging_instance) logging_instance->color_console_backend.enabled = enabled; diff --git a/src/common/logging.h b/src/common/logging.h index d273eb0c49..8ec1d8a3aa 100644 --- a/src/common/logging.h +++ b/src/common/logging.h @@ -138,6 +138,7 @@ void Stop(); /// The global filter will prevent any messages from even being processed if they are filtered. void SetGlobalFilter(const Filter& filter); +[[nodiscard]] bool IsMessageEnabled(Class log_class, Level log_level); void SetColorConsoleBackendEnabled(bool enabled); } // namespace Common::Log diff --git a/src/common/overlay_panels.h b/src/common/overlay_panels.h new file mode 100644 index 0000000000..7cd13eb3e6 --- /dev/null +++ b/src/common/overlay_panels.h @@ -0,0 +1,107 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "common/common_types.h" + +namespace Common { + +/// The screen corner a panel is placed against +enum class OverlayAnchor { + TopLeft, + BottomLeft, + TopRight, +}; + +/// An image drawn over the game inside the presented frame, so it also shows under gamescope, +/// where no Qt widget can composite over the game. The frontend fills it (RGBA8); the presenter +/// blends it in last. +struct OverlayPanel { + std::mutex mutex; + std::vector pixels; ///< RGBA8, width * height * 4 + u32 width = 0; + u32 height = 0; + bool enabled = false; + /// Incremented on every push so presenters can cache by version + u64 version = 0; + OverlayAnchor anchor = OverlayAnchor::TopLeft; + /// A top-anchored panel sits this share of the screen's height lower (clear of other + /// overlays in the corner) + float drop = 0.0f; +}; + +/// The panels, in drawing order +enum class OverlayPanelId : std::size_t { + Players, ///< The controller players (top left) + Hints, ///< The controller hints (bottom left) + Cheats, ///< The cheats (top right) + Count, +}; + +inline constexpr std::size_t OverlayPanelCount = static_cast(OverlayPanelId::Count); + +[[nodiscard]] inline std::array& GetOverlayPanels() { + static std::array panels; + static const bool placed = [] { + panels[static_cast(OverlayPanelId::Hints)].anchor = + OverlayAnchor::BottomLeft; + panels[static_cast(OverlayPanelId::Cheats)].anchor = + OverlayAnchor::TopRight; + return true; + }(); + (void)placed; + return panels; +} + +[[nodiscard]] inline OverlayPanel& GetOverlayPanel(OverlayPanelId id) { + return GetOverlayPanels()[static_cast(id)]; +} + +/// A panel's place, in the pixels of the screen area the game is drawn in +struct OverlayRect { + float x; + float y; + float width; + float height; +}; + +/// Where a panel goes on a screen area (left, top, right, bottom), for both the presenter and +/// the mouse handling. Whole pixels, or the image's edge blends into a dark line. Call with the +/// panel's mutex held. +[[nodiscard]] inline OverlayRect PlaceOverlayPanel(const OverlayPanel& panel, float left, + float top, float right, float bottom) { + constexpr float margin = 4.0f; + const float width = static_cast(panel.width); + const float height = static_cast(panel.height); + const float x = panel.anchor == OverlayAnchor::TopRight ? right - width - margin + : left + margin; + const float y = panel.anchor == OverlayAnchor::BottomLeft + ? bottom - height - margin + : top + margin + (bottom - top) * panel.drop; + return {std::floor(x), std::floor(y), width, height}; +} + +/// The width a top-left panel has before it reaches the panels shown at the top right. Takes +/// the other panels' mutexes: never call it with one held. +[[nodiscard]] inline float OverlayRoomTopLeft(float screen_width) { + constexpr float margin = 4.0f; + constexpr float apart = 8.0f; + float right_taken = 0.0f; + for (auto& panel : GetOverlayPanels()) { + std::scoped_lock lock{panel.mutex}; + if (panel.enabled && panel.anchor == OverlayAnchor::TopRight) { + right_taken = (std::max)(right_taken, static_cast(panel.width) + margin + apart); + } + } + return screen_width - margin - right_taken; +} + +} // namespace Common diff --git a/src/common/settings.h b/src/common/settings.h index d1f891607b..427850c3d2 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -202,6 +202,66 @@ struct Values { // Core SwitchableSetting use_multi_core{linkage, true, "use_multi_core", Category::Core}; + + /// Show the controller debug overlay (the real pad state plus the logic's actions) + SwitchableSetting console_debug_overlay{linkage, true, "console_debug_overlay", + Category::LibraryApplet, + Specialization::Default, true, true}; + /// Modern Console: each player's starting input profile, comma-separated in player order + Setting modern_seat_profiles{linkage, std::string{}, "modern_seat_profiles", + Category::LibraryApplet}; + /// Name a controller on screen for a moment when it takes a player or leaves one + SwitchableSetting console_hints{linkage, true, "console_hints", Category::LibraryApplet, + Specialization::Default, true, true}; + /// The overlay's button history: shown, how many inputs it keeps, how long each lasts (in + /// seconds), and the time between inputs + SwitchableSetting console_history{linkage, true, "console_history", + Category::LibraryApplet}; + SwitchableSetting console_history_size{ + linkage, 10, 5, 20, "console_history_size", Category::LibraryApplet}; + SwitchableSetting console_history_seconds{ + linkage, 5, 1, 30, "console_history_seconds", Category::LibraryApplet}; + SwitchableSetting console_history_gaps{linkage, false, "console_history_gaps", + Category::LibraryApplet}; + /// Under Steam: Eden reads the real controllers instead of Steam's virtual ones. At startup. + SwitchableSetting console_bypass_steam{linkage, false, "console_bypass_steam", + Category::LibraryApplet}; + /// Modern Console: when a game only takes Joy-Cons, controllers act as Joy-Cons + SwitchableSetting console_joycon_auto{linkage, true, "console_joycon_auto", + Category::LibraryApplet}; + /// Modern Console: pause when a player's controller is turned off or gone for 3 seconds, + /// resume when a controller takes the player again + SwitchableSetting console_pause_disconnect{linkage, true, "console_pause_disconnect", + Category::LibraryApplet}; + /// Modern Console: controllers' player lights and light bars show their player + SwitchableSetting console_player_lights{linkage, true, "console_player_lights", + Category::LibraryApplet}; + /// Modern Console: Xbox and PlayStation style buttons by label instead of position + SwitchableSetting console_button_labels{linkage, false, "console_button_labels", + Category::LibraryApplet}; + /// Detailed controller traces in the log, for bug reports + SwitchableSetting console_debug_probes{linkage, false, "console_debug_probes", + Category::LibraryApplet}; + + /// The user picked the handheld's own pad (picker or Identify): auto-detect keeps it + SwitchableSetting builtin_pad_manual{linkage, false, "builtin_pad_manual", + Category::Core}; + + /// The handheld's own pad identity, latched when Handheld Console Mode engages + SwitchableSetting builtin_pad_identity{linkage, std::string{}, + "builtin_pad_identity", Category::Core}; + + /// A controller the user removed as the handheld's own (Steam handle, else identity): + /// auto-detect skips it until it is allowed again + SwitchableSetting builtin_pad_blocked{linkage, std::string{}, + "builtin_pad_blocked", Category::Core}; + /// Under Steam, the handheld's own pad's Steam handle: stable across sessions, unlike the + /// virtual pads' shared GUID + SwitchableSetting builtin_pad_steam_handle{ + linkage, std::string{}, "builtin_pad_steam_handle", Category::Core}; + /// The user picked the Steam handle (picker or Identify): kept whatever the pad reports + SwitchableSetting builtin_pad_steam_manual{linkage, false, "builtin_pad_steam_manual", + Category::Core}; SwitchableSetting memory_layout_mode{linkage, MemoryLayout::Memory_4Gb, "memory_layout_mode", @@ -247,6 +307,7 @@ struct Values { SwitchableSetting sync_core_speed{linkage, false, "sync_core_speed", Category::Core, Specialization::Default}; + SwitchableSetting enable_cheats_by_default{linkage, true, "enable_cheats_by_default", Category::Core}; // Cpu SwitchableSetting cpu_backend{linkage, @@ -639,8 +700,6 @@ struct Values { Specialization::Default, true, true}; - SwitchableSetting nce_invalidation_gpu_readback{ - linkage, false, "nce_invalidation_gpu_readback", Category::RendererHacks}; SwitchableSetting async_presentation{linkage, #ifdef __ANDROID__ true, diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index eaf3ec541d..aba53e918b 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -150,7 +150,7 @@ ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, Lanczos, Scale ENUM(AntiAliasing, None, Fxaa, Smaa); ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch); ENUM(ConsoleMode, Handheld, Docked); -ENUM(AppletMode, HLE, LLE, Disabled); +ENUM(AppletMode, HLE, LLE, Disabled, ConsoleMode, HandheldConsoleMode); ENUM(SpirvOptimizeMode, Never, OnLoad, Always); ENUM(GpuClock, Normal, Boost, Overclock) ENUM(GpuUnswizzleSize, VerySmall, Small, Normal, Large, VeryLarge) diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 9543a62343..e9465a4f5b 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -116,20 +116,122 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st } std::string UTF16ToUTF8(std::u16string_view input) { - std::wstring_convert, char16_t> convert; - return convert.to_bytes(input.data(), input.data() + input.size()); + std::string result; + result.reserve(input.size() * 4); + for (size_t i = 0; i < input.size(); ++i) { + uint32_t code = input[i]; + // Handle surrogate pairs + if (code >= 0xD800 && code <= 0xDBFF) { + if (i + 1 < input.size()) { + uint32_t low = input[i + 1]; + if (low >= 0xDC00 && low <= 0xDFFF) { + code = ((code - 0xD800) << 10) + (low - 0xDC00) + 0x10000; + ++i; + } + } + } + if (code <= 0x7F) { + result.push_back(char(code)); + } else if (code <= 0x7FF) { + result.push_back(char(0xC0 | (code >> 6))); + result.push_back(char(0x80 | (code & 0x3F))); + } else if (code <= 0xFFFF) { + result.push_back(char(0xE0 | (code >> 12))); + result.push_back(char(0x80 | ((code >> 6) & 0x3F))); + result.push_back(char(0x80 | (code & 0x3F))); + } else { + result.push_back(char(0xF0 | (code >> 18))); + result.push_back(char(0x80 | ((code >> 12) & 0x3F))); + result.push_back(char(0x80 | ((code >> 6) & 0x3F))); + result.push_back(char(0x80 | (code & 0x3F))); + } + } + return result; } std::u16string UTF8ToUTF16(std::string_view input) { - std::wstring_convert, char16_t> convert; - return convert.from_bytes(input.data(), input.data() + input.size()); + std::u16string result; + result.reserve(input.size() * 2); + for (size_t i = 0; i < input.size(); ) { + uint32_t code = 0; + unsigned char c = input[i]; + size_t len = 0; + if ((c & 0x80) == 0) { + code = c; + len = 1; + } else if ((c & 0xE0) == 0xC0) { + code = c & 0x1F; + len = 2; + } else if ((c & 0xF0) == 0xE0) { + code = c & 0x0F; + len = 3; + } else if ((c & 0xF8) == 0xF0) { + code = c & 0x07; + len = 4; + } else { + ++i; + continue; + } + if (i + len - 1 >= input.size()) + break; + for (size_t j = 1; j <= len - 1; ++j) { + if ((input[i + j] & 0xC0) != 0x80) { + code = 0xFFFD; + break; + } + code = (code << 6) | (input[i + j] & 0x3F); + } + if (code <= 0xFFFF) { + result.push_back(char16_t(code)); + } else { + code -= 0x10000; + result.push_back(char16_t(0xD800 + (code >> 10))); + result.push_back(char16_t(0xDC00 + (code & 0x3FF))); + } + i += len; + } + return result; } std::u32string UTF8ToUTF32(std::string_view input) { - std::wstring_convert, char32_t> convert; - return convert.from_bytes(input.data(), input.data() + input.size()); + std::u32string result; + result.reserve(input.size()); + for (size_t i = 0; i < input.size(); ) { + uint32_t code = 0; + unsigned char c = input[i]; + size_t len = 0; + if ((c & 0x80) == 0) { + code = c; + len = 1; + } else if ((c & 0xE0) == 0xC0) { + code = c & 0x1F; + len = 2; + } else if ((c & 0xF0) == 0xE0) { + code = c & 0x0F; + len = 3; + } else if ((c & 0xF8) == 0xF0) { + code = c & 0x07; + len = 4; + } else { + ++i; + continue; + } + if (i + len - 1 >= input.size()) + break; + for (size_t j = 1; j <= len - 1; ++j) { + if ((input[i + j] & 0xC0) != 0x80) { + code = 0xFFFD; + break; + } + code = (code << 6) | (input[i + j] & 0x3F); + } + result.push_back(code); + i += len; + } + return result; } + #ifdef _WIN32 static std::wstring CPToUTF16(u32 code_page, std::string_view input) { const auto size = diff --git a/src/common/zstd_compression.cpp b/src/common/zstd_compression.cpp index cb6ec171b5..7665482ee6 100644 --- a/src/common/zstd_compression.cpp +++ b/src/common/zstd_compression.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -46,4 +49,10 @@ std::vector DecompressDataZSTD(std::span compressed) { return decompressed; } +std::size_t DecompressDataZSTD(std::span compressed, std::span output) { + const std::size_t result = + ZSTD_decompress(output.data(), output.size(), compressed.data(), compressed.size()); + return ZSTD_isError(result) ? 0 : result; +} + } // namespace Common::Compression diff --git a/src/common/zstd_compression.h b/src/common/zstd_compression.h index a5ab2d05bd..819d7d201a 100644 --- a/src/common/zstd_compression.h +++ b/src/common/zstd_compression.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -42,4 +45,15 @@ namespace Common::Compression { */ [[nodiscard]] std::vector DecompressDataZSTD(std::span compressed); +/** + * Decompresses a single Zstandard frame into a caller-provided buffer of known size. + * + * @param compressed the compressed source memory region. + * @param output the destination buffer. Its size is the maximum number of bytes to write. + * + * @return the number of bytes written, or 0 if the frame is invalid or doesn't fit. An empty + * frame also returns 0. + */ +[[nodiscard]] std::size_t DecompressDataZSTD(std::span compressed, std::span output); + } // namespace Common::Compression diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f1d4bdae42..94b8eebb68 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -33,6 +33,8 @@ add_library(core STATIC crypto/encryption_layer.h crypto/key_manager.cpp crypto/key_manager.h + crypto/ncz_decompressor.cpp + crypto/ncz_decompressor.h crypto/partition_data_manager.cpp crypto/partition_data_manager.h crypto/xts_encryption_layer.cpp diff --git a/src/core/arm/nce/arm_nce.cpp b/src/core/arm/nce/arm_nce.cpp index 63d5638fce..438dd4d981 100644 --- a/src/core/arm/nce/arm_nce.cpp +++ b/src/core/arm/nce/arm_nce.cpp @@ -369,8 +369,8 @@ void ArmNce::SetContext(const Kernel::Svc::ThreadContext& ctx) { } void ArmNce::SignalInterrupt(Kernel::KThread* thread) { - // Add break loop condition. - m_guest_ctx.esr_el1.fetch_or(static_cast(HaltReason::BreakLoop)); + constexpr u64 break_loop = static_cast(HaltReason::BreakLoop); + if ((m_guest_ctx.esr_el1.fetch_or(break_loop) & break_loop) != 0) return; auto* params = &thread->GetNativeExecutionParameters(); LockThreadParameters(params); diff --git a/src/core/core.cpp b/src/core/core.cpp index 046ee53346..06c7ee368e 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "game_settings.h" @@ -249,30 +248,12 @@ struct System::Impl { } } - void NotifyNVDECChannelOpen(u64 process_id) { - std::scoped_lock lock{nvdec_active_mutex}; - ++nvdec_active_channels[process_id]; - } - - void NotifyNVDECChannelClose(u64 process_id) { - std::scoped_lock lock{nvdec_active_mutex}; - const auto it = nvdec_active_channels.find(process_id); - if (it == nvdec_active_channels.end()) { - return; - } - if (--it->second == 0) { - nvdec_active_channels.erase(it); - } + void SetNVDECActive(bool is_nvdec_active) { + nvdec_active = is_nvdec_active; } bool GetNVDECActive() { - std::scoped_lock lock{nvdec_active_mutex}; - return !nvdec_active_channels.empty(); - } - - bool IsNVDECActiveForProcess(u64 process_id) { - std::scoped_lock lock{nvdec_active_mutex}; - return nvdec_active_channels.contains(process_id); + return nvdec_active; } void InitializeDebugger(System& system, u16 port) { @@ -528,8 +509,6 @@ struct System::Impl { mutable std::mutex suspend_guard; std::mutex general_channel_mutex; - std::mutex nvdec_active_mutex; - std::unordered_map nvdec_active_channels; std::atomic_bool is_paused{}; std::atomic_bool is_shutting_down{}; std::atomic_bool is_powered_on{}; @@ -537,6 +516,7 @@ struct System::Impl { bool extended_memory_layout : 1 = false; bool exit_locked : 1 = false; bool exit_requested : 1 = false; + bool nvdec_active : 1 = false; void EnsureGeneralChannelInitialized(System& system) { if (!general_channel_event) { @@ -600,22 +580,14 @@ void System::UnstallApplication() { impl->UnstallApplication(); } -void System::NotifyNVDECChannelOpen(u64 process_id) { - impl->NotifyNVDECChannelOpen(process_id); -} - -void System::NotifyNVDECChannelClose(u64 process_id) { - impl->NotifyNVDECChannelClose(process_id); +void System::SetNVDECActive(bool is_nvdec_active) { + impl->SetNVDECActive(is_nvdec_active); } bool System::GetNVDECActive() { return impl->GetNVDECActive(); } -bool System::IsNVDECActiveForProcess(u64 process_id) { - return impl->IsNVDECActiveForProcess(process_id); -} - void System::InitializeDebugger() { impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue()); } @@ -814,6 +786,17 @@ void System::RegisterCheatList(const std::vector& list, impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size); } +std::vector System::GetRuntimeCheats() const { + if (!impl->cheat_engine) { + return {}; + } + return impl->cheat_engine->GetCheats(); +} + +bool System::SetCheatEnabled(u32 cheat_id, bool enabled) { + return impl->cheat_engine && impl->cheat_engine->SetCheatEnabled(cheat_id, enabled); +} + void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) { impl->frontend_applets.SetFrontendAppletSet(std::move(set)); } diff --git a/src/core/core.h b/src/core/core.h index e26093f260..22610dabe7 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -46,6 +46,7 @@ enum class ResultStatus : u16; namespace Core::Memory { struct CheatEntry; +struct RuntimeCheatInfo; class Memory; } // namespace Core::Memory @@ -191,10 +192,8 @@ public: std::unique_lock StallApplication(); void UnstallApplication(); - void NotifyNVDECChannelOpen(u64 process_id); - void NotifyNVDECChannelClose(u64 process_id); + void SetNVDECActive(bool is_nvdec_active); [[nodiscard]] bool GetNVDECActive(); - [[nodiscard]] bool IsNVDECActiveForProcess(u64 process_id); /** * Initialize the debugger. @@ -344,6 +343,8 @@ public: void RegisterCheatList(const std::vector& list, const std::array& build_id, u64 main_region_begin, u64 main_region_size); + [[nodiscard]] std::vector GetRuntimeCheats() const; + bool SetCheatEnabled(u32 cheat_id, bool enabled); void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set); diff --git a/src/core/crypto/ncz_decompressor.cpp b/src/core/crypto/ncz_decompressor.cpp new file mode 100644 index 0000000000..9b3e43d15c --- /dev/null +++ b/src/core/crypto/ncz_decompressor.cpp @@ -0,0 +1,472 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common/common_types.h" +#include "common/logging.h" +#include "common/zstd_compression.h" +#include "core/crypto/aes_util.h" +#include "core/crypto/key_manager.h" +#include "core/crypto/ncz_decompressor.h" +#include "core/file_sys/vfs/vfs.h" + +namespace Core::Crypto { + +namespace { + +constexpr u64 HeaderSize = 0x4000; +constexpr std::size_t SectionWire = 0x40; +constexpr std::size_t BlockFixed = 0x18; +constexpr std::size_t Chunk = 0x100000; +// Upper bound on NCZ section entries (64 bytes each, so the table is at most 4 MiB). A base NCA +// has a handful of sections, but nsz stores an update's patch (BKTR) data one entry per +// subsection, which is thousands of them. +constexpr u64 MaxSectionCount = 0x10000; +constexpr std::array SectionsMagic{'N', 'C', 'Z', 'S', 'E', 'C', 'T', 'N'}; +constexpr std::array BlockMagic{'N', 'C', 'Z', 'B', 'L', 'O', 'C', 'K'}; + +struct Section { + s64 offset, size; + u64 crypto_type; + Key128 key, counter; + bool Ctr() const { return crypto_type == 3 || crypto_type == 4; } +}; + +struct BlockHeader { + u32 exponent; + u64 decompressed_size; + std::vector sizes; +}; + +u64 Le(const u8* p, std::size_t n) { + u64 v = 0; + for (std::size_t i = n; i-- > 0;) v = (v << 8) | p[i]; + return v; +} + +// Mirrors nsz AESCTR.seek(): upper 8 bytes = stored counter, lower 8 = absolute NCA offset / 16. +void SetIv(Key128& iv, const Key128& base, u64 off) { + iv = base; + u64 blk = off >> 4; + for (std::size_t i = 0; i < 8; ++i) { iv[15 - i] = static_cast(blk & 0xFF); blk >>= 8; } +} + +// Parse header + section table + optional block header. Returns payload_start. +std::optional, std::optional>> ParseHeader( + const FileSys::VirtualFile& f, u64& payload_start) { + const u64 fsize = f->GetSize(); + if (fsize < HeaderSize + 16) return std::nullopt; + + const auto head = f->ReadBytes(16, HeaderSize); + if (head.size() != 16 || !std::equal(head.begin(), head.begin() + 8, SectionsMagic.begin())) + return std::nullopt; + const u64 count = Le(head.data() + 8, 8); + if (count == 0 || count > MaxSectionCount || count * SectionWire > fsize - HeaderSize - 16) + return std::nullopt; + + const auto table = f->ReadBytes(count * SectionWire, HeaderSize + 16); + if (table.size() != count * SectionWire) return std::nullopt; + + std::vector

sections; + sections.reserve(count + 1); + for (u64 i = 0; i < count; ++i) { + const u8* e = table.data() + i * SectionWire; + Section s{}; + s.offset = static_cast(Le(e, 8)); + s.size = static_cast(Le(e + 8, 8)); + s.crypto_type = Le(e + 16, 8); + std::memcpy(s.key.data(), e + 32, 16); + std::memcpy(s.counter.data(), e + 48, 16); + sections.push_back(s); + } + + const u64 block_start = HeaderSize + 16 + count * SectionWire; + const auto fixed = f->ReadBytes(BlockFixed, block_start); + std::optional bh; + if (fixed.size() == BlockFixed && + std::equal(fixed.begin(), fixed.begin() + 8, BlockMagic.begin())) { + BlockHeader b{}; + b.exponent = fixed[11]; + const s32 n = static_cast(Le(fixed.data() + 12, 4)); + if (n <= 0) return std::nullopt; + b.decompressed_size = Le(fixed.data() + 16, 8); + const auto sizes = f->ReadBytes(static_cast(n) * 4, block_start + BlockFixed); + if (sizes.size() != static_cast(n) * 4) return std::nullopt; + b.sizes.resize(n); + for (s32 i = 0; i < n; ++i) b.sizes[i] = static_cast(Le(sizes.data() + i * 4, 4)); + payload_start = block_start + BlockFixed + static_cast(n) * 4; + bh = std::move(b); + } else { + payload_start = block_start; + } + + if (!sections.empty() && sections[0].offset > static_cast(HeaderSize)) { + Section fake{}; + fake.offset = static_cast(HeaderSize); + fake.size = sections[0].offset - static_cast(HeaderSize); + sections.insert(sections.begin(), fake); + } + return std::make_pair(std::move(sections), std::move(bh)); +} + +// Sequential reader over independently-compressed blocks. Uses a direct-mapped cache (like +// NCZVirtualFile) instead of an LRU list: block_index % CacheSlots picks the slot, so a hit is +// O(1). Reuses one ZSTD_DCtx for the lifetime of the reader. +class BlockReader { +public: + static constexpr std::size_t CacheSlots = 32; + + BlockReader(FileSys::VirtualFile f, const BlockHeader& bh, u64 payload_start) + : source{std::move(f)}, block_size{1ULL << bh.exponent}, sizes{bh.sizes}, + decompressed_size{bh.decompressed_size} { + if (bh.exponent < 14 || bh.exponent > 32 || sizes.empty()) + throw std::runtime_error("bad NCZBLOCK header"); + u64 off = payload_start; + offsets.reserve(sizes.size()); + for (u32 s : sizes) { offsets.push_back(off); off += s; } + dctx = ZSTD_createDCtx(); + if (dctx == nullptr) throw std::runtime_error("ZSTD_createDCtx failed"); + cache.resize(CacheSlots); + for (auto& slot : cache) slot.id = ~0ULL; + } + + ~BlockReader() { + if (dctx != nullptr) ZSTD_freeDCtx(dctx); + } + + BlockReader(const BlockReader&) = delete; + BlockReader& operator=(const BlockReader&) = delete; + + std::size_t ReadAt(u64 position, std::span out) { + std::size_t done = 0; + while (done < out.size() && position < decompressed_size) { + const u64 id = position / block_size; + if (id >= sizes.size()) break; + const std::vector* block = GetBlock(id); + if (block == nullptr) break; + const u64 in = position - id * block_size; + if (in >= block->size()) break; + const std::size_t n = static_cast( + std::min(out.size() - done, block->size() - in)); + std::memcpy(out.data() + done, block->data() + in, n); + done += n; + position += n; + } + return done; + } + +private: + struct Slot { + u64 id = ~0ULL; + std::vector data; + }; + + const std::vector* GetBlock(u64 id) { + Slot& slot = cache[id % CacheSlots]; + if (slot.id == id) { + return &slot.data; // O(1) hit + } + std::vector buffer; + buffer.swap(slot.data); // reuse existing allocation + if (!DecodeBlock(id, buffer)) { + return nullptr; + } + slot.data = std::move(buffer); + slot.id = id; + return &slot.data; + } + + bool DecodeBlock(u64 id, std::vector& buffer) { + u64 want = block_size; + if (id + 1 == sizes.size()) { + const u64 rem = decompressed_size % block_size; + if (rem > 0) want = rem; // avoid the 0-size bug from the original nsz + } + try { buffer.resize(static_cast(want)); } + catch (const std::bad_alloc&) { return false; } + const u32 csize = sizes[id]; + if (csize < want) { + const auto comp = source->ReadBytes(csize, offsets[id]); + if (comp.size() != csize) return false; + const std::size_t res = ZSTD_decompressDCtx( + dctx, buffer.data(), buffer.size(), comp.data(), comp.size()); + if (ZSTD_isError(res) || res != want) { + LOG_ERROR(Crypto, "Failed to decompress NCZBLOCK block {}: {}", id, + ZSTD_isError(res) ? ZSTD_getErrorName(res) : "size mismatch"); + return false; + } + } else if (source->Read(buffer.data(), buffer.size(), offsets[id]) != buffer.size()) { + return false; + } + return true; + } + + FileSys::VirtualFile source; + u64 block_size; + std::vector offsets; + std::vector sizes; + u64 decompressed_size; + ZSTD_DCtx* dctx = nullptr; + std::vector cache; // direct-mapped, CacheSlots entries +}; + +class BlockNczFile final : public FileSys::VfsFile { +public: + BlockNczFile(std::string name_, std::vector hdr_, std::vector
sections_, + std::unique_ptr body_) + : name{std::move(name_)}, hdr{std::move(hdr_)}, sections{std::move(sections_)}, + body{std::move(body_)} { + nca_size = HeaderSize; + for (const auto& s : sections) + nca_size = std::max(nca_size, static_cast(s.offset + s.size)); + } + + std::string GetName() const override { return name; } + std::size_t GetSize() const override { return static_cast(nca_size); } + bool Resize(std::size_t) override { return false; } + FileSys::VirtualDir GetContainingDirectory() const override { return nullptr; } + bool IsWritable() const override { return false; } + bool IsReadable() const override { return true; } + + // NCZ stores CTR sections decrypted; this file serves them as-is, and NcaFileSystemDriver + // skips its AES layers because of this flag. + bool HasDecryptedSections() const override { return true; } + + std::size_t Read(u8* data, std::size_t len, std::size_t off) const override { + if (off >= nca_size) return 0; + len = static_cast(std::min(len, nca_size - off)); + const u64 end = off + len; + u64 pos = off; + if (pos < HeaderSize) { + const u64 n = std::min(end, HeaderSize) - pos; + std::memcpy(data, hdr.data() + pos, static_cast(n)); + pos += n; + } + std::scoped_lock lock{mutex}; + // Sections are sorted by offset; find the first one whose stop > pos. + auto it = std::lower_bound( + sections.begin(), sections.end(), pos, [](const Section& s, u64 p) { + const u64 b = std::max(static_cast(s.offset), HeaderSize); + const u64 e = std::max(static_cast(s.offset) + static_cast(s.size), b); + return e <= p; + }); + for (; it != sections.end() && pos < end; ++it) { + const auto& s = *it; + const u64 begin = std::max(static_cast(s.offset), HeaderSize); + const u64 stop = std::max(static_cast(s.offset + s.size), begin); + if (stop <= pos) continue; + if (pos < begin) { + const u64 g = std::min(end, begin); + std::memset(data + (pos - off), 0, static_cast(g - pos)); + pos = g; + if (pos >= end) break; + } + const u64 pe = std::min(end, stop); + const std::span piece(data + (pos - off), static_cast(pe - pos)); + if (body->ReadAt(pos - HeaderSize, piece) != piece.size()) + return static_cast(pos - off); + // No CTR here: NCZ body is already decrypted, and NcaFileSystemDriver skips AES. + pos = pe; + } + return len; + } + + std::size_t Write(const u8*, std::size_t, std::size_t) override { return 0; } + bool Rename(std::string_view) override { return false; } + +private: + const std::string name; + const std::vector hdr; + const std::vector
sections; + const std::unique_ptr body; + mutable std::mutex mutex; + u64 nca_size{}; +}; + +// Solid NCZ: one zstd stream over the whole body. Decoded incrementally into memory, up to the +// requested offset, so sequential install reads are O(n) instead of O(n^2). +class SolidNczFile final : public FileSys::VfsFile { +public: + SolidNczFile(std::string name_, FileSys::VirtualFile source_, + std::vector
sections_, u64 payload_start_) + : name{std::move(name_)}, source{std::move(source_)}, sections{std::move(sections_)}, + payload_start{payload_start_} { + const auto raw_header = source->ReadBytes(HeaderSize, 0); + data.assign(raw_header.begin(), raw_header.end()); + frontier = HeaderSize; + } + + ~SolidNczFile() override { + if (stream != nullptr) ZSTD_freeDStream(stream); + } + + std::string GetName() const override { return name; } + std::size_t GetSize() const override { + u64 size = HeaderSize; + for (const auto& s : sections) + size = std::max(size, static_cast(s.offset + s.size)); + return static_cast(size); + } + bool Resize(std::size_t) override { return false; } + FileSys::VirtualDir GetContainingDirectory() const override { return nullptr; } + bool IsWritable() const override { return false; } + bool IsReadable() const override { return true; } + + std::size_t Read(u8* out, std::size_t len, std::size_t off) const override { + std::scoped_lock lock{mutex}; + const u64 nca_size = GetSize(); + if (off >= nca_size) return 0; + len = static_cast(std::min(len, nca_size - off)); + const u64 needed = off + len; + if (needed > frontier && !DecodeTo(needed)) return 0; + std::memcpy(out, data.data() + off, len); + return len; + } + + std::size_t Write(const u8*, std::size_t, std::size_t) override { return 0; } + bool Rename(std::string_view) override { return false; } + +private: + bool DecodeTo(u64 needed) const { + if (stream == nullptr) { + stream = ZSTD_createDStream(); + if (stream == nullptr) return false; + ZSTD_DCtx_setParameter(stream, ZSTD_d_windowLogMax, 31); + read_pos = payload_start; + } + + const u64 file_size = source->GetSize(); + std::vector out_buf(Chunk); + + std::size_t index = 0; + for (; index < sections.size(); ++index) { + const auto& s = sections[index]; + const u64 begin = std::max(static_cast(s.offset), HeaderSize); + const u64 end = std::max(static_cast(s.offset) + static_cast(s.size), + begin); + if (end > frontier) break; + } + + for (; index < sections.size() && frontier < needed; ++index) { + const auto& s = sections[index]; + const u64 begin = std::max(static_cast(s.offset), HeaderSize); + const u64 end = std::max(static_cast(s.offset) + static_cast(s.size), + begin); + if (end <= frontier) continue; + u64 pos = std::max(begin, frontier); + + std::optional> cipher; + if (s.Ctr()) cipher.emplace(s.key, Mode::CTR); + + while (pos < end && frontier < needed) { + const u64 want = std::min(end - pos, out_buf.size()); + std::size_t produced = 0; + while (produced < want) { + if (in.pos >= in.size) { + const u64 remaining = file_size - read_pos; + const std::size_t chunk = static_cast( + std::min(Chunk, remaining)); + if (chunk == 0) { LOG_ERROR(Crypto, "Solid NCZ: truncated"); return false; } + const auto bytes = source->ReadBytes(chunk, read_pos); + if (bytes.empty()) { LOG_ERROR(Crypto, "Solid NCZ: truncated"); return false; } + read_pos += bytes.size(); + in_buf.assign(bytes.begin(), bytes.end()); + in.src = in_buf.data(); + in.size = in_buf.size(); + in.pos = 0; + } + ZSTD_outBuffer outb{out_buf.data() + produced, want - produced, 0}; + const std::size_t res = ZSTD_decompressStream(stream, &outb, &in); + if (ZSTD_isError(res)) { + LOG_ERROR(Crypto, "Solid NCZ: zstd error"); + return false; + } + produced += outb.pos; + } + if (cipher) { + Key128 iv{}; + SetIv(iv, s.counter, pos); + cipher->SetIV(iv); + cipher->Transcode(out_buf.data(), produced, out_buf.data(), Op::Encrypt); + } + data.insert(data.end(), out_buf.begin(), out_buf.begin() + produced); + pos += produced; + frontier = pos; + } + } + return frontier >= needed; + } + + const std::string name; + const FileSys::VirtualFile source; + const std::vector
sections; + const u64 payload_start; + mutable std::mutex mutex; + mutable std::vector data; + mutable ZSTD_DStream* stream = nullptr; + mutable u64 read_pos = 0; + mutable u64 frontier = 0; + mutable std::vector in_buf; + mutable ZSTD_inBuffer in{nullptr, 0, 0}; +}; + +// Shared opener: block path always; solid only when allow_solid is true. +FileSys::VirtualFile OpenNcz(const FileSys::VirtualFile& f, std::string_view name, + bool allow_solid) { + if (!f) return nullptr; + u64 ps = 0; + auto parsed = ParseHeader(f, ps); + if (!parsed) return nullptr; + auto& [sections, block] = *parsed; + + if (block) { + auto hdr = f->ReadBytes(HeaderSize, 0); + if (hdr.size() != HeaderSize) return nullptr; + std::unique_ptr body; + try { body = std::make_unique(f, *block, ps); } + catch (const std::exception& e) { + LOG_ERROR(Crypto, "Failed to open NCZBLOCK: {}", e.what()); + return nullptr; + } + return std::make_shared(std::string{name}, std::move(hdr), + std::move(sections), std::move(body)); + } + + if (allow_solid) { + return std::make_shared(std::string{name}, f, std::move(sections), ps); + } + + LOG_DEBUG(Crypto, "Solid NCZ {} skipped (only NCZBLOCK is supported for play)", name); + return nullptr; +} + +} // Anonymous namespace + +bool IsBlockCompressedNCZ(const FileSys::VirtualFile& f) { + if (!f) return false; + u64 ps = 0; + const auto p = ParseHeader(f, ps); + return p && p->second.has_value(); +} + +FileSys::VirtualFile DecompressNCZ(const FileSys::VirtualFile& f, std::string_view name) { + return OpenNcz(f, name, /*allow_solid=*/false); +} + +FileSys::VirtualFile DecompressNCZForInstall(const FileSys::VirtualFile& f, + std::string_view name) { + return OpenNcz(f, name, /*allow_solid=*/true); +} + +} // namespace Core::Crypto \ No newline at end of file diff --git a/src/core/crypto/ncz_decompressor.h b/src/core/crypto/ncz_decompressor.h new file mode 100644 index 0000000000..9557f8c517 --- /dev/null +++ b/src/core/crypto/ncz_decompressor.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include "core/file_sys/vfs/vfs_types.h" + +namespace Core::Crypto { + +/** + * Opens an NCZBLOCK-compressed NCA (nsz -B / .xcz block format) as a VirtualFile backed by + * on-demand block decoding. Nothing is written to disk; each read decodes only the blocks it + * covers and re-encrypts CTR sections. Solid NCZ is not supported. + * + * @param ncz_file The raw NCZ payload (e.g. ".ncz" entry from an NSZ/XCZ PFS0). + * @param output_name Name to give the returned VirtualFile (e.g. ".nca"). + * + * @return a VirtualFile for the NCA, or nullptr if the NCZ is malformed or not NCZBLOCK. + */ +[[nodiscard]] FileSys::VirtualFile DecompressNCZ(const FileSys::VirtualFile& ncz_file, + std::string_view output_name); + +/** + * Returns true if the given file is an NCZ payload in block-compressed (NCZBLOCK) form, + * i.e. one that DecompressNCZ() can open. Solid NCZ returns false. + */ +[[nodiscard]] bool IsBlockCompressedNCZ(const FileSys::VirtualFile& ncz_file); + +// Install to NAND: same as DecompressNCZ, but solid NCZ is decoded on demand too. +[[nodiscard]] FileSys::VirtualFile DecompressNCZForInstall( + const FileSys::VirtualFile& ncz_file, std::string_view output_name); + +} // namespace Core::Crypto \ No newline at end of file diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index b47b9437d0..1ba7bd3de3 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -45,6 +45,7 @@ NCA::NCA(VirtualFile file_, const NCA* base_nca, bool allow_missing_base) // Ensure we have the proper key area keys to continue. const u8 master_key_id = MasterKeyIdForKeyGeneration(reader->GetKeyGeneration()); if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, reader->GetKeyIndex())) { + LOG_ERROR(Loader, "Cannot decrypt {}: keys for gen 0x{:02X}+ required.", file->GetName(), reader->GetKeyGeneration()); status = Loader::ResultStatus::ErrorMissingKeyAreaKey; return; } diff --git a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp index d496d58cec..f3462dc8a3 100644 --- a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp +++ b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project @@ -93,6 +93,11 @@ Result NcaFileSystemDriver::OpenStorageImpl(VirtualFile* out, NcaFsHeaderReader* // Initialize our header reader for the fs index. R_TRY(out_header_reader->Initialize(*m_reader, fs_index)); + // NCZ files serve already-decrypted body data (CTR sections are stored decrypted). + // Skip the AES layers so we don't decrypt plaintext twice. + const bool is_pre_decrypted = + m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections(); + // Declare the storage we're opening. VirtualFile storage; @@ -158,7 +163,7 @@ Result NcaFileSystemDriver::OpenStorageImpl(VirtualFile* out, NcaFsHeaderReader* out_header_reader->GetPatchMetaDataHashDataInfo())); } - if (patch_info.HasAesCtrExTable()) { + if (patch_info.HasAesCtrExTable() && !is_pre_decrypted) { // Check the encryption type. ASSERT(out_header_reader->GetEncryptionType() == NcaFsHeader::EncryptionType::None || out_header_reader->GetEncryptionType() == NcaFsHeader::EncryptionType::AesCtrEx || @@ -196,32 +201,34 @@ Result NcaFileSystemDriver::OpenStorageImpl(VirtualFile* out, NcaFsHeaderReader* } } else { // Create the appropriate storage for the encryption type. - switch (out_header_reader->GetEncryptionType()) { - case NcaFsHeader::EncryptionType::None: - // If there's no encryption, use the base storage we made previously. - break; - case NcaFsHeader::EncryptionType::AesXts: - R_TRY(this->CreateAesXtsStorage(std::addressof(storage), std::move(storage), - fs_data_offset)); - break; - case NcaFsHeader::EncryptionType::AesCtr: - R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage), - fs_data_offset, out_header_reader->GetAesCtrUpperIv(), - AlignmentStorageRequirement::None)); - break; - case NcaFsHeader::EncryptionType::AesCtrSkipLayerHash: { - // Create the aes ctr storage. - VirtualFile aes_ctr_storage; - R_TRY(this->CreateAesCtrStorage(std::addressof(aes_ctr_storage), storage, - fs_data_offset, out_header_reader->GetAesCtrUpperIv(), - AlignmentStorageRequirement::None)); + if (!is_pre_decrypted) { + switch (out_header_reader->GetEncryptionType()) { + case NcaFsHeader::EncryptionType::None: + // If there's no encryption, use the base storage we made previously. + break; + case NcaFsHeader::EncryptionType::AesXts: + R_TRY(this->CreateAesXtsStorage(std::addressof(storage), std::move(storage), + fs_data_offset)); + break; + case NcaFsHeader::EncryptionType::AesCtr: + R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage), + fs_data_offset, out_header_reader->GetAesCtrUpperIv(), + AlignmentStorageRequirement::None)); + break; + case NcaFsHeader::EncryptionType::AesCtrSkipLayerHash: { + // Create the aes ctr storage. + VirtualFile aes_ctr_storage; + R_TRY(this->CreateAesCtrStorage(std::addressof(aes_ctr_storage), storage, + fs_data_offset, out_header_reader->GetAesCtrUpperIv(), + AlignmentStorageRequirement::None)); - // Create region switch storage. - R_TRY(this->CreateRegionSwitchStorage(std::addressof(storage), out_header_reader, - std::move(storage), std::move(aes_ctr_storage))); - } break; - default: - R_THROW(ResultInvalidNcaFsHeaderEncryptionType); + // Create region switch storage. + R_TRY(this->CreateRegionSwitchStorage(std::addressof(storage), out_header_reader, + std::move(storage), std::move(aes_ctr_storage))); + } break; + default: + R_THROW(ResultInvalidNcaFsHeaderEncryptionType); + } } // Potentially save storages to our context. @@ -382,21 +389,25 @@ Result NcaFileSystemDriver::OpenIndirectableStorageAsOriginal( } // Create the appropriate storage for the encryption type. - switch (header_reader->GetEncryptionType()) { - case NcaFsHeader::EncryptionType::None: - // If there's no encryption, use the base storage we made previously. - break; - case NcaFsHeader::EncryptionType::AesXts: - R_TRY( - this->CreateAesXtsStorage(std::addressof(storage), std::move(storage), fs_data_offset)); - break; - case NcaFsHeader::EncryptionType::AesCtr: - R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage), fs_data_offset, - header_reader->GetAesCtrUpperIv(), - AlignmentStorageRequirement::CacheBlockSize)); - break; - default: - R_THROW(ResultInvalidNcaFsHeaderEncryptionType); + const bool is_pre_decrypted = + m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections(); + if (!is_pre_decrypted) { + switch (header_reader->GetEncryptionType()) { + case NcaFsHeader::EncryptionType::None: + // If there's no encryption, use the base storage we made previously. + break; + case NcaFsHeader::EncryptionType::AesXts: + R_TRY(this->CreateAesXtsStorage(std::addressof(storage), std::move(storage), + fs_data_offset)); + break; + case NcaFsHeader::EncryptionType::AesCtr: + R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage), + fs_data_offset, header_reader->GetAesCtrUpperIv(), + AlignmentStorageRequirement::CacheBlockSize)); + break; + default: + R_THROW(ResultInvalidNcaFsHeaderEncryptionType); + } } // Set output storage. @@ -432,6 +443,11 @@ Result NcaFileSystemDriver::CreateAesCtrStorage( ASSERT(out != nullptr); ASSERT(base_storage != nullptr); + if (m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections()) { + *out = std::move(base_storage); + R_SUCCEED(); + } + // Create the iv. std::array iv{}; AesCtrStorage::MakeIv(iv.data(), sizeof(iv), upper_iv.value, offset); @@ -469,6 +485,11 @@ Result NcaFileSystemDriver::CreateAesXtsStorage(VirtualFile* out, VirtualFile ba ASSERT(out != nullptr); ASSERT(base_storage != nullptr); + if (m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections()) { + *out = std::move(base_storage); + R_SUCCEED(); + } + // Create the iv. std::array iv{}; AesXtsStorage::MakeAesXtsIv(iv.data(), sizeof(iv), offset, NcaHeader::XtsBlockSize); @@ -809,6 +830,12 @@ Result NcaFileSystemDriver::CreateAesCtrExStorageMetaStorage( // Validate preconditions. ASSERT(out != nullptr); ASSERT(base_storage != nullptr); + + if (m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections()) { + *out = std::move(base_storage); + R_SUCCEED(); + } + ASSERT(encryption_type == NcaFsHeader::EncryptionType::None || encryption_type == NcaFsHeader::EncryptionType::AesCtrEx || encryption_type == NcaFsHeader::EncryptionType::AesCtrExSkipLayerHash); @@ -871,6 +898,11 @@ Result NcaFileSystemDriver::CreateAesCtrExStorage( ASSERT(meta_storage != nullptr); ASSERT(patch_info.HasAesCtrExTable()); + if (m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections()) { + *out = std::move(base_storage); + R_SUCCEED(); + } + // Read the bucket tree header. BucketTree::Header header; std::memcpy(std::addressof(header), patch_info.aes_ctr_ex_header.data(), sizeof(header)); diff --git a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h index ad8095b6f0..74f969154f 100644 --- a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h +++ b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.h @@ -104,6 +104,7 @@ public: const NcaCompressionConfiguration& compression_cfg); VirtualFile GetSharedBodyStorage(); + VirtualFile GetStorage() const { return m_body_storage; } u32 GetMagic() const; NcaHeader::DistributionType GetDistributionType() const; NcaHeader::ContentType GetContentType() const; diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 4fd7dc6c71..75aff5af9d 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -503,10 +503,11 @@ std::vector PatchManager::CreateCheatList(const BuildI for (const auto& subdir : patch_dirs) { if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) == disabled.cend()) { if (auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats"); cheats_dir != nullptr) { - if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true)) - std::copy(res->begin(), res->end(), std::back_inserter(out)); - if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false)) + if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true)) { std::copy(res->begin(), res->end(), std::back_inserter(out)); + } else if (auto const lower_res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false)) { + std::copy(lower_res->begin(), lower_res->end(), std::back_inserter(out)); + } } } } diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 1f430434f7..26e73d260a 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -16,6 +16,7 @@ #include "common/random.h" #include "common/string_util.h" #include "core/crypto/key_manager.h" +#include "core/crypto/ncz_decompressor.h" #include "core/file_sys/card_image.h" #include "core/file_sys/common_funcs.h" #include "core/file_sys/content_archive.h" @@ -158,6 +159,25 @@ static std::shared_ptr OpenContainerAsNsp(const VirtualFile& file, Loader:: return nullptr; } +// Checks that every .ncz entry in the container is NCZBLOCK. Solid NCZ has no random access, +// and the whole point of this build is to reject it at scan time so such files never appear +// in the game list. Containers without any .ncz (plain NSP/XCI) pass through. +static bool ContainerIsFullyBlockCompressed(const std::shared_ptr& nsp) { + if (!nsp) { + return false; + } + for (const auto& entry : nsp->GetFiles()) { + const auto name = entry->GetName(); + if (name.size() < 4 || name.substr(name.size() - 4) != ".ncz") { + continue; + } + if (!Core::Crypto::IsBlockCompressedNCZ(entry)) { + return false; // solid NCZ -> reject the whole container + } + } + return true; // no .ncz at all, or all block-compressed +} + template bool ForEachContainerEntry(const std::shared_ptr& nsp, bool only_content, std::optional base_program_id, Callback&& on_entry) { @@ -811,7 +831,14 @@ std::vector RegisteredCache::ListEntriesFilter( } static std::shared_ptr GetNCAFromNSPForID(const NSP& nsp, const NcaID& id) { - auto file = nsp.GetFile(fmt::format("{}.nca", Common::HexToString(id, false))); + const auto id_string = Common::HexToString(id, false); + auto file = nsp.GetFile(fmt::format("{}.nca", id_string)); + if (file == nullptr) { + if (auto ncz_file = nsp.GetFile(fmt::format("{}.ncz", id_string))) { + file = Core::Crypto::DecompressNCZForInstall( + ncz_file, fmt::format("{}.nca", id_string)); + } + } if (file == nullptr) { return nullptr; } @@ -1273,6 +1300,12 @@ bool ManualContentProvider::AddEntriesFromContainer(VirtualFile file, bool only_ return false; } + // Reject solid NCZ (.nsz without -B): only block-compressed NCZ is supported. + if (!ContainerIsFullyBlockCompressed(nsp)) { + LOG_DEBUG(Service_FS, "Skipping solid-compressed container: {}", file->GetName()); + return false; + } + return ForEachContainerEntry( nsp, only_content, base_program_id, [this](TitleType title_type, ContentRecordType content_type, u64 title_id, @@ -1415,8 +1448,9 @@ void ExternalContentProvider::ScanDirectory(const VirtualDir& dir) { } const auto extension = Common::ToLower(filename.substr(dot_pos + 1)); - - if (extension == "nsp") { + // .xcz is an XCI container, but its updates only work through the NSP/PFS0 path + // (DecompressNCZ), not ProcessXCI. So route .xcz here on purpose. + if (extension == "nsp" || extension == "nsz" || extension == "xcz") { ProcessNSP(file); } else if (extension == "xci") { ProcessXCI(file); @@ -1434,6 +1468,12 @@ void ExternalContentProvider::ProcessNSP(const VirtualFile& file) { return; } + // Reject solid NCZ (.nsz without -B): Eden only supports block-compressed NCZ. + if (!ContainerIsFullyBlockCompressed(nsp)) { + LOG_DEBUG(Service_FS, "Skipping solid-compressed container: {}", file->GetName()); + return; + } + LOG_DEBUG(Service_FS, "Processing NSP file: {}", file->GetName()); AddExternalEntriesFromContainer(nsp, entries, versions, multi_version_entries); } diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index 0ea323492b..1a39d819f6 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp @@ -12,6 +12,7 @@ #include "common/hex_util.h" #include "common/logging.h" #include "core/crypto/key_manager.h" +#include "core/crypto/ncz_decompressor.h" #include "core/file_sys/common_funcs.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/nca_metadata.h" @@ -246,6 +247,17 @@ void NSP::ReadNCAs(const std::vector& files) { const auto id_string = Common::HexToString(rec.nca_id, false); auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string)); + if (next_file == nullptr) { + auto ncz_file = pfs->GetFile(fmt::format("{}.ncz", id_string)); + if (ncz_file != nullptr) { + next_file = Core::Crypto::DecompressNCZ(ncz_file, fmt::format("{}.nca", id_string)); + if (next_file == nullptr) { + LOG_DEBUG(Service_FS, "Skipping solid or unsupported NCZ content {}.ncz", id_string); + continue; + } + } + } + if (next_file == nullptr) { if (rec.type != ContentRecordType::DeltaFragment) { LOG_WARNING(Service_FS, diff --git a/src/core/file_sys/vfs/vfs.h b/src/core/file_sys/vfs/vfs.h index c3d73364bc..cd8eebcd8c 100644 --- a/src/core/file_sys/vfs/vfs.h +++ b/src/core/file_sys/vfs/vfs.h @@ -112,6 +112,9 @@ public: // Returns whether or not the file can be read from. virtual bool IsReadable() const = 0; + // Returns true if this file serves NCA body data that is already decrypted (e.g. NCZ). + virtual bool HasDecryptedSections() const { return false; } + // The primary method of reading from the file. Reads length bytes into data starting at offset // into file. Returns number of bytes successfully read. virtual std::size_t Read(u8* data, std::size_t length, std::size_t offset = 0) const = 0; diff --git a/src/core/file_sys/vfs/vfs_offset.h b/src/core/file_sys/vfs/vfs_offset.h index 9800b4fd09..1a19cac1a5 100644 --- a/src/core/file_sys/vfs/vfs_offset.h +++ b/src/core/file_sys/vfs/vfs_offset.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -37,6 +40,10 @@ public: std::size_t GetOffset() const; + bool HasDecryptedSections() const override { + return file && file->HasDecryptedSections(); + } + private: std::size_t TrimToFit(std::size_t r_size, std::size_t r_offset) const; diff --git a/src/core/hle/service/bcat/delivery_cache_file_service.cpp b/src/core/hle/service/bcat/delivery_cache_file_service.cpp index d9b6ff77ee..dfe771a3ec 100644 --- a/src/core/hle/service/bcat/delivery_cache_file_service.cpp +++ b/src/core/hle/service/bcat/delivery_cache_file_service.cpp @@ -39,7 +39,7 @@ Result IDeliveryCacheFileService::Open(const DirectoryName& dir_name_raw, LOG_DEBUG(Service_BCAT, "called, dir_name={}, file_name={}", dir_name, file_name); R_TRY(VerifyNameValidDir(dir_name_raw)); - R_TRY(VerifyNameValidDir(file_name_raw)); + R_TRY(VerifyNameValidFile(file_name_raw)); R_UNLESS(current_file == nullptr, ResultEntityAlreadyOpen); const auto dir = root->GetSubdirectory(dir_name); diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp index ac884b3b28..f5cbcfa0b2 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp +++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp @@ -4,6 +4,10 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include + #include "core/file_sys/errors.h" #include "core/hle/service/cmif_serialization.h" #include "core/hle/service/filesystem/fsp/fs_i_storage.h" @@ -22,6 +26,14 @@ Result IStorage::Read( R_UNLESS(length >= 0, FileSys::ResultInvalidSize); R_UNLESS(offset >= 0, FileSys::ResultInvalidOffset); + const auto now = std::chrono::steady_clock::now(); + if (now < next_read_tick) { + std::this_thread::sleep_for(next_read_tick - now); + } + next_read_tick = std::chrono::steady_clock::now() + + std::chrono::nanoseconds{std::min(length, MaxChargedReadSize) * + 1'000'000'000 / ReadBytesPerSecond}; + // Read the data from the Storage backend backend->Read(out_bytes.data(), length, offset); diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.h b/src/core/hle/service/filesystem/fsp/fs_i_storage.h index 44d5a6c8bb..9293f13c7c 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_storage.h +++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.h @@ -6,6 +6,8 @@ #pragma once +#include + #include "core/file_sys/vfs/vfs.h" #include "core/hle/service/cmif_types.h" #include "core/hle/service/filesystem/filesystem.h" @@ -18,6 +20,10 @@ public: explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_); private: + static constexpr s64 ReadBytesPerSecond = 40'000'000; + static constexpr s64 MaxChargedReadSize = 64 * 1024; + std::chrono::steady_clock::time_point next_read_tick{}; + Result Read( OutBuffer out_bytes, s64 offset, s64 length); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index f47369adb8..7ac3dfaa46 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -8,7 +8,6 @@ #include "common/assert.h" #include "common/logging.h" #include "core/core.h" -#include "core/hle/kernel/k_process.h" #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" @@ -72,23 +71,17 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span in void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) { LOG_INFO(Service_NVDRV, "NVDEC video stream started"); + system.SetNVDECActive(true); sessions[fd] = session_id; - if (const auto* session = core.GetSession(session_id); - session != nullptr && session->process != nullptr) { - system.NotifyNVDECChannelOpen(session->process->GetId()); - } host1x.StartDevice(fd, Tegra::Host1x::ChannelType::NvDec, channel_syncpoint); } void nvhost_nvdec::OnClose(DeviceFD fd) { LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); host1x.StopDevice(fd, Tegra::Host1x::ChannelType::NvDec); + system.SetNVDECActive(false); auto it = sessions.find(fd); if (it != sessions.end()) { - if (const auto* session = core.GetSession(it->second); - session != nullptr && session->process != nullptr) { - system.NotifyNVDECChannelClose(session->process->GetId()); - } sessions.erase(it); } } diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index e8f3b5a4e0..203339067a 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -4,16 +4,12 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include #include -#include -#include #include "common/assert.h" #include "common/logging.h" #include "common/settings.h" #include "core/core.h" #include "core/hle/ipc.h" -#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/kernel.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/service.h" @@ -38,7 +34,6 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se : SessionRequestHandler(system_.Kernel(), service_name_) , system{system_} , service_name{service_name_} - , is_i_storage{std::string_view{service_name_} == "IStorage"} , handler_invoker{handler_invoker_} , max_sessions{max_sessions_} {} @@ -87,7 +82,6 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx, c } void ServiceFrameworkBase::InvokeRequest(HLERequestContext& ctx) { - const bool is_cmd_read = ctx.GetCommand() == 0; auto const info = FindRequest(ctx.GetCommand()); if (!info.has_value() || info->handler_callback == nullptr) return ReportUnimplementedFunction(ctx, &*info, false); @@ -99,12 +93,6 @@ void ServiceFrameworkBase::InvokeRequest(HLERequestContext& ctx) { LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer())); handler_invoker(this, info->handler_callback, ctx); - if (is_i_storage && is_cmd_read) { - const auto* const process = ctx.GetThread().GetOwnerProcess(); - if (process != nullptr && system.IsNVDECActiveForProcess(process->GetId())) { - std::this_thread::sleep_for(std::chrono::microseconds{600}); - } - } } void ServiceFrameworkBase::InvokeRequestTipc(HLERequestContext& ctx) { diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index e8bd8683ea..6a8ba0a393 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -116,8 +116,6 @@ protected: Core::System& system; /// Identifier string used to connect to the service. const char* service_name; - /// Whether this is the IStorage service. - const bool is_i_storage; /// Function used to safely up-cast pointers to the derived class before invoking a handler. InvokerFn* handler_invoker; /// Maximum number of concurrent sessions that this service can handle. diff --git a/src/core/internal_network/network_interface.cpp b/src/core/internal_network/network_interface.cpp index f68d4617eb..1c1de880b0 100644 --- a/src/core/internal_network/network_interface.cpp +++ b/src/core/internal_network/network_interface.cpp @@ -13,7 +13,7 @@ #include #include #include -#elif defined(__linux__) || defined(__ANDROID__) +#elif defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__) #include #include #include @@ -33,6 +33,13 @@ #include #include #include +// Darwin doesn't define this for some very odd reason +// See https://stackoverflow.com/questions/5390164/getting-routing-table-on-macosx-programmatically +#ifndef SA_SIZE +#define SA_SIZE(sa) \ + ((!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? sizeof(long) \ + : 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) +#endif #endif #include "common/common_types.h" @@ -104,7 +111,7 @@ std::vector GetAvailableNetworkInterfaces() { #else std::vector GetAvailableNetworkInterfaces() { -#if defined(__ANDROID__) || defined(__linux__) +#if defined(__ANDROID__) || defined(__linux__) || defined(__APPLE__) || defined(__managarm__) struct ifaddrs* ifaddr = nullptr; if (getifaddrs(&ifaddr) != 0) { LOG_ERROR(Network, "getifaddrs: {}", std::strerror(errno)); @@ -119,8 +126,9 @@ std::vector GetAvailableNetworkInterfaces() { u32 flags; }; std::vector routes{}; -#ifdef __ANDROID__ +#if defined(__ANDROID__) || defined(__APPLE__) // Even through Linux based, we can't reliably obtain routing information from there :( + // macOS not Linux based and would murder us if we attempt to access /proc #else if (std::ifstream file("/proc/net/route"); file.is_open()) { file.ignore((std::numeric_limits::max)(), '\n'); //ignore header @@ -138,7 +146,10 @@ std::vector GetAvailableNetworkInterfaces() { std::vector ifaces; for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr /* Have a netmask and address */ + // Apple hates human beings so lets pretend all families are fine +#if !defined(__APPLE__) && !defined(__managarm__) || ifa->ifa_addr->sa_family != AF_INET /* Must be of kind AF_INET */ +#endif || (ifa->ifa_flags & IFF_UP) == 0 || (ifa->ifa_flags & IFF_LOOPBACK) != 0) /* Not loopback */ continue; // Just use 0 as the gateway address if not found OR routes are empty :) @@ -158,7 +169,7 @@ std::vector GetAvailableNetworkInterfaces() { } freeifaddrs(ifaddr); return ifaces; -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__APPLE__) std::vector ifaces; int fd = ::socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); if (fd < 0) { @@ -198,11 +209,15 @@ std::vector GetAvailableNetworkInterfaces() { if (msglen == 0 || msglen < SA_SIZE(sa)) break; if (i == RTA_NETMASK && sa->sa_family == AF_LINK) { - size_t namelen = 0; struct sockaddr_dl const* sdl = reinterpret_cast(sa); +#if defined(__FreeBSD__) && __FreeBSD__ < 15 + iface.name = std::string{::link_ntoa(sdl)}; +#else + size_t namelen = 0; ::link_ntoa_r(sdl, nullptr, &namelen); iface.name = std::string(namelen, ' '); ::link_ntoa_r(sdl, iface.name.data(), &namelen); +#endif std::memcpy(&iface.ip_address, sa, sizeof(struct sockaddr_in)); } msglen -= SA_SIZE(sa); diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 90e23ccc11..92e2e2f602 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -82,23 +82,27 @@ std::shared_ptr OpenContainerAsNsp(FileSys::VirtualFile file, File return nullptr; } - if (type == FileType::NSP) { + if (type == FileType::NSP || type == FileType::NSZ) { auto nsp = std::make_shared(file, program_id, program_index); return nsp->GetStatus() == ResultStatus::Success ? nsp : nullptr; } - if (type == FileType::XCI) { + if (type == FileType::XCI || type == FileType::XCZ) { FileSys::XCI xci{file, program_id, program_index}; - if (xci.GetStatus() != ResultStatus::Success) { - return nullptr; + if (xci.GetStatus() == ResultStatus::Success) { + auto secure_nsp = xci.GetSecurePartitionNSP(); + if (secure_nsp != nullptr && secure_nsp->GetStatus() == ResultStatus::Success) { + return secure_nsp; + } } - auto secure_nsp = xci.GetSecurePartitionNSP(); - if (secure_nsp == nullptr || secure_nsp->GetStatus() != ResultStatus::Success) { - return nullptr; + // PFS0-shaped .xcz (NSZ-style container) does not parse as XCI; fall back to NSP. + if (type == FileType::XCZ) { + auto nsp = std::make_shared(file, program_id, program_index); + return nsp->GetStatus() == ResultStatus::Success ? nsp : nullptr; } - return secure_nsp; + return nullptr; } return nullptr; @@ -144,7 +148,8 @@ FileType IdentifyFile(FileSys::VirtualFile file) { } bool IsContainerType(FileType type) { - return type == FileType::NSP || type == FileType::XCI; + return type == FileType::NSP || type == FileType::NSZ || type == FileType::XCI || + type == FileType::XCZ; } bool IsBootableGameContainer(FileSys::VirtualFile file, FileType type, u64 program_id, @@ -180,8 +185,12 @@ FileType GuessFromFilename(const std::string& name) { return FileType::NCA; else if (extension == "xci") return FileType::XCI; + else if (extension == "xcz") + return FileType::XCZ; else if (extension == "nsp") return FileType::NSP; + else if (extension == "nsz") + return FileType::NSZ; else if (extension == "kip") return FileType::KIP; return FileType::Unknown; @@ -197,10 +206,14 @@ std::string GetFileTypeString(FileType type) { return "NCA"; case FileType::XCI: return "XCI"; + case FileType::XCZ: + return "XCZ"; case FileType::NAX: return "NAX"; case FileType::NSP: return "NSP"; + case FileType::NSZ: + return "NSZ"; case FileType::KIP: return "KIP"; case FileType::DeconstructedRomDirectory: @@ -326,12 +339,29 @@ static std::unique_ptr GetFileLoader(Core::System& system, FileSys::V system.GetContentProvider(), program_id, program_index); + // NCZ-compressed XCI container. XCI-shaped .xcz goes to the XCI loader, while + // PFS0-shaped (NSZ-style) .xcz containers fall back to the NSP loader. + case FileType::XCZ: { + FileSys::XCI probe{file, program_id, program_index}; + if (probe.GetStatus() == ResultStatus::Success && + probe.GetSecurePartitionNSP() != nullptr) { + return std::make_unique(std::move(file), + system.GetFileSystemController(), + system.GetContentProvider(), program_id, + program_index); + } + return std::make_unique(std::move(file), system.GetFileSystemController(), + system.GetContentProvider(), program_id, + program_index); + } + // NX NAX (NintendoAesXts) file format. case FileType::NAX: return std::make_unique(std::move(file)); // NX NSP (Nintendo Submission Package) file format case FileType::NSP: + case FileType::NSZ: return std::make_unique(std::move(file), system.GetFileSystemController(), system.GetContentProvider(), program_id, program_index); diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 95ce638da0..d3c0230cb0 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -42,7 +42,9 @@ enum class FileType { NRO, NCA, NSP, + NSZ, XCI, + XCZ, NAX, KIP, DeconstructedRomDirectory, diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index cfc908b4ef..8b2c79394d 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp @@ -56,6 +56,17 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_, AppLoader_NSP::~AppLoader_NSP() = default; FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& nsp_file) { + // .nsz is NSP-compatible; return NSZ so the game list shows the right type. + if (nsp_file->GetName().ends_with(".nsz")) { + return FileType::NSZ; + } + + // PFS0-shaped .xcz containers are handled by this loader too; report XCZ so the game + // list does not show them as NSP. XCI-shaped .xcz is identified by AppLoader_XCI. + if (nsp_file->GetName().ends_with(".xcz")) { + return FileType::XCZ; + } + const FileSys::NSP nsp(nsp_file); if (nsp.GetStatus() != ResultStatus::Success) { diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 983184a226..afc332cbab 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -54,7 +54,8 @@ FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& xci_file) { // Identify XCI as a valid container even when it does not include a bootable Program NCA. // Bootability is handled by AppLoader_XCI::Load(). if (xci.GetSecurePartitionNSP() != nullptr) { - return FileType::XCI; + return xci_file->GetName().ends_with(".xcz") ? FileType::XCZ + : FileType::XCI; } return FileType::Error; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index eabc6dfccb..837016de1d 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -757,7 +757,7 @@ struct Memory::Impl { }; auto& gpu = system.GPU(); gpu_device_memory->ApplyOpOnPointer( - p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size, true); }); + p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); }); } Core::System& system; diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index e14147f5c9..0af2299b62 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -4,8 +4,11 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include "common/hex_util.h" +#include "common/logging.h" +#include "common/settings.h" #include "common/swap.h" #include "core/arm/debug.h" #include "core/core.h" @@ -28,11 +31,11 @@ constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12}; std::string_view ExtractName(std::size_t& out_name_size, std::string_view data, std::size_t start_index, char match) { auto end_index = start_index; - while (data[end_index] != match) { + while (end_index < data.size() && data[end_index] != match) { ++end_index; - if (end_index > data.size()) { - return {}; - } + } + if (end_index == data.size()) { + return {}; } out_name_size = end_index - start_index; @@ -130,6 +133,11 @@ void StandardVmCallbacks::CommandLog(std::string_view data) { data.back() == '\n' ? data.substr(0, data.size() - 1) : data); } +bool StandardVmCallbacks::IsCommandLogEnabled() const { + return Common::Log::IsMessageEnabled(Common::Log::Class::CheatEngine, + Common::Log::Level::Debug); +} + bool StandardVmCallbacks::IsAddressInRange(VAddr in) const { if ((in < metadata.main_nso_extents.base || in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) && @@ -166,8 +174,9 @@ std::vector TextCheatParser::Parse(std::string_view data) const { if (data[i] == '{') { current_entry = 0; + out[*current_entry].is_master = true; - if (out[*current_entry].definition.num_opcodes > 0) { + if (!out[*current_entry].definition.opcodes.empty()) { return {}; } @@ -203,32 +212,33 @@ std::vector TextCheatParser::Parse(std::string_view data) const { '\0'; i += name_size + 1; - } else if (::isxdigit(data[i])) { - if (!current_entry || out[*current_entry].definition.num_opcodes >= - out[*current_entry].definition.opcodes.size()) { + } else if (std::isxdigit(static_cast(data[i]))) { + if (!current_entry || data.size() - i < 8) { return {}; } const auto hex = std::string(data.substr(i, 8)); - if (!std::all_of(hex.begin(), hex.end(), ::isxdigit)) { + if (!std::all_of(hex.begin(), hex.end(), [](char value) { + return std::isxdigit(static_cast(value)); + })) { return {}; } const auto value = static_cast(std::strtoul(hex.c_str(), nullptr, 0x10)); - out[*current_entry].definition.opcodes[out[*current_entry].definition.num_opcodes++] = - value; + out[*current_entry].definition.opcodes.push_back(value); - i += 8; + i += 7; } else { return {}; } } - out[0].enabled = out[0].definition.num_opcodes > 0; + out[0].enabled = out[0].is_master && !out[0].definition.opcodes.empty(); out[0].cheat_id = 0; for (u32 i = 1; i < out.size(); ++i) { - out[i].enabled = out[i].definition.num_opcodes > 0; + out[i].enabled = Settings::values.enable_cheats_by_default.GetValue() && + !out[i].definition.opcodes.empty(); out[i].cheat_id = i; } @@ -240,6 +250,10 @@ CheatEngine::CheatEngine(System& system_, std::vector cheats_, : vm{std::make_unique(system_, metadata)}, cheats(std::move(cheats_)), core_timing{system_.CoreTiming()}, system{system_} { metadata.main_nso_build_id = build_id_; + for (u32 i = 0; i < cheats.size(); ++i) { + cheats[i].cheat_id = i; + cheats[i].enabled = cheats[i].is_master || cheats[i].enabled; + } } CheatEngine::~CheatEngine() { @@ -286,12 +300,56 @@ void CheatEngine::SetMainMemoryParameters(VAddr main_region_begin, u64 main_regi } void CheatEngine::Reload(std::vector reload_cheats) { - cheats = std::move(reload_cheats); - is_pending_reload.exchange(true); + { + std::scoped_lock lock{cheats_mutex}; + cheats = std::move(reload_cheats); + for (u32 i = 0; i < cheats.size(); ++i) { + cheats[i].cheat_id = i; + cheats[i].enabled = cheats[i].is_master || cheats[i].enabled; + } + } + is_pending_reload.store(true); +} + +std::vector CheatEngine::GetCheats() const { + std::scoped_lock lock{cheats_mutex}; + std::vector result; + result.reserve(cheats.size()); + for (const auto& cheat : cheats) { + if (cheat.definition.opcodes.empty()) { + continue; + } + result.push_back({ + .id = cheat.cheat_id, + .name = cheat.definition.readable_name.data(), + .enabled = cheat.enabled || cheat.is_master, + .is_master = cheat.is_master, + }); + } + return result; +} + +bool CheatEngine::SetCheatEnabled(u32 cheat_id, bool enabled) { + std::scoped_lock lock{cheats_mutex}; + const auto entry = std::find_if(cheats.begin(), cheats.end(), [cheat_id](const auto& cheat) { + return cheat.cheat_id == cheat_id && !cheat.definition.opcodes.empty(); + }); + if (entry == cheats.end()) { + return false; + } + if (entry->is_master) { + return enabled; + } + if (entry->enabled != enabled) { + entry->enabled = enabled; + is_pending_reload.store(true); + } + return true; } void CheatEngine::FrameCallback(std::chrono::nanoseconds ns_late) { if (is_pending_reload.exchange(false)) { + std::scoped_lock lock{cheats_mutex}; vm.LoadProgram(cheats); } diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h index abd3abc93f..190eedd3f1 100644 --- a/src/core/memory/cheat_engine.h +++ b/src/core/memory/cheat_engine.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "common/common_types.h" #include "core/memory/dmnt_cheat_types.h" @@ -41,6 +42,7 @@ public: void ResumeProcess() override; void DebugLog(u8 id, u64 value) override; void CommandLog(std::string_view data) override; + [[nodiscard]] bool IsCommandLogEnabled() const override; private: bool IsAddressInRange(VAddr address) const; @@ -81,6 +83,8 @@ public: void SetMainMemoryParameters(VAddr main_region_begin, u64 main_region_size); void Reload(std::vector reload_cheats); + [[nodiscard]] std::vector GetCheats() const; + bool SetCheatEnabled(u32 cheat_id, bool enabled); private: void FrameCallback(std::chrono::nanoseconds ns_late); @@ -89,6 +93,7 @@ private: CheatProcessMetadata metadata; std::vector cheats; + mutable std::mutex cheats_mutex; std::atomic_bool is_pending_reload{false}; std::shared_ptr event; diff --git a/src/core/memory/dmnt_cheat_types.h b/src/core/memory/dmnt_cheat_types.h index 64c072d3de..c36b6686ad 100644 --- a/src/core/memory/dmnt_cheat_types.h +++ b/src/core/memory/dmnt_cheat_types.h @@ -1,8 +1,14 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#include +#include + #include "common/common_types.h" namespace Core::Memory { @@ -24,14 +30,21 @@ struct CheatProcessMetadata { struct CheatDefinition { std::array readable_name{}; - u32 num_opcodes{}; - std::array opcodes{}; + std::vector opcodes; }; struct CheatEntry { bool enabled{}; + bool is_master{}; u32 cheat_id{}; CheatDefinition definition{}; }; +struct RuntimeCheatInfo { + u32 id{}; + std::string name; + bool enabled{}; + bool is_master{}; +}; + } // namespace Core::Memory diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp index caceeec4fc..df6fe4b77f 100644 --- a/src/core/memory/dmnt_cheat_vm.cpp +++ b/src/core/memory/dmnt_cheat_vm.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -233,7 +236,7 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) { // Helper function for getting instruction dwords. const auto GetNextDword = [&] { - if (instruction_ptr >= num_opcodes) { + if (instruction_ptr >= program.size()) { valid = false; return static_cast(0); } @@ -709,20 +712,20 @@ void DmntCheatVm::ResetState() { } bool DmntCheatVm::LoadProgram(const std::vector& entries) { - // Reset opcode count. - num_opcodes = 0; + program.clear(); - for (std::size_t i = 0; i < entries.size(); i++) { - if (entries[i].enabled) { - // Bounds check. - if (entries[i].definition.num_opcodes + num_opcodes > MaximumProgramOpcodeCount) { - num_opcodes = 0; - return false; - } + std::size_t program_size{}; + for (const auto& entry : entries) { + if (entry.enabled || entry.is_master) { + program_size += entry.definition.opcodes.size(); + } + } + program.reserve(program_size); - for (std::size_t n = 0; n < entries[i].definition.num_opcodes; n++) { - program[num_opcodes++] = entries[i].definition.opcodes[n]; - } + for (const auto& entry : entries) { + if (entry.enabled || entry.is_master) { + program.insert(program.end(), entry.definition.opcodes.begin(), + entry.definition.opcodes.end()); } } @@ -735,27 +738,35 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { // Get Keys down. u64 kDown = callbacks->HidKeysDown(); - callbacks->CommandLog("Started VM execution."); - callbacks->CommandLog(fmt::format("Main NSO: {:012X}", metadata.main_nso_extents.base)); - callbacks->CommandLog(fmt::format("Heap: {:012X}", metadata.main_nso_extents.base)); - callbacks->CommandLog(fmt::format("Keys Down: {:08X}", static_cast(kDown & 0x0FFFFFFF))); + const bool command_log_enabled = callbacks->IsCommandLogEnabled(); + if (command_log_enabled) { + callbacks->CommandLog("Started VM execution."); + callbacks->CommandLog(fmt::format("Main NSO: {:012X}", metadata.main_nso_extents.base)); + callbacks->CommandLog(fmt::format("Heap: {:012X}", metadata.main_nso_extents.base)); + callbacks->CommandLog( + fmt::format("Keys Down: {:08X}", static_cast(kDown & 0x0FFFFFFF))); + } // Clear VM state. ResetState(); // Loop until program finishes. while (DecodeNextOpcode(cur_opcode)) { - callbacks->CommandLog( - fmt::format("Instruction Ptr: {:04X}", static_cast(instruction_ptr))); + if (command_log_enabled) { + callbacks->CommandLog( + fmt::format("Instruction Ptr: {:04X}", static_cast(instruction_ptr))); - for (std::size_t i = 0; i < NumRegisters; i++) { - callbacks->CommandLog(fmt::format("Registers[{:02X}]: {:016X}", i, registers[i])); - } + for (std::size_t i = 0; i < NumRegisters; i++) { + callbacks->CommandLog(fmt::format("Registers[{:02X}]: {:016X}", i, + registers[i])); + } - for (std::size_t i = 0; i < NumRegisters; i++) { - callbacks->CommandLog(fmt::format("SavedRegs[{:02X}]: {:016X}", i, saved_values[i])); + for (std::size_t i = 0; i < NumRegisters; i++) { + callbacks->CommandLog(fmt::format("SavedRegs[{:02X}]: {:016X}", i, + saved_values[i])); + } + LogOpcode(cur_opcode); } - LogOpcode(cur_opcode); // Increment conditional depth, if relevant. if (cur_opcode.begin_conditional_block) { diff --git a/src/core/memory/dmnt_cheat_vm.h b/src/core/memory/dmnt_cheat_vm.h index de5e81add2..f7c10f9130 100644 --- a/src/core/memory/dmnt_cheat_vm.h +++ b/src/core/memory/dmnt_cheat_vm.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project @@ -281,9 +281,9 @@ public: virtual void DebugLog(u8 id, u64 value) = 0; virtual void CommandLog(std::string_view data) = 0; + [[nodiscard]] virtual bool IsCommandLogEnabled() const = 0; }; - static constexpr std::size_t MaximumProgramOpcodeCount = 0x400; static constexpr std::size_t NumRegisters = 0x10; static constexpr std::size_t NumReadableStaticRegisters = 0x80; static constexpr std::size_t NumWritableStaticRegisters = 0x80; @@ -294,7 +294,7 @@ public: ~DmntCheatVm(); std::size_t GetProgramSize() const { - return this->num_opcodes; + return program.size(); } bool LoadProgram(const std::vector& cheats); @@ -303,11 +303,10 @@ public: private: std::unique_ptr callbacks; - std::size_t num_opcodes = 0; std::size_t instruction_ptr = 0; std::size_t condition_depth = 0; bool decode_success = false; - std::array program{}; + std::vector program; std::array registers{}; std::array saved_values{}; std::array static_registers{}; diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt index bacbd7ab57..0837a502cf 100644 --- a/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/CMakeLists.txt @@ -11,34 +11,15 @@ set(dynarmic_VERSION ${dynarmic_VERSION_MAJOR}.${dynarmic_VERSION_MINOR}.${dynar project(dynarmic LANGUAGES C CXX ASM VERSION ${dynarmic_VERSION}) -# Determine if we're built as a subproject (using add_subdirectory) -# or if this is the master project. -set(MASTER_PROJECT OFF) -if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) - set(MASTER_PROJECT ON) -endif() - -if (MASTER_PROJECT) - include(CTest) -endif() - -# Dynarmic project options -option(DYNARMIC_ENABLE_CPU_FEATURE_DETECTION "Turning this off causes dynarmic to assume the host CPU doesn't support anything later than SSE3" ON) - if (OPENBSD OR DRAGONFLY OR NETBSD) set(REQUIRE_WX ON) else() set(REQUIRE_WX OFF) endif() option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" ${REQUIRE_WX}) - -option(DYNARMIC_IGNORE_ASSERTS "Ignore asserts" ON) option(DYNARMIC_TESTS_USE_UNICORN "Enable fuzzing tests against unicorn" OFF) CMAKE_DEPENDENT_OPTION(DYNARMIC_USE_LLVM "Support disassembly of jitted x86_64 code using LLVM" OFF "NOT YUZU_DISABLE_LLVM" OFF) -option(DYNARMIC_INSTALL "Install dynarmic headers and CMake files" OFF) -option(DYNARMIC_USE_BUNDLED_EXTERNALS "Use all bundled externals (useful when e.g. cross-compiling)" OFF) - # Set hard requirements for C++ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -88,7 +69,7 @@ if (MSVC) -Wno-missing-braces) endif() else() - set(DYNARMIC_CXX_FLAGS + list(APPEND DYNARMIC_CXX_FLAGS -Wall -Wextra -Wcast-qual @@ -103,37 +84,35 @@ else() # to Address& after first checking isMEM(), and that code is inlined in a situation where # GCC knows that the variable is actually a Reg64. isMEM() will never return true for a # Reg64, but GCC doesn't know that. - list(APPEND DYNARMIC_CXX_FLAGS -Wno-array-bounds) - list(APPEND DYNARMIC_CXX_FLAGS -Wstack-usage=4096) + list(APPEND DYNARMIC_CXX_FLAGS + -Wno-array-bounds + -Wstack-usage=4096) endif() if (CXX_CLANG) - # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6. - # And this in turns limits the size of a std::array. - list(APPEND DYNARMIC_CXX_FLAGS -fbracket-depth=1024) - # Clang mistakenly blames CMake for using unused arguments during compilation - list(APPEND DYNARMIC_CXX_FLAGS -Wno-unused-command-line-argument) + list(APPEND DYNARMIC_CXX_FLAGS + # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6. + # And this in turns limits the size of a std::array. + -fbracket-depth=1024 + # Clang mistakenly blames CMake for using unused arguments during compilation + -Wno-unused-command-line-argument) endif() endif() if (NOT Boost_FOUND) find_package(Boost 1.57 REQUIRED) endif() - find_package(fmt 8 CONFIG) -if ("arm64" IN_LIST ARCHITECTURE OR DYNARMIC_TESTS) +if (ARCHITECTURE_arm64) find_package(oaknut 2.0.1 CONFIG) endif() - -if ("riscv64" IN_LIST ARCHITECTURE) +if (ARCHITECTURE_riscv64) find_package(biscuit 0.9.1 REQUIRED) endif() - -if ("loongarch64" IN_LIST ARCHITECTURE) +if (ARCHITECTURE_loongarch64) find_package(lagoon REQUIRED) endif() - -if ("x86_64" IN_LIST ARCHITECTURE) +if (ARCHITECTURE_x86_64) find_package(xbyak 7 CONFIG) endif() @@ -142,44 +121,12 @@ if (DYNARMIC_USE_LLVM) separate_arguments(LLVM_DEFINITIONS) endif() +# Dynarmic project files +add_subdirectory(src/dynarmic) if (DYNARMIC_TESTS) find_package(Catch2 3 CONFIG) if (DYNARMIC_TESTS_USE_UNICORN) find_package(Unicorn REQUIRED) endif() -endif() - -# Dynarmic project files -add_subdirectory(src/dynarmic) -if (DYNARMIC_TESTS) add_subdirectory(tests) endif() - -# -# Install -# -if (DYNARMIC_INSTALL) - include(GNUInstallDirs) - include(CMakePackageConfigHelpers) - - install(TARGETS dynarmic EXPORT dynarmicTargets) - install(EXPORT dynarmicTargets - NAMESPACE dynarmic:: - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynarmic" - ) - - configure_package_config_file(CMakeModules/dynarmicConfig.cmake.in - dynarmicConfig.cmake - INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynarmic" - ) - write_basic_package_version_file(dynarmicConfigVersion.cmake - COMPATIBILITY SameMajorVersion - ) - install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/dynarmicConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/dynarmicConfigVersion.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynarmic" - ) - - install(DIRECTORY src/dynarmic TYPE INCLUDE FILES_MATCHING PATTERN "*.h") -endif() diff --git a/src/dynarmic/CMakeModules/TargetArchitectureSpecificSources.cmake b/src/dynarmic/CMakeModules/TargetArchitectureSpecificSources.cmake deleted file mode 100644 index 7af6cc518b..0000000000 --- a/src/dynarmic/CMakeModules/TargetArchitectureSpecificSources.cmake +++ /dev/null @@ -1,29 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -# SPDX-License-Identifier: GPL-3.0-or-later - -function(target_architecture_specific_sources project arch) - if (NOT MULTIARCH_BUILD) - target_sources("${project}" PRIVATE ${ARGN}) - return() - endif() - - foreach(input_file IN LISTS ARGN) - if(input_file MATCHES ".cpp$") - if(NOT IS_ABSOLUTE ${input_file}) - set(input_file "${CMAKE_CURRENT_SOURCE_DIR}/${input_file}") - endif() - - set(output_file "${CMAKE_CURRENT_BINARY_DIR}/arch_gen/${input_file}") - add_custom_command( - OUTPUT "${output_file}" - COMMAND ${CMAKE_COMMAND} "-Darch=${arch}" - "-Dinput_file=${input_file}" - "-Doutput_file=${output_file}" - -P "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/impl/TargetArchitectureSpecificSourcesWrapFile.cmake" - DEPENDS "${input_file}" - VERBATIM - ) - target_sources(${project} PRIVATE "${output_file}") - endif() - endforeach() -endfunction() diff --git a/src/dynarmic/CMakeModules/dynarmicConfig.cmake.in b/src/dynarmic/CMakeModules/dynarmicConfig.cmake.in deleted file mode 100644 index baa1db7c45..0000000000 --- a/src/dynarmic/CMakeModules/dynarmicConfig.cmake.in +++ /dev/null @@ -1,31 +0,0 @@ -@PACKAGE_INIT@ - -include(CMakeFindDependencyMacro) - -set(ARCHITECTURE "@ARCHITECTURE@") - -if (NOT @BUILD_SHARED_LIBS@) - find_dependency(Boost 1.57) - find_dependency(fmt 9) - find_dependency(mcl 0.1.12 EXACT) - - if ("arm64" IN_LIST ARCHITECTURE) - find_dependency(oaknut 2.0.1) - endif() - - if ("riscv" IN_LIST ARCHITECTURE) - find_dependency(biscuit 0.9.1) - endif() - - if ("x86_64" IN_LIST ARCHITECTURE) - find_dependency(xbyak 7) - endif() - - if (@DYNARMIC_USE_LLVM@) - find_dependency(LLVM) - endif() -endif() - -include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") - -check_required_components(@PROJECT_NAME@) diff --git a/src/dynarmic/CMakeModules/impl/TargetArchitectureSpecificSourcesWrapFile.cmake b/src/dynarmic/CMakeModules/impl/TargetArchitectureSpecificSourcesWrapFile.cmake deleted file mode 100644 index 82c6c3bae0..0000000000 --- a/src/dynarmic/CMakeModules/impl/TargetArchitectureSpecificSourcesWrapFile.cmake +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -# SPDX-License-Identifier: GPL-3.0-or-later - -string(TOUPPER "${arch}" arch) -file(READ "${input_file}" f_contents) -file(WRITE "${output_file}" "#if defined(ARCHITECTURE_${arch})\n${f_contents}\n#endif\n") diff --git a/src/dynarmic/src/dynarmic/CMakeLists.txt b/src/dynarmic/src/dynarmic/CMakeLists.txt index cc1cbcbe39..4e0aa0fa7e 100644 --- a/src/dynarmic/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/src/dynarmic/CMakeLists.txt @@ -1,7 +1,5 @@ # SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -include(TargetArchitectureSpecificSources) - add_library(dynarmic STATIC mcl/bit.hpp mcl/function_info.hpp @@ -135,7 +133,7 @@ add_library(dynarmic STATIC interface/A64/config.h ) -if ("x86_64" IN_LIST ARCHITECTURE) +if (ARCHITECTURE_x86_64) # Newer versions of xbyak (>= 7.25.0) have stricter checks that currently # fail in dynarmic target_compile_definitions(dynarmic PRIVATE XBYAK_STRICT_CHECK_MEM_REG_SIZE=0) @@ -143,7 +141,7 @@ if ("x86_64" IN_LIST ARCHITECTURE) target_compile_definitions(dynarmic PRIVATE XBYAK_OLD_DISP_CHECK=1) target_link_libraries(dynarmic PRIVATE xbyak::xbyak) - target_architecture_specific_sources(dynarmic "x86_64" + target_sources(dynarmic PRIVATE backend/x64/abi.cpp backend/x64/abi.h backend/x64/block_of_code.cpp @@ -201,10 +199,10 @@ if ("x86_64" IN_LIST ARCHITECTURE) ) endif() -if ("arm64" IN_LIST ARCHITECTURE) +if (ARCHITECTURE_arm64) target_link_libraries(dynarmic PRIVATE merry::oaknut) - target_architecture_specific_sources(dynarmic "arm64" + target_sources(dynarmic PRIVATE backend/arm64/a32_jitstate.cpp backend/arm64/a32_jitstate.h backend/arm64/a64_jitstate.h @@ -255,7 +253,7 @@ if ("arm64" IN_LIST ARCHITECTURE) ) endif() -if ("riscv64" IN_LIST ARCHITECTURE) +if (ARCHITECTURE_riscv64) target_link_libraries(dynarmic PRIVATE biscuit::biscuit) target_sources(dynarmic PRIVATE @@ -295,7 +293,7 @@ if ("riscv64" IN_LIST ARCHITECTURE) message(WARNING "TODO: Incomplete frontend for this host architecture") endif() -if ("loongarch64" IN_LIST ARCHITECTURE) +if (ARCHITECTURE_loongarch64) target_link_libraries(dynarmic PRIVATE lagoon::lagoon) target_sources(dynarmic PRIVATE @@ -400,15 +398,9 @@ if (DYNARMIC_USE_LLVM) target_compile_definitions(dynarmic PRIVATE DYNARMIC_USE_LLVM=1 ${LLVM_DEFINITIONS}) llvm_config(dynarmic USE_SHARED armdesc armdisassembler aarch64desc aarch64disassembler x86desc x86disassembler) endif() -if (DYNARMIC_ENABLE_CPU_FEATURE_DETECTION) - target_compile_definitions(dynarmic PRIVATE DYNARMIC_ENABLE_CPU_FEATURE_DETECTION=1) -endif() if (DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT) target_compile_definitions(dynarmic PRIVATE DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT=1) endif() -if (DYNARMIC_IGNORE_ASSERTS) - target_compile_definitions(dynarmic PRIVATE MCL_IGNORE_ASSERTS=1) -endif() if (CMAKE_SYSTEM_NAME STREQUAL "Windows") target_compile_definitions(dynarmic PRIVATE FMT_USE_WINDOWS_H=0) endif() diff --git a/src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp b/src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp index 0cf9bb9fae..f06274acc6 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp @@ -201,7 +201,7 @@ A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf) void A32AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const { ir_block.Reset(descriptor); - A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); + A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf); Optimization::Optimize(ir_block, conf, {}); } diff --git a/src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp b/src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp index 492242fa73..ff7f1b313f 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp @@ -366,8 +366,7 @@ A64AddressSpace::A64AddressSpace(const A64::UserConfig& conf) void A64AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const { ir_block.Reset(descriptor); - const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); }; - A64::Translate(ir_block, A64::LocationDescriptor{descriptor}, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct}); + A64::Translate(ir_block, A64::LocationDescriptor{descriptor}, conf); Optimization::Optimize(ir_block, conf, {}); } diff --git a/src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.cpp b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.cpp index f1a7d55d2c..b8ae04ed5d 100644 --- a/src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.cpp +++ b/src/dynarmic/src/dynarmic/backend/loongarch64/a32_address_space.cpp @@ -21,7 +21,7 @@ A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf) } void A32AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const { - A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); + A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf); Optimization::Optimize(ir_block, conf, {.sha256 = true}); } diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/a32_address_space.cpp b/src/dynarmic/src/dynarmic/backend/riscv64/a32_address_space.cpp index 490398931c..99aa45984d 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/a32_address_space.cpp +++ b/src/dynarmic/src/dynarmic/backend/riscv64/a32_address_space.cpp @@ -27,7 +27,7 @@ A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf) } void A32AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const { - A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); + A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf); Optimization::Optimize(ir_block, conf, {}); } diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64_a32.cpp b/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64_a32.cpp index 36709c7dbc..6504a006e6 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64_a32.cpp +++ b/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64_a32.cpp @@ -197,15 +197,15 @@ void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::CheckHa void EmitA32LeafTerminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::LeafTerminal terminal, IR::LocationDescriptor initial_location, bool is_single_step) { if (auto const x = std::get_if(&terminal)) - return EmitA32LeafTerminal(as, ctx, *x, initial_location, is_single_step); + return EmitA32Terminal(as, ctx, *x, initial_location, is_single_step); if (auto const x = std::get_if(&terminal)) - return EmitA32LeafTerminal(as, ctx, *x, initial_location, is_single_step); + return EmitA32Terminal(as, ctx, *x, initial_location, is_single_step); if (auto const x = std::get_if(&terminal)) - return EmitA32LeafTerminal(as, ctx, *x, initial_location, is_single_step); + return EmitA32Terminal(as, ctx, *x, initial_location, is_single_step); if (auto const x = std::get_if(&terminal)) - return EmitA32LeafTerminal(as, ctx, *x, initial_location, is_single_step); + return EmitA32Terminal(as, ctx, *x, initial_location, is_single_step); if (auto const x = std::get_if(&terminal)) - return EmitA32LeafTerminal(as, ctx, *x, initial_location, is_single_step); + return EmitA32Terminal(as, ctx, *x, initial_location, is_single_step); UNREACHABLE(); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp index 72627b9e1a..1faa882021 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp @@ -202,7 +202,7 @@ private: // LocationDescriptor ctor() does important ops (like tflags) do not skip auto const arch_descriptor = A32::LocationDescriptor{descriptor}; ir_block.Reset(arch_descriptor); - A32::Translate(ir_block, arch_descriptor, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions}); + A32::Translate(ir_block, arch_descriptor, conf); Optimization::Optimize(ir_block, conf, polyfill_options); return emitter.Emit(ir_block); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp index bb072129e7..163614df8a 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp @@ -254,11 +254,10 @@ private: block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE); // JIT Compile - const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); }; // LocationDescriptor ctor() does important ops (like tflags) do not skip auto const arch_descriptor = A64::LocationDescriptor{descriptor}; ir_block.Reset(arch_descriptor); - A64::Translate(ir_block, arch_descriptor, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct}); + A64::Translate(ir_block, arch_descriptor, conf); Optimization::Optimize(ir_block, conf, polyfill_options); return emitter.Emit(ir_block).entrypoint; } diff --git a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp index 384d6203a4..5158c0876b 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp @@ -78,7 +78,6 @@ void ProtectMemory(const void* base, size_t size, bool is_executable) { static const HostFeature features = []() { HostFeature f{}; -#ifdef DYNARMIC_ENABLE_CPU_FEATURE_DETECTION using Cpu = Xbyak::util::Cpu; Xbyak::util::Cpu cpu_info{}; if (cpu_info.has(Cpu::tSSSE3)) f |= HostFeature::SSSE3; @@ -121,7 +120,6 @@ static const HostFeature features = []() { } } return f; -#endif }(); HostFeature GetHostFeatures() { return features; diff --git a/src/dynarmic/src/dynarmic/backend/x64/constant_pool.cpp b/src/dynarmic/src/dynarmic/backend/x64/constant_pool.cpp index 8782ab0c73..77fbedc296 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/constant_pool.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/constant_pool.cpp @@ -7,34 +7,27 @@ */ #include - -#include "common/assert.h" - +#include #include "dynarmic/backend/x64/block_of_code.h" #include "dynarmic/backend/x64/constant_pool.h" namespace Dynarmic::Backend::X64 { -ConstantPool::ConstantPool(BlockOfCode& code, size_t size) - : insertion_point(0) -{ - code.EnsureMemoryCommitted(align_size + size); - code.int3(); +ConstantPool::ConstantPool(BlockOfCode& code, size_t size) noexcept { + auto const align_size = 64; //always align to cacheline + code.EnsureMemoryCommitted(2 * align_size + size); code.align(align_size); - pool = std::span(reinterpret_cast(code.AllocateFromCodeSpace(size)), size / align_size); + pool = std::span(static_cast(code.AllocateFromCodeSpace(size)), size / sizeof(u128)); } -Xbyak::Address ConstantPool::GetConstant(BlockOfCode& code, const Xbyak::AddressFrame& frame, u64 lower, u64 upper) { - const auto constant = ConstantT(lower, upper); - auto it = constant_info.find(constant); - if (it == constant_info.end()) { - ASSERT(insertion_point < pool.size()); - ConstantT& target_constant = pool[insertion_point]; - target_constant = constant; - it = constant_info.insert({constant, &target_constant}).first; - ++insertion_point; - } - return frame[code.rip + it->second]; +Xbyak::Address ConstantPool::GetConstant(BlockOfCode& code, const Xbyak::AddressFrame& frame, u64 lo, u64 hi) noexcept { + // offset grows iff new constant is added + auto const key = std::make_pair(lo, hi); + auto const val = u32(constant_info.size()); + auto const [it, _] = constant_info.insert({key, val}); + // if it != constant_info.end(): assume(pool[it->second] == c); + pool[it->second] = u128{lo, hi}; + return frame[code.rip + std::addressof(pool[it->second])]; } } // namespace Dynarmic::Backend::X64 diff --git a/src/dynarmic/src/dynarmic/backend/x64/constant_pool.h b/src/dynarmic/src/dynarmic/backend/x64/constant_pool.h index d3bad95d70..2d557766de 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/constant_pool.h +++ b/src/dynarmic/src/dynarmic/backend/x64/constant_pool.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "common/common_types.h" #include "common/container/unordered_map.h" @@ -21,31 +22,17 @@ namespace Dynarmic::Backend::X64 { class BlockOfCode; -/// ConstantPool allocates a block of memory from BlockOfCode. +/// @brief ConstantPool allocates a block of memory from BlockOfCode. /// It places constants into this block of memory, returning the address /// of the memory location where the constant is placed. If the constant /// already exists, its memory location is reused. class ConstantPool final { public: - ConstantPool(BlockOfCode& code, size_t size); - - Xbyak::Address GetConstant(BlockOfCode& code, const Xbyak::AddressFrame& frame, u64 lower, u64 upper = 0); - -private: - static constexpr size_t align_size = 16; // bytes - - using ConstantT = std::pair; - static_assert(sizeof(ConstantT) == align_size); - - struct ConstantHash { - std::size_t operator()(const ConstantT& constant) const noexcept { - return constant.first ^ std::rotl(constant.second, 1); - } - }; - - ::Common::unordered_map constant_info; - std::span pool; - std::size_t insertion_point; + ConstantPool(BlockOfCode& code, size_t size) noexcept; + Xbyak::Address GetConstant(BlockOfCode& code, const Xbyak::AddressFrame& frame, u64 lower, u64 upper = 0) noexcept; + // key = identity hash, value = offset from pool.data() + ::Common::unordered_map, u32, boost::hash>> constant_info; + std::span pool; }; } // namespace Dynarmic::Backend::X64 diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h index d072b9963d..102d451bde 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h @@ -275,6 +275,7 @@ const void* EmitReadMemoryMov(BlockOfCode& code, int value_idx, const Xbyak::Reg code.xadd(qword[addr], Xbyak::Reg64(value_idx)); break; case 128: + ASSERT(Xbyak::Xmm(value_idx) != xmm0); code.lock(); code.cmpxchg16b(xword[addr]); if (code.HasHostFeature(HostFeature::SSE41)) { diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp index 1165abb0e4..7a6796d543 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp @@ -6226,9 +6226,7 @@ void EmitX64::EmitVectorZeroExtend64(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorZeroUpper(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - code.movq(a, a); // TODO: !IsLastUse - ctx.reg_alloc.DefineValue(code, inst, a); } diff --git a/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp b/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp index f1898a92ef..47e1144e31 100644 --- a/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp +++ b/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp @@ -14,12 +14,6 @@ #include "dynarmic/backend/x64/hostloc.h" #include "dynarmic/common/spin_lock.h" -#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT -static const auto default_cg_mode = Xbyak::DontSetProtectRWE; -#else -static const auto default_cg_mode = nullptr; //Allow RWE -#endif - namespace Dynarmic { void EmitSpinLockLock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg32 tmp, bool waitpkg) { @@ -78,7 +72,13 @@ namespace { struct SpinLockImpl { void Initialize() noexcept; static void GlobalInitialize() noexcept; - Xbyak::CodeGenerator code = Xbyak::CodeGenerator(4096, default_cg_mode); + Xbyak::CodeGenerator code = Xbyak::CodeGenerator(4096 +#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT + , Xbyak::DontSetProtectRWE +#else + , nullptr //Allow RWE +#endif + ); void (*lock)(volatile int*) = nullptr; void (*unlock)(volatile int*) = nullptr; }; diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp index c3b90717a1..fa12472a2c 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp @@ -9,15 +9,16 @@ #include "dynarmic/frontend/A32/translate/a32_translate.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" +#include "dynarmic/interface/A32/config.h" #include "dynarmic/ir/basic_block.h" namespace Dynarmic::A32 { -void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options); -void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options); +void TranslateArm(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf); +void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf); -void Translate(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) { - return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(block, descriptor, tcb, options); +void Translate(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) { + return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(block, descriptor, conf); } bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction); diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.h b/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.h index d39e80a54f..173b216210 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.h @@ -10,6 +10,7 @@ #include "common/common_types.h" #include "dynarmic/interface/A32/arch_version.h" +#include "dynarmic/interface/A32/config.h" namespace Dynarmic::IR { class Block; @@ -20,28 +21,14 @@ namespace Dynarmic::A32 { class LocationDescriptor; struct TranslateCallbacks; -struct TranslationOptions { - ArchVersion arch_version; - - /// This changes what IR we emit when we translate an unpredictable instruction. - /// If this is false, the ExceptionRaised IR instruction is emitted. - /// If this is true, we define some behaviour for some instructions. - bool define_unpredictable_behaviour = false; - - /// This changes what IR we emit when we translate a hint instruction. - /// If this is false, we treat the instruction as a NOP. - /// If this is true, we emit an ExceptionRaised instruction. - bool hook_hint_instructions = true; -}; - /** * This function translates instructions in memory into our intermediate representation. * @param descriptor The starting location of the basic block. Includes information like PC, Thumb state, &c. * @param tcb The callbacks we should use to read emulated memory. - * @param options Configures how certain instructions are translated. + * @param conf Configures how certain instructions are translated. * @return A translated basic block in the intermediate representation. */ -void Translate(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options); +void Translate(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf); /** * This function translates a single provided instruction into our intermediate representation. diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_exception_generating.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_exception_generating.cpp index c9616b0871..33501cb0e0 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_exception_generating.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_exception_generating.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2016 MerryMage * SPDX-License-Identifier: 0BSD @@ -10,7 +13,7 @@ namespace Dynarmic::A32 { // BKPT # bool TranslatorVisitor::arm_BKPT(Cond cond, Imm<12> /*imm12*/, Imm<4> /*imm4*/) { - if (cond != Cond::AL && !options.define_unpredictable_behaviour) { + if (cond != Cond::AL && !conf.define_unpredictable_behaviour) { return UnpredictableInstruction(); } // UNPREDICTABLE: The instruction executes conditionally. diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h index dd88b79237..9ac7dd1f77 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h @@ -9,6 +9,7 @@ #pragma once #include "common/assert.h" +#include "dynarmic/interface/A32/config.h" #include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/a32_ir_emitter.h" @@ -25,12 +26,14 @@ enum class Exception; struct TranslatorVisitor final { using instruction_return_type = bool; - explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const TranslationOptions& options) - : ir(block, descriptor, options.arch_version), options(options) {} + explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) + : ir(block, descriptor, conf.arch_version) + , conf(conf) + {} A32::IREmitter ir; ConditionalState cond_state = ConditionalState::None; - TranslationOptions options; + A32::UserConfig const& conf; size_t current_instruction_size; diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/hint.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/hint.cpp index 0ec6aeff9a..65253fbb0f 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/hint.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/hint.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2019 MerryMage * SPDX-License-Identifier: 0BSD @@ -9,7 +12,7 @@ namespace Dynarmic::A32 { bool TranslatorVisitor::arm_PLD_imm(bool /*add*/, bool R, Reg /*n*/, Imm<12> /*imm12*/) { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } @@ -18,7 +21,7 @@ bool TranslatorVisitor::arm_PLD_imm(bool /*add*/, bool R, Reg /*n*/, Imm<12> /*i } bool TranslatorVisitor::arm_PLD_reg(bool /*add*/, bool R, Reg /*n*/, Imm<5> /*imm5*/, ShiftType /*shift*/, Reg /*m*/) { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } @@ -27,7 +30,7 @@ bool TranslatorVisitor::arm_PLD_reg(bool /*add*/, bool R, Reg /*n*/, Imm<5> /*im } bool TranslatorVisitor::arm_SEV() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } @@ -35,7 +38,7 @@ bool TranslatorVisitor::arm_SEV() { } bool TranslatorVisitor::arm_SEVL() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } @@ -43,7 +46,7 @@ bool TranslatorVisitor::arm_SEVL() { } bool TranslatorVisitor::arm_WFE() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } @@ -51,7 +54,7 @@ bool TranslatorVisitor::arm_WFE() { } bool TranslatorVisitor::arm_WFI() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } @@ -59,7 +62,7 @@ bool TranslatorVisitor::arm_WFI() { } bool TranslatorVisitor::arm_YIELD() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp index 082cd30db2..629cf26c62 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp @@ -642,7 +642,7 @@ bool TranslatorVisitor::thumb16_SUB_sp(Imm<7> imm7) { // SEV bool TranslatorVisitor::thumb16_SEV() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } return RaiseException(Exception::SendEvent); @@ -650,7 +650,7 @@ bool TranslatorVisitor::thumb16_SEV() { // SEVL bool TranslatorVisitor::thumb16_SEVL() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } return RaiseException(Exception::SendEventLocal); @@ -658,7 +658,7 @@ bool TranslatorVisitor::thumb16_SEVL() { // WFE bool TranslatorVisitor::thumb16_WFE() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } return RaiseException(Exception::WaitForEvent); @@ -666,7 +666,7 @@ bool TranslatorVisitor::thumb16_WFE() { // WFI bool TranslatorVisitor::thumb16_WFI() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } return RaiseException(Exception::WaitForInterrupt); @@ -674,7 +674,7 @@ bool TranslatorVisitor::thumb16_WFI() { // YIELD bool TranslatorVisitor::thumb16_YIELD() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } return RaiseException(Exception::Yield); diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_byte.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_byte.cpp index d309d42d66..f3f1f93b22 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_byte.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_byte.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2021 MerryMage * SPDX-License-Identifier: 0BSD @@ -8,7 +11,7 @@ namespace Dynarmic::A32 { static bool PLDHandler(TranslatorVisitor& v, bool W) { - if (!v.options.hook_hint_instructions) { + if (!v.conf.hook_hint_instructions) { return true; } @@ -18,7 +21,7 @@ static bool PLDHandler(TranslatorVisitor& v, bool W) { } static bool PLIHandler(TranslatorVisitor& v) { - if (!v.options.hook_hint_instructions) { + if (!v.conf.hook_hint_instructions) { return true; } diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp index 6c89a4af36..e6c4a8040e 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp @@ -22,10 +22,12 @@ namespace Dynarmic::A32 { -void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) { +void TranslateArm(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) { const bool single_step = descriptor.SingleStepping(); - TranslatorVisitor visitor{block, descriptor, options}; + TranslatorVisitor visitor{block, descriptor, conf}; bool should_continue = true; + + auto tcb = conf.callbacks; do { const u32 arm_pc = visitor.ir.current_location.PC(); u64 ticks_for_instruction = 1; diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp index 2a2fbea63f..f98f7ed9c1 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp @@ -103,10 +103,12 @@ inline bool MaybeVFPOrASIMDInstruction(u32 thumb_instruction) noexcept { } // namespace -void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) { +void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) { const bool single_step = descriptor.SingleStepping(); - TranslatorVisitor visitor{block, descriptor, options}; + TranslatorVisitor visitor{block, descriptor, conf}; bool should_continue = true; + + auto tcb = conf.callbacks; do { const u32 arm_pc = visitor.ir.current_location.PC(); u64 ticks_for_instruction = 1; diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp index 7840c63d79..eaada1d042 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp @@ -11,19 +11,20 @@ #include "dynarmic/frontend/A64/a64_location_descriptor.h" #include "dynarmic/frontend/A64/decoder/a64.h" #include "dynarmic/frontend/A64/translate/impl/impl.h" +#include "dynarmic/interface/A64/config.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/terminal.h" namespace Dynarmic::A64 { -void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options) { +void Translate(IR::Block& block, LocationDescriptor descriptor, A64::UserConfig const& conf) { const bool single_step = descriptor.SingleStepping(); - TranslatorVisitor visitor{block, descriptor, std::move(options)}; + TranslatorVisitor visitor{block, descriptor, conf}; bool should_continue = true; do { const u64 pc = visitor.ir.current_location->PC(); - if (const auto instruction = memory_read_code(pc)) { + if (const auto instruction = conf.callbacks->MemoryReadCode(pc)) { if (auto decoder = Decode(visitor, *instruction)) { should_continue = *decoder; } else { diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.h b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.h index 61033eb530..7a988c6cba 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.h +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.h @@ -11,6 +11,7 @@ #include #include "common/common_types.h" +#include "dynarmic/interface/A64/config.h" namespace Dynarmic { @@ -22,32 +23,14 @@ namespace A64 { class LocationDescriptor; -using MemoryReadCodeFuncType = std::function(u64 vaddr)>; - -struct TranslationOptions { - /// This changes what IR we emit when we translate an unpredictable instruction. - /// If this is false, the ExceptionRaised IR instruction is emitted. - /// If this is true, we define some behaviour for some instructions. - bool define_unpredictable_behaviour = false; - - /// This tells the translator a wall clock will be used, thus allowing it - /// to avoid writting certain unnecessary code only needed for cycle timers. - bool wall_clock_cntpct = false; - - /// This changes what IR we emit when we translate a hint instruction. - /// If this is false, we treat the instruction as a NOP. - /// If this is true, we emit an ExceptionRaised instruction. - bool hook_hint_instructions = true; -}; - /** * This function translates instructions in memory into our intermediate representation. * @param descriptor The starting location of the basic block. Includes information like PC, FPCR state, &c. * @param memory_read_code The function we should use to read emulated memory. - * @param options Configures how certain instructions are translated. + * @param conf Configures how certain instructions are translated. * @return A translated basic block in the intermediate representation. */ -void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options); +void Translate(IR::Block& block, LocationDescriptor descriptor, A64::UserConfig const& conf); /** * This function translates a single provided instruction into our intermediate representation. diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/impl.h b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/impl.h index c8afef3283..0916c7044c 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/impl.h +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/impl.h @@ -15,17 +15,20 @@ #include "dynarmic/frontend/A64/a64_types.h" #include "dynarmic/frontend/A64/translate/a64_translate.h" #include "dynarmic/frontend/imm.h" +#include "dynarmic/interface/A64/config.h" namespace Dynarmic::A64 { struct TranslatorVisitor final { using instruction_return_type = bool; - explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, TranslationOptions options) - : ir(block, descriptor), options(std::move(options)) {} + explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, A64::UserConfig const& conf) + : ir(block, descriptor) + , conf(conf) + {} A64::IREmitter ir; - TranslationOptions options; + A64::UserConfig const& conf; bool UnpredictableInstruction(); bool DecodeError(); diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/load_store_exclusive.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/load_store_exclusive.cpp index 0e67e11b4b..708366722a 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/load_store_exclusive.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/load_store_exclusive.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD @@ -25,7 +28,7 @@ static bool ExclusiveSharedDecodeAndOperation(TranslatorVisitor& v, bool pair, s if (memop == IR::MemOp::LOAD && pair && Rt == *Rt2) { return v.UnpredictableInstruction(); } else if (memop == IR::MemOp::STORE && (*Rs == Rt || (pair && *Rs == *Rt2))) { - if (!v.options.define_unpredictable_behaviour) { + if (!v.conf.define_unpredictable_behaviour) { return v.UnpredictableInstruction(); } // UNPREDICTABLE: The Constraint_NONE case is executed. diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/system.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/system.cpp index c60fdc3ae0..26769394cd 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/system.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/system.cpp @@ -42,35 +42,35 @@ bool TranslatorVisitor::NOP() { } bool TranslatorVisitor::YIELD() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } return RaiseException(Exception::Yield); } bool TranslatorVisitor::WFE() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } return RaiseException(Exception::WaitForEvent); } bool TranslatorVisitor::WFI() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } return RaiseException(Exception::WaitForInterrupt); } bool TranslatorVisitor::SEV() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } return RaiseException(Exception::SendEvent); } bool TranslatorVisitor::SEVL() { - if (!options.hook_hint_instructions) { + if (!conf.hook_hint_instructions) { return true; } return RaiseException(Exception::SendEventLocal); @@ -129,7 +129,7 @@ bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3 return true; case SystemRegisterEncoding::CNTPCT_EL0: // HACK: Ensure that this is the first instruction in the block it's emitted in, so the cycle count is most up-to-date. - if (!ir.block.instructions.empty() && !options.wall_clock_cntpct) { + if (!ir.block.instructions.empty() && !conf.wall_clock_cntpct) { ir.block.CycleCount()--; ir.SetTerm(IR::Term::LinkBlock{*ir.current_location}); return false; diff --git a/src/dynarmic/src/dynarmic/frontend/decoder/decoder_detail.h b/src/dynarmic/src/dynarmic/frontend/decoder/decoder_detail.h index e383fb0262..ff27ffb3c7 100644 --- a/src/dynarmic/src/dynarmic/frontend/decoder/decoder_detail.h +++ b/src/dynarmic/src/dynarmic/frontend/decoder/decoder_detail.h @@ -91,7 +91,7 @@ struct detail { shifts[arg_index] = bit_position; } } -#if !defined(DYNARMIC_IGNORE_ASSERTS) && !defined(__ANDROID__) +#if !defined(__ANDROID__) // Avoids a MSVC ICE, and avoids Android NDK issue. DEBUG_ASSERT(std::all_of(masks.begin(), masks.end(), [](auto m) { return m != 0; })); #endif diff --git a/src/dynarmic/tests/A32/fuzz_thumb.cpp b/src/dynarmic/tests/A32/fuzz_thumb.cpp index a29b877f3e..1f5457016b 100644 --- a/src/dynarmic/tests/A32/fuzz_thumb.cpp +++ b/src/dynarmic/tests/A32/fuzz_thumb.cpp @@ -180,7 +180,7 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32::UserConf while (num_insts < instructions_to_execute_count) { A32::LocationDescriptor descriptor = {u32(num_insts * 4), cpsr, A32::FPSCR{}}; ir_block.Reset(descriptor); - A32::Translate(ir_block, descriptor, &test_env, {}); + A32::Translate(ir_block, descriptor, config); Optimization::Optimize(ir_block, config, {}); printf("\n\nIR:\n%s", IR::DumpBlock(ir_block).c_str()); printf("\n\nx86_64:\n"); diff --git a/src/dynarmic/tests/A64/a64.cpp b/src/dynarmic/tests/A64/a64.cpp index 24ddfd4084..b5060e3ea5 100644 --- a/src/dynarmic/tests/A64/a64.cpp +++ b/src/dynarmic/tests/A64/a64.cpp @@ -2632,3 +2632,66 @@ TEST_CASE("A64: Rounding", "[a64]") { CHECK(jit.GetVector(5) == Vector{0x4000000040000000, 0x4000000040000000}); CHECK(jit.GetVector(6) == Vector{0x4000000040000000, 0x4000000040000000}); } + +TEST_CASE("A64: SM4", "[a64]") { + A64TestEnv env; + A64::UserConfig jit_user_config{}; + jit_user_config.callbacks = &env; + A64::Jit jit{jit_user_config}; + + oaknut::VectorCodeGenerator code{env.code_mem, nullptr}; + + code.SM4EKEY(V4.S4(), V0.S4(), V1.S4()); + code.SM4E(V5.S4(), V0.S4(), V1.S4()); + + jit.SetPC(0); + jit.SetVector(0, {0xefcdab8967452301, 0x1032547698badcfe}); + jit.SetVector(1, {0xefcdab8967452301, 0x1032547698badcfe}); + env.ticks_left = env.code_mem.size(); + CheckedRun([&]() { jit.Run(); }); + + CHECK(jit.GetVector(4) == Vector{0x486a0c2e00224466, 0x5c7e183a62402604}); + CHECK(jit.GetVector(5) == Vector{0xc2e086a43c1e785a, 0xd7f593b104264062}); +} + +TEST_CASE("A64: SM3", "[a64]") { + A64TestEnv env; + A64::UserConfig jit_user_config{}; + jit_user_config.callbacks = &env; + SECTION("SM3SS1") { + A64::Jit jit{jit_user_config}; + oaknut::VectorCodeGenerator code{env.code_mem, nullptr}; + code.SM3SS1(V0.S4(), V0.S4(), V1.S4(), V2.S4()); + jit.SetPC(0); + jit.SetVector(0, {0xec4aff517369c667, 0x46e3fbf2abbacd29}); + jit.SetVector(1, {0x8de7e81bf854c27c, 0x9ac99f33632e5a76}); + jit.SetVector(2, {0x5aa35831b70d3266, 0xd45ee95817055d25}); + env.ticks_left = env.code_mem.size(); + CheckedRun([&]() { jit.Run(); }); + CHECK(jit.GetVector(0) == Vector{0x0000000000000000, 0x73d67cd700000000}); + } + SECTION("SM3PARTW1") { + A64::Jit jit{jit_user_config}; + oaknut::VectorCodeGenerator code{env.code_mem, nullptr}; + code.SM3PARTW1(V0.S4(), V0.S4(), V1.S4(), V2.S4()); + jit.SetPC(0); + jit.SetVector(0, {0xec4aff517369c667, 0x46e3fbf2abbacd29}); + jit.SetVector(1, {0x8de7e81bf854c27c, 0x9ac99f33632e5a76}); + jit.SetVector(2, {0x5aa35831b70d3266, 0xd45ee95817055d25}); + env.ticks_left = env.code_mem.size(); + CheckedRun([&]() { jit.Run(); }); + CHECK(jit.GetVector(0) == Vector{0x653c64995693280c, 0xabcc7db97adebf12}); + } + SECTION("SM3PARTW2") { + A64::Jit jit{jit_user_config}; + oaknut::VectorCodeGenerator code{env.code_mem, nullptr}; + code.SM3PARTW2(V0.S4(), V0.S4(), V1.S4(), V2.S4()); + jit.SetPC(0); + jit.SetVector(0, {0xec4aff517369c667, 0x46e3fbf2abbacd29}); + jit.SetVector(1, {0x8de7e81bf854c27c, 0x9ac99f33632e5a76}); + jit.SetVector(2, {0x5aa35831b70d3266, 0xd45ee95817055d25}); + env.ticks_left = env.code_mem.size(); + CheckedRun([&]() { jit.Run(); }); + CHECK(jit.GetVector(0) == Vector{0x30010fe70da43740, 0x6702425b4a3a05d4}); + } +} diff --git a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp index ea5b5302f8..1e1e37d888 100644 --- a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp +++ b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp @@ -268,7 +268,7 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv // const auto get_code = [&jit_env](u64 vaddr) { return jit_env.MemoryReadCode(vaddr); }; // const A64::LocationDescriptor location{instructions_start, FP::FPCR{fpcr}}; // IR::Block ir_block{location}; - // A64::Translate(ir_block, location, get_code, {}); + // A64::Translate(ir_block, location, config); // fmt::print("IR:\n{}\n", IR::DumpBlock(ir_block)); // Optimization::Optimize(ir_block, conf, {}); // fmt::print("Optimized IR:\n{}\n", IR::DumpBlock(ir_block)); diff --git a/src/dynarmic/tests/CMakeLists.txt b/src/dynarmic/tests/CMakeLists.txt index 15a77e4b5c..a18dbe7507 100644 --- a/src/dynarmic/tests/CMakeLists.txt +++ b/src/dynarmic/tests/CMakeLists.txt @@ -1,7 +1,5 @@ # SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -include(TargetArchitectureSpecificSources) - add_executable(dynarmic_tests fp/FPToFixed.cpp fp/FPValue.cpp @@ -44,13 +42,13 @@ if (DYNARMIC_TESTS_USE_UNICORN) ) endif() -if ("riscv" IN_LIST ARCHITECTURE) +if (ARCHITECTURE_riscv64) target_link_libraries(dynarmic_tests PRIVATE biscuit::biscuit) endif() -if ("x86_64" IN_LIST ARCHITECTURE) +if (ARCHITECTURE_x86_64) target_link_libraries(dynarmic_tests PRIVATE xbyak::xbyak) - target_architecture_specific_sources(dynarmic_tests "x86_64" + target_sources(dynarmic_tests PRIVATE x64_cpu_info.cpp native/preserve_xmm.cpp ) diff --git a/src/frontend_common/content_manager.h b/src/frontend_common/content_manager.h index 4f3112e3fb..6d79098efa 100644 --- a/src/frontend_common/content_manager.h +++ b/src/frontend_common/content_manager.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2024 yuzu Emulator Project @@ -163,7 +163,9 @@ inline InstallResult InstallNSP(Core::System& system, FileSys::VfsFilesystem& vf std::shared_ptr nsp; FileSys::VirtualFile file = vfs.OpenFile(filename, FileSys::OpenMode::Read); - if (boost::to_lower_copy(file->GetName()).ends_with("nsp")) { + const auto lower_name = boost::to_lower_copy(file->GetName()); + + if (lower_name.ends_with("nsp") || lower_name.ends_with("nsz")) { nsp = std::make_shared(file); if (nsp->IsExtractedType()) { return InstallResult::Failure; diff --git a/src/hid_core/hid_core.cpp b/src/hid_core/hid_core.cpp index cbc193b741..fcf87d6d63 100644 --- a/src/hid_core/hid_core.cpp +++ b/src/hid_core/hid_core.cpp @@ -130,6 +130,14 @@ NpadStyleTag HIDCore::GetSupportedStyleTag() const { return supported_style_tag; } +void HIDCore::SetJoyHoldHorizontal(bool horizontal) { + joy_hold_horizontal = horizontal; +} + +bool HIDCore::IsJoyHoldHorizontal() const { + return joy_hold_horizontal; +} + s8 HIDCore::GetPlayerCount() const { s8 active_players = 0; for (std::size_t player_index = 0; player_index < available_controllers - 2; ++player_index) { @@ -196,6 +204,7 @@ void HIDCore::DisableAllControllerConfiguration() { } void HIDCore::ReloadInputDevices() { + std::scoped_lock lock{reload_mutex}; player_1->ReloadFromSettings(); player_2->ReloadFromSettings(); player_3->ReloadFromSettings(); diff --git a/src/hid_core/hid_core.h b/src/hid_core/hid_core.h index 7da11897ca..1cd3427724 100644 --- a/src/hid_core/hid_core.h +++ b/src/hid_core/hid_core.h @@ -6,7 +6,9 @@ #pragma once +#include #include +#include #include "common/common_funcs.h" #include "hid_core/hid_types.h" @@ -46,6 +48,10 @@ public: void SetSupportedStyleTag(NpadStyleTag style_tag); NpadStyleTag GetSupportedStyleTag() const; + /// How the running game holds a single Joy-Con: sideways (horizontal) or upright (the default) + void SetJoyHoldHorizontal(bool horizontal); + bool IsJoyHoldHorizontal() const; + /// Counts the connected players from P1-P8 s8 GetPlayerCount() const; @@ -76,6 +82,9 @@ public: /// Number of emulated controllers static constexpr std::size_t available_controllers{10}; + /// Reloads come from the HID service (starting a game) and the frontend (settings, the + /// console modes): one at a time, or two threads rebuild the same controllers + std::mutex reload_mutex; std::unique_ptr player_1; std::unique_ptr player_2; std::unique_ptr player_3; @@ -90,6 +99,7 @@ public: std::unique_ptr devices; Kernel::KernelCore& kernel; NpadStyleTag supported_style_tag{NpadStyleSet::All}; + std::atomic joy_hold_horizontal{false}; NpadIdType last_active_controller{NpadIdType::Handheld}; }; diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp index 2b04e2c670..485f4a8f80 100644 --- a/src/hid_core/resources/npad/npad.cpp +++ b/src/hid_core/resources/npad/npad.cpp @@ -45,6 +45,8 @@ NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service AbstractPad{hid_core_.kernel}, }} { + // (A new game holds its Joy-Cons upright until it says otherwise) + hid_core.SetJoyHoldHorizontal(false); for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) { for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) { auto& controller = controller_data[aruid_index][i]; @@ -149,6 +151,18 @@ void NPad::ControllerUpdate(Kernel::KernelCore& kernel, Core::HID::ControllerTri ControllerUpdate(kernel, Core::HID::ControllerTriggerType::Battery, controller_idx); return; } + // Only connection and battery changes concern the npad here. Motion arrives hundreds of + // times a second from its own thread (a DSU server's socket), and the callbacks are live + // from the constructor on, before SetNpadExternals provides the applet resource: an update + // in that window during boot dereferenced a null applet resource (SIGSEGV). + if (type != Core::HID::ControllerTriggerType::Connected && + type != Core::HID::ControllerTriggerType::Disconnected && + type != Core::HID::ControllerTriggerType::Battery) { + return; + } + if (!applet_resource_holder.applet_resource) { + return; + } for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { if (controller_idx >= controller_data[aruid_index].size()) { @@ -703,7 +717,11 @@ Result NPad::SetSupportedNpadIdType(Kernel::KernelCore& kernel, u64 aruid, std:: Result NPad::SetNpadJoyHoldType(u64 aruid, NpadJoyHoldType hold_type) { std::scoped_lock lock{mutex}; - return npad_resource.SetNpadJoyHoldType(aruid, hold_type); + const Result result = npad_resource.SetNpadJoyHoldType(aruid, hold_type); + if (result.IsSuccess()) { + hid_core.SetJoyHoldHorizontal(hold_type == NpadJoyHoldType::Horizontal); + } + return result; } Result NPad::GetNpadJoyHoldType(u64 aruid, NpadJoyHoldType& out_hold_type) const { diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index c3e9a066b3..588d7fa8cd 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -3,8 +3,19 @@ // SPDX-FileCopyrightText: 2018 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include "common/controller_console_state.h" #include "common/logging.h" #include "common/math_util.h" #include "common/param_package.h" @@ -450,6 +461,29 @@ std::shared_ptr SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl return *vec_it; } +std::optional> SDLDriver::GetBindingForSDLID(SDL_JoystickID sdl_id) { + const auto joystick = GetSDLJoystickBySDLID(sdl_id); + if (!joystick) { + return std::nullopt; + } + return std::pair{joystick->GetGUID().RawString(), joystick->GetPort()}; +} + +void SDLDriver::MarkActivity(SDL_JoystickID sdl_id) { + std::scoped_lock lock{activity_mutex}; + last_activity[sdl_id] = std::chrono::steady_clock::now(); +} + +std::optional SDLDriver::GetLastActivity( + SDL_JoystickID sdl_id) const { + std::scoped_lock lock{activity_mutex}; + const auto it = last_activity.find(sdl_id); + if (it == last_activity.end()) { + return std::nullopt; + } + return it->second; +} + std::shared_ptr SDLDriver::GetSDLJoystickByGamepadID(SDL_JoystickID sdl_id) { auto* const sdl_gamepad = SDL_GetGamepadFromID(sdl_id); if (sdl_gamepad == nullptr) { @@ -535,6 +569,11 @@ void SDLDriver::InitJoystick(SDL_JoystickID joystick_id) { [](const auto& joystick) { return !joystick->GetSDLJoystick(); }); if (joystick_it != joystick_guid_list.end()) { + const int port = static_cast(joystick_it - joystick_guid_list.begin()); + if (Common::ControllerProbes()) { + LOG_INFO(Input, "input: attach guid={} port={} name={} (reusing a freed slot)", + guid.RawString(), port, SDL_GetJoystickName(sdl_joystick)); + } (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller); (*joystick_it)->EnableMotion(); SetBattery((*joystick_it)->GetPadIdentifier(), @@ -563,6 +602,10 @@ void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) { }); if (joystick_it != joystick_guid_list.end()) { + if (Common::ControllerProbes()) { + LOG_INFO(Input, "input: detach guid={} port={}", guid.RawString(), + static_cast(joystick_it - joystick_guid_list.begin())); + } (*joystick_it)->SetSDLJoystick(nullptr, nullptr); } } @@ -583,6 +626,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { break; } case SDL_EVENT_JOYSTICK_BUTTON_DOWN: { + MarkActivity(event.jbutton.which); if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { const PadIdentifier identifier = joystick->GetPadIdentifier(); SetButton(identifier, event.jbutton.button, true); @@ -590,6 +634,9 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { break; } case SDL_EVENT_JOYSTICK_HAT_MOTION: { + if (event.jhat.value != SDL_HAT_CENTERED) { + MarkActivity(event.jhat.which); + } if (const auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) { const PadIdentifier identifier = joystick->GetPadIdentifier(); SetHatButton(identifier, event.jhat.hat, event.jhat.value); @@ -597,8 +644,20 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { break; } case SDL_EVENT_JOYSTICK_AXIS_MOTION: { - if (const auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) { - const PadIdentifier identifier = joystick->GetPadIdentifier(); + // Half travel, so resting drift never counts. A trigger rests at one end of its range + // (-32768 here), so for it half travel is past the middle. + Sint16 rest = 0; + const auto moved = GetSDLJoystickBySDLID(event.jaxis.which); + SDL_Joystick* const moved_js = moved ? moved->GetSDLJoystick() : nullptr; + const bool trigger = + moved_js && SDL_GetJoystickAxisInitialState(moved_js, event.jaxis.axis, &rest) && + rest < -16384; + if (trigger ? event.jaxis.value > 0 + : event.jaxis.value > 16384 || event.jaxis.value < -16384) { + MarkActivity(event.jaxis.which); + } + if (moved) { + const PadIdentifier identifier = moved->GetPadIdentifier(); SetAxis(identifier, event.jaxis.axis, event.jaxis.value / 32767.0f); } break; @@ -640,6 +699,152 @@ void SDLDriver::CloseJoysticks() { joystick_map.clear(); } +namespace { + +/// Controllers with motion sensors that Steam Input hides behind its sensorless virtual pads +bool IsMotionController(unsigned vendor, unsigned product) { + switch (vendor) { + case 0x28DE: + // The Steam Deck only: SDL's driver would talk to a Steam Controller alongside Steam + // (Bypass Steam Input gives SDL Steam Controllers, motion included) + return product == 0x1205; + case 0x054C: // Sony + case 0x057E: // Nintendo + return true; + default: + return false; + } +} + +/// Controllers Steam Input hid that Eden opened again for their motion (vendor << 16 | product). +/// Motion sources only: never offered as input devices. +std::set& UnhiddenControllers() { + static std::set unhidden; + return unhidden; +} + +/// Logs the system's motion sensors and HID devices once (Debug Probes), to identify handhelds +/// from users' logs: a built-in gyro is often a system sensor (IIO) that SDL never sees. +void LogMotionHardware() { +#ifdef __linux__ + if (!Common::ControllerProbes()) { + return; + } + namespace fs = std::filesystem; + const auto read_line = [](const fs::path& path) { + std::ifstream file{path}; + std::string line; + std::getline(file, line); + return line; + }; + std::error_code error; + std::string sensors; + // (No exceptions: a device can disappear while it is read) + for (fs::directory_iterator it{"/sys/bus/iio/devices", error}, end; !error && it != end; + it.increment(error)) { + const fs::path dir = it->path(); + std::error_code ignored; + const bool gyro = fs::exists(dir / "in_anglvel_x_raw", ignored); + const bool accel = fs::exists(dir / "in_accel_x_raw", ignored); + if (!gyro && !accel) { + continue; + } + std::string mount = read_line(dir / "in_anglvel_mount_matrix"); + if (mount.empty()) { + mount = read_line(dir / "in_accel_mount_matrix"); + } + const fs::path device = fs::canonical(dir / "device", ignored); + sensors += fmt::format("\n {} name={} gyro={} accel={} mount=[{}] at={}", + dir.filename().string(), read_line(dir / "name"), gyro, accel, mount, + ignored ? std::string{"?"} : device.string()); + } + LOG_INFO(Input, "Motion sensors of the system (IIO):{}", + sensors.empty() ? std::string{" none"} : sensors); + + std::string hid; + error.clear(); + for (fs::directory_iterator it{"/sys/class/hidraw", error}, end; !error && it != end; + it.increment(error)) { + const auto& entry = *it; + std::ifstream uevent{entry.path() / "device" / "uevent"}; + std::string line; + std::string id; + std::string name; + while (std::getline(uevent, line)) { + if (line.starts_with("HID_ID=")) { + // bus:vendor:product, each zero-padded to 8 hex digits + unsigned bus = 0, vendor = 0, product = 0; + if (std::sscanf(line.c_str() + 7, "%x:%x:%x", &bus, &vendor, &product) == 3) { + id = fmt::format("{:04x}:{:04x} bus={}", vendor, product, bus); + } + } else if (line.starts_with("HID_NAME=")) { + name = line.substr(9); + } + } + hid += fmt::format("\n {} {} name={}", entry.path().filename().string(), id, name); + } + LOG_INFO(Input, "HID devices:{}", hid.empty() ? std::string{" none"} : hid); +#endif +} + +/// A controller Eden opened again under Steam Input for its motion alone +bool IsUnhiddenController(SDL_Joystick* joystick) { + const u32 id = + static_cast(SDL_GetJoystickVendor(joystick)) << 16 | SDL_GetJoystickProduct(joystick); + return UnhiddenControllers().contains(id); +} + +/// Under Steam, takes the motion controllers off Steam's hide list, so SDL also opens the real +/// devices next to Steam's sensorless virtual pads +void UnhideMotionControllers() { + if (!Common::RunningUnderSteam()) { + return; + } + const char* env = std::getenv("SDL_GAMECONTROLLER_IGNORE_DEVICES"); + std::string list = env ? env : ""; + if (list.starts_with('@')) { + std::ifstream file{list.substr(1)}; + list.assign(std::istreambuf_iterator{file}, std::istreambuf_iterator{}); + } + std::string kept; + std::string dropped; + std::stringstream entries{list}; + for (std::string entry; std::getline(entries, entry, ',');) { + entry.erase(std::remove_if(entry.begin(), entry.end(), + [](unsigned char c) { return std::isspace(c); }), + entry.end()); + unsigned vendor = 0; + unsigned product = 0; + if (entry.empty()) { + continue; + } + if (std::sscanf(entry.c_str(), "%x/%x", &vendor, &product) == 2 && + IsMotionController(vendor, product)) { + dropped += entry + ','; + UnhiddenControllers().insert(vendor << 16 | product); + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.steam_hidden_models.insert(vendor << 16 | product); + } + continue; + } + kept += entry + ','; + } + if (!kept.empty()) { + kept.pop_back(); + } + if (Common::ControllerProbes()) { + LOG_INFO(Input, "Steam Input: opening motion controllers for their sensors: {}", + dropped.empty() ? std::string{"none hidden"} : dropped); + } + SDL_SetHintWithPriority(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES, kept.c_str(), + SDL_HINT_OVERRIDE); + SDL_SetHintWithPriority(SDL_HINT_JOYSTICK_HIDAPI_STEAMDECK, "1", SDL_HINT_OVERRIDE); +} + +} // Anonymous namespace + SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { // Set our application name. Currently passed to DBus by SDL and visible to the user through // their desktop environment. @@ -657,6 +862,24 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en // SDL3 defaults Steam Controller Bluetooth HIDAPI support to off, which can disable gyro. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STEAM, "1"); + // Bypass Steam Input (Modern Console, under Steam): SDL takes every controller Steam hides, + // and the engine uses those instead of Steam's virtual pads + const auto mode = Settings::values.controller_applet_mode.GetValue(); + const bool automatic = mode == Settings::AppletMode::ConsoleMode || + mode == Settings::AppletMode::HandheldConsoleMode; + if (Common::RunningUnderSteam() && automatic && + Settings::values.console_bypass_steam.GetValue()) { + SDL_SetHintWithPriority(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES, "", SDL_HINT_OVERRIDE); + SDL_SetHintWithPriority(SDL_HINT_JOYSTICK_HIDAPI_STEAMDECK, "1", SDL_HINT_OVERRIDE); + Common::GetControllerConsoleState().steam_bypassed = true; + if (Common::ControllerProbes()) { + LOG_INFO(Input, "Steam Input bypassed: SDL opens every controller"); + } + } else if (automatic) { + // (Only the automatic modes read their motion) + UnhideMotionControllers(); + } + LogMotionHardware(); SDL_SetHint(SDL_HINT_GAMECONTROLLER_SENSOR_FUSION, "1"); SDL_SetHint(SDL_HINT_AUTO_UPDATE_SENSORS, "1"); @@ -727,8 +950,17 @@ std::vector SDLDriver::GetInputDevices() const { if (!joystick->GetSDLJoystick()) { continue; } + // Steam's virtual pads carry the real controller's name: mark them. Their GUID + // keeps Steam's ids (Valve 0x28DE, virtual gamepad 0x11FF, at bytes 4 and 8). + const SDL_GUID sdl_guid = SDL_GetJoystickGUID(joystick->GetSDLJoystick()); + const bool steam_virtual = sdl_guid.data[4] == 0xDE && sdl_guid.data[5] == 0x28 && + sdl_guid.data[8] == 0xFF && sdl_guid.data[9] == 0x11; + if (!steam_virtual && IsUnhiddenController(joystick->GetSDLJoystick())) { + continue; + } const std::string name = - fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort()); + fmt::format("{} {}{}", joystick->GetControllerName(), joystick->GetPort(), + steam_virtual ? " (Steam)" : ""); devices.emplace_back(Common::ParamPackage{ {"engine", GetEngineName()}, {"display", std::move(name)}, @@ -744,7 +976,8 @@ std::vector SDLDriver::GetInputDevices() const { // Add dual controllers for (const auto& [key, value] : joystick_map) { for (const auto& joystick : value) { - if (joystick->IsJoyconRight()) { + if (joystick->IsJoyconRight() && joystick->GetSDLJoystick() && + !IsUnhiddenController(joystick->GetSDLJoystick())) { if (!joycon_pairs.contains(joystick->GetPort())) { continue; } diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index e6751b6688..d97811f9fc 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -7,8 +7,12 @@ #pragma once #include +#include #include +#include +#include #include +#include #include "common/container/unordered_map.h" #include @@ -45,6 +49,15 @@ public: std::shared_ptr GetSDLJoystickBySDLID(SDL_JoystickID sdl_id); std::shared_ptr GetSDLJoystickByGamepadID(SDL_JoystickID sdl_id); + /// The guid and port that bindings use to address this SDL instance, if the driver has it + /// open. Must not be called while holding SDL_LockJoysticks (the driver locks its map). + std::optional> GetBindingForSDLID(SDL_JoystickID sdl_id); + + /// When this SDL instance last had a deliberate input: a button or d-pad press, or a + /// stick or trigger past half travel (not drift, not motion) + std::optional GetLastActivity( + SDL_JoystickID sdl_id) const; + /** * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so * tie it to a SDLJoystick with the same guid and that port @@ -117,6 +130,10 @@ private: ::Common::unordered_map>> joystick_map; std::mutex joystick_map_mutex; + void MarkActivity(SDL_JoystickID sdl_id); + std::unordered_map last_activity; + mutable std::mutex activity_mutex; + std::atomic initialized = false; bool start_thread; }; diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 576fd0244c..6c5ad4e2c1 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -25,10 +25,25 @@ public: using Button = std::unique_ptr; Stick(Button up_, Button down_, Button left_, Button right_, Button modifier_, Button updater_, - float modifier_scale_, float modifier_angle_) + Button stick_, float modifier_scale_, float modifier_angle_) : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), right(std::move(right_)), modifier(std::move(modifier_)), updater(std::move(updater_)), - modifier_scale(modifier_scale_), modifier_angle(modifier_angle_) { + stick(std::move(stick_)), modifier_scale(modifier_scale_), + modifier_angle(modifier_angle_) { + // A real stick alongside the buttons: it moves the stick while no button is held + stick_status.x.properties = properties; + stick_status.y.properties = properties; + if (stick) { + stick->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback_) { + stick_status = callback_.stick_status; + if (amplitude == 0) { + SoftUpdate(); + } + }, + }); + } up->SetCallback({ .on_change = [this](const Common::Input::CallbackStatus& callback_) { @@ -220,6 +235,9 @@ public: left->ForceUpdate(); right->ForceUpdate(); modifier->ForceUpdate(); + if (stick) { + stick->ForceUpdate(); + } } void SoftUpdate() { @@ -237,6 +255,9 @@ public: } Common::Input::StickStatus GetStatus() const { + if (stick && amplitude == 0) { + return stick_status; + } Common::Input::StickStatus status{}; status.x.properties = properties; status.y.properties = properties; @@ -270,6 +291,8 @@ private: Button right; Button modifier; Button updater; + Button stick; + Common::Input::StickStatus stick_status{}; float modifier_scale{}; float modifier_angle{}; float angle{}; @@ -296,9 +319,13 @@ std::unique_ptr StickFromButton::Create( auto updater = Common::Input::CreateInputDeviceFromString("engine:updater,button:0"); auto modifier_scale = params.Get("modifier_scale", 0.5f); auto modifier_angle = params.Get("modifier_angle", 5.5f); + // (Optional: a real stick the buttons move alongside) + Stick::Button stick = params.Has("stick") + ? Common::Input::CreateInputDeviceFromString(params.Get("stick", "")) + : nullptr; return std::make_unique(std::move(up), std::move(down), std::move(left), std::move(right), std::move(modifier), std::move(updater), - modifier_scale, modifier_angle); + std::move(stick), modifier_scale, modifier_angle); } } // namespace InputCommon diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 188e862d7f..bbabbb9d70 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -1,3 +1,5 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -557,9 +559,9 @@ private: class InputFromMotion final : public Common::Input::InputDevice { public: explicit InputFromMotion(PadIdentifier identifier_, int motion_sensor_, float gyro_threshold_, - InputEngine* input_engine_) + int turn_, InputEngine* input_engine_) : identifier(identifier_), motion_sensor(motion_sensor_), gyro_threshold(gyro_threshold_), - input_engine(input_engine_) { + turn(turn_), input_engine(input_engine_) { UpdateCallback engine_callback{[this]() { OnChange(); }}; const InputIdentifier input_identifier{ .identifier = identifier, @@ -589,6 +591,17 @@ public: status.gyro.x = {.raw_value = basic_motion.gyro_x, .properties = properties}; status.gyro.y = {.raw_value = basic_motion.gyro_y, .properties = properties}; status.gyro.z = {.raw_value = basic_motion.gyro_z, .properties = properties}; + // Turned a quarter about the face for a controller standing in for a sideways Joy-Con + // (1: clockwise, as a right one; -1: the other way): the Joy-Con's x is the + // controller's -y, its y the controller's x (the left one: y, and -x) + if (turn != 0) { + for (auto* axes : {&status.accel, &status.gyro}) { + const float x = axes->x.raw_value; + const float y = axes->y.raw_value; + axes->x.raw_value = turn > 0 ? -y : y; + axes->y.raw_value = turn > 0 ? x : -x; + } + } status.delta_timestamp = basic_motion.delta_timestamp; return status; } @@ -606,6 +619,7 @@ private: const PadIdentifier identifier; const int motion_sensor; const float gyro_threshold; + const int turn; int callback_key; InputEngine* input_engine; }; @@ -1069,9 +1083,10 @@ std::unique_ptr InputFactory::CreateMotionDevice( if (params.Has("motion")) { const auto motion_sensor = params.Get("motion", 0); const auto gyro_threshold = params.Get("threshold", 0.007f); + const auto turn = std::clamp(params.Get("turn", 0), -1, 1); input_engine->PreSetController(identifier); input_engine->PreSetMotion(identifier, motion_sensor); - return std::make_unique(identifier, motion_sensor, gyro_threshold, + return std::make_unique(identifier, motion_sensor, gyro_threshold, turn, input_engine.get()); } diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 6c8443ff62..765d44fdd7 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -442,6 +442,23 @@ std::vector InputSubsystem::GetInputDevices() const { return impl->GetInputDevices(); } +std::optional> InputSubsystem::GetSDLBinding(u32 sdl_instance) const { +#ifdef HAVE_SDL3 + return impl->sdl->GetBindingForSDLID(static_cast(sdl_instance)); +#else + return std::nullopt; +#endif +} + +std::optional InputSubsystem::GetSDLLastActivity( + u32 sdl_instance) const { +#ifdef HAVE_SDL3 + return impl->sdl->GetLastActivity(static_cast(sdl_instance)); +#else + return std::nullopt; +#endif +} + AnalogMapping InputSubsystem::GetAnalogMappingForDevice(const Common::ParamPackage& device) const { return impl->GetAnalogMappingForDevice(device); } diff --git a/src/input_common/main.h b/src/input_common/main.h index 3b33ef30eb..cf9bffb414 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -6,10 +6,14 @@ #pragma once +#include #include +#include #include -#include "common/container/unordered_map.h" +#include #include +#include "common/common_types.h" +#include "common/container/unordered_map.h" namespace Common { class ParamPackage; @@ -152,6 +156,13 @@ public: /// Returns true if axis of a stick aren't mapped in the correct direction [[nodiscard]] bool IsStickInverted(const Common::ParamPackage& device) const; + /// The SDL guid and port that bindings use for an SDL joystick instance, if SDL has it open. + [[nodiscard]] std::optional> GetSDLBinding(u32 sdl_instance) const; + + /// When an SDL joystick last had a deliberate input (a stick or trigger past half travel) + [[nodiscard]] std::optional GetSDLLastActivity( + u32 sdl_instance) const; + /// Reloads the input devices. void ReloadInputDevices(); diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 8858b819d6..ea8b745567 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -42,10 +42,6 @@ add_library(qt_common STATIC render/context.h render/emu_thread.h render/emu_thread.cpp) -if (UNIX) - target_sources(qt_common PRIVATE gui_settings.cpp gui_settings.h) -endif() - create_target_directory_groups(qt_common) if (USE_DISCORD_PRESENCE) diff --git a/src/qt_common/config/shared_translation.cpp b/src/qt_common/config/shared_translation.cpp index 09e64b98f0..737ea2a90d 100644 --- a/src/qt_common/config/shared_translation.cpp +++ b/src/qt_common/config/shared_translation.cpp @@ -30,9 +30,41 @@ std::unique_ptr InitializeTranslations(QObject* parent) { // A setting can be ignored by giving it a blank name + // Toggled from View > Show Controller Overlay + INSERT(Settings, console_debug_overlay, tr("Controller overlay"), + tr("The players, their controllers and their last buttons in the top-left corner.")); + INSERT(Settings, console_hints, tr("Controller hints"), + tr("Names a controller in the bottom-left corner when it joins or leaves.")); + INSERT(Settings, console_history, QString(), QString()); + INSERT(Settings, console_history_size, QString(), QString()); + INSERT(Settings, console_history_seconds, QString(), QString()); + INSERT(Settings, console_history_gaps, QString(), QString()); + INSERT(Settings, console_debug_probes, QString(), QString()); + INSERT(Settings, console_bypass_steam, QString(), QString()); + INSERT(Settings, console_joycon_auto, tr("Use any controller as Joy-Cons"), + tr("When the game only takes Joy-Cons, controllers act as Joy-Cons.")); + INSERT(Settings, console_pause_disconnect, tr("Pause when a controller disconnects"), + tr("Pauses when a player's controller is turned off, or has been gone for 3 seconds. " + "+ on another controller goes on without that player.")); + INSERT(Settings, console_player_lights, tr("Player lights"), + tr("Controllers' player lights show their player.")); + INSERT(Settings, console_button_labels, tr("Button layout by label"), + tr("Xbox and PlayStation style controllers' buttons by their labels instead of their " + "positions.")); + INSERT(Settings, modern_seat_profiles, QString(), QString()); + INSERT(Settings, builtin_pad_identity, QString(), QString()); + INSERT(Settings, builtin_pad_steam_handle, QString(), QString()); + INSERT(Settings, builtin_pad_blocked, QString(), QString()); + INSERT(Settings, builtin_pad_manual, QString(), QString()); + INSERT(Settings, builtin_pad_steam_manual, QString(), QString()); + // Applets INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); - INSERT(Settings, controller_applet_mode, tr("Controller configuration"), QString()); + // Chosen in Controls > Players ("Assign players") + INSERT(Settings, controller_applet_mode, tr("Controller configuration"), + tr("How games get their players: Modern Console and Handheld Console assign them " + "automatically; Custom Frontend and Real Hardware show a controller applet; " + "Disabled uses the players set in each player's tab.")); INSERT(Settings, data_erase_applet_mode, tr("Data erase"), QString()); INSERT(Settings, error_applet_mode, tr("Error"), QString()); INSERT(Settings, net_connect_applet_mode, tr("Net connect"), QString()); @@ -86,6 +118,10 @@ std::unique_ptr InitializeTranslations(QObject* parent) { tr("Synchronizes CPU core speed with the game's maximum rendering speed to boost FPS " "without affecting game speed (animations, physics, etc.).\n" "Can help reduce stuttering at lower framerates.")); + INSERT(Settings, enable_cheats_by_default, tr("Enable cheats by default"), + tr("Enables regular cheats when a game starts. Master Code entries are always enabled. " + "Individual cheats can still be toggled from Cheats in the menu bar while the game is " + "running.")); // Cpu INSERT(Settings, cpu_accuracy, tr("Accuracy:"), @@ -194,10 +230,6 @@ std::unique_ptr InitializeTranslations(QObject* parent) { INSERT(Settings, skip_cpu_inner_invalidation, tr("Skip CPU Inner Invalidation"), tr("Skips certain cache invalidations during memory updates, reducing CPU usage and " "improving latency. This may cause soft-crashes.")); - INSERT(Settings, nce_invalidation_gpu_readback, - tr("GPU Readback Before NCE Invalidation"), - tr("Flushes GPU buffer data back to guest memory before NCE invalidates the whole " - "guest page, preserving it while the CPU store proceeds.")); INSERT(Settings, vsync_mode, tr("VSync Mode:"), tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " "refresh rate.\nFIFO Relaxed allows tearing as it recovers from a slow down.\n" @@ -345,10 +377,6 @@ std::unique_ptr InitializeTranslations(QObject* parent) { // Linux INSERT(UISettings, enable_gamemode, tr("Enable Gamemode"), QString()); -#ifdef __unix__ - INSERT(UISettings, gui_force_x11, tr("Force X11 as Graphics Backend"), QString()); - INSERT(UISettings, gui_hide_backend_warning, QString(), QString()); -#endif // Ui Debugging @@ -373,9 +401,11 @@ std::unique_ptr ComboboxEnumeration(QObject* parent) { // Intentionally skipping VSyncMode to let the UI fill that one out translations->insert({Settings::EnumMetadata::Index(), { - PAIR(AppletMode, HLE, tr("Custom frontend")), - PAIR(AppletMode, LLE, tr("Real applet")), + PAIR(AppletMode, HLE, tr("Custom Frontend")), + PAIR(AppletMode, LLE, tr("Real Hardware")), PAIR(AppletMode, Disabled, tr("Disabled")), + PAIR(AppletMode, ConsoleMode, tr("Modern Console")), + PAIR(AppletMode, HandheldConsoleMode, tr("Handheld Console")), }}); translations->insert({Settings::EnumMetadata::Index(), diff --git a/src/qt_common/config/uisettings.cpp b/src/qt_common/config/uisettings.cpp index f4f5688781..00e7095c0c 100644 --- a/src/qt_common/config/uisettings.cpp +++ b/src/qt_common/config/uisettings.cpp @@ -30,7 +30,7 @@ namespace UISettings { // 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 default_hotkeys{{ +const std::array default_hotkeys{{ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, @@ -64,6 +64,7 @@ const std::array default_hotkeys{{ {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Performance Overlay")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+V"), std::string(""), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Controller Overlay")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Shift+V"), std::string(""), Qt::WindowShortcut, false}}, }}; // clang-format on diff --git a/src/qt_common/config/uisettings.h b/src/qt_common/config/uisettings.h index a790cfcc22..b027b5f8eb 100644 --- a/src/qt_common/config/uisettings.h +++ b/src/qt_common/config/uisettings.h @@ -148,11 +148,6 @@ struct Values { false, #endif "enable_gamemode", Category::UiGeneral}; -#ifdef __unix__ - SwitchableSetting gui_force_x11{linkage, false, "gui_force_x11", Category::UiGeneral}; - Setting gui_hide_backend_warning{linkage, false, "gui_hide_backend_warning", - Category::UiGeneral}; -#endif // Discord RPC Setting enable_discord_presence{linkage, false, "enable_discord_presence", Category::Ui}; @@ -244,7 +239,7 @@ void SaveWindowState(); void RestoreWindowState(std::unique_ptr& qtConfig); // sync with uisettings.cpp -extern const std::array default_hotkeys; +extern const std::array default_hotkeys; } // namespace UISettings diff --git a/src/qt_common/game_list/worker.cpp b/src/qt_common/game_list/worker.cpp index 586a26e8b9..6b6f93447d 100644 --- a/src/qt_common/game_list/worker.cpp +++ b/src/qt_common/game_list/worker.cpp @@ -360,7 +360,8 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa } if (target == ScanTarget::PopulateGameList && - (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP) && + (file_type == Loader::FileType::XCI || file_type == Loader::FileType::XCZ || + file_type == Loader::FileType::NSP || file_type == Loader::FileType::NSZ) && !Loader::IsBootableGameContainer(file, file_type)) { return true; } @@ -375,7 +376,9 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa program_id, file); } else if (Settings::values.ext_content_from_game_dirs.GetValue() && (file_type == Loader::FileType::XCI || - file_type == Loader::FileType::NSP)) { + file_type == Loader::FileType::XCZ || + file_type == Loader::FileType::NSP || + file_type == Loader::FileType::NSZ)) { void(provider->AddEntriesFromContainer(file)); } } else { @@ -402,7 +405,8 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa }; if (res2 == Loader::ResultStatus::Success && program_ids.size() > 1 && - (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) { + (file_type == Loader::FileType::XCI || file_type == Loader::FileType::XCZ || + file_type == Loader::FileType::NSP || file_type == Loader::FileType::NSZ)) { for (const auto id : program_ids) { // dravee suggested this, only viable way to // not show sub-games in qlaunch for now. diff --git a/src/qt_common/gui_settings.cpp b/src/qt_common/gui_settings.cpp deleted file mode 100644 index 8b85fe43d6..0000000000 --- a/src/qt_common/gui_settings.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "common/fs/fs.h" -#include "common/fs/path_util.h" -#include "gui_settings.h" - -namespace FS = Common::FS; - -namespace GraphicsBackend { - -QString GuiConfigPath() { - return QString::fromStdString( - FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "gui_config.ini")); -} - -void SetForceX11(bool state) { - (void)FS::CreateParentDir(GuiConfigPath().toStdString()); - QSettings(GuiConfigPath(), QSettings::IniFormat).setValue("gui_force_x11", state); -} - -bool GetForceX11() { - return QSettings(GuiConfigPath(), QSettings::IniFormat).value("gui_force_x11", false).toBool(); -} - -} // namespace GraphicsBackend diff --git a/src/qt_common/gui_settings.h b/src/qt_common/gui_settings.h deleted file mode 100644 index d7d471d9ab..0000000000 --- a/src/qt_common/gui_settings.h +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include -#include - -namespace GraphicsBackend { - -QString GuiConfigPath(); -void SetForceX11(bool state); -bool GetForceX11(); - -} // namespace GraphicsBackend diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index b9b8caf6e8..fa34a74cb9 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -27,7 +27,6 @@ #include #include -#include #include #if !defined(WIN32) && !defined(__APPLE__) @@ -37,7 +36,6 @@ #endif #ifdef _WIN32 -#include #include #include #include "common/windows/timer_resolution.h" @@ -57,7 +55,8 @@ std::unique_ptr emu_thread = nullptr; const QStringList supported_file_extensions = {QStringLiteral("nro"), QStringLiteral("nso"), QStringLiteral("nca"), QStringLiteral("xci"), - QStringLiteral("nsp"), QStringLiteral("kip")}; + QStringLiteral("xcz"), QStringLiteral("nsp"), + QStringLiteral("nsz"), QStringLiteral("kip")}; Core::Frontend::WindowSystemType GetWindowSystemType() { // Determine WSI type based on Qt platform. @@ -276,6 +275,14 @@ void Init(QWidget* root) { // Remove cached contents generated during the previous session RemoveCachedContents(); + + // Platform checks + const auto qpa = QGuiApplication::platformName(); + LOG_INFO(Frontend, "Qt Platform Backend: {}", qpa.toStdString()); + if (qpa == QStringLiteral("wayland")) + LOG_WARNING( + Frontend, + "Platform backend is set to Wayland, which may cause performance/stability issues"); } std::filesystem::path GetEdenCommand() { @@ -324,4 +331,47 @@ QPixmap CreateCirclePixmapFromColor(const QColor& color) { return circle_pixmap; } +#ifdef _WIN32 +static void OverrideWindowsFont() { + // Qt chooses these fonts on Windows and they have fairly ugly alphanumeric/cyrillic characters + // Asking to use "MS Shell Dlg 2" gives better other chars while leaving the Chinese Characters. + // https://github.com/qt/qtbase/blob/v6.12.0/src/gui/text/windows/qwindowsfontdatabasebase.cpp#L970-L1020 + const QString startup_font = QGuiApplication::font().family(); + const QStringList ugly_fonts = {QStringLiteral("SimSun"), QStringLiteral("PMingLiU")}; + if (ugly_fonts.contains(startup_font)) { + QGuiApplication::setFont(QFont(QStringLiteral("MS Shell Dlg 2"), 9, QFont::Normal)); + } +} +#endif + +void SetupApplication() { + // Init settings params + QCoreApplication::setOrganizationName(QStringLiteral("eden")); + QCoreApplication::setApplicationName(QStringLiteral("eden")); + +#ifdef __unix__ + // Set the DISPLAY variable in order to open web browsers + // TODO (lat9nq): Find a better solution for AppImages to start external applications + if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) { + qputenv("DISPLAY", ":0"); + } + + // Always prefer X11 but allow Wayland if the user is missing X11 for some reason. + if (qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM")) + qputenv("QT_QPA_PLATFORM", "xcb;wayland"); + + // Fix the Wayland appId. This needs to match the name of the .desktop file without the .desktop + // suffix. + QGuiApplication::setDesktopFileName(QStringLiteral("dev.eden_emu.eden")); +#endif + + // Enables the core to make the qt created contexts current on std::threads + QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); + + // Make the app look a little better. +#ifdef _WIN32 + OverrideWindowsFont(); +#endif +} + } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index ea8e3f73a2..0307dda1dc 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -42,6 +42,9 @@ void Init(QWidget* root); void SetupContentProviders(); void SetupHID(); +// setup env vars, scaling, and app attributes +void SetupApplication(); + const QString tr(const char* str); const QString tr(const std::string& str); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp index 5d4983b9f7..f8e32d1e9a 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp @@ -6,7 +6,6 @@ #include -#include "common/settings.h" #include "shader_recompiler/backend/spirv/emit_spirv.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" #include "shader_recompiler/backend/spirv/spirv_emit_context.h" @@ -590,11 +589,6 @@ Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& Id result = Emit(&EmitContext::OpImageSparseSampleExplicitLod, &EmitContext::OpImageSampleExplicitLod, ctx, inst, result_type, Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); -#ifdef __ANDROID__ - if (!is_integer && Settings::values.fix_bloom_effects.GetValue()) { - result = ctx.OpVectorTimesScalar(ctx.F32[4], result, ctx.Const(0.98f)); - } -#endif return is_integer ? ctx.OpBitcast(ctx.F32[4], result) : result; } diff --git a/src/shader_recompiler/frontend/ir/breadth_first_search.h b/src/shader_recompiler/frontend/ir/breadth_first_search.h index ec55425549..afe153f180 100644 --- a/src/shader_recompiler/frontend/ir/breadth_first_search.h +++ b/src/shader_recompiler/frontend/ir/breadth_first_search.h @@ -1,8 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#include #include #include #include @@ -13,9 +17,10 @@ namespace Shader::IR { -template -auto BreadthFirstSearch(const Value& value, Pred&& pred) +template +auto BreadthFirstSearch(Value value, Pred&& pred, Resolve&& resolve = {}) -> std::invoke_result_t { + value = resolve(value); if (value.IsImmediate()) { // Nothing to do with immediates return std::nullopt; @@ -36,7 +41,7 @@ auto BreadthFirstSearch(const Value& value, Pred&& pred) } // Visit the right most arguments first for (size_t arg = inst->NumArgs(); arg--;) { - const Value arg_value{inst->Arg(arg)}; + const Value arg_value{resolve(inst->Arg(arg))}; if (arg_value.IsImmediate()) { continue; } diff --git a/src/shader_recompiler/host_translate_info.h b/src/shader_recompiler/host_translate_info.h index 44df85ccb2..9c1838acaf 100644 --- a/src/shader_recompiler/host_translate_info.h +++ b/src/shader_recompiler/host_translate_info.h @@ -40,6 +40,8 @@ struct HostTranslateInfo { bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional ///< control flow bool single_lane_geometry_subgroups{}; + bool support_attribute_texture_handle{}; ///< True when the host binds texture handles that + ///< arrive as vertex attributes void ApplyDescriptorLimitPolicy() noexcept { if (min_ssbo_alignment == 0) { diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index fe34a67555..db569edc79 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp @@ -31,6 +31,60 @@ struct TextureInst { using TextureInstVector = boost::container::small_vector; +const IR::Block* ConditionalHeader(const IR::Block* body) { + const auto predecessors{body->ImmPredecessors()}; + const auto successors{body->ImmSuccessors()}; + if (predecessors.size() != 1 || successors.size() != 1) return nullptr; + const IR::Block* const header{predecessors[0]}; + const auto targets{header->ImmSuccessors()}; + if (targets.size() != 2 || targets[0] != body || targets[1] != successors[0] || + targets[1]->ImmPredecessors().size() != 2 || header->empty() || + header->back().GetOpcode() != IR::Opcode::ConditionRef) { + return nullptr; + } + return header; +} + +std::pair Condition(IR::Value value) { + bool negated{}; + while (const IR::Inst* inst = value.TryInstRecursive()) { + if (inst->GetOpcode() == IR::Opcode::LogicalNot) negated = !negated; + else if (inst->GetOpcode() != IR::Opcode::ConditionRef) break; + value = inst->Arg(0); + } + return {value.Resolve(), negated}; +} + +IR::Value ResolveConditionalPhi(IR::Value value, const IR::Block* block) { + if (!value.Resolve().IsPhi() || !(block = ConditionalHeader(block))) return value; + const auto [condition, negated]{Condition(block->back().Arg(0))}; + boost::container::small_vector visited; + while (value.Resolve().IsPhi() && std::ranges::find(visited, block) == visited.end()) { + visited.push_back(block); + const IR::Inst* const phi{value.InstRecursive()}; + const auto predecessors{block->ImmPredecessors()}; + if (predecessors.size() == 1) { + block = predecessors[0]; + continue; + } + if (predecessors.size() != 2 || phi->NumArgs() != 2) break; + const IR::Block* body{predecessors[0]}; + const IR::Block* header{ConditionalHeader(body)}; + if (header != predecessors[1]) { + body = predecessors[1]; + header = ConditionalHeader(body); + if (header != predecessors[0]) break; + } + const auto [other_condition, other_negated]{Condition(header->back().Arg(0))}; + if (condition == other_condition && (phi->PhiBlock(0) == header || phi->PhiBlock(0) == body)) { + const IR::Block* const incoming{negated == other_negated ? body : header}; + value = phi->Arg(phi->PhiBlock(0) == incoming ? 0 : 1); + } + block = header; + } + return value; +} + constexpr u32 DESCRIPTOR_SIZE = 8; constexpr u32 DESCRIPTOR_SIZE_SHIFT = u32(std::countr_zero(DESCRIPTOR_SIZE)); constexpr u32 DESCRIPTOR_MAX_COUNT = 1024; @@ -268,6 +322,10 @@ static inline u32 ReadCbufCached(Environment& env, u32 index, u32 offset) { return v; } +static inline bool IsAttributeHandle(const ConstBufferAddr& cbuf) { + return cbuf.index == ATTRIBUTE_HANDLE_CBUF_INDEX; +} + static inline u32 GetTextureHandleCached(Environment& env, const ConstBufferAddr& cbuf) { // Must all be uniquely different variables // If has secondary, then it will be cbuf.secondary_{index|offset}, else its 0. @@ -287,35 +345,44 @@ static inline u32 GetTextureHandleCached(Environment& env, const ConstBufferAddr // Cached variants of existing helpers static inline TextureType ReadTextureTypeCached(Environment& env, const ConstBufferAddr& cbuf) { + if (IsAttributeHandle(cbuf)) { + return TextureType::Color2D; + } return env.ReadTextureType(GetTextureHandleCached(env, cbuf)); } static inline TexturePixelFormat ReadTexturePixelFormatCached(Environment& env, const ConstBufferAddr& cbuf) { + if (IsAttributeHandle(cbuf)) { + return TexturePixelFormat::A8B8G8R8_UNORM; + } return env.ReadTexturePixelFormat(GetTextureHandleCached(env, cbuf)); } static inline bool IsTexturePixelFormatIntegerCached(Environment& env, const ConstBufferAddr& cbuf) { + if (IsAttributeHandle(cbuf)) { + return false; + } return env.IsTexturePixelFormatInteger(GetTextureHandleCached(env, cbuf)); } -std::optional Track(const IR::Value& value, Environment& env, const HostTranslateInfo& host_info); -static inline std::optional TrackCached(const IR::Value& v, Environment& env, const HostTranslateInfo& host_info) { - if (const IR::Inst* key = v.InstRecursive()) { +std::optional Track(const IR::Value& value, Environment& env, const HostTranslateInfo& host_info, const IR::Block* block); +static inline std::optional TrackCached(const IR::Value& v, Environment& env, const HostTranslateInfo& host_info, const IR::Block* block) { + if (const IR::Inst* key = v.TryInstRecursive()) { if (auto it = env.track_cache.find(key); it != env.track_cache.end()) return it->second; - auto found = Track(v, env, host_info); + auto found = Track(v, env, host_info, block); if (found) env.track_cache.emplace(key, *found); return found; } - return Track(v, env, host_info); + return Track(v, env, host_info, block); } -std::optional TryGetConstBuffer(const IR::Inst* inst, Environment& env, const HostTranslateInfo& host_info); +std::optional TryGetConstBuffer(const IR::Inst* inst, Environment& env, const HostTranslateInfo& host_info, const IR::Block* block); -std::optional Track(const IR::Value& value, Environment& env, const HostTranslateInfo& host_info) { - return IR::BreadthFirstSearch(value, [&env, &host_info](const IR::Inst* inst) { - return TryGetConstBuffer(inst, env, host_info); - }); +std::optional Track(const IR::Value& value, Environment& env, const HostTranslateInfo& host_info, const IR::Block* block) { + return IR::BreadthFirstSearch(value, [&env, &host_info, block](const IR::Inst* inst) { + return TryGetConstBuffer(inst, env, host_info, block); + }, [&](IR::Value operand) { return ResolveConditionalPhi(operand, block); }); } std::optional TryGetConstant(IR::Value& value, Environment& env) { @@ -339,13 +406,13 @@ std::optional TryGetConstant(IR::Value& value, Environment& env) { return ReadCbufCached(env, index_number, offset_number); } -std::optional TryGetConstBuffer(const IR::Inst* inst, Environment& env, const HostTranslateInfo& host_info) { +std::optional TryGetConstBuffer(const IR::Inst* inst, Environment& env, const HostTranslateInfo& host_info, const IR::Block* block) { switch (inst->GetOpcode()) { default: return std::nullopt; case IR::Opcode::BitwiseOr32: { - std::optional lhs{TrackCached(inst->Arg(0), env, host_info)}; - std::optional rhs{TrackCached(inst->Arg(1), env, host_info)}; + std::optional lhs{TrackCached(inst->Arg(0), env, host_info, block)}; + std::optional rhs{TrackCached(inst->Arg(1), env, host_info, block)}; if (!lhs || !rhs) { return std::nullopt; } @@ -375,7 +442,7 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme if (!shift.IsImmediate()) { return std::nullopt; } - std::optional lhs{TrackCached(inst->Arg(0), env, host_info)}; + std::optional lhs{TrackCached(inst->Arg(0), env, host_info, block)}; if (lhs) { lhs->shift_left = shift.U32(); } @@ -403,7 +470,7 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme return std::nullopt; } while (false); } - std::optional lhs{TrackCached(op1, env, host_info)}; + std::optional lhs{TrackCached(op1, env, host_info, block)}; if (lhs) { lhs->shift_left = static_cast(std::countr_zero(op2.U32())); } @@ -466,15 +533,43 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme }; } +bool IsAttributeSourcedHandle(const IR::Value& handle) { + if (handle.IsImmediate()) { + return false; + } + const IR::Inst* inst{handle.InstRecursive()}; + if (inst->GetOpcode() == IR::Opcode::BitCastU32F32 && !inst->Arg(0).IsImmediate()) { + inst = inst->Arg(0).InstRecursive(); + } + return inst->GetOpcode() == IR::Opcode::GetAttribute || + inst->GetOpcode() == IR::Opcode::GetAttributeU32; +} + TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst, const HostTranslateInfo& host_info) { ConstBufferAddr addr; if (IsBindless(inst)) { - const std::optional track_addr{TrackCached(inst.Arg(0), env, host_info)}; + const std::optional track_addr{TrackCached(inst.Arg(0), env, host_info, block)}; - if (!track_addr) { - throw NotImplementedException("Failed to track bindless texture constant buffer"); - } else { + if (track_addr) { addr = *track_addr; + } else if (host_info.support_attribute_texture_handle && + IsAttributeSourcedHandle(inst.Arg(0))) { + // The handle travels with the vertices (sprite batches pick the texture per quad), so + // there is no constant buffer to read it from. The host binds the handle of each run + // of vertices that share one. + addr = ConstBufferAddr{ + .index = ATTRIBUTE_HANDLE_CBUF_INDEX, + .offset = 0, + .shift_left = 0, + .secondary_index = 0, + .secondary_offset = 0, + .secondary_shift_left = 0, + .dynamic_offset = {}, + .count = 1, + .has_secondary = false, + }; + } else { + throw NotImplementedException("Failed to track bindless texture constant buffer"); } } else { addr = ConstBufferAddr{ @@ -671,6 +766,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo env.track_cache.clear(); TextureInstVector to_replace; for (IR::Block* const block : program.post_order_blocks) { + env.track_cache.clear(); for (IR::Inst& inst : block->Instructions()) { if (!IsTextureInstruction(inst)) { continue; diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index 71309e040e..d60be1238d 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h @@ -38,6 +38,10 @@ enum class TextureType : u32 { }; constexpr u32 NUM_TEXTURE_TYPES = 9; +/// Constant buffer index marking a texture handle that the shader receives as a vertex attribute +/// instead of reading it from a constant buffer. The host supplies the handle of each draw run. +constexpr u32 ATTRIBUTE_HANDLE_CBUF_INDEX = 0xFFFF; + enum class TexturePixelFormat { A8B8G8R8_UNORM, A8B8G8R8_SNORM, diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 53addb5dec..f30c85911f 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -1738,36 +1738,64 @@ void BufferCache

::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept { template bool BufferCache

::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 size) { - upload_copies.clear(); - u64 total_size_bytes = 0; - u64 largest_copy = 0; - const DAddr buffer_start = buffer.cpu_addr_cached; - const auto add_upload = [&](DAddr start, DAddr end) { - if (start == end) return; - const u64 range_size = end - start; - upload_copies.push_back(BufferCopy{ - .src_offset = total_size_bytes, - .dst_offset = start - buffer_start, - .size = range_size, +#ifdef __ANDROID__ + const bool use_optimized_vertex_buffers = Settings::values.use_optimized_vertex_buffers.GetValue(); +#else + constexpr bool use_optimized_vertex_buffers = true; +#endif + + if (use_optimized_vertex_buffers) { + upload_copies.clear(); + u64 total_size_bytes = 0; + u64 largest_copy = 0; + const DAddr buffer_start = buffer.cpu_addr_cached; + const auto add_upload = [&](DAddr start, DAddr end) { + if (start == end) return; + const u64 range_size = end - start; + upload_copies.push_back(BufferCopy{ + .src_offset = total_size_bytes, + .dst_offset = start - buffer_start, + .size = range_size, + }); + total_size_bytes += range_size; + largest_copy = (std::max)(largest_copy, range_size); + }; + memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) { + DAddr upload_start = device_addr_out; + gpu_modified_ranges.ForEachInRange(device_addr_out, range_size, [&](DAddr gpu_start, DAddr gpu_end) { + add_upload(upload_start, gpu_start); + upload_start = gpu_end; + }); + add_upload(upload_start, device_addr_out + range_size); }); - total_size_bytes += range_size; - largest_copy = (std::max)(largest_copy, range_size); - }; - memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) { - DAddr upload_start = device_addr_out; - gpu_modified_ranges.ForEachInRange(device_addr_out, range_size, [&](DAddr gpu_start, DAddr gpu_end) { - add_upload(upload_start, gpu_start); - upload_start = gpu_end; + if (total_size_bytes == 0) { + return true; + } + const std::span copies_span(upload_copies.data(), upload_copies.size()); + UploadMemory(buffer, total_size_bytes, largest_copy, copies_span); + any_buffer_uploaded = true; + return false; + } else { + boost::container::small_vector copies; + u64 total_size_bytes = 0; + u64 largest_copy = 0; + DAddr buffer_start = buffer.CpuAddr(); + memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) { + copies.push_back(BufferCopy{ + .src_offset = total_size_bytes, + .dst_offset = device_addr_out - buffer_start, + .size = range_size, + }); + total_size_bytes += range_size; + largest_copy = (std::max)(largest_copy, range_size); }); - add_upload(upload_start, device_addr_out + range_size); - }); - if (total_size_bytes == 0) { - return true; + if (total_size_bytes == 0) { + return true; + } + const std::span copies_span(copies.data(), copies.size()); + UploadMemory(buffer, total_size_bytes, largest_copy, copies_span); + return false; } - const std::span copies_span(upload_copies.data(), upload_copies.size()); - UploadMemory(buffer, total_size_bytes, largest_copy, copies_span); - any_buffer_uploaded = true; - return false; } template diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 4e36d086e6..9901cf4262 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -226,19 +226,7 @@ struct GPU::Impl { } /// Notify rasterizer that any caches of the specified region should be invalidated - void InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes) { - if (Settings::values.nce_invalidation_gpu_readback.GetValue()) { - VideoCore::RasterizerInterface* rasterizer = renderer->ReadRasterizer(); - if (preserve_gpu_writes && rasterizer->MustFlushRegion(addr, size, VideoCommon::CacheType::BufferCache)) { - const u64 fence = RequestSyncOperation([rasterizer, addr, size] { - rasterizer->FlushRegion(addr, size, VideoCommon::CacheType::BufferCache); - rasterizer->OnCacheInvalidation(addr, size); - }); - gpu_thread.TickGPU(is_async); - WaitForSyncOperation(fence); - return; - } - } + void InvalidateRegion(DAddr addr, u64 size) { gpu_thread.InvalidateRegion(addr, size); } @@ -530,8 +518,8 @@ void GPU::FlushRegion(DAddr addr, u64 size) { impl->FlushRegion(addr, size); } -void GPU::InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes) { - impl->InvalidateRegion(addr, size, preserve_gpu_writes); +void GPU::InvalidateRegion(DAddr addr, u64 size) { + impl->InvalidateRegion(addr, size); } bool GPU::OnCPUWrite(DAddr addr, u64 size) { diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 974d214e10..75956ea199 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -248,7 +248,7 @@ public: void FlushRegion(DAddr addr, u64 size); /// Notify rasterizer that any caches of the specified region should be invalidated - void InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes = false); + void InvalidateRegion(DAddr addr, u64 size); /// Notify rasterizer that CPU is trying to write this area. It returns true if the area is /// sensible, false otherwise, addr and size must be a valid combination diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index a01375e7be..d77dba8be9 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -30,7 +30,6 @@ void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Core::Fronten thread = std::jthread([&](std::stop_token stop_token) { Common::SetCurrentThreadName("GPU"); Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); - Common::SetCurrentThreadToPerformanceCores(); system.RegisterHostThread(); auto current_context = context.Acquire(); diff --git a/src/video_core/host1x/codec_types.h b/src/video_core/host1x/codec_types.h index b2f80c822a..da9b713b26 100644 --- a/src/video_core/host1x/codec_types.h +++ b/src/video_core/host1x/codec_types.h @@ -312,6 +312,10 @@ struct Vp9PictureInfo { bool allow_high_precision_mv; bool segment_enabled; bool mode_ref_delta_enabled; + + Segmentation segmentation; + std::array seg_tree_probs; + std::array seg_pred_probs; }; struct Vp9FrameContainer { @@ -377,6 +381,10 @@ struct PictureInfo { .allow_high_precision_mv = allow_high_precision_mv != 0, .segment_enabled = segmentation.enabled != 0, .mode_ref_delta_enabled = loop_filter.mode_ref_delta_enabled != 0, + + .segmentation = segmentation, + .seg_tree_probs = {}, + .seg_pred_probs = {}, }; } }; diff --git a/src/video_core/host1x/codecs/vp9.cpp b/src/video_core/host1x/codecs/vp9.cpp index dcc6261e5c..dd91f7f1b7 100644 --- a/src/video_core/host1x/codecs/vp9.cpp +++ b/src/video_core/host1x/codecs/vp9.cpp @@ -331,19 +331,16 @@ void VP9::WriteMvProbabilityUpdate(VpxRangeEncoder& writer, u8 new_prob, u8 old_ } void VP9::WriteSegmentation(VpxBitStreamWriter& writer) { - bool enabled = current_picture_info.segmentation.enabled != 0; + bool enabled = current_frame_info.segmentation.enabled != 0; writer.WriteBit(enabled); if (!enabled) { return; } - auto update_map = current_picture_info.segmentation.update_map != 0; + auto update_map = current_frame_info.segmentation.update_map != 0; writer.WriteBit(update_map); if (update_map) { - EntropyProbs entropy_probs{}; - host1x.gmmu_manager.ReadBlock(regs.vp9_prob_tab_buffer_offset.Address(), &entropy_probs, sizeof(entropy_probs)); - auto WriteProb = [&](u8 prob) { bool coded = prob != 255; writer.WriteBit(coded); @@ -352,55 +349,55 @@ void VP9::WriteSegmentation(VpxBitStreamWriter& writer) { } }; - for (size_t i = 0; i < entropy_probs.mb_segment_tree_probs.size(); i++) { - WriteProb(entropy_probs.mb_segment_tree_probs[i]); + for (size_t i = 0; i < current_frame_info.seg_tree_probs.size(); i++) { + WriteProb(current_frame_info.seg_tree_probs[i]); } - auto temporal_update = current_picture_info.segmentation.temporal_update != 0; + auto temporal_update = current_frame_info.segmentation.temporal_update != 0; writer.WriteBit(temporal_update); if (temporal_update) { for (s32 i = 0; i < 3; i++) { - WriteProb(entropy_probs.segment_pred_probs[i]); + WriteProb(current_frame_info.seg_pred_probs[i]); } } } - if (last_segmentation == current_picture_info.segmentation) { + if (last_segmentation == current_frame_info.segmentation) { writer.WriteBit(false); return; } - last_segmentation = current_picture_info.segmentation; + last_segmentation = current_frame_info.segmentation; writer.WriteBit(true); - writer.WriteBit(current_picture_info.segmentation.abs_delta != 0); + writer.WriteBit(current_frame_info.segmentation.abs_delta != 0); constexpr s32 MAX_SEGMENTS = 8; constexpr std::array SegmentationFeatureBits = {8, 6, 2, 0}; for (s32 i = 0; i < MAX_SEGMENTS; i++) { - auto q_enabled = current_picture_info.segmentation.feature_enabled[i][0] != 0; + auto q_enabled = current_frame_info.segmentation.feature_enabled[i][0] != 0; writer.WriteBit(q_enabled); if (q_enabled) { - writer.WriteS(current_picture_info.segmentation.feature_data[i][0], + writer.WriteS(current_frame_info.segmentation.feature_data[i][0], SegmentationFeatureBits[0]); } - auto lf_enabled = current_picture_info.segmentation.feature_enabled[i][1] != 0; + auto lf_enabled = current_frame_info.segmentation.feature_enabled[i][1] != 0; writer.WriteBit(lf_enabled); if (lf_enabled) { - writer.WriteS(current_picture_info.segmentation.feature_data[i][1], + writer.WriteS(current_frame_info.segmentation.feature_data[i][1], SegmentationFeatureBits[1]); } - auto ref_enabled = current_picture_info.segmentation.feature_enabled[i][2] != 0; + auto ref_enabled = current_frame_info.segmentation.feature_enabled[i][2] != 0; writer.WriteBit(ref_enabled); if (ref_enabled) { - writer.WriteU(current_picture_info.segmentation.feature_data[i][2], + writer.WriteU(current_frame_info.segmentation.feature_data[i][2], SegmentationFeatureBits[2]); } - auto skip_enabled = current_picture_info.segmentation.feature_enabled[i][3] != 0; + auto skip_enabled = current_frame_info.segmentation.feature_enabled[i][3] != 0; writer.WriteBit(skip_enabled); } } @@ -411,6 +408,14 @@ Vp9PictureInfo VP9::GetVp9PictureInfo() { InsertEntropy(regs.vp9_prob_tab_buffer_offset.Address(), vp9_info.entropy); + EntropyProbs entropy_probs{}; + host1x.gmmu_manager.ReadBlock(regs.vp9_prob_tab_buffer_offset.Address(), + &entropy_probs, sizeof(entropy_probs)); + + vp9_info.seg_tree_probs = entropy_probs.mb_segment_tree_probs; + vp9_info.seg_pred_probs = entropy_probs.segment_pred_probs; + + // surface_luma_offset[0:3] contains the address of the reference frame offsets in the following // order: last, golden, altref, current. for (size_t i = 0; i < 4; i++) { diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 481efbf53b..06cb8b7aba 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index df69eb97f5..277cf222fa 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -414,6 +414,11 @@ GraphicsPipeline* ShaderCache::BuiltPipeline(GraphicsPipeline* pipeline) const n if (!use_asynchronous_shaders) { return pipeline; } + // If something is using depth, we can assume that games are not rendering anything which + // will be used one time. + if (maxwell3d->regs.zeta_enable) { + return nullptr; + } // If games are using a small index count, we can assume these are full screen quads. // Usually these shaders are only used once for building textures so we can assume they // can't be built async diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index 0ced890929..71f35e18d4 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -129,7 +129,13 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe topology.Assign(can_collapse_topology_class ? TOPOLOGY_CLASS_REPRESENTATIVE_LUT[static_cast(topology_)] : topology_); - msaa_mode.Assign(regs.anti_alias_samples_mode); + // Target-independent rasterization rasterizes (and depth tests) at the raster sample count + if (regs.tir_mode == Maxwell::TIRMode::RasterNTargetM && + regs.anti_alias_raster != Maxwell::AntiAliasRaster::Mode1x1) { + msaa_mode.Assign(static_cast(regs.anti_alias_raster)); + } else { + msaa_mode.Assign(regs.anti_alias_samples_mode); + } attachment0_dual_source_blend.Assign(ComputeAttachment0DualSourceBlend(regs) ? 1 : 0); raw2 = 0; diff --git a/src/video_core/renderer_vulkan/present/filters.cpp b/src/video_core/renderer_vulkan/present/filters.cpp index 6203b41218..d8dc2291f6 100644 --- a/src/video_core/renderer_vulkan/present/filters.cpp +++ b/src/video_core/renderer_vulkan/present/filters.cpp @@ -30,29 +30,29 @@ namespace Vulkan { -std::unique_ptr MakeNearestNeighbor(const Device& device, VkFormat frame_format) { - return std::make_unique(device, frame_format, CreateNearestNeighborSampler(device), +std::unique_ptr MakeNearestNeighbor(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format) { + return std::make_unique(device, memory_allocator, frame_format, CreateNearestNeighborSampler(device), BuildShader(device, VULKAN_PRESENT_FRAG_SPV)); } -std::unique_ptr MakeBilinear(const Device& device, VkFormat frame_format) { - return std::make_unique(device, frame_format, CreateBilinearSampler(device), +std::unique_ptr MakeBilinear(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format) { + return std::make_unique(device, memory_allocator, frame_format, CreateBilinearSampler(device), BuildShader(device, VULKAN_PRESENT_FRAG_SPV)); } -std::unique_ptr MakeSpline1(const Device& device, VkFormat frame_format) { - return std::make_unique(device, frame_format, CreateBilinearSampler(device), +std::unique_ptr MakeSpline1(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format) { + return std::make_unique(device, memory_allocator, frame_format, CreateBilinearSampler(device), BuildShader(device, PRESENT_SPLINE1_FRAG_SPV)); } -std::unique_ptr MakeBicubic(const Device& device, VkFormat frame_format, VkCubicFilterWeightsQCOM qcom_weights) { +std::unique_ptr MakeBicubic(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format, VkCubicFilterWeightsQCOM qcom_weights) { // No need for handrolled shader -- if the VK impl can do it for us ;) // Catmull-Rom is default bicubic for all implementations... if (device.IsExtFilterCubicSupported() && (device.IsQcomFilterCubicWeightsSupported() || qcom_weights == VK_CUBIC_FILTER_WEIGHTS_CATMULL_ROM_QCOM)) { - return std::make_unique(device, frame_format, CreateCubicSampler(device, + return std::make_unique(device, memory_allocator, frame_format, CreateCubicSampler(device, qcom_weights), BuildShader(device, VULKAN_PRESENT_FRAG_SPV)); } else { - return std::make_unique(device, frame_format, CreateBilinearSampler(device), [&](){ + return std::make_unique(device, memory_allocator, frame_format, CreateBilinearSampler(device), [&](){ switch (qcom_weights) { case VK_CUBIC_FILTER_WEIGHTS_CATMULL_ROM_QCOM: return BuildShader(device, PRESENT_BICUBIC_FRAG_SPV); @@ -69,32 +69,32 @@ std::unique_ptr MakeBicubic(const Device& device, VkFormat fram } } -std::unique_ptr MakeGaussian(const Device& device, VkFormat frame_format) { - return std::make_unique(device, frame_format, CreateBilinearSampler(device), +std::unique_ptr MakeGaussian(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format) { + return std::make_unique(device, memory_allocator, frame_format, CreateBilinearSampler(device), BuildShader(device, PRESENT_GAUSSIAN_FRAG_SPV)); } -std::unique_ptr MakeLanczos(const Device& device, VkFormat frame_format) { - return std::make_unique(device, frame_format, CreateBilinearSampler(device), +std::unique_ptr MakeLanczos(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format) { + return std::make_unique(device, memory_allocator, frame_format, CreateBilinearSampler(device), BuildShader(device, PRESENT_LANCZOS_FRAG_SPV)); } -std::unique_ptr MakeScaleForce(const Device& device, VkFormat frame_format) { +std::unique_ptr MakeScaleForce(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format) { auto const select_fn = [&]() { return device.IsFloat16Supported() ? BuildShader(device, VULKAN_PRESENT_SCALEFORCE_FP16_FRAG_SPV) : BuildShader(device, VULKAN_PRESENT_SCALEFORCE_FP32_FRAG_SPV); }; - return std::make_unique(device, frame_format, CreateBilinearSampler(device), select_fn()); + return std::make_unique(device, memory_allocator, frame_format, CreateBilinearSampler(device), select_fn()); } -std::unique_ptr MakeArea(const Device& device, VkFormat frame_format) { - return std::make_unique(device, frame_format, CreateBilinearSampler(device), +std::unique_ptr MakeArea(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format) { + return std::make_unique(device, memory_allocator, frame_format, CreateBilinearSampler(device), BuildShader(device, PRESENT_AREA_FRAG_SPV)); } -std::unique_ptr MakeMmpx(const Device& device, VkFormat frame_format) { - return std::make_unique(device, frame_format, CreateNearestNeighborSampler(device), +std::unique_ptr MakeMmpx(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format) { + return std::make_unique(device, memory_allocator, frame_format, CreateNearestNeighborSampler(device), BuildShader(device, PRESENT_MMPX_FRAG_SPV)); } diff --git a/src/video_core/renderer_vulkan/present/filters.h b/src/video_core/renderer_vulkan/present/filters.h index afc3ba29a0..84e3c4068e 100644 --- a/src/video_core/renderer_vulkan/present/filters.h +++ b/src/video_core/renderer_vulkan/present/filters.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2024 Torzu Emulator Project @@ -15,14 +15,14 @@ namespace Vulkan { class MemoryAllocator; -std::unique_ptr MakeNearestNeighbor(const Device& device, VkFormat frame_format); -std::unique_ptr MakeBilinear(const Device& device, VkFormat frame_format); -std::unique_ptr MakeBicubic(const Device& device, VkFormat frame_format, VkCubicFilterWeightsQCOM qcom_weights); -std::unique_ptr MakeSpline1(const Device& device, VkFormat frame_format); -std::unique_ptr MakeGaussian(const Device& device, VkFormat frame_format); -std::unique_ptr MakeLanczos(const Device& device, VkFormat frame_format); -std::unique_ptr MakeScaleForce(const Device& device, VkFormat frame_format); -std::unique_ptr MakeArea(const Device& device, VkFormat frame_format); -std::unique_ptr MakeMmpx(const Device& device, VkFormat frame_format); +std::unique_ptr MakeNearestNeighbor(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format); +std::unique_ptr MakeBilinear(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format); +std::unique_ptr MakeBicubic(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format, VkCubicFilterWeightsQCOM qcom_weights); +std::unique_ptr MakeSpline1(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format); +std::unique_ptr MakeGaussian(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format); +std::unique_ptr MakeLanczos(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format); +std::unique_ptr MakeScaleForce(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format); +std::unique_ptr MakeArea(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format); +std::unique_ptr MakeMmpx(const Device& device, MemoryAllocator& memory_allocator, VkFormat frame_format); } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp index 549b0660c1..024d31adc7 100644 --- a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp +++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp @@ -6,10 +6,17 @@ #include "core/frontend/framebuffer_layout.h" #include "video_core/framebuffer_config.h" +#include "video_core/host_shaders/vulkan_present_frag_spv.h" #include "video_core/host_shaders/vulkan_present_vert_spv.h" #include "video_core/renderer_vulkan/present/layer.h" #include "video_core/renderer_vulkan/present/present_push_constants.h" #include "video_core/renderer_vulkan/present/util.h" +#include + +#include "common/overlay_panels.h" +#include "common/logging.h" +#include "video_core/renderer_vulkan/present/present_push_constants.h" +#include "video_core/renderer_vulkan/present/util.h" #include "video_core/renderer_vulkan/present/window_adapt_pass.h" #include "video_core/renderer_vulkan/vk_present_manager.h" #include "video_core/renderer_vulkan/vk_shader_util.h" @@ -18,8 +25,11 @@ namespace Vulkan { -WindowAdaptPass::WindowAdaptPass(const Device& device, VkFormat frame_format, vk::Sampler&& sampler_, vk::ShaderModule&& fragment_shader_) - : sampler(std::move(sampler_)) +WindowAdaptPass::WindowAdaptPass(const Device& device, MemoryAllocator& memory_allocator_, + VkFormat frame_format, vk::Sampler&& sampler_, + vk::ShaderModule&& fragment_shader_) + : memory_allocator{memory_allocator_} + , sampler(std::move(sampler_)) , fragment_shader(std::move(fragment_shader_)) { CreateDescriptorSetLayout(device); @@ -27,6 +37,10 @@ WindowAdaptPass::WindowAdaptPass(const Device& device, VkFormat frame_format, vk CreateVertexShader(device); CreateRenderPass(device, frame_format); CreatePipelines(device); + overlay_shader = BuildShader(device, VULKAN_PRESENT_FRAG_SPV); + overlay_sampler = CreateNearestNeighborSampler(device); + overlay_pipeline = CreateWrappedCoverageBlendingPipeline( + device, render_pass, pipeline_layout, std::tie(vertex_shader, overlay_shader)); } WindowAdaptPass::~WindowAdaptPass() = default; @@ -34,7 +48,8 @@ WindowAdaptPass::~WindowAdaptPass() = default; void WindowAdaptPass::Draw(const Device& device, RasterizerVulkan& rasterizer, Scheduler& scheduler, size_t image_index, std::list& layers, std::span configs, - const Layout::FramebufferLayout& layout, Frame* dst) { + const Layout::FramebufferLayout& layout, Frame* dst, + bool overlay_panels) { const VkFramebuffer host_framebuffer{*dst->framebuffer}; const VkRenderPass renderpass{*render_pass}; @@ -69,6 +84,129 @@ void WindowAdaptPass::Draw(const Device& device, RasterizerVulkan& rasterizer, S layer_it++; } + // The overlay panels (see common/overlay_panels.h): one more quad each, straight-alpha, + // drawn last. + std::array overlay_draw{}; + std::array overlay_push{}; + std::array overlay_set{}; + auto& panels = Common::GetOverlayPanels(); + for (size_t o = 0; overlay_panels && o < panels.size(); ++o) { + auto& overlay_frame = panels[o]; + auto& quad = overlays[o]; + std::scoped_lock lock{overlay_frame.mutex}; + if (!overlay_frame.enabled || overlay_frame.pixels.empty() || overlay_frame.width == 0 || + overlay_frame.height == 0) { + continue; + } + constexpr VkFormat overlay_format = VK_FORMAT_R8G8B8A8_UNORM; + const VkExtent2D extent{overlay_frame.width, overlay_frame.height}; + if (!quad.ready || quad.extent.width != extent.width || + quad.extent.height != extent.height) { + // (A frame still on the GPU may be drawing the old image: replaced once it's done) + scheduler.Wait(quad.used_tick); + quad.image = CreateWrappedImage(memory_allocator, extent, overlay_format); + quad.view = CreateWrappedImageView(device, quad.image, overlay_format); + quad.pool = CreateWrappedDescriptorPool(device, 1, 1); + const std::vector layouts(1u, *descriptor_set_layout); + quad.sets = CreateWrappedDescriptorSets(quad.pool, layouts); + quad.extent = extent; + quad.ready = true; + quad.version = 0; + } + if (quad.version != overlay_frame.version) { + // Copied through one of the panel's two staging buffers: only that buffer's last + // copy is waited for, never the whole GPU + const std::size_t k = quad.next_staging; + quad.next_staging ^= 1; + scheduler.Wait(quad.staging_tick[k]); + auto& staging = quad.staging[k]; + const std::size_t bytes = overlay_frame.pixels.size(); + if (!staging || quad.staging_size[k] < bytes) { + const VkBufferCreateInfo staging_ci{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = bytes, + .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }; + staging = memory_allocator.CreateBuffer(staging_ci, MemoryUsage::Upload); + quad.staging_size[k] = bytes; + } + std::ranges::copy(overlay_frame.pixels, staging.Mapped().begin()); + staging.Flush(); + const VkBuffer source = *staging; + const VkImage target = *quad.image; + const VkBufferImageCopy region{ + .bufferOffset = 0, + .bufferRowLength = extent.width, + .bufferImageHeight = extent.height, + .imageSubresource{.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1}, + .imageOffset{}, + .imageExtent{.width = extent.width, .height = extent.height, .depth = 1}, + }; + scheduler.RequestOutsideRenderPassOperationContext(); + scheduler.Record([source, target, region](vk::CommandBuffer cmdbuf) { + TransitionImageLayout(cmdbuf, target, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_UNDEFINED); + cmdbuf.CopyBufferToImage(source, target, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + std::array{region}); + TransitionImageLayout(cmdbuf, target, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + }); + quad.staging_tick[k] = scheduler.CurrentTick(); + quad.version = overlay_frame.version; + const VkDescriptorImageInfo image_info{ + .sampler = *overlay_sampler, + .imageView = *quad.view, + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + }; + const VkWriteDescriptorSet write{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = quad.sets[0], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &image_info, + .pBufferInfo = nullptr, + .pTexelBufferView = nullptr, + }; + device.GetLogical().UpdateDescriptorSets(std::array{write}, {}); + } + overlay_set[o] = quad.sets[0]; + + auto& push = overlay_push[o]; + push.modelview_matrix = + MakeOrthographicMatrix(f32(layout.width), static_cast(layout.height)); + const auto& screen = layout.screen; + const auto place = Common::PlaceOverlayPanel(overlay_frame, f32(screen.left), + f32(screen.top), f32(screen.right), + f32(screen.bottom)); + const f32 w = place.width; + const f32 h = place.height; + const f32 x = place.x; + const f32 y = place.y; + push.vertices[0] = ScreenRectVertex(x, y, 0.f, 0.f); + push.vertices[1] = ScreenRectVertex(x + w, y, 1.f, 0.f); + push.vertices[2] = ScreenRectVertex(x, y + h, 0.f, 1.f); + push.vertices[3] = ScreenRectVertex(x + w, y + h, 1.f, 1.f); + overlay_draw[o] = true; + quad.used_tick = scheduler.CurrentTick(); + + static u32 logged_quads = 0; + if (logged_quads < 3) { + ++logged_quads; + LOG_INFO(Render_Vulkan, "overlay: quad drawn {}x{} at {},{}", extent.width, + extent.height, x, y); + } + } + scheduler.Record([=](vk::CommandBuffer cmdbuf) { const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; @@ -103,6 +241,18 @@ void WindowAdaptPass::Draw(const Device& device, RasterizerVulkan& rasterizer, S cmdbuf.Draw(4, 1, 0, 0); } + for (size_t o = 0; o < overlay_draw.size(); ++o) { + if (!overlay_draw[o]) { + continue; + } + cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *overlay_pipeline); + cmdbuf.PushConstants(graphics_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, + overlay_push[o]); + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, + 0, overlay_set[o], {}); + cmdbuf.Draw(4, 1, 0, 0); + } + cmdbuf.EndRenderPass(); }); } diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.h b/src/video_core/renderer_vulkan/present/window_adapt_pass.h index 58d6fc01c0..ec9004dc38 100644 --- a/src/video_core/renderer_vulkan/present/window_adapt_pass.h +++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.h @@ -6,9 +6,12 @@ #pragma once +#include +#include #include #include "common/math_util.h" +#include "common/overlay_panels.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Layout { @@ -22,6 +25,7 @@ struct FramebufferConfig; namespace Vulkan { class Device; +class MemoryAllocator; struct Frame; class Layer; class Scheduler; @@ -29,13 +33,15 @@ class RasterizerVulkan; class WindowAdaptPass final { public: - explicit WindowAdaptPass(const Device& device, VkFormat frame_format, vk::Sampler&& sampler, + explicit WindowAdaptPass(const Device& device, MemoryAllocator& memory_allocator, + VkFormat frame_format, vk::Sampler&& sampler, vk::ShaderModule&& fragment_shader); ~WindowAdaptPass(); + /// (With the overlay panels on top only where asked: the screen's, not a capture) void Draw(const Device& device, RasterizerVulkan& rasterizer, Scheduler& scheduler, size_t image_index, std::list& layers, std::span configs, - const Layout::FramebufferLayout& layout, Frame* dst); + const Layout::FramebufferLayout& layout, Frame* dst, bool overlay_panels = false); VkDescriptorSetLayout GetDescriptorSetLayout(); VkRenderPass GetRenderPass(); @@ -47,6 +53,8 @@ private: void CreateRenderPass(const Device& device, VkFormat frame_format); void CreatePipelines(const Device& device); + MemoryAllocator& memory_allocator; + vk::DescriptorSetLayout descriptor_set_layout; vk::PipelineLayout pipeline_layout; vk::Sampler sampler; @@ -56,6 +64,33 @@ private: vk::Pipeline opaque_pipeline; vk::Pipeline premultiplied_pipeline; vk::Pipeline coverage_pipeline; + + // The overlay panels' own pipeline: the plain present shader, pixel for pixel (the scaling + // filter's shader would blur their text) + vk::ShaderModule overlay_shader; + vk::Sampler overlay_sampler; + vk::Pipeline overlay_pipeline; + + // The overlay panels (common/overlay_panels.h): a straight-alpha quad each, composited on + // top of the layers, for both the accelerated and the unaccelerated present paths. + struct OverlayQuad { + vk::Image image; + vk::ImageView view; + vk::DescriptorPool pool; + vk::DescriptorSets sets; + VkExtent2D extent{}; + std::uint64_t version = 0; + bool ready = false; + /// Staging buffers, used in turn: each is written again only once the GPU is past its + /// last copy (normally no wait) + std::array staging; + std::array staging_size{}; + std::array staging_tick{}; + std::size_t next_staging = 0; + /// The GPU tick that last drew the image: replaced only once the GPU is past it + std::uint64_t used_tick = 0; + }; + std::array overlays; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 27ca531186..a1c6c4d907 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -180,6 +180,8 @@ try , frame_gen(memory_allocator, scheduler) #endif { + // The overlay panels go on the screen only: not in screenshots or the applets' capture + blit_swapchain.DrawOverlayPanels(true); if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { turbo_mode.emplace(instance, dld); diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 205382f81a..4228440423 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -44,44 +44,44 @@ void BlitScreen::SetWindowAdaptPass(const Device& device) { switch (scaling_filter) { case Settings::ScalingFilter::NearestNeighbor: - window_adapt = MakeNearestNeighbor(device, swapchain_view_format); + window_adapt = MakeNearestNeighbor(device, memory_allocator, swapchain_view_format); break; case Settings::ScalingFilter::Bicubic: - window_adapt = MakeBicubic(device, swapchain_view_format, VK_CUBIC_FILTER_WEIGHTS_CATMULL_ROM_QCOM); + window_adapt = MakeBicubic(device, memory_allocator, swapchain_view_format, VK_CUBIC_FILTER_WEIGHTS_CATMULL_ROM_QCOM); break; case Settings::ScalingFilter::ZeroTangent: - window_adapt = MakeBicubic(device, swapchain_view_format, VK_CUBIC_FILTER_WEIGHTS_ZERO_TANGENT_CARDINAL_QCOM); + window_adapt = MakeBicubic(device, memory_allocator, swapchain_view_format, VK_CUBIC_FILTER_WEIGHTS_ZERO_TANGENT_CARDINAL_QCOM); break; case Settings::ScalingFilter::BSpline: - window_adapt = MakeBicubic(device, swapchain_view_format, VK_CUBIC_FILTER_WEIGHTS_B_SPLINE_QCOM); + window_adapt = MakeBicubic(device, memory_allocator, swapchain_view_format, VK_CUBIC_FILTER_WEIGHTS_B_SPLINE_QCOM); break; case Settings::ScalingFilter::Mitchell: - window_adapt = MakeBicubic(device, swapchain_view_format, VK_CUBIC_FILTER_WEIGHTS_MITCHELL_NETRAVALI_QCOM); + window_adapt = MakeBicubic(device, memory_allocator, swapchain_view_format, VK_CUBIC_FILTER_WEIGHTS_MITCHELL_NETRAVALI_QCOM); break; case Settings::ScalingFilter::Spline1: - window_adapt = MakeSpline1(device, swapchain_view_format); + window_adapt = MakeSpline1(device, memory_allocator, swapchain_view_format); break; case Settings::ScalingFilter::Gaussian: - window_adapt = MakeGaussian(device, swapchain_view_format); + window_adapt = MakeGaussian(device, memory_allocator, swapchain_view_format); break; case Settings::ScalingFilter::Lanczos: - window_adapt = MakeLanczos(device, swapchain_view_format); + window_adapt = MakeLanczos(device, memory_allocator, swapchain_view_format); break; case Settings::ScalingFilter::ScaleForce: - window_adapt = MakeScaleForce(device, swapchain_view_format); + window_adapt = MakeScaleForce(device, memory_allocator, swapchain_view_format); break; case Settings::ScalingFilter::Area: - window_adapt = MakeArea(device, swapchain_view_format); + window_adapt = MakeArea(device, memory_allocator, swapchain_view_format); break; case Settings::ScalingFilter::Mmpx: - window_adapt = MakeMmpx(device, swapchain_view_format); + window_adapt = MakeMmpx(device, memory_allocator, swapchain_view_format); break; case Settings::ScalingFilter::Fsr: case Settings::ScalingFilter::Sgsr: case Settings::ScalingFilter::SgsrEdge: case Settings::ScalingFilter::Bilinear: default: - window_adapt = MakeBilinear(device, swapchain_view_format); + window_adapt = MakeBilinear(device, memory_allocator, swapchain_view_format); break; } } @@ -155,7 +155,8 @@ void BlitScreen::DrawToFrame(const Device& device, RasterizerVulkan& rasterizer, } } - window_adapt->Draw(device, rasterizer, scheduler, image_index, layers, framebuffers, layout, frame); + window_adapt->Draw(device, rasterizer, scheduler, image_index, layers, framebuffers, layout, frame, + overlay_panels); if (++image_index >= image_count) { image_index = 0; diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 56b429ae53..719e348d43 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h @@ -62,6 +62,12 @@ public: void PrepareFrame(const Device& device, Frame* frame, const Layout::FramebufferLayout& layout); + /// Draws the overlay panels on top (the screen's pass only: never in a screenshot or the + /// applets' capture) + void DrawOverlayPanels(bool draw) { + overlay_panels = draw; + } + [[nodiscard]] vk::Framebuffer CreateFramebuffer(const Device& device, const Layout::FramebufferLayout& layout, VkImageView image_view, VkFormat current_view_format); @@ -83,6 +89,7 @@ private: Settings::ScalingFilter scaling_filter{}; std::unique_ptr window_adapt{}; + bool overlay_panels = false; std::list layers{}; }; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index fff1f8164d..b8840c1689 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -219,9 +219,13 @@ public: void BindTextureBuffer(Buffer& buffer, u32 offset, u32 size, VideoCore::Surface::PixelFormat format) { - guest_descriptor_queue.AddTexelBuffer(buffer.View(offset, size, format), - buffer.DeviceAddress(), offset, size, - TexelBufferFormat(format)); + if (guest_descriptor_queue.UsesDescriptorBuffer()) { + const VkDeviceAddress address = buffer.DeviceAddress(); + const VkFormat vk_format = address == 0 ? VK_FORMAT_UNDEFINED : TexelBufferFormat(format); + guest_descriptor_queue.AddTexelBuffer(VK_NULL_HANDLE, address, offset, size, vk_format); + } else { + guest_descriptor_queue.AddTexelBuffer(buffer.View(offset, size, format)); + } } bool ShouldLimitDynamicStorageBuffers() const { diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 8b5b0bc9c5..c9e4f939b1 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -276,6 +276,9 @@ GraphicsPipeline::GraphicsPipeline( num_textures += Shader::NumDescriptors(info->texture_descriptors); num_image_elements += Shader::NumDescriptors(info->texture_descriptors); num_image_elements += Shader::NumDescriptors(info->image_descriptors); + for (const auto& desc : info->texture_descriptors) { + uses_attribute_handle |= desc.cbuf_index == Shader::ATTRIBUTE_HANDLE_CBUF_INDEX; + } num_descriptor_entries += NumDescriptorEntries(*info); } fragment_has_color0_output = stage_infos[NUM_STAGES - 1].stores_frag_color[0]; @@ -375,6 +378,9 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) { } const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers}; const auto read_handle{[&](const auto& desc, u32 index) { + if (desc.cbuf_index == Shader::ATTRIBUTE_HANDLE_CBUF_INDEX) { + return TexturePair(attribute_handle, via_header_index); + } ASSERT(cbufs[desc.cbuf_index].enabled); const u32 index_offset{index << desc.size_shift}; const u32 offset{desc.cbuf_offset + index_offset}; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index b1ac5a3fcc..a6edab8bc0 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -110,6 +110,16 @@ public: return configure_func(this, is_indexed); } + /// True when a shader samples a texture whose handle arrives as a vertex attribute. + [[nodiscard]] bool UsesAttributeHandle() const noexcept { + return uses_attribute_handle; + } + + /// Handle bound to those textures by the next Configure. + void SetAttributeHandle(u32 handle) noexcept { + attribute_handle = handle; + } + [[nodiscard]] GraphicsPipeline* Next(const GraphicsPipelineCacheKey& current_key) noexcept { if (key == current_key) { return this; @@ -168,6 +178,8 @@ private: u32 num_descriptor_entries{}; size_t num_image_elements{}; u32 num_textures{}; + u32 attribute_handle{}; + bool uses_attribute_handle{}; bool fragment_has_color0_output{}; vk::DescriptorSetLayout descriptor_set_layout; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index a85e2811a3..228c2c41f8 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -447,7 +447,9 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE || driver_id == VK_DRIVER_ID_MESA_RADV || driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS || - driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA, + driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA || + driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || + driver_id == VK_DRIVER_ID_MESA_TURNIP, .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS, .has_broken_spirv_position_input = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY, @@ -491,6 +493,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), .support_conditional_barrier = device.SupportsConditionalBarriers(), .single_lane_geometry_subgroups = !profile.SupportsSubgroupStage(Shader::Stage::Geometry), + .support_attribute_texture_handle = true, }; host_info.ApplyDescriptorLimitPolicy(); @@ -787,6 +790,11 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const if (!use_asynchronous_shaders) { return pipeline; } + // If something is using depth, we can assume that games are not rendering anything which + // will be used one time. + if (maxwell3d->regs.zeta_enable) { + return nullptr; + } // If games are using a small index count, we can assume these are full screen quads. // Usually these shaders are only used once for building textures so we can assume they // can't be built async diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f43bea1220..1483d37355 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -82,7 +82,12 @@ VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t in if (lower_left) { // Flip by surface clip height - y += conv(static_cast(regs.surface_clip.height)); + const float clip_height = conv(static_cast(regs.surface_clip.height)); + if (src.scale_y < 0.0f && y >= clip_height) { + y = clip_height - y; + } else { + y += clip_height; + } height = -height; } @@ -248,6 +253,15 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; // update engine as channel may be different. pipeline->SetEngine(maxwell3d, gpu_memory); + attribute_handle_pipeline = nullptr; + attribute_handle_runs.clear(); + if (split_attribute_handles && pipeline->UsesAttributeHandle()) { + CollectAttributeHandleRuns(is_indexed); + if (!attribute_handle_runs.empty()) { + attribute_handle_pipeline = pipeline; + pipeline->SetAttributeHandle(attribute_handle_runs.front().handle); + } + } if (!pipeline->Configure(is_indexed)) return; @@ -259,22 +273,110 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { draw_func(); } +void RasterizerVulkan::CollectAttributeHandleRuns(bool is_indexed) { + using VertexAttribute = Maxwell::VertexAttribute; + const auto& regs = maxwell3d->regs; + const auto& draw_state = maxwell3d->draw_manager.draw_state; + const u32 total = is_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count; + if (total == 0) { + return; + } + // The handle is an integer attribute; sprite batches repeat it on every vertex of a quad. + const VertexAttribute* source{}; + for (const auto& attr : regs.vertex_attrib_format) { + if (attr.constant || attr.size == VertexAttribute::Size::Invalid) { + continue; + } + if (attr.type == VertexAttribute::Type::UInt || attr.type == VertexAttribute::Type::SInt) { + source = &attr; + break; + } + } + const auto& stream = regs.vertex_streams[source ? source->buffer.Value() : 0]; + if (!source || !stream.IsEnabled()) { + attribute_handle_runs.push_back({0, total, 0}); + return; + } + // Only plain triangle lists are split; anything else keeps the handle of its first vertex. + const u32 primitive_size = + draw_state.topology == Maxwell::PrimitiveTopology::Triangles ? 3 : total; + const GPUVAddr base_address = stream.Address() + source->offset; + const auto read_handle = [&](u32 position) { + u32 vertex; + if (is_indexed) { + const auto& index_buffer = draw_state.index_buffer; + const GPUVAddr address = + index_buffer.IndexStart() + size_t{position} * index_buffer.FormatSizeInBytes(); + u32 index{}; + gpu_memory->ReadBlockUnsafe(address, &index, index_buffer.FormatSizeInBytes()); + vertex = static_cast(draw_state.base_index + index); + } else { + vertex = draw_state.vertex_buffer.first + position; + } + return gpu_memory->Read(base_address + static_cast(vertex) * stream.stride); + }; + for (u32 position = 0; position + primitive_size <= total; position += primitive_size) { + const u32 handle = read_handle(position); + if (!attribute_handle_runs.empty() && attribute_handle_runs.back().handle == handle) { + attribute_handle_runs.back().count += primitive_size; + } else { + attribute_handle_runs.push_back({position, primitive_size, handle}); + } + } + if (attribute_handle_runs.empty()) { + attribute_handle_runs.push_back({0, total, read_handle(0)}); + } else { + const u32 covered = attribute_handle_runs.back().first + attribute_handle_runs.back().count; + if (covered < total) { + attribute_handle_runs.back().count += total - covered; + } + } +} + void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { + split_attribute_handles = true; + SCOPE_EXIT { + split_attribute_handles = false; + }; PrepareDraw(is_indexed, [this, is_indexed, instance_count] { const auto& draw_state = maxwell3d->draw_manager.draw_state; const u32 num_instances{instance_count}; const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)}; - scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { - if (draw_params.is_indexed) { - cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, - draw_params.first_index, draw_params.base_vertex, - draw_params.base_instance); - } else { - cmdbuf.Draw(draw_params.num_vertices, draw_params.num_instances, - draw_params.base_vertex, draw_params.base_instance); + const auto record_draw = [this](const DrawParams& params) { + scheduler.Record([params](vk::CommandBuffer cmdbuf) { + if (params.is_indexed) { + cmdbuf.DrawIndexed(params.num_vertices, params.num_instances, + params.first_index, params.base_vertex, + params.base_instance); + } else { + cmdbuf.Draw(params.num_vertices, params.num_instances, params.base_vertex, + params.base_instance); + } + }); + }; + if (attribute_handle_pipeline && attribute_handle_runs.size() > 1) { + // The first run is already configured, each further one binds its own texture. + for (size_t i = 0; i < attribute_handle_runs.size(); ++i) { + const AttributeHandleRun& run = attribute_handle_runs[i]; + if (i != 0) { + attribute_handle_pipeline->SetAttributeHandle(run.handle); + if (!attribute_handle_pipeline->Configure(is_indexed)) { + continue; + } + } + DrawParams run_params = draw_params; + run_params.num_vertices = run.count; + if (is_indexed) { + run_params.first_index += run.first; + } else { + run_params.base_vertex += run.first; + } + record_draw(run_params); } - }); + } else { + record_draw(draw_params); + } // Log draw call if (GPU::Logging::IsActive() && diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 7470aa4f14..fcef3b9149 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -157,6 +157,20 @@ private: template void PrepareDraw(bool is_indexed, Func&&); + /// A stretch of a draw whose vertices all carry the same texture handle. + struct AttributeHandleRun { + u32 first; + u32 count; + u32 handle; + }; + + /// Splits the current draw wherever the texture handle carried in the vertex data changes. + void CollectAttributeHandleRuns(bool is_indexed); + + std::vector attribute_handle_runs; + GraphicsPipeline* attribute_handle_pipeline{}; + bool split_attribute_handles{}; + void FlushWork(); void UpdateDynamicStates(); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 583cb6edaf..36e0857c86 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1089,6 +1089,58 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk return *shadow.view; } +VkImageView TextureCacheRuntime::GetOrCreateTirColorScratch(VkImage color_image, VkFormat format, + VkExtent2D extent, u32 layers, + VkSampleCountFlagBits samples) { + TirColorScratch& scratch = tir_color_scratch[color_image]; + if (scratch.image && scratch.format == format && scratch.extent.width == extent.width && + scratch.extent.height == extent.height && scratch.layers == layers && + scratch.samples == samples) { + return *scratch.view; + } + if (scratch.image) { + scheduler.Finish(); + } + scratch.image = memory_allocator.CreateImage(VkImageCreateInfo{ + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = format, + .extent = {extent.width, extent.height, 1}, + .mipLevels = 1, + .arrayLayers = layers, + .samples = samples, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }); + scratch.view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .image = *scratch.image, + .viewType = layers > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, + .format = format, + .components{}, + .subresourceRange{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = layers, + }, + }); + scratch.format = format; + scratch.extent = extent; + scratch.layers = layers; + scratch.samples = samples; + return *scratch.view; +} + const TextureCacheRuntime::ResolveShadow* TextureCacheRuntime::GetValidResolveShadow( VkImage msaa_image) const { const auto it = resolve_shadows.find(msaa_image); @@ -2970,6 +3022,26 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, ImageView* color_buffer, Framebuffer::~Framebuffer() = default; +/// Single-sampled color targets with a multisampled depth buffer, as used by target-independent +/// rasterization. Vulkan requires matching sample counts for these attachments. +static bool IsMixedSamplesTarget(std::span color_buffers, + const ImageView* depth_buffer) { + if (depth_buffer == nullptr || depth_buffer->Samples() == VK_SAMPLE_COUNT_1_BIT) { + return false; + } + bool has_color = false; + for (const ImageView* const color_buffer : color_buffers) { + if (color_buffer == nullptr) { + continue; + } + if (color_buffer->Samples() != VK_SAMPLE_COUNT_1_BIT) { + return false; + } + has_color = true; + } + return has_color; +} + void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, std::span color_buffers, ImageView* depth_buffer, bool is_rescaled_) { @@ -3024,6 +3096,13 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, } else { renderpass_key.depth_format = PixelFormat::Invalid; } + if (IsMixedSamplesTarget(color_buffers, depth_buffer)) { + const VkExtent2D extent{(std::min)(render_area.width, width), + (std::min)(render_area.height, height)}; + CreateMixedSamplesFramebuffer(runtime, color_buffers, attachments, renderpass_key, + static_cast((std::max)(num_layers, 1)), extent); + return; + } renderpass_key.samples = samples; const bool do_resolve_color = ENABLE_MSAA_TILER_RESOLVE && samples != VK_SAMPLE_COUNT_1_BIT && num_colors > 0 && runtime.device.IsTiler(); @@ -3040,10 +3119,7 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, discard_msaa_depth_stencil = ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_DEPTH_STENCIL_DISCARD && do_resolve_depth_stencil; - renderpass = runtime.render_pass_cache.Get(renderpass_key); - render_pass_key = renderpass_key; - render_pass_cache = &runtime.render_pass_cache; - runtime_ptr = &runtime; + UseRenderPass(runtime, renderpass_key); render_area.width = (std::min)(render_area.width, width); render_area.height = (std::min)(render_area.height, height); @@ -3075,6 +3151,53 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, } num_color_buffers = static_cast(num_colors); + CreateVkFramebuffer(runtime, attachments, static_cast((std::max)(num_layers, 1))); +} + +void Framebuffer::CreateMixedSamplesFramebuffer(TextureCacheRuntime& runtime, + std::span color_buffers, + std::span attachments, + RenderPassKey renderpass_key, u32 layers, + VkExtent2D extent) { + // attachments holds the real color targets followed by the depth buffer + const size_t num_colors = attachments.size() - 1; + boost::container::small_vector mixed_attachments; + for (const ImageView* const color_buffer : color_buffers) { + if (!color_buffer) { + continue; + } + const VkFormat vk_format = MaxwellToVK::SurfaceFormat(runtime.device, FormatType::Optimal, + true, color_buffer->format) + .format; + mixed_attachments.push_back(runtime.GetOrCreateTirColorScratch( + color_buffer->ImageHandle(), vk_format, extent, layers, samples)); + } + mixed_attachments.push_back(attachments[num_colors]); + for (size_t index = 0; index < num_colors; ++index) { + mixed_attachments.push_back(attachments[index]); + } + // Multisampled scratch color + depth, resolving color into the real single-sampled targets + renderpass_key.samples = samples; + renderpass_key.resolve_color = true; + renderpass_key.resolve_depth_stencil = false; + discard_msaa_color = false; + discard_msaa_depth_stencil = false; + UseRenderPass(runtime, renderpass_key); + render_area = extent; + num_color_buffers = static_cast(num_colors); + CreateVkFramebuffer(runtime, mixed_attachments, layers); +} + +void Framebuffer::UseRenderPass(TextureCacheRuntime& runtime, + const RenderPassKey& renderpass_key) { + renderpass = runtime.render_pass_cache.Get(renderpass_key); + render_pass_key = renderpass_key; + render_pass_cache = &runtime.render_pass_cache; + runtime_ptr = &runtime; +} + +void Framebuffer::CreateVkFramebuffer(TextureCacheRuntime& runtime, + std::span attachments, u32 layers) { framebuffer = runtime.device.GetLogical().CreateFramebuffer({ .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, .pNext = nullptr, @@ -3084,7 +3207,7 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, .pAttachments = attachments.data(), .width = render_area.width, .height = render_area.height, - .layers = static_cast((std::max)(num_layers, 1)), + .layers = layers, }); } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 2e9736f707..cdfe56ab05 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -133,6 +133,11 @@ public: [[nodiscard]] const ResolveShadow* GetValidResolveShadow(VkImage msaa_image) const; + /// Multisampled stand-in for a single-sampled color target rendered with a TIR depth buffer + [[nodiscard]] VkImageView GetOrCreateTirColorScratch(VkImage color_image, VkFormat format, + VkExtent2D extent, u32 layers, + VkSampleCountFlagBits samples); + void InvalidateResolveShadow(VkImage msaa_image); void MarkResolveShadowUpToDate(VkImage msaa_image); @@ -187,6 +192,15 @@ public: std::vector msaa_scratch_images; ::Common::unordered_map resolve_shadows; + struct TirColorScratch { + vk::Image image; + vk::ImageView view; + VkFormat format = VK_FORMAT_UNDEFINED; + VkExtent2D extent{}; + u32 layers = 0; + VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; + }; + ::Common::unordered_map tir_color_scratch; std::vector> pending_resolve_shadows; }; @@ -279,6 +293,22 @@ public: void MarkResolveShadowsUpToDate() const; private: + /// Builds a framebuffer for single-sampled color targets drawn with a multisampled depth + /// buffer (target-independent rasterization). Color is rendered into multisampled scratch + /// images that resolve into the real targets at the end of the pass. + void CreateMixedSamplesFramebuffer(TextureCacheRuntime& runtime, + std::span color_buffers, + std::span attachments, + RenderPassKey renderpass_key, u32 layers, + VkExtent2D extent); + + /// Fetches the render pass for the key from the cache and remembers it for variants. + void UseRenderPass(TextureCacheRuntime& runtime, const RenderPassKey& renderpass_key); + + /// Creates the Vulkan framebuffer for the current render pass and render area. + void CreateVkFramebuffer(TextureCacheRuntime& runtime, + std::span attachments, u32 layers); + static constexpr size_t NUM_MEMOIZED_RENDER_PASS_VARIANTS = 8; vk::Framebuffer framebuffer; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index e92e54f8ce..5dd866451e 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1928,7 +1928,26 @@ ImageViewId TextureCache

::FindDepthBuffer() { if (gpu_addr == 0) { return ImageViewId{}; } - const ImageInfo info(regs.zeta, regs.zeta_size, regs.anti_alias_samples_mode); + // Target-independent rasterization: the depth buffer keeps the raster sample count while + // the color targets use anti_alias_samples_mode. + Tegra::Texture::MsaaMode zeta_msaa_mode = regs.anti_alias_samples_mode; + if (regs.anti_alias_raster != Tegra::Engines::Maxwell3D::Regs::AntiAliasRaster::Mode1x1) { + const auto raster_mode = static_cast(regs.anti_alias_raster); + bool use_raster = regs.tir_mode == Tegra::Engines::Maxwell3D::Regs::TIRMode::RasterNTargetM; + if (!use_raster && regs.anti_alias_samples_mode == Tegra::Texture::MsaaMode::Msaa1x1) { + // Clears can be issued before tir_mode is enabled. Only a depth buffer sized for the + // raster samples relative to the color target is treated as multisampled, otherwise + // it ping-pongs between a 1x and a multisampled image every frame. + const auto& rt0 = regs.rt[0]; + use_raster = rt0.Address() != 0 && rt0.format != Tegra::RenderTargetFormat::NONE && + regs.zeta_size.width == rt0.width * NumSamplesX(raster_mode) && + regs.zeta_size.height == rt0.height * NumSamplesY(raster_mode); + } + if (use_raster) { + zeta_msaa_mode = raster_mode; + } + } + const ImageInfo info(regs.zeta, regs.zeta_size, zeta_msaa_mode); return FindRenderTargetView(info, gpu_addr); } diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index b93080f2a1..6d7c25e15b 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -43,6 +43,8 @@ add_executable(yuzu configuration/configure_applets.cpp configuration/configure_applets.h configuration/configure_applets.ui + configuration/configure_modern_per_game.cpp + configuration/configure_modern_per_game.h configuration/configure_audio.cpp configuration/configure_audio.h configuration/configure_audio.ui @@ -90,6 +92,8 @@ add_executable(yuzu configuration/configure_input_advanced.cpp configuration/configure_input_advanced.h configuration/configure_input_advanced.ui + configuration/configure_player_assignment.cpp + configuration/configure_player_assignment.h configuration/configure_input_per_game.cpp configuration/configure_input_per_game.h configuration/configure_input_per_game.ui @@ -194,6 +198,8 @@ add_executable(yuzu multiplayer/state.cpp multiplayer/state.h multiplayer/validation.h + overlay_panel.cpp + overlay_panel.h startup_checks.cpp startup_checks.h set_play_time_dialog.cpp @@ -204,6 +210,8 @@ add_executable(yuzu util/controller_navigation.h util/limitable_input_dialog.cpp util/limitable_input_dialog.h + util/gamescope.cpp + util/gamescope.h util/overlay_dialog.cpp util/overlay_dialog.h util/overlay_dialog.ui diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui index 78a340beed..03c8e28bed 100644 --- a/src/yuzu/aboutdialog.ui +++ b/src/yuzu/aboutdialog.ui @@ -128,7 +128,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://nitter.poast.org/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="https://eden-emulator.github.io/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.eden-emu.dev"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/activity/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://discord.gg/HstXbPch7X"><span style=" text-decoration: underline; color:#039be5;">Discord</span></a> | <a href="https://stt.gg/qKgFEAbH"><span style=" text-decoration: underline; color:#039be5;">Stoat</span></a> | <a href="https://x.com/edenemuofficial"><span style=" text-decoration: underline; color:#039be5;">Twitter</span></a> | <a href="https://git.eden-emu.dev/eden-emu/eden/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> true diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index aa77e082bd..583565fdbf 100644 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp @@ -19,6 +19,7 @@ #include "yuzu/applets/qt_software_keyboard.h" #include "yuzu/main_window.h" #include "yuzu/util/overlay_dialog.h" +#include "yuzu/util/gamescope.h" namespace { @@ -42,8 +43,12 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog( is_inline{is_inline_}, initialize_parameters{std::move(initialize_parameters_)} { ui->setupUi(this); + // Under gamescope only one normal window shows at a time: a window bypassing the window + // manager is drawn over the game instead of in its place + const bool gamescope = Gamescope::IsRunningUnder(); setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowTitleHint | - Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint); + Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint | + (gamescope ? Qt::X11BypassWindowManagerHint : Qt::WindowFlags{})); setWindowModality(Qt::WindowModal); setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_TranslucentBackground); diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 308db3621b..ccebaf2513 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -131,7 +131,8 @@ GRenderWindow::GRenderWindow(MainWindow* parent, strict_context_required = QGuiApplication::platformName() == QStringLiteral("wayland") || QGuiApplication::platformName() == QStringLiteral("wayland-egl"); - connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &MainWindow::OnLoadComplete); + connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &MainWindow::OnLoadComplete, + Qt::QueuedConnection); connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &MainWindow::OnExecuteProgram, Qt::QueuedConnection); connect(this, &GRenderWindow::ExitSignal, parent, &MainWindow::OnExit, Qt::QueuedConnection); @@ -178,11 +179,6 @@ bool GRenderWindow::IsShown() const { return !isMinimized(); } -// On Qt 5.0+, this correctly gets the size of the framebuffer (pixels). -// -// Older versions get the window size (density independent pixels), -// and hence, do not support DPI scaling ("retina" displays). -// The result will be a viewport that is smaller than the extent of the window. void GRenderWindow::OnFramebufferSizeChanged() { // Screen changes potentially incur a change in screen DPI, hence we should update the // framebuffer size diff --git a/src/yuzu/configuration/configure_applets.cpp b/src/yuzu/configuration/configure_applets.cpp index 139bfa9da3..2ed88f1f77 100644 --- a/src/yuzu/configuration/configure_applets.cpp +++ b/src/yuzu/configuration/configure_applets.cpp @@ -1,6 +1,21 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "common/controller_console_state.h" #include "common/settings.h" #include "core/core.h" #include "ui_configure_applets.h" @@ -47,6 +62,16 @@ void ConfigureApplets::Setup(const ConfigurationShared::Builder& builder) { push(Settings::values.linkage.by_category[Settings::Category::LibraryApplet]); for (auto setting : settings) { + // The Modern Console options are the Controllers tab's (and a game's Modern Console + // tab). Skipped before they are built: building registers how to apply them. + if (setting->Id() == Settings::values.console_debug_overlay.Id() || + setting->Id() == Settings::values.console_hints.Id() || + setting->Id() == Settings::values.console_joycon_auto.Id() || + setting->Id() == Settings::values.console_pause_disconnect.Id() || + setting->Id() == Settings::values.console_player_lights.Id() || + setting->Id() == Settings::values.console_button_labels.Id()) { + continue; + } ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs); if (widget == nullptr) { diff --git a/src/yuzu/configuration/configure_applets.h b/src/yuzu/configuration/configure_applets.h index b794b49e0b..acd91dff8d 100644 --- a/src/yuzu/configuration/configure_applets.h +++ b/src/yuzu/configuration/configure_applets.h @@ -6,12 +6,17 @@ #pragma once +#include #include #include "yuzu/configuration/configuration_shared.h" class QCheckBox; -class QLineEdit; +class QComboBox; class QDateTimeEdit; +class QLabel; +class QLineEdit; +class QPushButton; +class QTimer; namespace Core { class System; } diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 547008262e..f4d94a47b3 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -121,6 +121,23 @@ ConfigureDialog::~ConfigureDialog() = default; void ConfigureDialog::SetConfiguration() {} +void ConfigureDialog::OpenPlayerTab(int player) { + QWidget* tab = input_tab->PlayerTab(player); + if (!tab) { + return; + } + // Controls is the page whose tabs are the input tab's + for (int row = 0; row < ui->selectorList->count(); ++row) { + const auto tabs = + qvariant_cast>(ui->selectorList->item(row)->data(Qt::UserRole)); + if (tabs.contains(tab)) { + ui->selectorList->setCurrentRow(row); + ui->tabWidget->setCurrentWidget(tab); + return; + } + } +} + void ConfigureDialog::ApplyConfiguration() { general_tab->ApplyConfiguration(); ui_tab->ApplyConfiguration(); diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index 73db11238e..65a086e5c9 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -55,6 +55,9 @@ public: Core::System& system_, bool enable_web_config = true); ~ConfigureDialog() override; + /// Opens on a player's tab of the Controls page (0-based player) + void OpenPlayerTab(int player); + void ApplyConfiguration(); private slots: diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 641f65d82a..c0d6b90d8a 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -4,6 +4,7 @@ // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +38,7 @@ #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics.h" #include "yuzu/configuration/shared_widget.h" +#include "yuzu/util/gamescope.h" #ifdef HAS_RESHADE #include "yuzu/configuration/configure_post_processing.h" @@ -79,7 +82,10 @@ ConfigureGraphics::ConfigureGraphics( } index++; } - if (static_cast(index) < vsync_mode_combobox_enum_map.size()) { + // (A mode greyed out for Game Mode is never selected) + const auto* vsync_model = qobject_cast(vsync_mode_combobox->model()); + if (static_cast(index) < vsync_mode_combobox_enum_map.size() && + (!vsync_model || vsync_model->item(index)->isEnabled())) { vsync_mode_combobox->setCurrentIndex(index); } @@ -169,6 +175,35 @@ void ConfigureGraphics::PopulateVSyncModeSelection(bool use_setting) { index++; } + // In Steam's Game Mode, gamescope offers only some present modes: the others are listed + // greyed out, saying how to get them, rather than missing without a word + const bool gamescope = Gamescope::IsRunningUnder(); + if (gamescope && backend == Settings::RendererBackend::Vulkan) { + auto* model = qobject_cast(vsync_mode_combobox->model()); + for (const auto missing : {VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR, + VK_PRESENT_MODE_MAILBOX_KHR}) { + if (std::find(present_modes.begin(), present_modes.end(), missing) != + present_modes.end()) { + continue; + } + const auto mode_name = TranslateVSyncMode(missing, backend); + if (mode_name.isEmpty() || !model) { + continue; + } + vsync_mode_combobox->insertItem(index, + tr("%1 - unavailable in Game Mode").arg(mode_name)); + vsync_mode_combobox->setItemData( + index, + tr("Steam's Game Mode does not offer this mode by default. In Steam's Performance " + "settings, turn off Disable Frame Limit and turn on Allow Tearing, then open " + "these settings again."), + Qt::ToolTipRole); + model->item(index)->setEnabled(false); + vsync_mode_combobox_enum_map.push_back(missing); + index++; + } + } + if (!Settings::IsConfiguringGlobal()) { vsync_restore_global_button->setVisible(!Settings::values.vsync_mode.UsingGlobal()); diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 4473df901e..24dcbb665b 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -4,9 +4,34 @@ // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common/controller_console_state.h" #include "common/settings.h" #include "common/settings_enums.h" #include "core/core.h" @@ -15,6 +40,7 @@ #include "core/hle/service/sm/sm.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" +#include "qt_common/config/uisettings.h" #include "qt_common/qt_compat.h" #include "ui_configure_input.h" #include "ui_configure_input_advanced.h" @@ -25,6 +51,7 @@ #include "yuzu/configuration/configure_input_advanced.h" #include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_motion_touch.h" +#include "yuzu/configuration/configure_player_assignment.h" #include "yuzu/configuration/configure_ringcon.h" #include "yuzu/configuration/configure_touchscreen_advanced.h" #include "yuzu/configuration/configure_vibration.h" @@ -142,6 +169,334 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged, [this](bool is_handheld) { UpdateDockedState(is_handheld); }); + // The Controllers tab comes first: how players are assigned, and who is which player now + assignment = new ConfigurePlayerAssignment(this); + assignment->setAccessibleName(tr("Controllers")); + assignment->SetOpenPlayerTab([this](int player) { + for (QWidget* parent = player_tabs[player]->parentWidget(); parent; + parent = parent->parentWidget()) { + if (auto* tabs = qobject_cast(parent)) { + tabs->setCurrentWidget(player_tabs[player]); + return; + } + } + }); + + // Console Mode first in the Controllers tab: a mirror of the player tabs' Docked/Handheld + // choice, which stays the one applied + { + auto* console_box = new QGroupBox(tr("Console Mode"), assignment); + auto* console_layout = new QHBoxLayout(console_box); + auto* console_group = new QButtonGroup(console_box); + console_layout->addWidget(ConfigurePlayerAssignment::MakeSegmented( + console_box, {tr("Docked"), tr("Handheld")}, {0, 1}, console_group)); + console_layout->addStretch(1); + auto* docked = console_group->button(0); + auto* handheld = console_group->button(1); + assignment->AddTopWidget(console_box); + const auto mirror = [this, docked, handheld] { + docked->setChecked(ui->radioDocked->isChecked()); + handheld->setChecked(ui->radioUndocked->isChecked()); + docked->setEnabled(ui->radioDocked->isEnabled()); + handheld->setEnabled(ui->radioUndocked->isEnabled()); + }; + connect(ui->radioDocked, &QRadioButton::toggled, this, mirror); + connect(ui->radioUndocked, &QRadioButton::toggled, this, mirror); + connect(docked, &QAbstractButton::clicked, this, + [this] { ui->radioDocked->setChecked(true); }); + connect(handheld, &QAbstractButton::clicked, this, + [this] { ui->radioUndocked->setChecked(true); }); + mirror_console_mode = mirror; + mirror(); + } + + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + followed_generation = state.generation; + } + follow_timer = new QTimer(this); + connect(follow_timer, &QTimer::timeout, this, [this] { + unsigned long long generation = 0; + std::vector rows; + bool engine_active = false; + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + generation = state.generation; + engine_active = state.engine_active; + rows = state.players; + } + last_rows = rows; + // In the automatic modes only the players' tabs show, and connection can't be toggled + const auto mode = Settings::values.controller_applet_mode.GetValue(); + const bool automatic = mode == Settings::AppletMode::ConsoleMode || + mode == Settings::AppletMode::HandheldConsoleMode; + QTabWidget* tabs = nullptr; + for (QWidget* parent = player_tabs[0]->parentWidget(); parent && !tabs; + parent = parent->parentWidget()) { + tabs = qobject_cast(parent); + } + // The tabs follow the engine's rows and flashes, like the overlay + constexpr long long flash_ms = 1500; + const long long now = QDateTime::currentMSecsSinceEpoch(); + // The player tabs' choice can be locked (player 1 set to Handheld) without toggling + if (mirror_console_mode) { + mirror_console_mode(); + } + // The tabs show the battery percent only while they all fit with it (else the bar + // scrolls, or squeezes the labels on macOS). Judged with "100%" so it doesn't flicker. + bool tab_percents = true; + if (tabs) { + QFont bold = tabs->tabBar()->font(); + bold.setBold(true); + const QFontMetrics fm{bold}; + int shown_extra = 0; + int most_extra = 0; + for (int t = 0; t < tabs->count(); ++t) { + if (!tabs->isTabVisible(t) || tabs->tabIcon(t).isNull()) { + continue; + } + const QString text = tabs->tabText(t); + const int at = text.lastIndexOf(QLatin1Char(' ')); + if (text.endsWith(QLatin1Char('%')) && at > 0) { + shown_extra += fm.horizontalAdvance(text.mid(at)); + } + most_extra += fm.horizontalAdvance(QStringLiteral(" 100%")); + } + const int need = tabs->tabBar()->sizeHint().width() - shown_extra + most_extra; + tab_percents = need <= tabs->width() - 8; + } + // Several players: the tabs drag and carry arrows; one alone has nothing to reorder + const bool several = + std::count_if(rows.begin(), rows.end(), [](const auto& r) { return !r.leaving; }) > 1; + for (std::size_t i = 0; i < player_tabs.size(); ++i) { + const auto row = std::find_if(rows.begin(), rows.end(), [i](const auto& r) { + return r.player == static_cast(i); + }); + bool shown = true; + const QColor label; // the tab's own text colour: the bubbles colour themselves + tab_lit[i] = 0; + if (automatic) { + shown = engine_active && row != rows.end(); + // Lit as the menu bar's chips are + const long long elapsed = shown ? now - row->flash_since : 0; + const bool blink = + shown && row->flash != 0 && elapsed < flash_ms && (elapsed / 125) % 2 == 0; + if (blink && row->flash == 2) { + tab_lit[i] = 3; + } else if (shown && row->active && !row->leaving) { + tab_lit[i] = 1; + } else if (blink) { + tab_lit[i] = 2; + } + } + if (tabs && !tab_dragging) { + if (const int index = tabs->indexOf(player_tabs[i]); index >= 0) { + if (player_tab_titles[i].isEmpty()) { + player_tab_titles[i] = tabs->tabText(index); + } + // Only what changed: each of these lays the tab bar out again + const auto set_text = [tabs, index](const QString& text) { + if (tabs->tabText(index) != text) { + tabs->setTabText(index, text); + } + }; + const auto set_tip = [tabs, index](const QString& tip) { + if (tabs->tabToolTip(index) != tip) { + tabs->setTabToolTip(index, tip); + } + }; + if (tabs->isTabVisible(index) != shown) { + tabs->setTabVisible(index, shown); + } + if (tabs->tabBar()->tabTextColor(index) != label) { + tabs->tabBar()->setTabTextColor(index, label); + } + // The controller's battery as the tab's icon, when it tells its charge + const int battery = automatic && shown && row->battery >= 0 && !row->leaving + ? row->battery * 2 + (row->charging ? 1 : 0) + : -1; + // (Also when the tab lost it: the dialog re-adds the tabs on page changes) + if (tab_battery[i] != battery || + tabs->tabIcon(index).isNull() != (battery < 0)) { + tab_battery[i] = battery; + tabs->setTabIcon(index, + battery < 0 ? QIcon{} + : QIcon(ConfigurePlayerAssignment::Battery( + row->battery, row->charging))); + } + if (!automatic) { + set_text(player_tab_titles[i]); + set_tip({}); + } else if (shown) { + // The grip shows the tab drags; the percent is in the label so the tab + // has room for it (the icon is drawn after it) + const QString percent = battery < 0 || !tab_percents + ? QString{} + : QStringLiteral(" %1%").arg(row->battery); + set_text((several ? QStringLiteral("\u283F P%1").arg(i + 1) + : QStringLiteral("P%1").arg(i + 1)) + + percent); + const QString battery_tip = + battery < 0 ? QString{} + : row->charging + ? tr("\nBattery %1% (charging)").arg(row->battery) + : tr("\nBattery %1%").arg(row->battery); + set_tip(tr("P%1: %2\nDrag left or right to change the player order") + .arg(i + 1) + .arg(QString::fromStdString(row->name)) + + battery_tip); + } + } + } + player_controllers[i]->SetConnectionLocked(automatic); + } + // In the automatic modes the player tabs drag to change the player order + if (tabs) { + const bool controls_page = tabs->indexOf(player_tabs[0]) >= 0; + tabs_editable = automatic && engine_active && controls_page && several; + // Under the dark themes Qt's drag would show the theme's tab: Eden drags it instead + tabs->setMovable(tabs_editable && !UISettings::IsDarkTheme()); + // Pill tabs in the players' colours (the tab bar is shared with the dialog's other + // pages: only on this page) + QTabBar* bar = tabs->tabBar(); + const bool pills = automatic && controls_page; + // (The bar is remembered: under a style sheet its style() is a wrapper, not ours) + if (pills && pill_bar != bar) { + auto* style = new PlayerTabStyle(QApplication::style()->name()); + style->setParent(bar); + bar->setStyle(style); + // (The battery icons' own shape: a square icon would shrink them) + bar->setIconSize(QSize(20, 12)); + pill_bar = bar; + } else if (!pills && pill_bar == bar) { + bar->setIconSize(QSize{}); + bar->setStyle(nullptr); + pill_bar = nullptr; + } + // The Midnight Blue themes resize a hovered tab (a 1-pixel border, less padding), so + // the page shook on hover: the hovered tab keeps its size + const bool midnight = QString::fromStdString(UISettings::values.theme) + .contains(QStringLiteral("midnight")); + const QString steady = + midnight ? QStringLiteral("QTabBar::tab:top:!selected:hover { padding-left: 7px; " + "padding-right: 7px; padding-top: 1px; " + "padding-bottom: 1px; }") + : QString{}; + if (bar->styleSheet() != steady) { + bar->setStyleSheet(steady); + } + // The dark themes' style sheet draws the tabs itself: the bubbles are painted over it + const bool painted = pills && UISettings::IsDarkTheme(); + if (painted) { + if (!tab_overlay || tab_overlay->parentWidget() != bar) { + delete tab_overlay; + tab_overlay = + new PlayerTabOverlay(bar, QString::fromStdString(UISettings::values.theme) + .contains(QStringLiteral("midnight")) + ? QColor(0x19, 0x23, 0x2D) + : QColor(0x31, 0x36, 0x3B)); + } + if (tab_overlay->geometry() != bar->rect()) { + tab_overlay->setGeometry(bar->rect()); + } + if (!tab_overlay->isVisible()) { + tab_overlay->lower(); + tab_overlay->show(); + } + tab_overlay->update(); + } else if (tab_overlay) { + tab_overlay->hide(); + } + // A player tab's colour is what makes it a bubble: none outside these modes + for (std::size_t i = 0; i < player_tabs.size(); ++i) { + if (const int index = tabs->indexOf(player_tabs[i]); index >= 0) { + const QVariant tab_data = + pills ? QVariant(QVariantList{ + ConfigurePlayerAssignment::PlayerColor(static_cast(i)), + tab_lit[i]}) + : QVariant{}; + if (bar->tabData(index) != tab_data) { + bar->setTabData(index, tab_data); + bar->update(); // (lit or not: the bubble repaints) + } + } + } + if (tabs != drag_tabs) { + drag_tabs = tabs; + tabs->tabBar()->installEventFilter(this); + connect(tabs, &QTabWidget::currentChanged, this, &ConfigureInput::UpdateTabArrows); + } + if (pending_select >= 0) { + const int index = tabs->indexOf(player_tabs[pending_select]); + if (index >= 0 && tabs->isTabVisible(index)) { + tabs->setCurrentIndex(index); + pending_select = -1; + } else if (now > pending_select_until) { + pending_select = -1; + } + } + if (!tab_dragging) { + UpdateTabArrows(); + } + } + + // Clicking a player's tab rumbles its controller, to tell which one it is + if (tabs && tabs != rumble_tabs) { + rumble_tabs = tabs; + connect(tabs->tabBar(), &QTabBar::tabBarClicked, this, [this, tabs](int index) { + const auto applet_mode = Settings::values.controller_applet_mode.GetValue(); + if (applet_mode != Settings::AppletMode::ConsoleMode && + applet_mode != Settings::AppletMode::HandheldConsoleMode) { + return; + } + const auto it = + std::find(player_tabs.begin(), player_tabs.end(), tabs->widget(index)); + if (it == player_tabs.end()) { + return; + } + const auto player = static_cast(it - player_tabs.begin()); + if (!Settings::values.vibration_enabled.GetValue() || + !Settings::values.players.GetValue()[player].vibration_enabled) { + return; + } + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.rumble_requests.push_back(static_cast(player)); + }); + } + + // The Controllers tab carries Console Mode in the automatic modes + ui->handheldGroup->setVisible(!automatic); + ui->connectedControllers->setVisible(!automatic); + // A player playing as a single Joy-Con: its mapping is the engine's (no Defaults/Clear) + if (auto* tab = qobject_cast(ui->consoleInputSettings->parent())) { + const bool locked = tab->JoyConLocked(); + ui->buttonClearAll->setEnabled(!locked); + ui->buttonRestoreDefaults->setEnabled(!locked); + } + + if (generation == followed_generation) { + return; + } + followed_generation = generation; + for (auto* controller : player_controllers) { + controller->RefreshFromController(); + } + // The boxes mirror the emulated controllers without acting on them + for (auto* checkbox : connected_controller_checkboxes) { + checkbox->blockSignals(true); + } + LoadPlayerControllerIndices(); + for (auto* checkbox : connected_controller_checkboxes) { + checkbox->blockSignals(false); + } + }); + follow_timer->start(50); + ui->tabWidget->insertTab(0, assignment, tr("Controllers")); + ui->tabWidget->setCurrentIndex(0); + advanced = new ConfigureInputAdvanced(hid_core, this); QHBoxLayout* advancedLayout = new QHBoxLayout(ui->tabAdvanced); @@ -201,10 +556,489 @@ void ConfigureInput::PropagatePlayerNumberChanged(size_t player_index, bool chec } } +namespace { + +/// A player tab's colour and how it is lit, from its data; nothing for other tabs +struct PlayerTabLook { + QColor accent; + int lit = 0; +}; + +std::optional TabLook(const QVariant& data) { + if (data.metaType() != QMetaType::fromType()) { + return std::nullopt; + } + const QVariantList list = data.toList(); + if (list.size() != 2) { + return std::nullopt; + } + return PlayerTabLook{list[0].value(), list[1].toInt()}; +} + +/// A player tab's label with its battery after it, the two centred together in the area +void PaintTabLabel(QPainter& painter, const QRect& area, const QString& text, const QIcon& icon, + const QSize& icon_size) { + if (icon.isNull()) { + painter.drawText(area, Qt::AlignCenter, text); + return; + } + const int text_w = QFontMetrics(painter.font()).horizontalAdvance(text); + const int left = area.center().x() - (text_w + 4 + icon_size.width()) / 2; + painter.drawText(QRect(left, area.top(), text_w + 2, area.height()), + Qt::AlignVCenter | Qt::AlignLeft, text); + icon.paint(&painter, QRect(left + text_w + 4, area.center().y() - icon_size.height() / 2, + icon_size.width(), icon_size.height())); +} + +/// Like the menu bar's chips: outlined, filled while an input is held; the selected tab the +/// other way round +struct TabPaint { + bool filled; + QColor fill; + QColor ink; +}; + +/// A chevron drawn as an icon, so it sits centred in its button; dimmed when disabled +QIcon ChevronIcon(const QColor& ink, bool left, qreal ratio) { + const auto draw = [&](int alpha) { + QPixmap pixmap(QSize(14, 14) * ratio); + pixmap.setDevicePixelRatio(ratio); + pixmap.fill(Qt::transparent); + QPainter painter{&pixmap}; + painter.setRenderHint(QPainter::Antialiasing); + QColor color = ink; + color.setAlpha(alpha); + painter.setPen(QPen(color, 2.2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + const qreal tip = left ? 4.5 : 9.5; + const qreal back = left ? 9.0 : 5.0; + const QPointF chevron[3] = {QPointF(back, 2.5), QPointF(tip, 7), QPointF(back, 11.5)}; + painter.drawPolyline(chevron, 3); + return pixmap; + }; + QIcon icon; + icon.addPixmap(draw(255), QIcon::Normal); + icon.addPixmap(draw(80), QIcon::Disabled); + return icon; +} + +TabPaint PaintFor(const PlayerTabLook& look, bool selected) { + if (look.lit == 3) { + return {true, QColor(200, 50, 50), QColor(Qt::white)}; + } + if (look.lit == 2) { + return {true, QColor(45, 160, 80), QColor(Qt::white)}; + } + const bool filled = selected != (look.lit == 1); + return {filled, look.accent, filled ? QColor(Qt::white) : look.accent}; +} + +} // Anonymous namespace + +PlayerTabStyle::PlayerTabStyle(const QString& base) : QProxyStyle(base) {} + +void PlayerTabStyle::drawControl(ControlElement element, const QStyleOption* option, + QPainter* painter, const QWidget* widget) const { + const auto* tab = qstyleoption_cast(option); + const auto* bar = qobject_cast(widget); + if (!tab || !bar || (element != CE_TabBarTabShape && element != CE_TabBarTabLabel)) { + QProxyStyle::drawControl(element, option, painter, widget); + return; + } + // Found by its text: a dragged tab is painted into an image of its own + int index = -1; + for (int i = 0; i < bar->count() && index < 0; ++i) { + if (bar->tabText(i) == tab->text) { + index = i; + } + } + // Only a player tab is a bubble, in its player's colour; the others stay as they were + const auto look = index >= 0 ? TabLook(bar->tabData(index)) : std::nullopt; + if (!look) { + QProxyStyle::drawControl(element, option, painter, widget); + return; + } + const bool selected = tab->state & State_Selected; + const TabPaint paint = PaintFor(*look, selected); + if (element == CE_TabBarTabShape) { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + const QRectF pill = QRectF(tab->rect).adjusted(2, 3, -2, -3); + if (paint.filled) { + painter->setPen(Qt::NoPen); + painter->setBrush(paint.fill); + } else { + painter->setPen(QPen(look->accent, 1.5)); + QColor hover = look->accent; + hover.setAlpha(tab->state & State_MouseOver ? 45 : 0); + painter->setBrush(hover); + } + painter->drawRoundedRect(pill, pill.height() / 2, pill.height() / 2); + painter->restore(); + return; + } + // The label: bold, white on a filled tab, else in the player's colour, with its battery + // after it (between the tab's arrows) + painter->save(); + QFont font = painter->font(); + font.setBold(true); + painter->setFont(font); + painter->setPen(paint.ink); + const QRect area = tab->rect.adjusted(tab->leftButtonSize.width(), 0, + -tab->rightButtonSize.width(), 0); + PaintTabLabel(*painter, area, tab->text, tab->icon, tab->iconSize); + painter->restore(); +} + +QSize PlayerTabStyle::sizeFromContents(ContentsType type, const QStyleOption* option, + const QSize& size, const QWidget* widget) const { + QSize result = QProxyStyle::sizeFromContents(type, option, size, widget); + // Room for a player tab's rounded ends and bold label + const auto* tab = qstyleoption_cast(option); + if (type == CT_TabBarTab && tab && + (tab->text.startsWith(QChar(0x283F)) || !tab->icon.isNull())) { + result += QSize(14, 4); + if (widget) { + QFont bold = widget->font(); + bold.setBold(true); + result.rwidth() += (std::max)(0, QFontMetrics(bold).horizontalAdvance(tab->text) - + widget->fontMetrics().horizontalAdvance(tab->text)); + } + } + return result; +} + +PlayerTabOverlay::PlayerTabOverlay(QTabBar* bar_, QColor background_) + : QWidget(bar_), bar{bar_}, background{background_} { + setAttribute(Qt::WA_TransparentForMouseEvents); + setAttribute(Qt::WA_NoSystemBackground); + // The dark themes give a plain widget a solid background, which would cover the tab bar + setStyleSheet(QStringLiteral("background: transparent;")); +} + +void PlayerTabOverlay::SetDrag(int index, int offset) { + drag_index = index; + drag_offset = offset; + update(); +} + +void PlayerTabOverlay::paintEvent(QPaintEvent*) { + QPainter painter{this}; + painter.setRenderHint(QPainter::Antialiasing); + const int hovered = bar->underMouse() ? bar->tabAt(bar->mapFromGlobal(QCursor::pos())) : -1; + const auto bubble = [&](int i, QRect tab, bool around_arrows) { + const auto look = TabLook(bar->tabData(i)); + const TabPaint paint = PaintFor(*look, i == bar->currentIndex()); + const QRectF pill = QRectF(tab).adjusted(2, 3, -2, -3); + if (paint.filled) { + painter.setPen(Qt::NoPen); + painter.setBrush(paint.fill); + } else { + painter.setPen(QPen(look->accent, 1.5)); + QColor hover = look->accent; + hover.setAlpha(i == hovered ? 45 : 0); + painter.setBrush(hover); + } + painter.drawRoundedRect(pill, pill.height() / 2, pill.height() / 2); + // The label, between the tab's arrows + QRect text = tab; + if (around_arrows) { + if (const QWidget* left = bar->tabButton(i, QTabBar::LeftSide)) { + text.setLeft(left->geometry().right() + 1); + } + if (const QWidget* right = bar->tabButton(i, QTabBar::RightSide)) { + text.setRight(right->geometry().left() - 1); + } + } + QFont font = bar->font(); + font.setBold(true); + painter.setFont(font); + painter.setPen(paint.ink); + // The battery after the label + PaintTabLabel(painter, text, bar->tabText(i), bar->tabIcon(i), bar->iconSize()); + }; + for (int i = 0; i < bar->count(); ++i) { + const auto look = TabLook(bar->tabData(i)); + if (!look || !bar->isTabVisible(i)) { + continue; + } + const QRect tab = bar->tabRect(i); + // The theme's tab goes under the theme's background, and the bubble goes on top + painter.fillRect(tab, background); + if (i == drag_index) { + // Where the dragged tab came from: an empty slot + QColor edge = look->accent; + edge.setAlpha(90); + painter.setPen(QPen(edge, 1, Qt::DashLine)); + painter.setBrush(Qt::NoBrush); + const QRectF slot = QRectF(tab).adjusted(3, 4, -3, -4); + painter.drawRoundedRect(slot, slot.height() / 2, slot.height() / 2); + continue; + } + bubble(i, tab, true); + } + // The dragged tab, last, over the others + if (drag_index >= 0 && drag_index < bar->count()) { + bubble(drag_index, bar->tabRect(drag_index).translated(drag_offset, 0), false); + } +} + +void ConfigureInput::SwapPlayers(int a, int b) { + if (a == b || a < 0 || b < 0 || a >= 8 || b >= 8) { + return; + } + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.swap_requests.emplace_back(a, b); +} + +bool ConfigureInput::eventFilter(QObject* object, QEvent* event) { + if (drag_tabs && object == drag_tabs->tabBar() && tab_overlay && tab_overlay->isVisible() && + DragPlayerTab(event)) { + return true; + } + if (drag_tabs && object == drag_tabs->tabBar() && drag_tabs->isMovable()) { + if (event->type() == QEvent::MouseButtonPress && + static_cast(event)->button() == Qt::LeftButton) { + tab_order.clear(); + for (int k = 0; k < drag_tabs->count(); ++k) { + tab_order.push_back(drag_tabs->widget(k)); + } + const QPoint at = static_cast(event)->position().toPoint(); + dragged_tab = drag_tabs->widget(drag_tabs->tabBar()->tabAt(at)); + tab_dragging = true; + } else if (event->type() == QEvent::MouseButtonRelease && tab_dragging) { + tab_dragging = false; + // After the tab bar has finished its own drop + QTimer::singleShot(0, this, &ConfigureInput::FinishTabDrag); + } + } + return QWidget::eventFilter(object, event); +} + +void ConfigureInput::FinishTabDrag() { + QTabWidget* tabs = drag_tabs; + if (!tabs || tab_order.isEmpty()) { + return; + } + // The players in the order their tabs were dropped in + std::vector dropped; + for (int k = 0; k < tabs->count(); ++k) { + const auto it = std::find(player_tabs.begin(), player_tabs.end(), tabs->widget(k)); + if (it != player_tabs.end() && tabs->isTabVisible(k)) { + dropped.push_back(static_cast(it - player_tabs.begin())); + } + } + // The tabs go back in player order: the controllers move instead + for (int k = 0; k < static_cast(tab_order.size()); ++k) { + const int from = tabs->indexOf(tab_order[k]); + if (from >= 0 && from != k) { + tabs->tabBar()->moveTab(from, k); + } + } + tab_order.clear(); + const auto dragged = std::find(player_tabs.begin(), player_tabs.end(), dragged_tab); + ApplyDroppedOrder(dropped, dragged != player_tabs.end() + ? static_cast(dragged - player_tabs.begin()) + : -1); +} + +void ConfigureInput::ApplyDroppedOrder(const std::vector& dropped, int dragged_player) { + std::vector places = dropped; + std::sort(places.begin(), places.end()); + if (dropped == places) { + return; + } + + // Place k takes the controller player dropped[k] has now, one swap at a time + std::map holder; + for (const int place : places) { + holder[place] = place; + } + for (std::size_t k = 0; k < places.size(); ++k) { + int from = places[k]; + for (const auto& [place, original] : holder) { + if (original == dropped[k]) { + from = place; + } + } + if (from != places[k]) { + SwapPlayers(places[k], from); + std::swap(holder[places[k]], holder[from]); + } + } + + // The selected tab follows the controller that was dragged + const auto at = std::find(dropped.begin(), dropped.end(), dragged_player); + if (at != dropped.end()) { + pending_select = places[at - dropped.begin()]; + pending_select_until = QDateTime::currentMSecsSinceEpoch() + 2000; + } +} + +bool ConfigureInput::DragPlayerTab(QEvent* event) { + QTabBar* bar = drag_tabs->tabBar(); + const auto type = event->type(); + if (type != QEvent::MouseButtonPress && type != QEvent::MouseMove && + type != QEvent::MouseButtonRelease) { + return false; + } + const auto* mouse = static_cast(event); + const QPoint at = mouse->position().toPoint(); + const auto set_arrows = [bar](int index, bool shown) { + for (const auto side : {QTabBar::LeftSide, QTabBar::RightSide}) { + if (QWidget* button = bar->tabButton(index, side)) { + button->setVisible(shown); + } + } + }; + if (type == QEvent::MouseButtonPress) { + const int index = bar->tabAt(at); + // (Player tabs carry their look: colour and lit state) + own_drag_index = + mouse->button() == Qt::LeftButton && index >= 0 && TabLook(bar->tabData(index)) ? index + : -1; + own_drag_press_x = at.x(); + own_dragging = false; + return false; // the tab bar still selects the tab + } + if (own_drag_index < 0) { + return false; + } + const int offset = at.x() - own_drag_press_x; + if (type == QEvent::MouseMove) { + if (!own_dragging && std::abs(offset) < QApplication::startDragDistance()) { + return false; + } + if (!own_dragging) { + own_dragging = true; + set_arrows(own_drag_index, false); + } + tab_overlay->SetDrag(own_drag_index, offset); + return true; + } + // Released: the players take the order of the tabs with the dragged one where it was let go + const int index = own_drag_index; + const bool dragged = own_dragging; + own_drag_index = -1; + own_dragging = false; + if (!dragged) { + return false; + } + set_arrows(index, true); + tab_overlay->SetDrag(-1, 0); + std::vector> centres; // (x, player) + int dragged_player = -1; + for (int k = 0; k < bar->count(); ++k) { + const auto it = std::find(player_tabs.begin(), player_tabs.end(), drag_tabs->widget(k)); + if (it == player_tabs.end() || !bar->isTabVisible(k)) { + continue; + } + const int player = static_cast(it - player_tabs.begin()); + const int x = bar->tabRect(k).center().x() + (k == index ? offset : 0); + if (k == index) { + dragged_player = player; + } + centres.emplace_back(x, player); + } + std::stable_sort(centres.begin(), centres.end()); + std::vector dropped; + for (const auto& [x, player] : centres) { + dropped.push_back(player); + } + ApplyDroppedOrder(dropped, dragged_player); + return true; +} + +void ConfigureInput::UpdateTabArrows() { + QTabWidget* tabs = drag_tabs; + if (!tabs) { + return; + } + const bool movable = tabs_editable; + int last_player = -1; + for (const auto& row : last_rows) { + if (!row.leaving) { + last_player = (std::max)(last_player, row.player); + } + } + for (int player = 0; player < static_cast(player_tabs.size()); ++player) { + const int index = tabs->indexOf(player_tabs[player]); + if (index < 0) { + continue; + } + // (A tab's buttons go when the tab is removed, as on leaving the Controls page) + auto& left = tab_lefts[player]; + auto& right = tab_rights[player]; + // Only a shown tab carries arrows (a hidden tab's would float over the bar) + if (!movable || !tabs->isTabVisible(index)) { + if (left || right) { + tabs->tabBar()->setTabButton(index, QTabBar::LeftSide, nullptr); + tabs->tabBar()->setTabButton(index, QTabBar::RightSide, nullptr); + delete left; + delete right; + } + continue; + } + if (!left || !right) { + const auto make = [this, player](Qt::ArrowType arrow, int step) { + auto* button = new QToolButton; + // A chevron in the tab's ink (the dark themes' arrows are large triangles) + button->setProperty("left", arrow == Qt::LeftArrow); + button->setIconSize(QSize(14, 14)); + button->setAutoRaise(true); + button->setFixedSize(20, 20); + // The tab makes room for the size a style sheet reports (12 pixels under the dark + // themes, too small) + button->setStyleSheet(QStringLiteral("QToolButton { width: 20px; height: 20px; " + "padding: 0px; border: none; " + "background: transparent; }")); + connect(button, &QToolButton::clicked, this, [this, player, step] { + SwapPlayers(player, player + step); + pending_select = player + step; + pending_select_until = QDateTime::currentMSecsSinceEpoch() + 2000; + }); + return button; + }; + left = make(Qt::LeftArrow, -1); + right = make(Qt::RightArrow, 1); + tabs->tabBar()->setTabButton(index, QTabBar::LeftSide, left); + tabs->tabBar()->setTabButton(index, QTabBar::RightSide, right); + } + // Above the dark themes' bubble layer, which would hide them (and shown, but mid-drag) + if (!own_dragging) { + left->show(); + right->show(); + } + left->raise(); + right->raise(); + // In the tab's ink, like the chips' arrows: white on a filled tab, else its colour + if (const auto look = TabLook(tabs->tabBar()->tabData(index))) { + const TabPaint paint = PaintFor(*look, index == tabs->currentIndex()); + for (QToolButton* button : {left.data(), right.data()}) { + if (button->property("ink").value() != paint.ink) { + button->setProperty("ink", paint.ink); + button->setIcon(ChevronIcon(paint.ink, button->property("left").toBool(), + button->devicePixelRatioF())); + } + } + } + left->setEnabled(player > 0); + left->setToolTip(tr("Swap with P%1").arg(player)); + right->setEnabled(player < last_player); + right->setToolTip(tr("Swap with P%1").arg(player + 2)); + } +} + +QWidget* ConfigureInput::PlayerTab(int player) const { + return player >= 0 && player < static_cast(player_tabs.size()) ? player_tabs[player] + : nullptr; +} + QList ConfigureInput::GetSubTabs() const { + // The settings dialog shows these, not this widget's own tab bar return { - ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4, ui->tabPlayer5, - ui->tabPlayer6, ui->tabPlayer7, ui->tabPlayer8, ui->tabAdvanced, + assignment, ui->tabAdvanced, ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, + ui->tabPlayer4, ui->tabPlayer5, ui->tabPlayer6, ui->tabPlayer7, ui->tabPlayer8, }; } @@ -216,6 +1050,7 @@ void ConfigureInput::ApplyConfiguration() { } advanced->ApplyConfiguration(); + assignment->ApplyConfiguration(); const bool pre_docked_mode = Settings::IsDockedMode(); const bool docked_mode_selected = ui->radioDocked->isChecked(); diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h index 9bdd0d68ca..6b1d46a4bf 100644 --- a/src/yuzu/configuration/configure_input.h +++ b/src/yuzu/configuration/configure_input.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2016 Citra Emulator Project @@ -7,12 +7,20 @@ #pragma once #include +#include #include +#include +#include #include #include +#include +#include +#include #include +#include "common/controller_console_state.h" + namespace Core { class System; } @@ -20,9 +28,12 @@ class System; class QCheckBox; class QString; class QTimer; +class QTabBar; +class QTabWidget; class ConfigureInputAdvanced; class ConfigureInputPlayer; +class ConfigurePlayerAssignment; class InputProfiles; @@ -36,6 +47,35 @@ class ConfigureInput; void OnDockedModeChanged(bool last_state, bool new_state, Core::System& system); +/// The settings tab bar in the automatic modes: player tabs drawn as bubbles in their colour +class PlayerTabStyle : public QProxyStyle { +public: + explicit PlayerTabStyle(const QString& base); + void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, + const QWidget* widget) const override; + QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, + const QWidget* widget) const override; +}; + +/// Under Eden's dark themes the style sheet draws the tabs: this layer paints the player tabs' +/// bubbles instead +class PlayerTabOverlay : public QWidget { +public: + PlayerTabOverlay(QTabBar* bar, QColor background); + /// A player tab being dragged (-1: none), drawn this far from its place + void SetDrag(int index, int offset); + +protected: + void paintEvent(QPaintEvent* event) override; + +private: + QTabBar* bar; + /// The theme's own background, which covers its tab under the bubble + QColor background; + int drag_index = -1; + int drag_offset = 0; +}; + class ConfigureInput : public QWidget { Q_OBJECT @@ -51,8 +91,22 @@ public: QList GetSubTabs() const; + /// A player's tab (0-based player) + QWidget* PlayerTab(int player) const; + private: void changeEvent(QEvent* event) override; + bool eventFilter(QObject* object, QEvent* event) override; + + /// Player tabs dropped in a new order: the controllers take that order, the tabs go back + void FinishTabDrag(); + /// The players' new order, as their tabs were dropped: the controllers move to match + void ApplyDroppedOrder(const std::vector& dropped, int dragged_player); + /// Eden's own drag of a player tab, under the dark themes (Qt's would be the theme's tab) + bool DragPlayerTab(QEvent* event); + /// The arrows on each player tab, swapping with the player before or after it + void UpdateTabArrows(); + void SwapPlayers(int a, int b); void RetranslateUI(); void ClearAll(); @@ -75,7 +129,39 @@ private: std::unique_ptr profiles; std::array player_controllers{}; + ConfigurePlayerAssignment* assignment = nullptr; + /// Redraws the player tabs when the engine reloads the controllers + QTimer* follow_timer = nullptr; + unsigned long long followed_generation = 0; + std::function mirror_console_mode; + /// The settings dialog's tab widget whose tab clicks rumble the players' controllers + QTabWidget* rumble_tabs = nullptr; std::array player_tabs{}; + /// Dragging the player tabs: the tab bar, and the order when the drag began + QTabWidget* drag_tabs = nullptr; + /// The tab bar drawn with PlayerTabStyle (its player tabs as bubbles) + QPointer pill_bar; + QPointer tab_overlay; + /// The players can be reordered from their tabs (the automatic modes, on this page) + bool tabs_editable = false; + /// Eden's own tab drag: the tab pressed, where, and whether it is being dragged + int own_drag_index = -1; + int own_drag_press_x = 0; + bool own_dragging = false; + QList tab_order; + QWidget* dragged_tab = nullptr; + bool tab_dragging = false; + std::array player_tab_titles{}; + std::vector last_rows; + /// How each player tab is lit (0 idle, 1 input held, 2 green blink, 3 red blink) + std::array tab_lit{}; + /// The battery each player tab shows (percent * 2 + charging, -1 none) + std::array tab_battery{-1, -1, -1, -1, -1, -1, -1, -1}; + std::array, 8> tab_lefts; + std::array, 8> tab_rights; + /// The tab to select once its player shows (the controller a drag or an arrow moved) + int pending_select = -1; + long long pending_select_until = 0; // Checkboxes representing the "Connected Controllers". std::array connected_controller_checkboxes{}; ConfigureInputAdvanced* advanced = nullptr; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 2750cd4a13..6178dadd53 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -6,13 +6,21 @@ #include #include +#include +#include #include +#include +#include +#include #include #include #include #include #include +#include +#include #include "common/assert.h" +#include "common/controller_console_state.h" #include "common/param_package.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" @@ -26,6 +34,7 @@ #include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/configuration/configure_mouse_panning.h" +#include "yuzu/configuration/configure_player_assignment.h" #include "yuzu/configuration/input_profiles.h" #include "yuzu/util/limitable_input_dialog.h" @@ -289,6 +298,42 @@ QString ConfigureInputPlayer::AnalogToText(const Common::ParamPackage& param, return QObject::tr("[unknown]"); } +namespace { + +/// The SDL controller (guid, port) a player's bindings point at +std::optional> SdlDevice(const Settings::PlayerInput& player) { + for (const std::string& raw : player.buttons) { + const Common::ParamPackage param{raw}; + if (!raw.empty() && param.Get("engine", "") == "sdl") { + return std::pair{param.Get("guid", ""), param.Get("port", 0)}; + } + } + return std::nullopt; +} + +/// Points a player's SDL bindings at one controller, leaving other engines alone +void KeepSdlDevice(Settings::PlayerInput& player, const std::pair& device) { + const auto keep = [&device](auto& params) { + for (std::string& raw : params) { + Common::ParamPackage param{raw}; + if (raw.empty() || param.Get("engine", "") != "sdl") { + continue; + } + if (param.Has("guid2") && param.Get("guid2", "") == param.Get("guid", "")) { + param.Set("guid2", device.first); + } + param.Set("guid", device.first); + param.Set("port", device.second); + raw = param.Serialize(); + } + }; + keep(player.buttons); + keep(player.analogs); + keep(player.motions); +} + +} // Anonymous namespace + ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index_, QWidget* bottom_row_, InputCommon::InputSubsystem* input_subsystem_, @@ -901,6 +946,552 @@ void ConfigureInputPlayer::ConnectPlayer(bool connected) { } } +void ConfigureInputPlayer::RefreshFromController() { + UpdateUI(); + UpdateInputDeviceCombobox(); + ApplyJoyConLock(); +} + +void ConfigureInputPlayer::ApplyJoyConLock() { + int held = 0; + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + if (state.engine_active && player_index < state.joycon_held.size()) { + held = state.joycon_held[player_index]; + } + } + const bool locked = held != 0; + const bool changed = locked != joycon_locked; + joycon_locked = locked; + for (auto* button : button_map) { + if (button) { + button->setEnabled(!locked); + } + } + for (std::size_t i = 0; i < analog_map_buttons.size(); ++i) { + for (auto* button : analog_map_buttons[i]) { + if (button) { + button->setEnabled(!locked); + } + } + for (QWidget* widget : std::initializer_list{ + analog_map_modifier_button[i], analog_map_deadzone_slider[i], + analog_map_modifier_slider[i], analog_map_range_spinbox[i]}) { + if (widget) { + widget->setEnabled(!locked); + } + } + } + // (Saving would keep the Joy-Con's arrangement as the player's own mapping) + if (card_save) { + card_save->setEnabled(!locked); + card_save_new->setEnabled(!locked); + } + if (joycon_note) { + joycon_note->setVisible(locked); + if (locked) { + joycon_note->setText( + (held == 1 ? tr("P%1 plays as a sideways Joy-Con for this game") + : tr("P%1 plays as an upright Joy-Con for this game")) + .arg(player_index + 1) + + tr(": its controls are set automatically. Pick a controller type to set them " + "yourself.")); + } + } + if (card_status) { + card_status->setVisible(!locked); + } + if (changed && !locked && profile_card && profile_card->isVisible()) { + UpdateProfileCard(); + } +} + +void ConfigureInputPlayer::SetConnectionLocked(bool locked) { + const bool changed = connection_locked != locked || !style_applied; + connection_locked = locked; + style_applied = true; + // The automatic modes draw the tab like the Controllers tab, keeping the spacing (the page + // fills the Deck's screen exactly) + if (changed) { + setStyleSheet( + locked ? ConfigurePlayerAssignment::Themed(QStringLiteral( + "QLabel { background: transparent; }" + "QGroupBox { border: 1px solid palette(mid); border-radius: 8px; " + "margin-top: 1.1em; padding-bottom: 5px; " + "background: palette(alternate-base); }" + "QGroupBox::title { subcontrol-origin: margin; " + "subcontrol-position: top center; padding: 0 3px; }" + "QGroupBox QGroupBox { border: none; background: transparent; " + "padding-bottom: 0px; }" + "QGroupBox QGroupBox::title { padding: 0px; }" + // The single-button boxes carry their label inside, above the button + "QGroupBox#buttonShoulderButtonsButtonZLGroup, " + "QGroupBox#buttonShoulderButtonsButtonLGroup, " + "QGroupBox#buttonMiscButtonsMinusGroup, " + "QGroupBox#buttonMiscButtonsPlusGroup, " + "QGroupBox#buttonShoulderButtonsZRGroup, " + "QGroupBox#buttonShoulderButtonsRGroup, " + "QGroupBox#buttonMiscButtonsHomeGroup, " + "QGroupBox#buttonMiscButtonsScreenshotGroup { margin-top: 0px; " + "padding-top: 1.3em; }" + // The top row starts level with the section cards beside it + "QGroupBox#buttonShoulderButtonsButtonZLGroup, " + "QGroupBox#buttonShoulderButtonsButtonLGroup, " + "QGroupBox#buttonMiscButtonsMinusGroup, " + "QGroupBox#buttonMiscButtonsPlusGroup, " + "QGroupBox#buttonShoulderButtonsZRGroup, " + "QGroupBox#buttonShoulderButtonsRGroup { margin-top: 1.1em; }" + "QGroupBox#buttonShoulderButtonsButtonZLGroup::title, " + "QGroupBox#buttonShoulderButtonsButtonLGroup::title, " + "QGroupBox#buttonMiscButtonsMinusGroup::title, " + "QGroupBox#buttonMiscButtonsPlusGroup::title, " + "QGroupBox#buttonShoulderButtonsZRGroup::title, " + "QGroupBox#buttonShoulderButtonsRGroup::title, " + "QGroupBox#buttonMiscButtonsHomeGroup::title, " + "QGroupBox#buttonMiscButtonsScreenshotGroup::title { " + "subcontrol-origin: padding; subcontrol-position: top center; " + "top: 3px; padding: 0px; }" + "QPushButton { border: 1px solid palette(mid); border-radius: 6px; " + "padding: 2px 6px; background: palette(base); }" + "QPushButton:hover { border-color: palette(highlight); }" + "QPushButton:pressed, QPushButton:checked { " + "background: palette(highlight); color: palette(highlighted-text); }")) + + ConfigurePlayerAssignment::ModernComboStyle() + : QString{}); + if (!locked) { + // The manual modes get the tab exactly as it was + if (home_centred) { + home_centred = false; + ui->miscButtons->setStretch(0, 0); + delete ui->miscButtons->takeAt(ui->miscButtons->count() - 1); + } + if (shoulders_raised) { + shoulders_raised = false; + for (QPushButton* button : + {ui->buttonL, ui->buttonR, ui->buttonMinus, ui->buttonPlus}) { + if (auto* box = qobject_cast( + button->parentWidget() ? button->parentWidget()->layout() : nullptr)) { + delete box->takeAt(box->count() - 1); + } + } + } + if (QLayout* connect = ui->groupConnectedController->layout()) { + connect->setAlignment(ui->comboControllerType, Qt::Alignment{}); + } + // Back to the inherited fonts + for (QGroupBox* box : bolded_boxes) { + if (box) { + box->setFont(QFont()); + for (QWidget* child : box->findChildren(Qt::FindDirectChildrenOnly)) { + child->setFont(QFont()); + } + } + } + bolded_boxes.clear(); + } + if (locked) { + ConfigurePlayerAssignment::ModernizeCombos(this); + // Bold section titles (a style sheet can't bold only a title) + QFont normal = font(); + normal.setBold(false); // explicit, or the box's bold is inherited after all + QFont bold = normal; + bold.setBold(true); + for (QGroupBox* box : findChildren()) { + // No box around a section + bool inside_box = false; + for (QWidget* up = box->parentWidget(); up && up != this; up = up->parentWidget()) { + inside_box = inside_box || qobject_cast(up) != nullptr; + } + const bool section = + !inside_box && !box->objectName().startsWith(QStringLiteral("buttonMisc")) && + !box->objectName().startsWith(QStringLiteral("buttonShoulderButtons")); + if (!section) { + continue; + } + box->setFont(bold); + for (QWidget* child : box->findChildren(Qt::FindDirectChildrenOnly)) { + child->setFont(normal); + } + bolded_boxes.push_back(box); + } + // Home centred under the controller + if (!home_centred) { + home_centred = true; + ui->miscButtons->setStretch(0, 1); + ui->miscButtons->addStretch(1); + } + // Connect Controller's drop-down level with the profile card's + if (QLayout* connect = ui->groupConnectedController->layout()) { + connect->setAlignment(ui->comboControllerType, Qt::AlignTop); + } + // L, R, Minus and Plus line up with ZL and ZR: a fixed space the size of ZL's + // trigger slider under each + if (!shoulders_raised) { + shoulders_raised = true; + const int slider = ui->sliderZLThreshold->sizeHint().height(); + for (QPushButton* button : + {ui->buttonL, ui->buttonR, ui->buttonMinus, ui->buttonPlus}) { + if (auto* box = qobject_cast( + button->parentWidget() ? button->parentWidget()->layout() : nullptr)) { + box->addSpacerItem(new QSpacerItem( + 0, slider + box->spacing(), QSizePolicy::Minimum, QSizePolicy::Fixed)); + } + } + } + } + } + if (!profile_card && locked) { + BuildProfileCard(); + } + ui->profilesGroup->setVisible(!locked); + if (profile_card) { + profile_card->setVisible(locked); + if (locked) { + card_timer->start(); + UpdateProfileCard(); + } else { + card_timer->stop(); + } + } + ApplyJoyConLock(); + ui->devicesGroup->setVisible(!locked); + // The automatic modes bind motion themselves (the controller's own, or its real device's) + ui->buttonMotionLeftGroup->setVisible(!locked); + ui->buttonMotionRightGroup->setVisible(!locked); + if (ui->groupConnectedController->isCheckable() == !locked) { + return; + } + const bool blocked = ui->groupConnectedController->blockSignals(true); + ui->groupConnectedController->setCheckable(!locked); + if (!locked) { + ui->groupConnectedController->setChecked(emulated_controller->IsConnected(true)); + } + ui->groupConnectedController->blockSignals(blocked); +} + +namespace { + +/// A binding without its controller (guid, port), its fields in a fixed order +std::string MappingKey(const std::string& raw) { + if (raw.empty()) { + return {}; + } + Common::ParamPackage param{raw}; + if (param.Get("engine", "") == "sdl") { + param.Erase("guid"); + param.Erase("guid2"); + param.Erase("port"); + } + std::vector fields; + std::string field; + for (const char c : param.Serialize() + ",") { + if (c != ',') { + field += c; + continue; + } + fields.push_back(field); + field.clear(); + } + std::sort(fields.begin(), fields.end()); + std::string out; + for (const auto& f : fields) { + out += f + ';'; + } + return out; +} + +/// Asks the engine to put a profile on a player's controller ("" drops it): the engine owns the +/// mappings in the automatic modes +void RequestProfile(std::size_t player, const QString& name, bool restore = false) { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.profile_requests.push_back({static_cast(player), name.toStdString(), restore}); +} + +/// The box layout that holds a widget, searched from a top layout down +QBoxLayout* LayoutHolding(QLayout* layout, QWidget* widget) { + if (!layout) { + return nullptr; + } + if (layout->indexOf(widget) >= 0) { + return qobject_cast(layout); + } + for (int i = 0; i < layout->count(); ++i) { + if (auto* found = LayoutHolding(layout->itemAt(i)->layout(), widget)) { + return found; + } + } + return nullptr; +} + +} // Anonymous namespace + +void ConfigureInputPlayer::BuildProfileCard() { + profile_card = new QGroupBox(tr("Mapping Profile"), this); + auto* column = new QVBoxLayout(profile_card); + // Connect Controller's margins, so the two drop-downs are level + if (const QLayout* connect = ui->groupConnectedController->layout()) { + column->setContentsMargins(connect->contentsMargins()); + } + auto* row = new QHBoxLayout; + card_profiles = new QComboBox(profile_card); + card_profiles->setPlaceholderText(tr("No profile")); + ConfigurePlayerAssignment::ModernizeCombos(profile_card); + // Fills the row up to its buttons, which end at the card's edge + card_profiles->setMinimumWidth(160); + card_profiles->setToolTip(tr("Picking a profile applies it to this player at once.")); + card_save = new QPushButton(tr("Save"), profile_card); + card_save->setDefault(false); + card_save->setAutoDefault(false); + // The profile's actions, all in view beside Save (Defaults, below the drawing, resets) + const auto action = [this](const QString& text, const QString& tip) { + auto* button = new QPushButton(text, profile_card); + button->setAutoDefault(false); + button->setToolTip(tip); + return button; + }; + card_save_new = action(tr("Save as New"), tr("Keep this mapping as a new profile")); + card_rename = action(tr("Rename"), tr("Rename the selected profile")); + card_duplicate = action(tr("Duplicate"), tr("Copy the selected profile under a new name")); + card_delete = action(tr("Delete"), tr("Delete the selected profile; this player keeps its " + "current mapping")); + // (Inside the drop-down) takes the profile off: the mappings from before it come back + card_remove = ConfigurePlayerAssignment::AddClearButton(card_profiles); + card_remove->setToolTip(tr("Remove the profile from this player")); + row->addWidget(card_profiles, 1); + row->addWidget(card_save); + row->addWidget(card_save_new); + row->addWidget(card_rename); + row->addWidget(card_duplicate); + row->addWidget(card_delete); + column->addLayout(row); + card_status = new QLabel(profile_card); + card_status->setWordWrap(true); + column->addWidget(card_status); + joycon_note = new QLabel(profile_card); + joycon_note->setWordWrap(true); + joycon_note->setVisible(false); + column->addWidget(joycon_note); + // No taller than its rows: the drawing below gets the height + profile_card->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + + connect(card_save_new, &QPushButton::clicked, this, [this] { + const int count = ui->comboProfiles->count(); + CreateProfile(); + if (ui->comboProfiles->count() > count) { + RequestProfile(player_index, ui->comboProfiles->currentText()); + } + RememberProfileMapping(); + UpdateProfileCard(); + }); + connect(card_rename, &QPushButton::clicked, this, &ConfigureInputPlayer::RenameProfile); + connect(card_duplicate, &QPushButton::clicked, this, &ConfigureInputPlayer::DuplicateProfile); + connect(card_delete, &QPushButton::clicked, this, &ConfigureInputPlayer::DeleteProfileAsked); + + // The engine owns the mappings here: picking or saving a profile goes through it + connect(card_profiles, qOverload(&QComboBox::activated), this, [this](int index) { + ui->comboProfiles->setCurrentIndex(index); + RequestProfile(player_index, ui->comboProfiles->currentText()); + RememberProfileMapping(); + UpdateProfileCard(); + }); + connect(card_remove, &QToolButton::clicked, this, [this] { + RequestProfile(player_index, {}, true); + ui->comboProfiles->setCurrentIndex(-1); + RememberProfileMapping(); + UpdateProfileCard(); + }); + connect(card_save, &QPushButton::clicked, this, [this] { + if (ui->comboProfiles->currentIndex() < 0) { + CreateProfile(); + } else { + SaveProfile(); + } + // (A new profile left unnamed leaves nothing selected) + if (ui->comboProfiles->currentIndex() >= 0) { + RequestProfile(player_index, ui->comboProfiles->currentText()); + } + RememberProfileMapping(); + UpdateProfileCard(); + }); + + // Mapping edits come from many places (polling, menus, defaults): look again now and then + card_timer = new QTimer(this); + card_timer->setInterval(500); + connect(card_timer, &QTimer::timeout, this, &ConfigureInputPlayer::UpdateProfileCard); + + if (auto* layout = LayoutHolding(this->layout(), ui->profilesGroup)) { + layout->insertWidget(layout->indexOf(ui->profilesGroup) + 1, profile_card, 1); + } + // A bold title like the other sections, with its contents in the normal font + QFont normal = font(); + normal.setBold(false); // explicit, or the card's bold is inherited after all + QFont bold = normal; + bold.setBold(true); + profile_card->setFont(bold); + for (QWidget* child : profile_card->findChildren(Qt::FindDirectChildrenOnly)) { + child->setFont(normal); + } + profile_card->setVisible(false); +} + +void ConfigureInputPlayer::UpdateProfileCard() { + if (!profile_card || !profile_card->isVisible()) { + return; + } + // Mirror the profile list the rest of the tab keeps in comboProfiles + bool same = card_profiles->count() == ui->comboProfiles->count(); + for (int i = 0; same && i < card_profiles->count(); ++i) { + same = card_profiles->itemText(i) == ui->comboProfiles->itemText(i); + } + if (!same || card_profiles->currentIndex() != ui->comboProfiles->currentIndex()) { + const bool blocked = card_profiles->blockSignals(true); + card_profiles->clear(); + for (int i = 0; i < ui->comboProfiles->count(); ++i) { + card_profiles->addItem(ui->comboProfiles->itemText(i)); + } + card_profiles->setCurrentIndex(ui->comboProfiles->currentIndex()); + card_profiles->blockSignals(blocked); + } + // The engine changes the player's profile too (a swap, the Controllers tab): follow it + const QString carried = + QString::fromStdString(Settings::values.players.GetValue()[player_index].profile_name); + if (carried != card_engine_profile) { + card_engine_profile = carried; + const bool blocked = ui->comboProfiles->blockSignals(true); + ui->comboProfiles->setCurrentIndex(ui->comboProfiles->findText(carried)); + ui->comboProfiles->blockSignals(blocked); + card_profiles->setCurrentIndex(ui->comboProfiles->currentIndex()); + } + const QString name = ui->comboProfiles->currentText(); + if (ui->comboProfiles->currentIndex() >= 0 && name != card_profile_name) { + RememberProfileMapping(); + } + + const QString follows = tr("Applies to this player's controller, whichever one it is."); + const bool selected = ui->comboProfiles->currentIndex() >= 0; + card_remove->setVisible(selected); + card_rename->setEnabled(selected); + card_duplicate->setEnabled(selected); + card_delete->setEnabled(selected); + if (ui->comboProfiles->currentIndex() < 0) { + card_save->setToolTip(tr("Keep this mapping as a new profile (asks for its name)")); + // In Modern Console a remap lasts the session; a profile is what keeps controls + card_status->setText(tr("No profile: this player uses its usual controls. Changes made " + "here last for this session; Save as New keeps them.")); + card_status->setPalette(palette()); + return; + } + card_save->setToolTip(tr("Save this mapping to \u201c%1\u201d").arg(name)); + QPalette status = palette(); + if (CurrentMappingKey() != card_profile_key) { + card_status->setText(tr("\u25cf Unsaved changes \u00b7 %1").arg(follows)); + status.setColor(QPalette::WindowText, QColor(208, 138, 30)); + } else { + card_status->setText(tr("\u2713 Saved \u00b7 %1").arg(follows)); + status.setColor(QPalette::WindowText, status.color(QPalette::PlaceholderText)); + } + card_status->setPalette(status); +} + +std::string ConfigureInputPlayer::CurrentMappingKey() const { + // Motion is the engine's while players are assigned automatically, so it is left out + std::string key; + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + key += MappingKey(emulated_controller->GetButtonParam(i).Serialize()) + '|'; + } + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + key += MappingKey(emulated_controller->GetStickParam(i).Serialize()) + '|'; + } + return key; +} + +void ConfigureInputPlayer::RememberProfileMapping() { + card_profile_name = ui->comboProfiles->currentText(); + // The player keeps its profile's name, so the card shows it the next time too + Settings::values.players.GetValue()[player_index].profile_name = + ui->comboProfiles->currentIndex() < 0 ? std::string{} : card_profile_name.toStdString(); + card_profile_key.clear(); + if (ui->comboProfiles->currentIndex() < 0) { + return; + } + const auto read = profiles->PeekProfile(card_profile_name.toStdString(), player_index); + if (!read) { + return; + } + for (const auto& button : read->buttons) { + card_profile_key += MappingKey(button) + '|'; + } + for (const auto& analog : read->analogs) { + card_profile_key += MappingKey(analog) + '|'; + } +} + +void ConfigureInputPlayer::SelectProfile(const QString& name) { + UpdateInputProfiles(); + ui->comboProfiles->setCurrentIndex(ui->comboProfiles->findText(name)); + emit RefreshInputProfiles(player_index); + RequestProfile(player_index, name); + RememberProfileMapping(); + UpdateProfileCard(); +} + +void ConfigureInputPlayer::RenameProfile() { + const QString old_name = ui->comboProfiles->currentText(); + if (ui->comboProfiles->currentIndex() < 0) { + return; + } + const auto new_name = + LimitableInputDialog::GetText(this, tr("Rename Profile"), tr("Enter a new name:"), 1, 30, + LimitableInputDialog::InputLimiter::Filesystem); + if (new_name.isEmpty() || new_name == old_name) { + return; + } + if (!InputProfiles::IsProfileNameValid(new_name.toStdString()) || + !profiles->RenameProfile(old_name.toStdString(), new_name.toStdString())) { + QMessageBox::critical( + this, tr("Rename Input Profile"), + tr("Could not rename \u201c%1\u201d to \u201c%2\u201d.").arg(old_name, new_name)); + return; + } + SelectProfile(new_name); +} + +void ConfigureInputPlayer::DuplicateProfile() { + const QString name = ui->comboProfiles->currentText(); + if (ui->comboProfiles->currentIndex() < 0) { + return; + } + QString copy = tr("%1 copy").arg(name); + for (int n = 2; ui->comboProfiles->findText(copy) >= 0; ++n) { + copy = tr("%1 copy %2").arg(name).arg(n); + } + if (!profiles->DuplicateProfile(name.toStdString(), copy.toStdString())) { + QMessageBox::critical(this, tr("Duplicate Input Profile"), + tr("Could not duplicate \u201c%1\u201d.").arg(name)); + return; + } + SelectProfile(copy); +} + +void ConfigureInputPlayer::DeleteProfileAsked() { + const QString name = ui->comboProfiles->currentText(); + if (ui->comboProfiles->currentIndex() < 0) { + return; + } + if (QMessageBox::question(this, tr("Delete Input Profile"), + tr("Delete the profile \u201c%1\u201d? This player keeps its " + "current mapping.") + .arg(name)) != QMessageBox::Yes) { + return; + } + DeleteProfile(); + RequestProfile(player_index, {}); + RememberProfileMapping(); + UpdateProfileCard(); +} + void ConfigureInputPlayer::UpdateInputDeviceCombobox() { // Skip input device persistence if "Input Devices" is set to "Any". if (ui->comboDevices->currentIndex() == 0) { @@ -978,10 +1569,76 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { } void ConfigureInputPlayer::RestoreDefaults() { + if (joycon_locked) { + return; + } + // In the automatic modes the device list is hidden (and may say "Any"): the defaults are + // those of the controller the bindings point at, or pointed at before Clear + if (connection_locked) { + if (const auto device = CurrentSdlDevice()) { + locked_device = device; + } + if (locked_device) { + const auto it = std::find_if( + input_devices.begin(), input_devices.end(), [this](const auto& param) { + return param.Get("engine", "") == "sdl" && + param.Get("guid", "") == locked_device->first && + param.Get("port", 0) == locked_device->second; + }); + if (it != input_devices.end()) { + ui->comboDevices->setCurrentIndex( + static_cast(std::distance(input_devices.begin(), it))); + } + } + } + // (Motion is the engine's in these modes, and hidden: a DSU binding stays) + const auto motions = KeptMotions(); UpdateMappingWithDefaults(); + RestoreMotions(motions); +} + +std::optional> ConfigureInputPlayer::CurrentSdlDevice() const { + for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { + const auto param = emulated_controller->GetButtonParam(button_id); + if (param.Get("engine", "") == "sdl") { + return std::pair{param.Get("guid", ""), param.Get("port", 0)}; + } + } + return std::nullopt; +} + +std::vector ConfigureInputPlayer::KeptMotions() const { + std::vector motions; + if (connection_locked) { + for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { + motions.push_back( + emulated_controller->GetMotionParam(static_cast(motion_id))); + } + } + return motions; +} + +void ConfigureInputPlayer::RestoreMotions(const std::vector& motions) { + for (std::size_t motion_id = 0; motion_id < motions.size(); ++motion_id) { + emulated_controller->SetMotionParam(motion_id, motions[motion_id]); + } } void ConfigureInputPlayer::ClearAll() { + if (joycon_locked) { + return; + } + // (The controller is remembered, for Defaults afterwards) + if (const auto device = CurrentSdlDevice()) { + locked_device = device; + } + // (Motion is the engine's in the automatic modes, and hidden: a DSU binding stays) + const auto motions = KeptMotions(); + ClearMappings(); + RestoreMotions(motions); +} + +void ConfigureInputPlayer::ClearMappings() { for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { const auto* const button = button_map[button_id]; if (button == nullptr) { @@ -1634,6 +2291,11 @@ void ConfigureInputPlayer::LoadProfile() { ApplyConfiguration(); + // In the automatic modes the profile goes onto the player's current controller (the one + // saved with it would read as a swap) + auto& player = Settings::values.players.GetValue()[player_index]; + const auto device = connection_locked ? SdlDevice(player) : std::nullopt; + if (!profiles->LoadProfile(profile_name.toStdString(), player_index)) { QMessageBox::critical(this, tr("Load Input Profile"), tr("Failed to load the input profile \"%1\"").arg(profile_name)); @@ -1641,6 +2303,9 @@ void ConfigureInputPlayer::LoadProfile() { emit RefreshInputProfiles(player_index); return; } + if (device) { + KeepSdlDevice(player, *device); + } LoadConfiguration(); } diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index fda09e9257..2c0db9bbca 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -10,6 +13,7 @@ #include #include +#include #include #include "common/param_package.h" @@ -17,6 +21,8 @@ #include "ui_configure_input.h" class QCheckBox; +class QComboBox; +class QGroupBox; class QKeyEvent; class QLabel; class QPushButton; @@ -24,6 +30,7 @@ class QSlider; class QSpinBox; class QString; class QTimer; +class QToolButton; class QWidget; class InputProfiles; @@ -65,6 +72,18 @@ public: /// Update the input devices combobox. void UpdateInputDeviceCombobox(); + /// Redraws the tab from its emulated controller after the engine reloaded it + void RefreshFromController(); + + /// Use Any Controller as Joy-Cons: while this player plays as a single Joy-Con its mapping + /// is set automatically, and read-only here (with a note why) + [[nodiscard]] bool JoyConLocked() const { + return joycon_locked; + } + + /// In the automatic modes the tab hides the connection, device and motion choices + void SetConnectionLocked(bool locked); + /// Updates the list of controller profiles. void UpdateInputProfiles(); @@ -74,6 +93,15 @@ public: /// Clear all input configuration. void ClearAll(); + /// The SDL controller (guid, port) the player's bindings point at now, if any + [[nodiscard]] std::optional> CurrentSdlDevice() const; + /// Clear's work: every binding emptied + void ClearMappings(); + /// The player's motion bindings, kept across Clear and Defaults in the automatic modes + /// (motion is hidden there); none otherwise + [[nodiscard]] std::vector KeptMotions() const; + void RestoreMotions(const std::vector& motions); + signals: /// Emitted when this controller is (dis)connected by the user. void Connected(bool connected); @@ -172,6 +200,44 @@ private: std::size_t player_index; bool debug; bool is_powered_on; + /// Players are assigned automatically: the connection and controller are not this tab's + bool connection_locked{}; + /// The SDL controller (guid, port) the bindings last pointed at, for Defaults after Clear + std::optional> locked_device; + bool style_applied{}; + bool home_centred{}; + bool shoulders_raised{}; + /// The section boxes given a bold title in the automatic modes + std::vector> bolded_boxes; + + /// The profile card shown instead of the Profile group in the automatic modes (comboProfiles + /// stays the selection) + void BuildProfileCard(); + void UpdateProfileCard(); + /// The selected profile's mapping, kept to tell when the tab's mapping differs from it + void RememberProfileMapping(); + std::string CurrentMappingKey() const; + void SelectProfile(const QString& name); + void RenameProfile(); + void DuplicateProfile(); + void DeleteProfileAsked(); + QGroupBox* profile_card{}; + QComboBox* card_profiles{}; + QPushButton* card_save{}; + QToolButton* card_remove{}; + QPushButton* card_save_new{}; + QPushButton* card_rename{}; + QPushButton* card_duplicate{}; + QPushButton* card_delete{}; + QLabel* card_status{}; + QLabel* joycon_note{}; + bool joycon_locked = false; + void ApplyJoyConLock(); + QTimer* card_timer{}; + std::string card_profile_key; + QString card_profile_name; + /// The profile the engine last reported for this player + QString card_engine_profile; InputCommon::InputSubsystem* input_subsystem; diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index faf4e021ec..5d6584612a 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -230,6 +230,14 @@ void PlayerControlPreview::paintEvent(QPaintEvent* event) { QPainter p(this); p.setRenderHint(QPainter::Antialiasing); const QPointF center = rect().center(); + // The drawings need about 450x330: a smaller frame (the Steam Deck's 800-pixel screen) gets + // them scaled down to fit instead of cut off at the bottom + const qreal fit = std::min({1.0, width() / 450.0, height() / 330.0}); + if (fit < 1.0) { + p.translate(center); + p.scale(fit, fit); + p.translate(-center); + } switch (controller_type) { case Core::HID::NpadStyleIndex::Handheld: diff --git a/src/yuzu/configuration/configure_modern_per_game.cpp b/src/yuzu/configuration/configure_modern_per_game.cpp new file mode 100644 index 0000000000..97a61f2345 --- /dev/null +++ b/src/yuzu/configuration/configure_modern_per_game.cpp @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include +#include + +#include "common/settings.h" +#include "core/core.h" +#include "yuzu/configuration/configure_modern_per_game.h" +#include "yuzu/configuration/shared_widget.h" + +ConfigureModernPerGame::ConfigureModernPerGame( + Core::System& system_, std::shared_ptr> group, + const ConfigurationShared::Builder& builder, QWidget* parent) + : Tab(group, parent), system{system_} { + auto* layout = new QVBoxLayout(this); + auto* box = new QGroupBox(tr("Modern Console"), this); + auto* box_layout = new QVBoxLayout(box); + auto* note = new QLabel(tr("For this game only. Each option follows the one in Emulation > " + "Configure > Controls > Controllers until it is set here."), + box); + note->setWordWrap(true); + box_layout->addWidget(note); + for (Settings::BasicSetting* setting : std::initializer_list{ + &Settings::values.console_joycon_auto, &Settings::values.console_button_labels, + &Settings::values.console_pause_disconnect, &Settings::values.console_player_lights, + &Settings::values.console_debug_overlay, &Settings::values.console_hints}) { + ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs); + if (widget == nullptr) { + continue; + } + if (!widget->Valid()) { + widget->deleteLater(); + continue; + } + box_layout->addWidget(widget); + } + layout->addWidget(box); + layout->addStretch(1); +} + +ConfigureModernPerGame::~ConfigureModernPerGame() = default; + +void ConfigureModernPerGame::SetConfiguration() {} + +void ConfigureModernPerGame::ApplyConfiguration() { + // (While a game runs, only the options it can change in game are applied) + const bool powered_on = system.IsPoweredOn(); + for (const auto& apply : apply_funcs) { + apply(powered_on); + } +} diff --git a/src/yuzu/configuration/configure_modern_per_game.h b/src/yuzu/configuration/configure_modern_per_game.h new file mode 100644 index 0000000000..644f247550 --- /dev/null +++ b/src/yuzu/configuration/configure_modern_per_game.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include + +#include "yuzu/configuration/configuration_shared.h" + +namespace ConfigurationShared { +class Builder; +} + +namespace Core { +class System; +} + +/// The Modern Console options a game can have of its own (in its properties): each follows the +/// global choice (Emulation > Configure > Controls) unless set for the game +class ConfigureModernPerGame : public ConfigurationShared::Tab { +public: + explicit ConfigureModernPerGame(Core::System& system_, + std::shared_ptr> group, + const ConfigurationShared::Builder& builder, + QWidget* parent = nullptr); + ~ConfigureModernPerGame() override; + + void ApplyConfiguration() override; + void SetConfiguration() override; + +private: + Core::System& system; + std::vector> apply_funcs; +}; diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 6f530eb0ab..692db5ab48 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -41,6 +41,7 @@ #include "yuzu/configuration/configure_graphics_advanced.h" #include "yuzu/configuration/configure_graphics_extensions.h" #include "yuzu/configuration/configure_input_per_game.h" +#include "yuzu/configuration/configure_modern_per_game.h" #include "yuzu/configuration/configure_network.h" #include "yuzu/configuration/configure_per_game.h" #include "yuzu/configuration/configure_per_game_addons.h" @@ -72,6 +73,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st system_tab = std::make_unique(system_, tab_group, *builder, this); network_tab = std::make_unique(system_, this); applets_tab = std::make_unique(system_, tab_group, *builder, this); + modern_tab = std::make_unique(system_, tab_group, *builder, this); ui->setupUi(this); @@ -85,6 +87,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st ui->tabWidget->addTab(input_tab.get(), tr("Input Profiles")); ui->tabWidget->addTab(network_tab.get(), tr("Network")); ui->tabWidget->addTab(applets_tab.get(), tr("Applets")); + ui->tabWidget->addTab(modern_tab.get(), tr("Modern Console")); setFocusPolicy(Qt::ClickFocus); setWindowTitle(tr("Properties")); diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index bc6561235e..b7ff975022 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -39,6 +39,7 @@ class ConfigureInputPerGame; class ConfigureSystem; class ConfigureNetwork; class ConfigureApplets; +class ConfigureModernPerGame; class QGraphicsScene; class QStandardItem; @@ -95,4 +96,5 @@ private: std::unique_ptr system_tab; std::unique_ptr network_tab; std::unique_ptr applets_tab; + std::unique_ptr modern_tab; }; diff --git a/src/yuzu/configuration/configure_player_assignment.cpp b/src/yuzu/configuration/configure_player_assignment.cpp new file mode 100644 index 0000000000..1e8711b5df --- /dev/null +++ b/src/yuzu/configuration/configure_player_assignment.cpp @@ -0,0 +1,1634 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/controller_console_state.h" +#include "common/fs/path_util.h" +#include "common/settings.h" +#include "qt_common/config/uisettings.h" +#include "yuzu/configuration/configure_player_assignment.h" +#include "yuzu/configuration/input_profiles.h" + +namespace { + +/// A dark look: one of Eden's dark themes, or the system's dark mode under the default theme +bool DarkUi() { + return UISettings::IsDarkTheme() || + QApplication::palette().color(QPalette::Window).lightness() < 128; +} + +bool IsAutomatic(Settings::AppletMode mode) { + return mode == Settings::AppletMode::ConsoleMode || + mode == Settings::AppletMode::HandheldConsoleMode; +} + +constexpr int MaxPlayers = 8; + +/// The players' colours, as the overlay draws their badges +constexpr std::array PlayerColors{ + QColor(79, 142, 247), QColor(239, 91, 91), QColor(47, 191, 113), QColor(245, 184, 46), + QColor(155, 108, 242), QColor(242, 140, 56), QColor(46, 196, 201), QColor(227, 107, 174), +}; + +/// An on/off switch: a rounded track with a knob, like a phone's settings +class ToggleSwitch : public QAbstractButton { +public: + explicit ToggleSwitch(QWidget* parent) : QAbstractButton(parent) { + setCheckable(true); + setCursor(Qt::PointingHandCursor); + } + + QSize sizeHint() const override { + return {42, 24}; + } + +protected: + void paintEvent(QPaintEvent*) override { + QPainter painter{this}; + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(Qt::NoPen); + const QRectF track = QRectF(rect()).adjusted(1, 1, -1, -1); + QColor fill = isChecked() ? ConfigurePlayerAssignment::Accent(this) + : (DarkUi() ? QColor(255, 255, 255, 70) + : palette().mid().color()); + if (!isEnabled()) { + fill.setAlpha(110); + } + painter.setBrush(fill); + painter.drawRoundedRect(track, track.height() / 2, track.height() / 2); + const qreal knob = track.height() - 6; + const qreal x = isChecked() ? track.right() - 3 - knob : track.left() + 3; + painter.setBrush(Qt::white); + painter.drawEllipse(QRectF(x, track.top() + 3, knob, knob)); + } +}; +constexpr char PlayerMime[] = "application/x-eden-player"; + +/// Keeps a drop-down's ✕ inside it, left of its arrow +class ClearButtonPlacer : public QObject { +public: + ClearButtonPlacer(QComboBox* combo_, QToolButton* button_) + : QObject(combo_), combo{combo_}, button{button_} {} + +protected: + bool eventFilter(QObject* watched, QEvent* event) override { + if (watched == combo && + (event->type() == QEvent::Resize || event->type() == QEvent::Show)) { + button->move(combo->width() - 22 - button->width(), + (combo->height() - button->height()) / 2); + } + return QObject::eventFilter(watched, event); + } + +private: + QComboBox* combo; + QToolButton* button; +}; + +/// The power symbol on Turn Off: white, grey while it waits +QIcon PowerIcon() { + const auto draw = [](const QColor& color) { + QPixmap pixmap(QSize(14, 14) * 2); + pixmap.setDevicePixelRatio(2); + pixmap.fill(Qt::transparent); + QPainter painter{&pixmap}; + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(QPen(color, 2, Qt::SolidLine, Qt::RoundCap)); + painter.drawArc(QRectF(2, 2.5, 10, 10), 125 * 16, 290 * 16); + painter.drawLine(QPointF(7, 1), QPointF(7, 7)); + painter.end(); + return pixmap; + }; + QIcon icon; + icon.addPixmap(draw(Qt::white), QIcon::Normal); + icon.addPixmap(draw(QColor(138, 143, 150)), QIcon::Disabled); + return icon; +} + +/// The edit field of a player's name: Enter and Esc don't reach the dialog +class PlayerNameEdit : public QLineEdit { +public: + using QLineEdit::QLineEdit; + + std::function on_apply; + std::function on_cancel; + +protected: + void keyPressEvent(QKeyEvent* event) override { + if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { + event->accept(); + if (on_apply) { + on_apply(); + } + return; + } + if (event->key() == Qt::Key_Escape) { + event->accept(); + if (on_cancel) { + on_cancel(); + } + return; + } + QLineEdit::keyPressEvent(event); + } +}; + +/// A setting's row: its title in bold, a line about it, and its control on the right +void AddOptionRow(QBoxLayout* to, QWidget* parent, const QString& title, const QString& note, + QWidget* control) { + auto* line = new QHBoxLayout(); + auto* text = new QVBoxLayout(); + text->setSpacing(1); + auto* title_label = new QLabel(title, parent); + QFont font = title_label->font(); + font.setBold(true); + title_label->setFont(font); + auto* note_label = new QLabel(note, parent); + note_label->setWordWrap(true); + note_label->setObjectName(QStringLiteral("note")); + text->addWidget(title_label); + text->addWidget(note_label); + line->addLayout(text, 1); + line->addWidget(control, 0, Qt::AlignVCenter); + to->addLayout(line); +} + +/// A controller's battery, as the overlay draws it +QPixmap BatteryIcon(int percent, bool charging) { + QPixmap pixmap(QSize(20, 12) * 2); + pixmap.setDevicePixelRatio(2); + pixmap.fill(Qt::transparent); + QPainter painter{&pixmap}; + painter.setRenderHint(QPainter::Antialiasing); + const QRectF cell(1, 2, 15, 8); + painter.setPen(QPen(QColor(150, 155, 162), 1.2)); + painter.setBrush(Qt::NoBrush); + painter.drawRoundedRect(cell, 2, 2); + painter.setPen(Qt::NoPen); + painter.setBrush(QColor(150, 155, 162)); + painter.drawRect(QRectF(cell.right() + 0.6, cell.center().y() - 1.5, 1.8, 3)); + painter.setBrush(percent <= 15 && !charging ? QColor(220, 60, 60) : QColor(70, 180, 100)); + painter.drawRect(QRectF(cell.left() + 1.5, cell.top() + 1.5, + (cell.width() - 3) * (std::clamp)(percent, 0, 100) / 100.0, + cell.height() - 3)); + if (charging) { + painter.setPen(QPen(Qt::white, 1.2)); + const QPointF c = cell.center(); + const QPointF bolt[3] = {QPointF(c.x() + 1, c.y() - 3), QPointF(c.x() - 1.5, c.y() + 0.5), + QPointF(c.x() + 1.5, c.y() - 0.5)}; + painter.drawPolyline(bolt, 3); + painter.drawLine(bolt[2], QPointF(c.x() - 1, c.y() + 3)); + } + painter.end(); + return pixmap; +} + +/// The name's icons (edit, apply, remove), drawn so they look the same everywhere +QIcon NameIcon(int kind, const QColor& color) { + QPixmap pixmap(QSize(14, 14) * 2); + pixmap.setDevicePixelRatio(2); + pixmap.fill(Qt::transparent); + QPainter painter{&pixmap}; + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(QPen(color, 1.6, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + painter.setBrush(Qt::NoBrush); + if (kind == 0) { // pencil + painter.drawLine(QPointF(3, 11), QPointF(10.5, 3.5)); + painter.drawLine(QPointF(9, 2), QPointF(12, 5)); + painter.drawLine(QPointF(2.5, 11.5), QPointF(2, 12)); + } else if (kind == 1) { // check + const QPointF check[3] = {QPointF(2.5, 7.5), QPointF(5.5, 10.5), QPointF(11.5, 3.5)}; + painter.drawPolyline(check, 3); + } else { // bin + painter.drawLine(QPointF(2, 3.5), QPointF(12, 3.5)); + painter.drawLine(QPointF(5.5, 3.5), QPointF(5.5, 2)); + painter.drawLine(QPointF(5.5, 2), QPointF(8.5, 2)); + painter.drawLine(QPointF(8.5, 2), QPointF(8.5, 3.5)); + painter.drawRoundedRect(QRectF(3.5, 3.5, 7, 9), 1, 1); + painter.drawLine(QPointF(6, 6), QPointF(6, 10)); + painter.drawLine(QPointF(8, 6), QPointF(8, 10)); + } + painter.end(); + return QIcon{pixmap}; +} + +/// One player in the list: a click rumbles its controller, a drag onto another player swaps them +class PlayerRow : public QFrame { +public: + PlayerRow(int player_, QWidget* parent) : QFrame(parent), player{player_} { + setObjectName(QStringLiteral("playerRow")); + setAcceptDrops(true); + setCursor(Qt::OpenHandCursor); + long_press.setSingleShot(true); + long_press.setInterval(400); + QObject::connect(&long_press, &QTimer::timeout, this, [this] { StartDrag(); }); + } + + std::function on_click; + std::function on_drop; + +protected: + void mousePressEvent(QMouseEvent* event) override { + if (event->button() == Qt::LeftButton) { + press_pos = event->position().toPoint(); + pressed = true; + long_press.start(); + } + QFrame::mousePressEvent(event); + } + + void mouseMoveEvent(QMouseEvent* event) override { + if (pressed && (event->position().toPoint() - press_pos).manhattanLength() >= + QApplication::startDragDistance()) { + StartDrag(); + } + QFrame::mouseMoveEvent(event); + } + + void mouseReleaseEvent(QMouseEvent* event) override { + if (pressed && long_press.isActive() && on_click) { + on_click(player); + } + pressed = false; + long_press.stop(); + QFrame::mouseReleaseEvent(event); + } + + void dragEnterEvent(QDragEnterEvent* event) override { + if (event->mimeData()->hasFormat(QString::fromLatin1(PlayerMime))) { + event->acceptProposedAction(); + drop_hover = true; + update(); + } + } + + void dragLeaveEvent(QDragLeaveEvent* event) override { + drop_hover = false; + update(); + QFrame::dragLeaveEvent(event); + } + + void paintEvent(QPaintEvent* event) override { + QFrame::paintEvent(event); + if (drop_hover) { + // Where the dragged player lands + QPainter painter{this}; + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(QPen(ConfigurePlayerAssignment::Accent(this), 2, Qt::DashLine)); + painter.drawRoundedRect(QRectF(rect()).adjusted(1, 1, -1, -1), 4, 4); + } + } + + void dropEvent(QDropEvent* event) override { + drop_hover = false; + update(); + const int from = event->mimeData()->data(QString::fromLatin1(PlayerMime)).toInt(); + if (from != player && on_drop) { + on_drop(from, player); + } + event->acceptProposedAction(); + } + +private: + void StartDrag() { + if (!pressed) { + return; + } + pressed = false; + long_press.stop(); + auto* mime = new QMimeData; + mime->setData(QString::fromLatin1(PlayerMime), QByteArray::number(player)); + auto* drag = new QDrag(this); + drag->setMimeData(mime); + drag->setPixmap(grab()); + drag->setHotSpot(press_pos); + setCursor(Qt::ClosedHandCursor); + drag->exec(Qt::MoveAction); + setCursor(Qt::OpenHandCursor); + } + + int player; + bool pressed = false; + bool drop_hover = false; + QPoint press_pos; + QTimer long_press; +}; + +} // Anonymous namespace + +QToolButton* ConfigurePlayerAssignment::AddClearButton(QComboBox* combo) { + auto* button = new QToolButton(combo); + button->setText(QStringLiteral("\u2715")); + button->setCursor(Qt::ArrowCursor); + button->setFixedSize(18, 18); + button->setStyleSheet(Themed( + QStringLiteral("QToolButton { border: none; border-radius: 9px; background: transparent; " + "color: muted-text; padding: 0px; }" + "QToolButton:hover { background: palette(highlight); " + "color: palette(highlighted-text); }"))); + // (Room for it between the text and the arrow) + combo->setStyleSheet(QStringLiteral("QComboBox { padding-right: 40px; }")); + combo->installEventFilter(new ClearButtonPlacer(combo, button)); + return button; +} + +QString ConfigurePlayerAssignment::Themed(QString style) { + if (!DarkUi()) { + return style.replace(QStringLiteral("muted-text"), QStringLiteral("#7d838b")) + .replace(QStringLiteral("popup-base"), QStringLiteral("palette(base)")); + } + // An open drop-down list is a window of its own: a solid background (a tint shows white) + style.replace( + QStringLiteral("popup-base"), + !UISettings::IsDarkTheme() + ? QApplication::palette().color(QPalette::Window).name() + : QString::fromStdString(UISettings::values.theme).contains(QStringLiteral("midnight")) + ? QStringLiteral("#19232D") + : QStringLiteral("#31363B")); + // Cards show the theme's background, fields and buttons a light tint + static const std::array, 8> dark{{ + {"palette(alternate-base)", "transparent"}, + {"palette(base)", "rgba(255, 255, 255, 14)"}, + {"palette(button)", "rgba(255, 255, 255, 22)"}, + {"palette(mid)", "rgba(255, 255, 255, 70)"}, + {"palette(highlighted-text)", "#ffffff"}, + {"palette(highlight)", "#3daee9"}, + {"palette(text)", "#eff0f1"}, + {"muted-text", "#9da3aa"}, + }}; + for (const auto& [from, to] : dark) { + style.replace(QString::fromLatin1(from), QString::fromLatin1(to)); + } + return style; +} + +QColor ConfigurePlayerAssignment::Accent(const QWidget* widget) { + return DarkUi() ? QColor(0x3d, 0xae, 0xe9) + : widget->palette().highlight().color(); +} + +QPixmap ConfigurePlayerAssignment::Battery(int percent, bool charging) { + return BatteryIcon(percent, charging); +} + +QColor ConfigurePlayerAssignment::PlayerColor(int player) { + return PlayerColors[static_cast(player) % PlayerColors.size()]; +} + +QString ConfigurePlayerAssignment::ModernComboStyle() { + return Themed(QStringLiteral( + "QComboBox { border: 1px solid palette(mid); border-radius: 6px; padding: 3px 10px; " + "background: palette(base); }" + "QComboBox:hover, QComboBox:focus { border-color: palette(highlight); }" + "QComboBox:disabled { color: palette(mid); }" + // The open list: readable rows, the hovered one in the highlight colour + "QComboBox QAbstractItemView { background: popup-base; color: palette(text); " + "border: 1px solid palette(mid); outline: 0; padding: 2px; }" + "QComboBox QAbstractItemView::item { min-height: 24px; padding: 0 8px; }" + "QComboBox QAbstractItemView::item:hover, QComboBox QAbstractItemView::item:selected { " + "background: palette(highlight); color: palette(highlighted-text); }")); +} + +void ConfigurePlayerAssignment::ModernizeCombos(QWidget* root) { + // A combo box's own list painter ignores the style sheet: the standard one follows it + for (auto* combo : root->findChildren()) { + if (!combo->property("modern_list").toBool()) { + combo->setItemDelegate(new QStyledItemDelegate(combo)); + // The list's frame takes its solid background (its padding showed white) + if (QWidget* frame = combo->view()->window(); frame && frame != combo->window()) { + frame->setStyleSheet(Themed(QStringLiteral( + "QFrame { background: popup-base; border: 1px solid palette(mid); }"))); + } + combo->setProperty("modern_list", true); + } + } +} + +QString ConfigurePlayerAssignment::OutlinedButtonStyle() { + return Themed(QStringLiteral( + "QPushButton, QToolButton { border: 1px solid palette(highlight); border-radius: 6px; " + "padding: 3px 12px; color: palette(highlight); font-weight: bold; " + "background: palette(base); }" + "QPushButton:hover, QToolButton:hover { background: palette(highlight); " + "color: palette(highlighted-text); }" + "QPushButton:disabled, QToolButton:disabled { border-color: palette(mid); " + "color: palette(mid); }")); +} + +QWidget* ConfigurePlayerAssignment::MakeSegmented(QWidget* parent, const QStringList& labels, + const std::vector& ids, + QButtonGroup* group) { + auto* bar = new QWidget(parent); + auto* bar_layout = new QHBoxLayout(bar); + bar_layout->setContentsMargins(0, 0, 0, 0); + bar_layout->setSpacing(0); + for (int k = 0; k < labels.size(); ++k) { + auto* button = new QPushButton(labels[k], bar); + button->setCheckable(true); + button->setCursor(Qt::PointingHandCursor); + QString style = + QStringLiteral("QPushButton { padding: 5px 14px; border: 1px solid palette(mid); " + "background: palette(button); }" + "QPushButton:checked { background: palette(highlight); " + "color: palette(highlighted-text); border-color: palette(highlight); }" + "QPushButton:disabled { color: palette(mid); }"); + if (k == 0) { + style += QStringLiteral("QPushButton { border-top-left-radius: 6px; " + "border-bottom-left-radius: 6px; }"); + } else { + style += QStringLiteral("QPushButton { border-left-width: 0px; }"); + } + if (k == labels.size() - 1) { + style += QStringLiteral("QPushButton { border-top-right-radius: 6px; " + "border-bottom-right-radius: 6px; }"); + } + button->setStyleSheet(Themed(style)); + group->addButton(button, ids[static_cast(k)]); + bar_layout->addWidget(button); + } + return bar; +} + +ConfigurePlayerAssignment::ConfigurePlayerAssignment(QWidget* parent) : QWidget(parent) { + // The cards keep their height and the page scrolls when they don't fit + auto* outer = new QVBoxLayout(this); + outer->setContentsMargins(0, 0, 0, 0); + auto* scroll = new QScrollArea(this); + scroll->setFrameShape(QFrame::NoFrame); + scroll->setWidgetResizable(true); + scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scroll->viewport()->setAutoFillBackground(false); + auto* content = new QWidget(scroll); + content->setAutoFillBackground(false); + scroll->setWidget(content); + outer->addWidget(scroll); + auto* layout = new QVBoxLayout(content); + content_layout = layout; + layout->setSpacing(8); + // Each section is a rounded card (kept tight: the Deck's screen is 800 pixels tall) + setStyleSheet( + Themed(QStringLiteral("QGroupBox { border: 1px solid palette(mid); border-radius: 10px; " + "margin-top: 10px; padding: 8px 8px 4px 8px; " + "background: palette(alternate-base); }" + "QGroupBox::title { subcontrol-origin: margin; left: 14px; " + "padding: 0 4px; font-weight: bold; }" + // Labels show the card behind them (a dark theme paints every widget) + "QLabel { background: transparent; }" + "QLabel#note { color: muted-text; }")) + + ModernComboStyle()); + + // The handler, as a segmented control + auto* mode_box = new QGroupBox(tr("Controller Assignment Handler"), this); + auto* mode_layout = new QVBoxLayout(mode_box); + handler_group = new QButtonGroup(this); + auto* handler_row = new QHBoxLayout(); + handler_row->addWidget(MakeSegmented(mode_box, {tr("Modern Console"), tr("Manual")}, + {HandlerModern, HandlerManual}, handler_group)); + handler_row->addStretch(1); + mode_layout->addLayout(handler_row); + + // Under Manual: the controller applet a game sees when it asks for its players + manual_panel = new QFrame(mode_box); + manual_panel->setObjectName(QStringLiteral("manualPanel")); + manual_panel->setStyleSheet( + Themed(QStringLiteral("#manualPanel { border: 1px solid palette(mid); " + "border-radius: 8px; background: palette(base); }"))); + auto* manual_layout = new QVBoxLayout(manual_panel); + manual_layout->setContentsMargins(12, 8, 12, 8); + auto* manual_title = new QLabel(tr("Controller Applet"), manual_panel); + QFont manual_font = manual_title->font(); + manual_font.setBold(true); + manual_title->setFont(manual_font); + auto* manual_note = new QLabel(tr("What a game sees when it asks for its players. These are " + "the legacy ways of handling controllers: they do not have " + "Modern Console's features, such as players assigned " + "automatically, the overlay and the hints."), + manual_panel); + manual_note->setWordWrap(true); + manual_note->setObjectName(QStringLiteral("note")); + manual_group = new QButtonGroup(this); + auto* manual_row = new QHBoxLayout(); + manual_row->addWidget(MakeSegmented( + manual_panel, {tr("Disabled"), tr("Custom Frontend"), tr("Real Hardware")}, + {static_cast(Settings::AppletMode::Disabled), + static_cast(Settings::AppletMode::HLE), static_cast(Settings::AppletMode::LLE)}, + manual_group)); + manual_row->addStretch(1); + // What Manual itself does, under the choices + auto* manual_about = new QLabel(tr("In Manual, each player's controller is set by hand in " + "its player tab (P1 to P8) and stays until you change " + "it. The same choices are in System > Applets, also per " + "game."), + manual_panel); + manual_about->setWordWrap(true); + manual_about->setObjectName(QStringLiteral("note")); + manual_layout->addWidget(manual_title); + manual_layout->addWidget(manual_note); + manual_layout->addLayout(manual_row); + manual_layout->addWidget(manual_about); + auto* manual_indent = new QHBoxLayout(); + manual_indent->setContentsMargins(16, 0, 0, 0); + manual_indent->addWidget(manual_panel); + mode_layout->addLayout(manual_indent); + + // Under Modern Console: whether this is a handheld with its own controls + handheld_panel = new QFrame(mode_box); + handheld_panel->setObjectName(QStringLiteral("handheldPanel")); + handheld_panel->setStyleSheet( + Themed(QStringLiteral("#handheldPanel { border: 1px solid palette(mid); " + "border-radius: 8px; background: palette(base); }"))); + auto* panel_layout = new QHBoxLayout(handheld_panel); + panel_layout->setContentsMargins(12, 8, 12, 8); + auto* panel_text = new QVBoxLayout(); + auto* panel_title = + new QLabel(tr("Portable Handheld Gaming Device with Built-in Controller"), handheld_panel); + QFont title_font = panel_title->font(); + title_font.setBold(true); + panel_title->setFont(title_font); + panel_title->setWordWrap(true); + auto* panel_note = new QLabel(tr("For a handheld with its own controls, like a Steam Deck, " + "Legion Go or ROG Ally: connected controllers take the " + "players first, and the built-in controls play only when " + "no other controller is connected."), + handheld_panel); + panel_note->setWordWrap(true); + panel_note->setObjectName(QStringLiteral("note")); + panel_text->addWidget(panel_title); + panel_text->addWidget(panel_note); + panel_layout->addLayout(panel_text, 1); + handheld_switch = new ToggleSwitch(handheld_panel); + handheld_switch->setToolTip(tr("On: this is a handheld with its own controls")); + panel_layout->addWidget(handheld_switch, 0, Qt::AlignVCenter); + auto* indent = new QHBoxLayout(); + indent->setContentsMargins(16, 0, 0, 0); + indent->addWidget(handheld_panel); + mode_layout->addLayout(indent); + + mode_info = new QLabel(mode_box); + mode_info->setWordWrap(true); + mode_layout->addWidget(mode_info); + layout->addWidget(mode_box); + + // Under Steam: read the controllers directly instead of through Steam Input + auto* steam_box = new QGroupBox(tr("Steam Input"), this); + steam_panel = steam_box; + auto* steam_column = new QVBoxLayout(steam_box); + auto* steam_layout = new QHBoxLayout(); + steam_column->addLayout(steam_layout); + auto* steam_text = new QVBoxLayout(); + steam_text->setSpacing(1); + auto* steam_title = new QLabel(tr("Bypass Steam Input"), steam_box); + steam_title->setFont(title_font); + auto* steam_note = new QLabel( + tr("Eden reads your controllers directly instead of through Steam's virtual " + "controllers, so Steam Input layouts don't apply in Eden. Try this if a controller " + "doesn't work under Steam, such as the Steam Controller or a newer controller. Takes " + "effect after restarting Eden; connected controllers may be assigned to different " + "players."), + steam_box); + steam_note->setWordWrap(true); + steam_note->setObjectName(QStringLiteral("note")); + steam_restart = new QLabel(tr("Restart Eden to apply this change."), steam_box); + steam_text->addWidget(steam_title); + steam_text->addWidget(steam_note); + steam_layout->addLayout(steam_text, 1); + steam_switch = new ToggleSwitch(steam_box); + steam_switch->setToolTip(tr("On: Eden reads the controllers directly")); + steam_layout->addWidget(steam_switch, 0, Qt::AlignVCenter); + original_bypass = Settings::values.console_bypass_steam.GetValue(); + steam_switch->setChecked(original_bypass); + connect(steam_switch, &QAbstractButton::toggled, this, [this](bool on) { + Settings::values.console_bypass_steam.SetValue(on); + UpdateModeUi(); + }); + + steam_column->addWidget(steam_restart); + layout->addWidget(steam_box); + + // Assign Handheld Controller: declare the handheld's own controller (that mode only) + builtin_row = new QGroupBox(tr("Assign Handheld Controller"), this); + auto* builtin_layout = new QVBoxLayout(builtin_row); + auto* picker_row = new QHBoxLayout(); + picker_row->addWidget(new QLabel(tr("Handheld's controller:"), builtin_row)); + builtin_picker = new QComboBox(builtin_row); + builtin_picker->addItem(tr("Auto-detect"), QString{}); + picker_row->addWidget(builtin_picker, 1); + builtin_identify = new QPushButton(tr("Identify"), builtin_row); + builtin_identify->setCursor(Qt::PointingHandCursor); + builtin_identify->setStyleSheet(OutlinedButtonStyle()); + picker_row->addWidget(builtin_identify); + builtin_layout->addLayout(picker_row); + // The ✕ inside the picker removes the handheld's controller (auto-detect then skips it) + builtin_remove = AddClearButton(builtin_picker); + builtin_remove->setToolTip(tr("Not the handheld's controller: remove it. Auto-detect will " + "not pick it again until you allow it.")); + builtin_remove->hide(); + // A removed controller: said plainly, with the way to allow it again + blocked_row = new QWidget(builtin_row); + auto* blocked_line = new QHBoxLayout(blocked_row); + blocked_line->setContentsMargins(0, 0, 0, 0); + blocked_label = new QLabel(blocked_row); + blocked_label->setWordWrap(true); + blocked_label->setObjectName(QStringLiteral("note")); + blocked_line->addWidget(blocked_label, 1); + blocked_allow = new QPushButton(tr("Allow Again"), blocked_row); + blocked_allow->setCursor(Qt::PointingHandCursor); + blocked_allow->setStyleSheet(OutlinedButtonStyle()); + blocked_line->addWidget(blocked_allow); + builtin_layout->addWidget(blocked_row); + builtin_status = new QLabel(builtin_row); + builtin_status->setWordWrap(true); + builtin_layout->addWidget(builtin_status); + connect(builtin_remove, &QToolButton::clicked, this, [] { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.builtin_remove_request = true; + }); + connect(blocked_allow, &QPushButton::clicked, this, + [] { Settings::values.builtin_pad_blocked.SetValue(std::string{}); }); + layout->addWidget(builtin_row); + + // The players right now, as the engine assigned them + now_box = new QGroupBox(tr("Connected Players"), this); + auto* now_layout = new QVBoxLayout(now_box); + players_box = new QWidget(now_box); + players_list = new QVBoxLayout(players_box); + players_list->setContentsMargins(0, 0, 0, 0); + players_list->setSpacing(6); + now_layout->addWidget(players_box); + players_note = new QLabel(now_box); + players_note->setWordWrap(true); + now_layout->addWidget(players_note); + layout->addWidget(now_box); + + // Gameplay: how players' controllers behave in games + auto* gameplay = new QGroupBox(tr("Gameplay"), this); + gameplay_box = gameplay; + auto* gameplay_layout = new QVBoxLayout(gameplay); + const auto add_option = [gameplay, gameplay_layout](const QString& title, const QString& note, + QWidget* control) { + AddOptionRow(gameplay_layout, gameplay, title, note, control); + }; + joycon_switch = new ToggleSwitch(gameplay); + add_option(tr("Use Any Controller as Joy-Cons"), + tr("When a game only takes Joy-Cons, such as one Joy-Con per player, your " + "controllers act as Joy-Cons automatically, with the buttons arranged to fit. A " + "controller type picked in a player's tab is left as it is."), + joycon_switch); + original_joycon = Settings::values.console_joycon_auto.GetValue(); + joycon_switch->setChecked(original_joycon); + connect(joycon_switch, &QAbstractButton::toggled, this, + [](bool on) { Settings::values.console_joycon_auto.SetValue(on); }); + + layout_group = new QButtonGroup(this); + auto* layout_choice = + MakeSegmented(gameplay, {tr("By Position"), tr("By Label")}, {0, 1}, layout_group); + add_option(tr("Button Layout"), + tr("For Xbox and PlayStation style controllers. By Position: the button where the " + "Switch has A acts as A. By Label: the button marked A acts as A. Nintendo " + "controllers already match both ways."), + layout_choice); + original_labels = Settings::values.console_button_labels.GetValue(); + layout_group->button(original_labels ? 1 : 0)->setChecked(true); + connect(layout_group, &QButtonGroup::idClicked, this, + [](int id) { Settings::values.console_button_labels.SetValue(id == 1); }); + + pause_switch = new ToggleSwitch(gameplay); + add_option(tr("Pause When a Controller Disconnects"), + tr("Pauses the game when a player's controller is turned off, or has been gone " + "for 3 seconds, and resumes when a controller takes that player again. Press + " + "on another controller to go on without that player."), + pause_switch); + original_pause = Settings::values.console_pause_disconnect.GetValue(); + pause_switch->setChecked(original_pause); + connect(pause_switch, &QAbstractButton::toggled, this, + [](bool on) { Settings::values.console_pause_disconnect.SetValue(on); }); + + lights_switch = new ToggleSwitch(gameplay); + add_option(tr("Player Lights"), + tr("Controllers' player lights and light bars show their player, in its colour. " + "Under Steam, Steam sets the lights of the controllers it handles."), + lights_switch); + original_lights = Settings::values.console_player_lights.GetValue(); + lights_switch->setChecked(original_lights); + connect(lights_switch, &QAbstractButton::toggled, this, + [](bool on) { Settings::values.console_player_lights.SetValue(on); }); + layout->addWidget(gameplay); + + // What shows over the game: a title, a line about it and a switch per item + auto* display = new QGroupBox(tr("On-Screen Display"), this); + display_box = display; + auto* display_layout = new QVBoxLayout(display); + const auto add_switch_to = [display](QVBoxLayout* to, const QString& title, + const QString& note) { + auto* toggle = new ToggleSwitch(display); + AddOptionRow(to, display, title, note, toggle); + return toggle; + }; + const auto add_switch = [&](const QString& title, const QString& note) { + return add_switch_to(display_layout, title, note); + }; + // The same switch as View > Show Controller Overlay + overlay_toggle = add_switch(tr("Controller Overlay"), + tr("The players, their controllers and their last buttons in " + "the top-left corner.")); + original_overlay = Settings::values.console_debug_overlay.GetValue(); + overlay_toggle->setChecked(original_overlay); + connect(overlay_toggle, &QAbstractButton::toggled, this, + [](bool shown) { Settings::values.console_debug_overlay.SetValue(shown); }); + + // The overlay's own options, indented under it: the button history and how it shows + history_options = new QWidget(display); + auto* history_layout = new QVBoxLayout(history_options); + history_layout->setContentsMargins(20, 0, 0, 4); + history_toggle = add_switch_to(history_layout, tr("Button History"), + tr("The last buttons each player pressed, beside their row. " + "Buttons pressed together show as one input.")); + // A slider with its value beside it + const auto add_slider = [this, display, history_layout](const QString& title, int min, int max, + int value, const QString& unit) { + auto* line = new QHBoxLayout(); + auto* label = new QLabel(title, display); + line->addWidget(label); + auto* slider = new QSlider(Qt::Horizontal, display); + slider->setRange(min, max); + slider->setValue(value); + slider->setPageStep(1); + line->addWidget(slider, 1); + auto* shown = new QLabel(display); + shown->setMinimumWidth(shown->fontMetrics().horizontalAdvance(unit.arg(max)) + 4); + shown->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + shown->setText(unit.arg(value)); + line->addWidget(shown); + connect(slider, &QSlider::valueChanged, this, + [shown, unit](int v) { shown->setText(unit.arg(v)); }); + auto* row = new QWidget(display); + row->setLayout(line); + line->setContentsMargins(0, 0, 0, 0); + history_layout->addWidget(row); + return std::pair{slider, row}; + }; + original_history = Settings::values.console_history.GetValue(); + original_history_size = Settings::values.console_history_size.GetValue(); + original_history_seconds = Settings::values.console_history_seconds.GetValue(); + original_history_gaps = Settings::values.console_history_gaps.GetValue(); + QWidget* size_row = nullptr; + QWidget* seconds_row = nullptr; + std::tie(history_size, size_row) = + add_slider(tr("Inputs kept"), 5, 20, original_history_size, tr("%1")); + std::tie(history_seconds, seconds_row) = + add_slider(tr("Expire after"), 1, 30, original_history_seconds, tr("%1 s")); + gaps_toggle = add_switch_to(history_layout, tr("Time Between Presses"), + tr("The milliseconds between inputs, never more than the expire " + "time.")); + display_layout->addWidget(history_options); + history_toggle->setChecked(original_history); + gaps_toggle->setChecked(original_history_gaps); + connect(history_toggle, &QAbstractButton::toggled, this, + [](bool shown) { Settings::values.console_history.SetValue(shown); }); + connect(history_size, &QSlider::valueChanged, this, + [](int v) { Settings::values.console_history_size.SetValue(v); }); + connect(history_seconds, &QSlider::valueChanged, this, + [](int v) { Settings::values.console_history_seconds.SetValue(v); }); + connect(gaps_toggle, &QAbstractButton::toggled, this, + [](bool shown) { Settings::values.console_history_gaps.SetValue(shown); }); + // Only what applies can be changed + const auto update_history_options = [this, size_row, seconds_row] { + const bool history_on = history_toggle->isChecked(); + history_options->setEnabled(overlay_toggle->isChecked()); + size_row->setEnabled(history_on); + seconds_row->setEnabled(history_on); + gaps_toggle->setEnabled(history_on); + }; + connect(overlay_toggle, &QAbstractButton::toggled, this, update_history_options); + connect(history_toggle, &QAbstractButton::toggled, this, update_history_options); + update_history_options(); + hints_toggle = add_switch(tr("Controller Hints"), + tr("Names a controller in the bottom-left corner for a moment " + "when it joins as a player or leaves.")); + original_hints = Settings::values.console_hints.GetValue(); + hints_toggle->setChecked(original_hints); + connect(hints_toggle, &QAbstractButton::toggled, this, + [](bool shown) { Settings::values.console_hints.SetValue(shown); }); + layout->addWidget(display); + + // Logging for bug reports + auto* debug = new QGroupBox(tr("Troubleshooting"), this); + debug_box = debug; + auto* debug_layout = new QVBoxLayout(debug); + probes_toggle = add_switch_to(debug_layout, tr("Debug Probes"), + tr("Writes detailed controller traces to the log several times " + "a second, for bug reports. Connected controllers are " + "always described in the log.")); + original_probes = Common::ControllerProbes(); + probes_toggle->setChecked(original_probes); + connect(probes_toggle, &QAbstractButton::toggled, this, + [](bool on) { Settings::values.console_debug_probes.SetValue(on); }); + layout->addWidget(debug); + + // A short word on the two automatic modes, last on the page + auto* about = new QGroupBox(tr("How It Works"), this); + about_box = about; + auto* about_layout = new QVBoxLayout(about); + const auto add_about = [about, about_layout](const QString& title, const QString& text) { + auto* title_label = new QLabel(title, about); + QFont font = title_label->font(); + font.setBold(true); + title_label->setFont(font); + auto* text_label = new QLabel(text, about); + text_label->setWordWrap(true); + text_label->setObjectName(QStringLiteral("note")); + about_layout->addWidget(title_label); + about_layout->addWidget(text_label); + }; + add_about(tr("Modern Console"), + tr("Controllers are assigned like on the console: each one that connects becomes " + "the next player, with nothing to set up. Players keep their own controls when " + "they swap, and a profile picked for a player is used again next time. Its " + "mappings are its own: each controller starts with its standard mapping, and " + "the Manual modes' players are never changed. Keyboard and mouse: use Manual.")); + add_about(tr("Handheld Console"), + tr("For a handheld PC with built-in controls. The same as Modern Console, but the " + "built-in controls always come last: connect a controller and it becomes " + "Player 1, so a docked handheld plays like a console.")); + add_about(tr("Steam Controller"), + tr("Under Steam, turn on Bypass Steam Input (Steam Input card) so Eden reads the " + "Steam Controller itself. Steam Input layouts then don't apply in Eden.")); + layout->addWidget(about); + layout->addStretch(1); + + // The mode applies at once; closing without applying puts the previous one back + original_mode = static_cast(Settings::values.controller_applet_mode.GetValue()); + connect(handler_group, &QButtonGroup::idClicked, this, + &ConfigurePlayerAssignment::OnModeChanged); + connect(manual_group, &QButtonGroup::idClicked, this, + &ConfigurePlayerAssignment::OnModeChanged); + connect(handheld_switch, &QAbstractButton::clicked, this, + &ConfigurePlayerAssignment::OnModeChanged); + connect(builtin_picker, &QComboBox::currentIndexChanged, this, + &ConfigurePlayerAssignment::OnBuiltinPicked); + connect(builtin_identify, &QPushButton::clicked, this, + &ConfigurePlayerAssignment::OnIdentifyPressed); + + timer = new QTimer(this); + connect(timer, &QTimer::timeout, this, &ConfigurePlayerAssignment::Refresh); + // Fast enough for the highlight to follow a button press + timer->start(50); + + LoadConfiguration(); + Refresh(); +} + +ConfigurePlayerAssignment::~ConfigurePlayerAssignment() { + if (!applied) { + Settings::values.controller_applet_mode.SetValue( + static_cast(original_mode)); + Settings::values.console_debug_overlay.SetValue(original_overlay); + Settings::values.console_hints.SetValue(original_hints); + Settings::values.console_history.SetValue(original_history); + Settings::values.console_history_size.SetValue(original_history_size); + Settings::values.console_history_seconds.SetValue(original_history_seconds); + Settings::values.console_history_gaps.SetValue(original_history_gaps); + Settings::values.console_debug_probes.SetValue(original_probes); + Settings::values.console_bypass_steam.SetValue(original_bypass); + Settings::values.console_joycon_auto.SetValue(original_joycon); + Settings::values.console_button_labels.SetValue(original_labels); + Settings::values.console_pause_disconnect.SetValue(original_pause); + Settings::values.console_player_lights.SetValue(original_lights); + } +} + +void ConfigurePlayerAssignment::LoadConfiguration() { + const auto current = Settings::values.controller_applet_mode.GetValue(); + const bool modern = IsAutomatic(current); + handler_group->button(modern ? HandlerModern : HandlerManual)->setChecked(true); + // Under Manual the applet as set; the default there is Custom Frontend + QAbstractButton* applet = manual_group->button(static_cast(current)); + (applet && !modern ? applet : manual_group->button(static_cast(Settings::AppletMode::HLE))) + ->setChecked(true); + handheld_switch->setChecked(current == Settings::AppletMode::HandheldConsoleMode); + UpdateModeUi(); +} + +int ConfigurePlayerAssignment::SelectedMode() const { + switch (handler_group->checkedId()) { + case HandlerModern: + return static_cast(handheld_switch->isChecked() + ? Settings::AppletMode::HandheldConsoleMode + : Settings::AppletMode::ConsoleMode); + default: + return manual_group->checkedId(); + } +} + +void ConfigurePlayerAssignment::OnModeChanged() { + Settings::values.controller_applet_mode.SetValue( + static_cast(SelectedMode())); + UpdateModeUi(); +} + +void ConfigurePlayerAssignment::ApplyConfiguration() { + Settings::values.controller_applet_mode.SetValue( + static_cast(SelectedMode())); + applied = true; +} + +void ConfigurePlayerAssignment::UpdateModeUi() { + const auto selected = static_cast(SelectedMode()); + handheld_panel->setVisible(handler_group->checkedId() == HandlerModern); + // (Bypass Steam Input: only under Steam; applies to a Modern Console start) + steam_panel->setVisible(handler_group->checkedId() == HandlerModern && + Common::RunningUnderSteam()); + steam_restart->setVisible(steam_switch->isChecked() != + Common::GetControllerConsoleState().steam_bypassed); + manual_panel->setVisible(handler_group->checkedId() == HandlerManual); + // Only the automatic modes have live players to show + const bool automatic = IsAutomatic(selected); + switch (selected) { + case Settings::AppletMode::ConsoleMode: + mode_info->setText(tr("Controller assignment is automatic. Each controller is assigned " + "to the next available player when it connects.")); + break; + case Settings::AppletMode::HandheldConsoleMode: + mode_info->setText(tr("Controller assignment is automatic, with the handheld's own " + "controls last.")); + break; + case Settings::AppletMode::Disabled: + mode_info->setText(tr("Controllers are assigned in each player's tab. Games use the " + "configured players without showing a controller applet.")); + break; + case Settings::AppletMode::LLE: + mode_info->setText(tr("Controllers are assigned in each player's tab. When a game " + "requests controller setup, the console's own controller applet " + "is shown. This requires the system firmware.")); + break; + default: + mode_info->setText(tr("Controllers are assigned in each player's tab. When a game " + "requests controller setup, Eden's controller applet is shown.")); + break; + } + now_box->setVisible(automatic); + display_box->setVisible(automatic); + gameplay_box->setVisible(automatic); + about_box->setVisible(automatic); + debug_box->setVisible(automatic); + builtin_row->setVisible(selected == Settings::AppletMode::HandheldConsoleMode); + Refresh(); +} + +void ConfigurePlayerAssignment::Refresh() { + RefreshBuiltin(); + RefreshPlayers(); +} + +void ConfigurePlayerAssignment::RefreshBuiltin() { + auto& state = Common::GetControllerConsoleState(); + std::vector> pads; + std::size_t builtin_pads = 0; + bool armed = false; + std::chrono::steady_clock::time_point armed_at{}; + std::string detected_name; + { + std::scoped_lock lock{state.mutex}; + pads = state.pads; + builtin_pads = state.builtin_pads; + armed = state.identify_armed; + armed_at = state.identify_armed_at; + detected_name = state.handheld_name; + } + + // The entries' data: the Steam handle under Steam (the virtual pads share one GUID), else + // the pad's identity + QString signature = QString::number(builtin_pads) + QLatin1Char('|'); + for (const auto& [display, ident] : pads) { + signature += QString::fromStdString(ident) + QLatin1Char('|'); + } + if (signature != builtin_signature) { + builtin_signature = signature; + const QString current = builtin_picker->currentData().toString(); + const bool blocked = builtin_picker->blockSignals(true); + builtin_picker->clear(); + builtin_picker->addItem(tr("Auto-detect"), QString{}); + for (std::size_t i = 0; i < pads.size(); ++i) { + if (i == builtin_pads) { + // A heading (not pickable) before the standalone controllers + builtin_picker->insertSeparator(builtin_picker->count()); + builtin_picker->addItem(tr("Other controllers")); + if (auto* model = qobject_cast(builtin_picker->model())) { + model->item(builtin_picker->count() - 1)->setEnabled(false); + } + } + builtin_picker->addItem(QString::fromStdString(pads[i].first), + QString::fromStdString(pads[i].second)); + } + const int keep = builtin_picker->findData(current); + builtin_picker->setCurrentIndex(keep > 0 ? keep : 0); + builtin_picker->blockSignals(blocked); + } + + if (armed) { + const auto left = + std::chrono::duration_cast( + std::chrono::seconds{15} - (std::chrono::steady_clock::now() - armed_at)) + .count(); + builtin_status->setText( + tr("Waiting for a button press (%1 seconds)...").arg(std::max(0, left))); + // (The line below counts down) + builtin_identify->setText(tr("Press a button...")); + return; + } + builtin_identify->setText(tr("Identify")); + + // Stored per launch kind: the Steam handle under Steam, else the pad's identity + const bool steam = Common::SteamPadsInUse(); + const QString identity = + QString::fromStdString(Settings::values.builtin_pad_identity.GetValue()); + const QString handle = + QString::fromStdString(Settings::values.builtin_pad_steam_handle.GetValue()); + const QString stored = + steam ? (handle.isEmpty() ? QString{} : QStringLiteral("steamhandle:") + handle) : identity; + const bool declared = steam ? Settings::values.builtin_pad_steam_manual.GetValue() + : Settings::values.builtin_pad_manual.GetValue(); + + // Keep the picker on a declared pad, else on automatic detection + const int stored_index = stored.isEmpty() ? -1 : builtin_picker->findData(stored); + const int want_index = declared && stored_index > 0 ? stored_index : 0; + if (builtin_picker->currentIndex() != want_index) { + const bool blocked = builtin_picker->blockSignals(true); + builtin_picker->setCurrentIndex(want_index); + builtin_picker->blockSignals(blocked); + } + + bool engine_active = false; + { + std::scoped_lock lock{state.mutex}; + engine_active = state.engine_active; + } + if (engine_active && detected_name.empty() && + Settings::values.controller_applet_mode.GetValue() == + Settings::AppletMode::HandheldConsoleMode) { + builtin_status->setText(tr("Handheld controller not detected \u2014 working like Modern " + "until it is. Pick it above, or use Identify.")); + } else if (stored.isEmpty() && detected_name.empty()) { + builtin_status->setText( + tr("Not set. Pick the handheld's controller above, or use Identify.")); + } else { + const QString name = stored_index > 0 ? builtin_picker->itemText(stored_index) + : !detected_name.empty() ? QString::fromStdString(detected_name) + : tr("not set"); + builtin_status->setText( + tr("Handheld: %1 (%2). %3") + .arg(name) + .arg(want_index > 0 ? tr("declared") : tr("auto-detected")) + .arg(!detected_name.empty() + ? tr("Takes no player while external controllers are connected.") + : tr("Not currently connected."))); + } + + // The picker shows the handheld's controller, with the ✕ inside it to remove it + const bool shown = engine_active && !detected_name.empty(); + const QString first = shown && want_index == 0 + ? tr("%1 (auto-detected)").arg(QString::fromStdString(detected_name)) + : tr("Auto-detect"); + if (builtin_picker->itemText(0) != first) { + builtin_picker->setItemText(0, first); + } + builtin_remove->setVisible(shown); + builtin_status->setVisible(true); + // A removed controller, kept from auto-detect + std::string blocked_name; + { + std::scoped_lock lock{state.mutex}; + blocked_name = state.handheld_blocked_name; + } + const bool blocked = !Settings::values.builtin_pad_blocked.GetValue().empty(); + blocked_row->setVisible(blocked); + if (blocked) { + blocked_label->setText( + tr("Auto-detect is off for %1: it will not be picked as the handheld's controller.") + .arg(blocked_name.empty() ? tr("the removed controller") + : QString::fromStdString(blocked_name))); + } +} + +void ConfigurePlayerAssignment::RefreshPlayers() { + auto& state = Common::GetControllerConsoleState(); + std::vector players; + std::string handheld_name; + bool handheld_has_player = false; + bool engine_active = false; + { + std::scoped_lock lock{state.mutex}; + players = state.players; + handheld_name = state.handheld_name; + handheld_has_player = state.handheld_has_player; + engine_active = state.engine_active; + } + const auto selected = static_cast(SelectedMode()); + const bool in_effect = selected == Settings::values.controller_applet_mode.GetValue(); + + // The engine decides the flashes, as in the overlay + constexpr qint64 flash_ms = 1500; + const qint64 now = QDateTime::currentMSecsSinceEpoch(); + int last_player = -1; + for (const auto& entry : players) { + if (!entry.leaving) { + last_player = (std::max)(last_player, entry.player); + } + } + + // The saved input profiles, by their files (cheap enough to look at every refresh) + QStringList profiles; + { + const QDir dir{QString::fromStdString(Common::FS::PathToUTF8String( + Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) / "input"))}; + for (const QString& file : + dir.entryList({QStringLiteral("*.ini")}, QDir::Files, QDir::Name)) { + const QString name = file.chopped(4); + if (InputProfiles::IsProfileNameValid(name.toStdString())) { + profiles.push_back(name); + } + } + } + + // Rebuild the rows when they change; the colours only restyle them + QString signature = QString::number(swap_from) + QLatin1Char(';') + + profiles.join(QLatin1Char(',')) + QLatin1Char(';'); + for (const auto& entry : players) { + signature += + QString::number(entry.player) + QLatin1Char(':') + QString::fromStdString(entry.name) + + QLatin1Char('/') + QString::fromStdString(entry.profile) + + (entry.leaving ? QStringLiteral("x") : QString{}) + QString::number(entry.turn_off) + + QLatin1Char('/') + QString::number(entry.origin) + + (entry.guessed ? QStringLiteral("?") : QString{}) + QLatin1Char('/') + + QString::number(entry.battery / 5) + + (entry.charging ? QStringLiteral("c") : QString{}) + QLatin1Char('|'); + } + if (!handheld_has_player) { + signature += QStringLiteral("h:") + QString::fromStdString(handheld_name); + } + // (Not while a name is being typed: the rows would be rebuilt under it) + if (signature != players_signature && !editing_name) { + players_signature = signature; + const bool any_turn_off = std::any_of(players.begin(), players.end(), + [](const auto& e) { return e.turn_off != 0; }); + for (QFrame* row : player_rows) { + players_list->removeWidget(row); + row->hide(); + row->deleteLater(); + } + player_rows.clear(); + row_players.clear(); + for (const auto& entry : players) { + const int player = entry.player; + auto* row = new PlayerRow(player, players_box); + row->setToolTip(tr("Click to rumble this controller. Hold, then drop on another " + "player to swap them.")); + row->on_click = [this](int p) { RequestRumble(p); }; + row->on_drop = [this](int from, int to) { RequestSwap(from, to); }; + auto* line = new QHBoxLayout(row); + line->setContentsMargins(8, 5, 6, 5); + line->setSpacing(6); + auto* grip = new QLabel(QStringLiteral("\u283F"), row); + grip->setToolTip(tr("Drag onto another player to swap")); + grip->setObjectName(QStringLiteral("note")); + line->addWidget(grip); + // The player's badge, marked with ? for a reconnect's guess, else a dot in the + // colour of the player the controller started as + auto* badge_box = new QWidget(row); + badge_box->setFixedSize(40, 24); + // (Only the badge and its mark show: the dark themes paint a plain widget) + badge_box->setAttribute(Qt::WA_TranslucentBackground); + badge_box->setStyleSheet(QStringLiteral("background: transparent;")); + auto* badge = new QLabel(QStringLiteral("P%1").arg(player + 1), badge_box); + badge->setAlignment(Qt::AlignCenter); + badge->setGeometry(0, 3, 34, 20); + badge->setStyleSheet( + QStringLiteral("QLabel { background: %1; color: white; " + "border-radius: 10px; font-weight: bold; }") + .arg(PlayerColors[static_cast(player) % 8].name())); + if (!entry.leaving && (entry.guessed || entry.origin >= 0)) { + auto* mark = new QLabel(badge_box); + if (entry.guessed) { + mark->setText(QStringLiteral("?")); + mark->setAlignment(Qt::AlignCenter); + mark->setGeometry(27, 0, 13, 13); + mark->setStyleSheet(QStringLiteral( + "QLabel { background: white; color: #0e0e12; border: 1px solid #0e0e12; " + "border-radius: 6px; font-weight: bold; font-size: 9px; }")); + badge_box->setToolTip(tr("This controller came back without a way to tell " + "which one it is. Swap it if it's in the wrong " + "place.")); + } else { + mark->setGeometry(29, 1, 10, 10); + mark->setStyleSheet( + QStringLiteral("QLabel { background: %1; border: 1px solid #0e0e12; " + "border-radius: 5px; }") + .arg(PlayerColors[static_cast(entry.origin) % 8].name())); + badge_box->setToolTip(tr("Started as P%1").arg(entry.origin + 1)); + } + } + line->addWidget(badge_box); + // The name, with a pencil to name the controller ("John" shows as "John (Xbox)") + const QString given = QString::fromStdString(entry.custom_name); + auto* name_label = new QLabel(QString::fromStdString(entry.name), row); + auto* name_edit = new PlayerNameEdit(given, row); + name_edit->setObjectName(QStringLiteral("playerName")); + name_edit->setMaxLength(16); + name_edit->setPlaceholderText(tr("Name this controller")); + name_edit->setStyleSheet(ModernComboStyle().replace(QStringLiteral("QComboBox"), + QStringLiteral("QLineEdit"))); + name_edit->hide(); + const QColor icon_color = Accent(this); + const auto name_button = [row, icon_color](int kind, const QString& tip) { + auto* button = new QToolButton(row); + button->setIcon(NameIcon(kind, icon_color)); + button->setIconSize(QSize(14, 14)); + button->setAutoRaise(true); + button->setCursor(Qt::PointingHandCursor); + button->setToolTip(tip); + // (Clicking it keeps the field focused: leaving the field cancels) + button->setFocusPolicy(Qt::NoFocus); + return button; + }; + auto* name_edit_button = name_button(0, tr("Name P%1's controller").arg(player + 1)); + auto* name_apply = name_button(1, tr("Apply the name")); + auto* name_remove = name_button(2, tr("Remove the name")); + name_apply->hide(); + // (The bin removes a given name) + name_remove->setVisible(!given.isEmpty()); + name_edit_button->setEnabled(!entry.leaving); + name_remove->setEnabled(!entry.leaving); + const auto request = [player](const QString& value) { + auto& console = Common::GetControllerConsoleState(); + std::scoped_lock lock{console.mutex}; + console.rename_requests.emplace_back(player, value.trimmed().toStdString()); + }; + const auto editing = [=, this](bool on) { + // (While a name is typed, the rows aren't rebuilt under it) + editing_name = on; + name_label->setVisible(!on); + name_edit_button->setVisible(!on); + name_edit->setVisible(on); + name_apply->setVisible(on); + name_remove->setVisible(!given.isEmpty()); + if (on) { + name_edit->setText(given); + name_edit->setFocus(); + name_edit->selectAll(); + } + }; + name_edit->on_apply = [=] { + editing(false); + if (name_edit->text().trimmed() != given) { + request(name_edit->text()); + } + }; + name_edit->on_cancel = [=] { editing(false); }; + connect(name_edit_button, &QToolButton::clicked, this, [=] { editing(true); }); + connect(name_apply, &QToolButton::clicked, this, [=] { name_edit->on_apply(); }); + connect(name_remove, &QToolButton::clicked, this, [=] { + editing(false); + request(QString{}); + }); + // The controller's battery, when it tells its charge + QLabel* battery = nullptr; + if (entry.battery >= 0 && !entry.leaving) { + battery = new QLabel(row); + battery->setPixmap(BatteryIcon(entry.battery, entry.charging)); + battery->setText(QString{}); + battery->setToolTip(entry.charging ? tr("Battery %1% (charging)").arg(entry.battery) + : tr("Battery %1%").arg(entry.battery)); + } + auto* battery_text = + battery ? new QLabel(QStringLiteral("%1%").arg(entry.battery), row) : nullptr; + if (battery_text) { + battery_text->setObjectName(QStringLiteral("note")); + battery_text->setToolTip(battery->toolTip()); + } + auto* name_line = new QHBoxLayout(); + name_line->setSpacing(2); + name_line->addWidget(name_label); + if (battery) { + name_line->addSpacing(6); + name_line->addWidget(battery_text); + name_line->addWidget(battery); + } + name_line->addWidget(name_edit, 1); + name_line->addWidget(name_edit_button); + name_line->addWidget(name_apply); + name_line->addWidget(name_remove); + name_line->addStretch(1); + line->addLayout(name_line, 1); + const bool live = !entry.leaving; + + // The controller's profile; "No profile" (or the ✕) takes it off + auto* profile = new QComboBox(row); + auto* clear = AddClearButton(profile); + profile->addItem(tr("No profile")); + profile->addItems(profiles); + // (Not found is -1: "No profile") + profile->setCurrentIndex( + static_cast(profiles.indexOf(QString::fromStdString(entry.profile)) + 1)); + profile->setToolTip(tr("Mapping profile for P%1's controller").arg(player + 1)); + // One width for every row, whatever the profile's name + profile->setFixedWidth(170); + // (A profile name with no file behind it shows as none: there is nothing to pick) + profile->setEnabled(live && !profiles.isEmpty()); + const auto take_off = [player] { + auto& console = Common::GetControllerConsoleState(); + std::scoped_lock lock{console.mutex}; + console.profile_requests.push_back({player, {}, true}); + }; + connect(profile, qOverload(&QComboBox::activated), this, + [player, profile, take_off](int index) { + if (index == 0) { + take_off(); + return; + } + auto& console = Common::GetControllerConsoleState(); + std::scoped_lock lock{console.mutex}; + console.profile_requests.push_back( + {player, profile->itemText(index).toStdString()}); + }); + clear->setToolTip(tr("Take the profile off P%1").arg(player + 1)); + // (A profile renamed or deleted elsewhere shows as none: no ✕ for it) + clear->setVisible(live && profiles.contains(QString::fromStdString(entry.profile))); + connect(clear, &QToolButton::clicked, this, take_off); + line->addWidget(profile); + + // (A disabled arrow is drawn plain, not as a dark block) + const QString plain_disabled = + QStringLiteral("QToolButton:disabled { background: transparent; border: none; }"); + auto* up = new QToolButton(row); + up->setArrowType(Qt::UpArrow); + up->setAutoRaise(true); + up->setStyleSheet(plain_disabled); + up->setToolTip(tr("Swap with P%1").arg(player)); + up->setEnabled(live && player > 0); + connect(up, &QToolButton::clicked, this, + [this, player] { RequestSwap(player, player - 1); }); + line->addWidget(up); + auto* down = new QToolButton(row); + down->setArrowType(Qt::DownArrow); + down->setAutoRaise(true); + down->setStyleSheet(plain_disabled); + down->setToolTip(tr("Swap with P%1").arg(player + 2)); + down->setEnabled(live && player < last_player); + connect(down, &QToolButton::clicked, this, + [this, player] { RequestSwap(player, player + 1); }); + line->addWidget(down); + + // Swap and Config outlined in the highlight colour (Swap filled while it waits) + const QString outlined = OutlinedButtonStyle(); + const QString filled = Themed(QStringLiteral( + "QToolButton { border: 1px solid palette(highlight); border-radius: 6px; " + "padding: 3px 12px; background: palette(highlight); " + "color: palette(highlighted-text); font-weight: bold; }")); + auto* swap = new QToolButton(row); + swap->setCursor(Qt::PointingHandCursor); + swap->setStyleSheet(swap_from >= 0 ? filled : outlined); + if (swap_from < 0) { + swap->setText(tr("Swap")); + } else if (swap_from == player) { + swap->setText(tr("Cancel")); + } else { + swap->setText(tr("Swap with P%1").arg(swap_from + 1)); + } + swap->setEnabled(live); + connect(swap, &QToolButton::clicked, this, [this, player] { OnSwapPressed(player); }); + line->addWidget(swap); + + auto* settings = new QToolButton(row); + settings->setText(tr("Config")); + settings->setCursor(Qt::PointingHandCursor); + settings->setStyleSheet(outlined); + settings->setToolTip(tr("Open P%1's tab").arg(player + 1)); + settings->setEnabled(static_cast(open_player_tab)); + connect(settings, &QToolButton::clicked, this, [this, player] { + if (open_player_tab) { + open_player_tab(player); + } + }); + line->addWidget(settings); + + // Turn Off, for a Bluetooth controller: Eden disconnects it, which turns most + // controllers off. (Room kept on the other rows so the buttons line up.) + if (any_turn_off) { + line->addSpacing(6); + auto* turn_off = new QToolButton(row); + turn_off->setText(tr("Turn Off")); + turn_off->setIcon(PowerIcon()); + turn_off->setIconSize(QSize(14, 14)); + turn_off->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + turn_off->setCursor(Qt::PointingHandCursor); + turn_off->setStyleSheet(Themed(QStringLiteral( + "QToolButton { border: 1px solid #c83c3c; border-radius: 6px; " + "padding: 3px 10px; background: #c83c3c; color: white; font-weight: bold; }" + "QToolButton:hover { background: #a82c2c; border-color: #a82c2c; }" + "QToolButton:disabled { background: transparent; border-color: palette(mid); " + "color: palette(mid); }"))); + turn_off->setToolTip( + entry.turn_off == 2 + ? tr("Turns off P%1's controller and frees the player. Turn the " + "controller on to join again.") + .arg(player + 1) + : tr("Press a button on this controller first, so Eden can tell it " + "from the others like it.")); + turn_off->setEnabled(live && entry.turn_off == 2); + QSizePolicy keep = turn_off->sizePolicy(); + keep.setRetainSizeWhenHidden(true); + turn_off->setSizePolicy(keep); + turn_off->setVisible(entry.turn_off != 0); + connect(turn_off, &QToolButton::clicked, this, [player] { + auto& console = Common::GetControllerConsoleState(); + std::scoped_lock lock{console.mutex}; + console.remove_requests.push_back(player); + }); + line->addWidget(turn_off); + } + + players_list->addWidget(row); + player_rows.push_back(row); + row_players.push_back(player); + } + if (!handheld_name.empty() && !handheld_has_player) { + auto* row = new QFrame(players_box); + auto* line = new QHBoxLayout(row); + line->setContentsMargins(4, 2, 4, 2); + line->addWidget(new QLabel(QStringLiteral("\u2014"), row)); + line->addWidget(new QLabel(tr("%1 (built-in, not a player while other controllers " + "are connected)") + .arg(QString::fromStdString(handheld_name)), + row), + 1); + players_list->addWidget(row); + player_rows.push_back(row); + row_players.push_back(-1); + } + } + + // Rows are cards; a fill marks what happens to them: red leaving, blue input held or + // rumbling, green new + const QString card = Themed(QStringLiteral("QFrame#playerRow { border: 1px solid " + "palette(mid); border-radius: 8px; " + "background: palette(base); }")); + const auto fill = [](const char* rgba) { + return Themed( + QStringLiteral("QFrame#playerRow { border: 1px solid palette(mid); border-radius: " + "8px; background-color: rgba(%1); } " + "QFrame#playerRow QLabel { color: white; }") + .arg(QString::fromLatin1(rgba))); + }; + const auto blink_on = [now](qint64 since) { + const qint64 elapsed = now - since; + return elapsed < flash_ms && (elapsed / 125) % 2 == 0; + }; + for (size_t k = 0; k < player_rows.size(); ++k) { + const int player = row_players[k]; + const auto entry = std::find_if(players.begin(), players.end(), + [&](const auto& row) { return row.player == player; }); + if (player < 0 || entry == players.end()) { + continue; + } + const auto rumbled = rumbled_at.find(player); + const bool active = + entry->active || (rumbled != rumbled_at.end() && now - rumbled->second < 500); + const bool blink = entry->flash != 0 && blink_on(entry->flash_since); + QString style = card; + if (entry->flash == 2) { + if (blink) { + style = fill("210, 60, 60, 190"); + } + } else if (active && !entry->leaving) { + style = fill("60, 120, 230, 190"); + } else if (blink) { + style = fill("60, 180, 90, 190"); + } + if (player_rows[k]->styleSheet() != style) { + player_rows[k]->setStyleSheet(style); + } + } + + if (!in_effect || (IsAutomatic(selected) && !engine_active)) { + players_note->setText(tr("Switching...")); + } else if (last_player < 0) { + players_note->setText(tr("No controller is a player right now.")); + } else { + players_note->setText(tr("Press a button on a controller to see its player. Swaps last " + "for this session and do not change your saved controls.")); + } + players_box->setVisible(in_effect && engine_active); + ModernizeCombos(this); +} + +void ConfigurePlayerAssignment::OnBuiltinPicked(int index) { + // Picking is the user's say: a removed controller is no longer kept from auto-detect + Settings::values.builtin_pad_blocked.SetValue(std::string{}); + const QString ident = builtin_picker->itemData(index).toString(); + if (ident.isEmpty()) { + // Detect automatically: forget the stored pad, so the engine detects it afresh + Settings::values.builtin_pad_identity.SetValue(std::string{}); + Settings::values.builtin_pad_steam_handle.SetValue(std::string{}); + Settings::values.builtin_pad_steam_manual.SetValue(false); + Settings::values.builtin_pad_manual.SetValue(false); + return; + } + // Under Steam the entries are Steam handles, set for Steam launches only + const QString prefix = QStringLiteral("steamhandle:"); + if (ident.startsWith(prefix)) { + Settings::values.builtin_pad_steam_handle.SetValue(ident.mid(prefix.size()).toStdString()); + Settings::values.builtin_pad_steam_manual.SetValue(true); + } else { + Settings::values.builtin_pad_identity.SetValue(ident.toStdString()); + Settings::values.builtin_pad_manual.SetValue(true); + } +} + +void ConfigurePlayerAssignment::OnIdentifyPressed() { + Settings::values.builtin_pad_blocked.SetValue(std::string{}); + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.identify_armed = true; + state.identify_armed_at = std::chrono::steady_clock::now(); +} + +void ConfigurePlayerAssignment::OnSwapPressed(int player) { + if (swap_from < 0) { + swap_from = player; + } else { + if (swap_from != player) { + RequestSwap(swap_from, player); + } + swap_from = -1; + } + RefreshPlayers(); +} + +void ConfigurePlayerAssignment::RequestSwap(int a, int b) { + if (a == b || a < 0 || b < 0 || a >= MaxPlayers || b >= MaxPlayers) { + return; + } + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.swap_requests.emplace_back(a, b); +} + +void ConfigurePlayerAssignment::RequestRumble(int player) { + rumbled_at[player] = QDateTime::currentMSecsSinceEpoch(); + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.rumble_requests.push_back(player); +} + +void ConfigurePlayerAssignment::AddTopWidget(QWidget* widget) { + content_layout->insertWidget(0, widget); +} + +void ConfigurePlayerAssignment::SetOpenPlayerTab(std::function open) { + open_player_tab = std::move(open); + players_signature.clear(); + RefreshPlayers(); +} diff --git a/src/yuzu/configuration/configure_player_assignment.h b/src/yuzu/configuration/configure_player_assignment.h new file mode 100644 index 0000000000..b90237b766 --- /dev/null +++ b/src/yuzu/configuration/configure_player_assignment.h @@ -0,0 +1,160 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include + +class QAbstractButton; +class QButtonGroup; +class QCheckBox; +class QComboBox; +class QFrame; +class QVBoxLayout; +class QLabel; +class QPushButton; +class QSlider; +class QTimer; +class QToolButton; +class QWidget; + +/// The Controllers tab: how players are assigned, the handheld's own controller, and the live +/// list of players. +class ConfigurePlayerAssignment : public QWidget { + Q_OBJECT + +public: + explicit ConfigurePlayerAssignment(QWidget* parent = nullptr); + ~ConfigurePlayerAssignment() override; + + void ApplyConfiguration(); + + /// How to bring a player's tab to the front (the settings dialog owns the tabs) + void SetOpenPlayerTab(std::function open); + + /// Puts a widget above everything else in the tab + void AddTopWidget(QWidget* widget); + + /// Rounded fields and outlined buttons, as the Controllers tab draws them + static QString ModernComboStyle(); + static QString OutlinedButtonStyle(); + /// A style sheet for the current theme: under a dark look the palette colours become + /// dark-friendly ones ("muted-text" is a note's colour) + static QString Themed(QString style); + /// The accent colour, as Themed gives palette(highlight) + static QColor Accent(const QWidget* widget); + /// A player's colour, as the overlay and the player badges draw it + static QColor PlayerColor(int player); + /// A controller's battery as a small cell (20x12), as the overlay draws it + static QPixmap Battery(int percent, bool charging); + /// A ✕ inside a drop-down, left of its arrow (hidden or shown by the caller) + static QToolButton* AddClearButton(QComboBox* combo); + /// Lets the open lists of a widget's drop-downs follow ModernComboStyle + static void ModernizeCombos(QWidget* root); + + /// A row of joined buttons, one checked at a time (the group gets them, with these ids) + static QWidget* MakeSegmented(QWidget* parent, const QStringList& labels, + const std::vector& ids, QButtonGroup* group); + +private: + void LoadConfiguration(); + /// The controller applet mode the controls select + int SelectedMode() const; + void OnModeChanged(); + void UpdateModeUi(); + void Refresh(); + void RefreshBuiltin(); + void RefreshPlayers(); + void OnBuiltinPicked(int index); + void OnIdentifyPressed(); + void OnSwapPressed(int player); + void RequestSwap(int a, int b); + void RequestRumble(int player); + + /// The handler (Manual, Modern Console): under Manual the controller applet, under Modern + /// Console whether this is a handheld + enum Handler { HandlerManual, HandlerModern }; + QButtonGroup* handler_group = nullptr; + QFrame* manual_panel = nullptr; + QButtonGroup* manual_group = nullptr; + QFrame* handheld_panel = nullptr; + QAbstractButton* handheld_switch = nullptr; + /// Bypass Steam Input (under Steam), a card of its own for both Modern Console modes + QWidget* steam_panel = nullptr; + QAbstractButton* steam_switch = nullptr; + QLabel* steam_restart = nullptr; + bool original_bypass = false; + /// The Gameplay card + QWidget* gameplay_box = nullptr; + QAbstractButton* joycon_switch = nullptr; + bool original_joycon = true; + QButtonGroup* layout_group = nullptr; + bool original_labels = false; + QAbstractButton* pause_switch = nullptr; + bool original_pause = false; + QAbstractButton* lights_switch = nullptr; + bool original_lights = true; + QLabel* mode_info = nullptr; + QWidget* display_box = nullptr; + QWidget* about_box = nullptr; + /// The scrolled page the cards stack in + QVBoxLayout* content_layout = nullptr; + QAbstractButton* overlay_toggle = nullptr; + bool original_overlay = false; + QAbstractButton* hints_toggle = nullptr; + bool original_hints = true; + /// The overlay's button history options (indented under Controller Overlay) + QWidget* history_options = nullptr; + QAbstractButton* history_toggle = nullptr; + QSlider* history_size = nullptr; + QSlider* history_seconds = nullptr; + QAbstractButton* gaps_toggle = nullptr; + bool original_history = true; + int original_history_size = 10; + int original_history_seconds = 5; + bool original_history_gaps = false; + /// Debug Probes, in the Troubleshooting card + QWidget* debug_box = nullptr; + QAbstractButton* probes_toggle = nullptr; + bool original_probes = false; + QWidget* now_box = nullptr; + + QWidget* builtin_row = nullptr; + QComboBox* builtin_picker = nullptr; + QPushButton* builtin_identify = nullptr; + QLabel* builtin_status = nullptr; + /// Removing the handheld's controller (the ✕), and allowing a removed one again + QToolButton* builtin_remove = nullptr; + QWidget* blocked_row = nullptr; + QLabel* blocked_label = nullptr; + QPushButton* blocked_allow = nullptr; + QString builtin_signature; + + QWidget* players_box = nullptr; + QVBoxLayout* players_list = nullptr; + QLabel* players_note = nullptr; + QString players_signature; + /// A player's name is being typed (the rows wait) + bool editing_name = false; + /// The player whose Swap was pressed first, waiting for the second (-1: none) + int swap_from = -1; + /// The rows and the player each shows, for restyling them while a controller is active + std::vector player_rows; + std::vector row_players; + /// When each player's row was clicked to rumble (blue for a moment) + std::map rumbled_at; + std::function open_player_tab; + + QTimer* timer = nullptr; + /// The mode when the dialog opened, put back unless the dialog applies + int original_mode = 0; + bool applied = false; +}; diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp index 952b5ab7b0..15437e0233 100644 --- a/src/yuzu/configuration/input_profiles.cpp +++ b/src/yuzu/configuration/input_profiles.cpp @@ -16,9 +16,12 @@ namespace FS = Common::FS; namespace { +std::filesystem::path ProfilePath(std::string_view profile_name) { + return FS::GetEdenPath(FS::EdenPath::ConfigDir) / "input" / fmt::format("{}.ini", profile_name); +} + bool ProfileExistsInFilesystem(std::string_view profile_name) { - return FS::Exists(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "input" / - fmt::format("{}.ini", profile_name)); + return FS::Exists(ProfilePath(profile_name)); } bool IsINI(const std::filesystem::path& filename) { @@ -132,6 +135,46 @@ bool InputProfiles::SaveProfile(const std::string& profile_name, std::size_t pla return true; } +bool InputProfiles::RenameProfile(const std::string& profile_name, const std::string& new_name) { + if (!ProfileExistsInMap(profile_name) || ProfileExistsInMap(new_name) || + ProfileExistsInFilesystem(new_name) || + !FS::RenameFile(ProfilePath(profile_name), ProfilePath(new_name))) { + return false; + } + map_profiles.erase(profile_name); + map_profiles.insert_or_assign( + new_name, std::make_unique(new_name, Config::ConfigType::InputProfile)); + return true; +} + +bool InputProfiles::DuplicateProfile(const std::string& profile_name, const std::string& new_name) { + if (!ProfileExistsInMap(profile_name) || ProfileExistsInMap(new_name) || + ProfileExistsInFilesystem(new_name)) { + return false; + } + std::error_code error; + std::filesystem::copy_file(ProfilePath(profile_name), ProfilePath(new_name), error); + if (error) { + return false; + } + map_profiles.insert_or_assign( + new_name, std::make_unique(new_name, Config::ConfigType::InputProfile)); + return true; +} + +std::optional InputProfiles::PeekProfile(const std::string& profile_name, + std::size_t player_index) { + if (!ProfileExistsInMap(profile_name)) { + return std::nullopt; + } + auto& player = Settings::values.players.GetValue()[player_index]; + const auto kept = player; + map_profiles[profile_name]->ReadQtControlPlayerValues(player_index); + auto read = player; + player = kept; + return read; +} + bool InputProfiles::ProfileExistsInMap(const std::string& profile_name) const { return map_profiles.find(profile_name) != map_profiles.end(); } diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h index 4ee7a266c4..84237ff409 100644 --- a/src/yuzu/configuration/input_profiles.h +++ b/src/yuzu/configuration/input_profiles.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include "common/container/unordered_map.h" @@ -31,6 +32,11 @@ public: bool DeleteProfile(const std::string& profile_name); bool LoadProfile(const std::string& profile_name, std::size_t player_index); bool SaveProfile(const std::string& profile_name, std::size_t player_index); + bool RenameProfile(const std::string& profile_name, const std::string& new_name); + bool DuplicateProfile(const std::string& profile_name, const std::string& new_name); + /// A profile's player values, read without touching the player they are read through + std::optional PeekProfile(const std::string& profile_name, + std::size_t player_index); private: bool ProfileExistsInMap(const std::string& profile_name) const; diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index 5e8e04be58..9410988bdb 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -139,13 +140,34 @@ QWidget* Widget::CreateCombobox(std::function& serializer, const ComboboxTranslations* enumeration{nullptr}; if (combobox_enumerations.contains(type)) { enumeration = &combobox_enumerations.at(type); + const bool applet = type == Settings::EnumMetadata::Index(); + const bool controller = setting.Id() == Settings::values.controller_applet_mode.Id(); for (const auto& [id, name] : *enumeration) { - if (type == Settings::EnumMetadata::Index() && - id == static_cast(Settings::AppletMode::Disabled) && - setting.Id() != Settings::values.controller_applet_mode.Id()) { + // The automatic modes are the controller applet's alone + const bool automatic = + id == static_cast(Settings::AppletMode::ConsoleMode) || + id == static_cast(Settings::AppletMode::HandheldConsoleMode); + if (applet && automatic && !controller) { continue; } combobox->addItem(name, id); + // Handheld Console needs to know the handheld's own controller + const bool handheld_set = !Settings::values.builtin_pad_identity.GetValue().empty() || + !Settings::values.builtin_pad_steam_handle.GetValue().empty(); + if (applet && controller && + id == static_cast(Settings::AppletMode::HandheldConsoleMode) && + !handheld_set) { + const int row = combobox->count() - 1; + if (auto* model = qobject_cast(combobox->model())) { + model->item(row)->setEnabled(false); + } + combobox->setItemData( + row, + tr("No handheld controller is set. Pick Modern Console in Controls > " + "Controllers, turn on Portable Handheld Gaming Device, and pick or " + "identify the handheld's controller."), + Qt::ToolTipRole); + } } } else { return combobox; @@ -163,7 +185,14 @@ QWidget* Widget::CreateCombobox(std::function& serializer, const u32 setting_value = std::strtoul(setting.ToString().c_str(), nullptr, 0); combobox->setCurrentIndex(find_index(setting_value)); - serializer = [this]() { + // The controller applet's mode is also set in Controls > Controllers, which applies at once: + // unless it was changed here, this keeps what it is by then (this tab applies last) + const bool controller_mode = setting.Id() == Settings::values.controller_applet_mode.Id(); + const int loaded_index = combobox->currentIndex(); + serializer = [this, controller_mode, loaded_index]() { + if (controller_mode && combobox->currentIndex() == loaded_index) { + return setting.ToString(); + } return std::to_string(combobox->currentData().toUInt()); }; diff --git a/src/yuzu/game/game_list.cpp b/src/yuzu/game/game_list.cpp index 6b89e59253..6a70b71ae7 100644 --- a/src/yuzu/game/game_list.cpp +++ b/src/yuzu/game/game_list.cpp @@ -76,6 +76,22 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid if (system.IsPoweredOn()) { return; } + if (controller_context_menu) { + // A submenu is its own popup window (isAncestorOf stops at windows) + QWidget* popup = QApplication::activePopupWidget(); + bool ours = false; + for (QWidget* w = popup; w != nullptr && !ours; w = w->parentWidget()) { + ours = w == controller_context_menu; + } + if (ours) { + QCoreApplication::postEvent( + popup, new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier)); + } + return; + } + if (QApplication::activePopupWidget() || QApplication::activeModalWidget()) { + return; + } if (!this->isActiveWindow()) { return; } @@ -83,6 +99,28 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid QCoreApplication::postEvent(m_currentView, event); }); + connect( + controller_navigation, &ControllerNavigation::TriggerContextMenu, this, + [this] { + if (system.IsPoweredOn() || !isActiveWindow() || QApplication::activePopupWidget() || + QApplication::activeModalWidget() || controller_context_menu) { + return; + } + const QModelIndex current = m_currentView->currentIndex(); + const QModelIndex selected = current.sibling(current.row(), 0); + if (!selected.isValid() || + selected.data(GameListItem::TypeRole).value() != + GameListItemType::Game) { + return; + } + m_currentView->scrollTo(current); + const QRect rect = m_currentView->visualRect(current); + if (rect.isValid()) { + PopupContextMenu(rect.center()); + } + }, + Qt::QueuedConnection); + connect(item_model, &GameListModel::PopulatingCompleted, this, &GameList::OnPopulatingCompleted); @@ -443,7 +481,9 @@ void GameList::PopupContextMenu(const QPoint& menu_location) { default: break; } + controller_context_menu = &context_menu; context_menu.exec(m_currentView->viewport()->mapToGlobal(menu_location)); + controller_context_menu = nullptr; } void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path) { diff --git a/src/yuzu/game/game_list.h b/src/yuzu/game/game_list.h index 1540dd9cf0..1305783e5d 100644 --- a/src/yuzu/game/game_list.h +++ b/src/yuzu/game/game_list.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ enum class StartGameType; class GameCarousel; class QAbstractItemView; +class QMenu; namespace Core { class System; } @@ -155,6 +157,7 @@ private: Settings::GameListMode game_list_mode; ControllerNavigation* controller_navigation = nullptr; + QPointer controller_context_menu; QVariantAnimation* vertical_scroll = nullptr; QVariantAnimation* horizontal_scroll = nullptr; diff --git a/src/yuzu/loading_screen.h b/src/yuzu/loading_screen.h index 2c71d85e55..e4db191107 100644 --- a/src/yuzu/loading_screen.h +++ b/src/yuzu/loading_screen.h @@ -12,6 +12,8 @@ #include #include +#include "common/container/unordered_map.h" + #if !QT_CONFIG(movie) #define YUZU_QT_MOVIE_MISSING 1 #endif @@ -91,7 +93,3 @@ private: std::chrono::steady_clock::time_point previous_time; std::size_t slow_shader_first_value = 0; }; - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -Q_DECLARE_METATYPE(VideoCore::LoadCallbackStage); -#endif diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e34f8f8d94..17aae46868 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -8,12 +8,11 @@ #include #include "dedicated_room/yuzu_room.h" #endif -#ifdef __unix__ -#include "qt_common/gui_settings.h" -#endif #ifndef _WIN32 #include +#else +#include #endif #if defined(__APPLE__) @@ -24,20 +23,7 @@ #include "main_window.h" -#ifdef _WIN32 -#include - -static void OverrideWindowsFont() { - // Qt5 chooses these fonts on Windows and they have fairly ugly alphanumeric/cyrillic characters - // Asking to use "MS Shell Dlg 2" gives better other chars while leaving the Chinese Characters. - const QString startup_font = QApplication::font().family(); - const QStringList ugly_fonts = {QStringLiteral("SimSun"), QStringLiteral("PMingLiU")}; - if (ugly_fonts.contains(startup_font)) { - QApplication::setFont(QFont(QStringLiteral("MS Shell Dlg 2"), 9, QFont::Normal)); - } -} -#endif - +// TODO(crueter): This is very annoying, see if there are any other solutions. static Qt::HighDpiScaleFactorRoundingPolicy GetHighDpiRoundingPolicy() { #ifdef _WIN32 // For Windows, we want to avoid scaling artifacts on fractional scaling ratios. @@ -107,10 +93,6 @@ int main(int argc, char* argv[]) { Breakpad::InstallCrashHandler(); #endif - // Init settings params - QCoreApplication::setOrganizationName(QStringLiteral("eden")); - QCoreApplication::setApplicationName(QStringLiteral("eden")); - // Increases the maximum open file limit. // TODO: This should be common to all frontends. #ifdef _WIN32 @@ -149,31 +131,10 @@ int main(int argc, char* argv[]) { chdir(Common::FS::PathToUTF8String(bin_path).c_str()); #endif -#ifdef __unix__ - // Set the DISPLAY variable in order to open web browsers - // TODO (lat9nq): Find a better solution for AppImages to start external applications - if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) { - qputenv("DISPLAY", ":0"); - } - - if (GraphicsBackend::GetForceX11() && qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM")) - qputenv("QT_QPA_PLATFORM", "xcb"); - - // Fix the Wayland appId. This needs to match the name of the .desktop file without the .desktop - // suffix. - QGuiApplication::setDesktopFileName(QStringLiteral("dev.eden_emu.eden")); -#endif + QtCommon::SetupApplication(); auto rounding_policy = GetHighDpiRoundingPolicy(); - QApplication::setHighDpiScaleFactorRoundingPolicy(rounding_policy); - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - // Disables the "?" button on all dialogs. Disabled by default on Qt6. - QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); -#endif - - // Enables the core to make the qt created contexts current on std::threads - QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); + QGuiApplication::setHighDpiScaleFactorRoundingPolicy(rounding_policy); #ifdef _WIN32 QApplication::setStyle(QStringLiteral("windowsvista")); @@ -181,21 +142,6 @@ int main(int argc, char* argv[]) { QApplication app(argc, argv); -#ifdef _WIN32 - OverrideWindowsFont(); -#endif - - // Workaround for QTBUG-85409, for Suzhou numerals the number 1 is actually \u3021 - // so we can see if we get \u3008 instead - // TL;DR all other number formats are consecutive in unicode code points - // This bug is fixed in Qt6, specifically 6.0.0-alpha1 -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - const QLocale locale = QLocale::system(); - if (QStringLiteral("\u3008") == locale.toString(1)) { - QLocale::setDefault(QLocale::system().name()); - } -#endif - // Qt changes the locale and causes issues in float conversion using std::to_string() when // generating shaders setlocale(LC_ALL, "C"); diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 92b725fa11..e432095be8 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -91,6 +91,14 @@ + + + false + + + &Cheats + + &View @@ -148,6 +156,8 @@ + + @@ -241,6 +251,7 @@ + @@ -605,6 +616,22 @@ Show &Performance Overlay + + + true + + + Show &Controller Overlay + + + + + true + + + Show Controller &Hints + + Post-Processing &Shaders... diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index 6e21265f9e..3bf345e62b 100644 --- a/src/yuzu/main_window.cpp +++ b/src/yuzu/main_window.cpp @@ -3,12 +3,15 @@ // Static Qt on macOS doesn't use Vulkan // Other platforms do, and thus have conflicting VulkanMemoryAllocator symbols +#include +#include #include "core/launch_params.h" #if defined(QT_STATICPLUGIN) && !defined(__APPLE__) #undef VMA_IMPLEMENTATION #endif #include +#include "common/controller_console_state.h" #include "common/fs/path_util.h" #include "common/settings.h" #include "common/settings_enums.h" @@ -42,6 +45,7 @@ #include "set_play_time_dialog.h" #include "util/util.h" #include "yuzu/game/game_list.h" +#include "yuzu/overlay_panel.h" #include "applets/qt_amiibo_settings.h" #include "applets/qt_controller.h" @@ -53,10 +57,13 @@ #include "configuration/configure_dialog.h" #include "configuration/configure_input.h" #include "configuration/configure_per_game.h" +#include "configuration/configure_player_assignment.h" #include "configuration/configure_tas.h" +#include "configuration/input_profiles.h" #include "util/clickable_label.h" #include "util/controller_navigation.h" +#include "util/gamescope.h" #include "util/overlay_dialog.h" #include "multiplayer/state.h" @@ -64,24 +71,48 @@ // Qt Stuff // #define QT_NO_OPENGL -#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) +#include +#include #include -#endif +#include +#include +#include #include #include #include #include +#include #include +#include #include #include +#include +#include +#include +#ifdef __linux__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif #include #include #include +#include #include #include #include #include +#include #include #include @@ -134,6 +165,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #endif // Core // +#include "core/core.h" #include "core/frontend/applets/general.h" #include "core/frontend/applets/mii_edit.h" #include "core/frontend/applets/software_keyboard.h" @@ -147,6 +179,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/file_sys/common_funcs.h" #include "core/file_sys/romfs.h" #include "core/file_sys/savedata_factory.h" +#include "core/memory/dmnt_cheat_types.h" #include "core/tools/renderdoc.h" @@ -165,6 +198,10 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "video_core/shader_notify.h" #include +#ifdef __linux__ +#include +#include +#endif #include @@ -180,10 +217,15 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include #include #include -#include "qt_common/gui_settings.h" #endif +#include +#include +#include +#include +#include "common/overlay_panels.h" +#include "common/param_package.h" #include "qt_common/gamemode.h" #ifdef _WIN32 @@ -191,8 +233,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/core_timing.h" #include -#include #include +#include #include #ifdef _MSC_VER #pragma comment(lib, "Dwmapi.lib") @@ -342,20 +384,393 @@ QString GetTranslatedGameIconSize(size_t index) { } // namespace #ifndef _WIN32 -// TODO(crueter): carboxyl does this, is it needed in qml? inline static bool isDarkMode() { -#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) const auto scheme = QGuiApplication::styleHints()->colorScheme(); return scheme == Qt::ColorScheme::Dark; -#else - const QPalette defaultPalette; - const auto text = defaultPalette.color(QPalette::WindowText); - const auto window = defaultPalette.color(QPalette::Window); - return text.lightness() > window.lightness(); -#endif // QT_VERSION } #endif // _WIN32 +namespace { + +/// Asks the engine to put the players in this order: place k takes the controller player +/// order[k] has now, one swap at a time +void RequestPlayerOrder(const std::vector& order) { + std::vector places = order; + std::sort(places.begin(), places.end()); + if (order == places) { + return; + } + std::map holder; + for (const int place : places) { + holder[place] = place; + } + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + for (std::size_t k = 0; k < places.size(); ++k) { + int from = places[k]; + for (const auto& [place, original] : holder) { + if (original == order[k]) { + from = place; + } + } + if (from != places[k]) { + state.swap_requests.emplace_back(places[k], from); + std::swap(holder[places[k]], holder[from]); + } + } +} + +/// The players as chips after the last menu: a click rumbles the controller and opens its tab; +/// a chip drags left or right to change the order +class PlayerChips : public QWidget { +public: + PlayerChips(QMenuBar* bar_, std::function open_settings_) + : QWidget(bar_), bar{bar_}, open_settings{std::move(open_settings_)} { + setAttribute(Qt::WA_NoSystemBackground); + // (A dark theme gives a plain widget a solid background.) By name, or the chips' + // tooltip takes the rule too and shows as a black box under gamescope + setObjectName(QStringLiteral("playerChips")); + setStyleSheet(QStringLiteral("#playerChips { background: transparent; }")); + setCursor(Qt::PointingHandCursor); + long_press.setSingleShot(true); + long_press.setInterval(400); + QObject::connect(&long_press, &QTimer::timeout, this, [this] { + if (pressed >= 0) { + dragging = true; + setCursor(Qt::ClosedHandCursor); + update(); + } + }); + QObject::connect(&poll, &QTimer::timeout, this, [this] { Refresh(); }); + poll.start(100); + hide(); + } + +protected: + void paintEvent(QPaintEvent*) override { + QPainter painter{this}; + painter.setRenderHint(QPainter::Antialiasing); + QFont font = bar->font(); + font.setBold(true); + painter.setFont(font); + const bool several = rows.size() > 1; + const auto chip = [&](const Common::ControllerConsoleState::PlayerRow& row, QRectF rect, + int k) { + const QColor color = ConfigurePlayerAssignment::PlayerColor(row.player); + // Filled while an input is held, else outlined; blinking green after a swap + const qint64 since = QDateTime::currentMSecsSinceEpoch() - row.flash_since; + const bool blink = row.flash == 1 && since < 1500 && (since / 125) % 2 == 0; + const bool lit = row.active || blink; + if (lit) { + painter.setPen(Qt::NoPen); + painter.setBrush(blink ? QColor(45, 160, 80) : color); + } else { + painter.setPen(QPen(color, 1.5)); + painter.setBrush(Qt::NoBrush); + } + painter.drawRoundedRect(rect, rect.height() / 2, rect.height() / 2); + const QColor ink = lit ? QColor(Qt::white) : color; + // The battery's percent, then its icon, at the right end + QRectF label = rect; + if (row.battery >= 0 && batteries) { + const QRectF cell(rect.right() - (several ? 16 : 6) - battery_w, + rect.center().y() - 6, battery_w, 12); + painter.drawPixmap(cell.topLeft(), + ConfigurePlayerAssignment::Battery(row.battery, row.charging)); + const QRectF percent(cell.left() - 2 - percent_w, rect.top(), percent_w, + rect.height()); + painter.save(); + QFont percent_font = painter.font(); + percent_font.setPointSizeF(percent_font.pointSizeF() * 0.85); + painter.setFont(percent_font); + painter.setPen(ink); + painter.drawText(percent, Qt::AlignVCenter | Qt::AlignRight, + QStringLiteral("%1%").arg(row.battery)); + painter.restore(); + label.setRight(percent.left() + (several ? 16 : 6)); + } + // With other players around: the grip, and the arrows swapping with a neighbour + painter.setPen(ink); + painter.drawText(label, Qt::AlignCenter, + several ? QStringLiteral("\u283F P%1").arg(row.player + 1) + : QStringLiteral("P%1").arg(row.player + 1)); + if (several) { + const auto arrow = [&](QRectF area, bool left, bool enabled) { + QColor fill = ink; + fill.setAlpha(enabled ? 255 : 70); + painter.setPen(Qt::NoPen); + painter.setBrush(fill); + const QPointF c = area.center(); + const qreal s = 3.5; + const QPointF tri[3] = {left ? QPointF(c.x() - s, c.y()) + : QPointF(c.x() + s, c.y()), + left ? QPointF(c.x() + s * 0.7, c.y() - s) + : QPointF(c.x() - s * 0.7, c.y() - s), + left ? QPointF(c.x() + s * 0.7, c.y() + s) + : QPointF(c.x() - s * 0.7, c.y() + s)}; + painter.drawPolygon(tri, 3); + }; + arrow(LeftArrow(rect), true, k > 0); + arrow(RightArrow(rect), false, k + 1 < static_cast(rows.size())); + } + }; + for (std::size_t k = 0; k < rows.size(); ++k) { + const QRectF rect = ChipRect(static_cast(k)); + if (dragging && static_cast(k) == pressed) { + // Where the dragged chip came from + QColor edge = ConfigurePlayerAssignment::PlayerColor(rows[k].player); + edge.setAlpha(100); + painter.setPen(QPen(edge, 1, Qt::DashLine)); + painter.setBrush(Qt::NoBrush); + painter.drawRoundedRect(rect, rect.height() / 2, rect.height() / 2); + continue; + } + chip(rows[k], rect, static_cast(k)); + } + if (dragging && pressed >= 0 && pressed < static_cast(rows.size())) { + chip(rows[static_cast(pressed)], ChipRect(pressed).translated(drag_dx, 0), + pressed); + } + } + + void mousePressEvent(QMouseEvent* event) override { + if (event->button() != Qt::LeftButton) { + return; + } + pressed = IndexAt(event->position().x()); + press_x = event->position().x(); + drag_dx = 0; + dragging = false; + // (Nothing to reorder with one player) + if (pressed >= 0 && rows.size() > 1) { + long_press.start(); + } + } + + void mouseMoveEvent(QMouseEvent* event) override { + if (dragging) { + drag_dx = event->position().x() - press_x; + update(); + } + } + + void mouseReleaseEvent(QMouseEvent* event) override { + long_press.stop(); + const int index = pressed; + pressed = -1; + setCursor(Qt::PointingHandCursor); + if (index < 0 || index >= static_cast(rows.size())) { + dragging = false; + return; + } + if (dragging) { + dragging = false; + // The players in the order of their chips, the dragged one where it was let go + std::vector> centres; + for (std::size_t k = 0; k < rows.size(); ++k) { + const double x = ChipRect(static_cast(k)).center().x() + + (static_cast(k) == index ? drag_dx : 0.0); + centres.emplace_back(x, rows[k].player); + } + std::stable_sort(centres.begin(), centres.end()); + std::vector order; + for (const auto& [x, player] : centres) { + order.push_back(player); + } + RequestPlayerOrder(order); + update(); + return; + } + if (IndexAt(event->position().x()) != index) { + return; + } + // An arrow: swap with the neighbouring chip's player + if (rows.size() > 1) { + const QRectF rect = ChipRect(index); + const QPointF at = event->position(); + const int step = LeftArrow(rect).contains(at) ? -1 + : RightArrow(rect).contains(at) ? 1 + : 0; + if (step != 0) { + const int other = index + step; + if (other >= 0 && other < static_cast(rows.size())) { + const int a = rows[static_cast(index)].player; + const int b = rows[static_cast(other)].player; + LOG_INFO(Frontend, "console-mode: menu chip swap P{} <-> P{}", a + 1, b + 1); + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.swap_requests.emplace_back(a, b); + } + return; + } + } + // A click: the controller rumbles (vibration on), and its settings open + const int player = rows[static_cast(index)].player; + if (Settings::values.vibration_enabled.GetValue() && + Settings::values.players.GetValue()[player].vibration_enabled) { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.rumble_requests.push_back(player); + } + QTimer::singleShot(0, this, [this, player] { open_settings(player); }); + } + + bool event(QEvent* event) override { + if (event->type() == QEvent::ToolTip) { + const auto* help = static_cast(event); + const int index = IndexAt(help->pos().x()); + if (index >= 0) { + const auto& row = rows[static_cast(index)]; + const QString battery = + row.battery < 0 ? QString{} + : row.charging ? QObject::tr("\nBattery %1% (charging)").arg(row.battery) + : QObject::tr("\nBattery %1%").arg(row.battery); + QToolTip::showText( + help->globalPos(), + (rows.size() > 1 + ? QObject::tr("P%1: %2\nClick: rumble and open its settings\nArrows, " + "or hold then drag: change the player order") + .arg(row.player + 1) + .arg(QString::fromStdString(row.name)) + : QObject::tr("P%1: %2\nClick: rumble and open its settings") + .arg(row.player + 1) + .arg(QString::fromStdString(row.name))) + + battery, + this); + } else { + QToolTip::hideText(); + } + return true; + } + return QWidget::event(event); + } + +private: + static constexpr int chip_w = 34; + /// With arrows and the grip, when there are several players + static constexpr int chip_w_full = 74; + static constexpr int chip_gap = 4; + /// A chip's battery, when its controller tells its charge (and the room it takes) + static constexpr int battery_w = 20; + /// Its percent after it ("100%" fits) + static constexpr int percent_w = 28; + static constexpr int battery_room = battery_w + percent_w + 4; + + /// A chip's width: wider with arrows and the grip (several players), and with a battery + static int ChipWidth(const std::vector& among, + std::size_t k, bool with_batteries) { + return (among.size() > 1 ? chip_w_full : chip_w) + + (with_batteries && among[k].battery >= 0 ? battery_room : 0); + } + + QRectF ChipRect(int k) const { + double x = 4; + for (int j = 0; j < k; ++j) { + x += ChipWidth(rows, static_cast(j), batteries) + chip_gap; + } + return QRectF(x, 3, ChipWidth(rows, static_cast(k), batteries), + height() - 6); + } + + static QRectF LeftArrow(const QRectF& chip) { + return QRectF(chip.left() + 2, chip.top(), 14, chip.height()); + } + + static QRectF RightArrow(const QRectF& chip) { + return QRectF(chip.right() - 16, chip.top(), 14, chip.height()); + } + + int IndexAt(double x) const { + for (int k = 0; k < static_cast(rows.size()); ++k) { + if (ChipRect(k) + .adjusted(-chip_gap / 2.0, 0, chip_gap / 2.0, 0) + .contains(x, height() / 2.0)) { + return k; + } + } + return -1; + } + + void Refresh() { + std::vector now; + bool engine_active = false; + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + engine_active = state.engine_active; + for (const auto& row : state.players) { + if (!row.leaving) { + now.push_back(row); + } + } + } + const auto mode = Settings::values.controller_applet_mode.GetValue(); + const bool automatic = mode == Settings::AppletMode::ConsoleMode || + mode == Settings::AppletMode::HandheldConsoleMode; + // Right after the last menu + int x = 0; + for (QAction* action : bar->actions()) { + if (action->isVisible()) { + const QRect place = bar->actionGeometry(action); + if (place.isValid()) { + x = (std::max)(x, place.right()); + } + } + } + // (Batteries go when the chips would run past the menu bar; they stay in the tooltips) + const auto chips_width = [&](bool with_batteries) { + int w = 8; + for (std::size_t k = 0; k < now.size(); ++k) { + w += ChipWidth(now, k, with_batteries) + chip_gap; + } + return w; + }; + const bool fit = x + 10 + chips_width(true) <= bar->width(); + if (fit != batteries) { + batteries = fit; + update(); + } + const int chips_w = chips_width(batteries); + const QRect place(x + 10, 0, chips_w, bar->height()); + if (geometry() != place) { + setGeometry(place); + } + const bool shown = automatic && engine_active && !now.empty(); + if (isVisible() != shown) { + setVisible(shown); + } + // Repainted when a player changes and while one blinks (not while dragging) + const auto same = [](const auto& a, const auto& b) { + return a.player == b.player && a.active == b.active && a.name == b.name && + a.flash == b.flash && a.flash_since == b.flash_since && + a.battery == b.battery && a.charging == b.charging; + }; + const qint64 now_ms = QDateTime::currentMSecsSinceEpoch(); + const bool blinking = std::any_of(now.begin(), now.end(), [now_ms](const auto& r) { + return r.flash != 0 && now_ms - r.flash_since < 1600; + }); + if (!dragging && (blinking || now.size() != rows.size() || + !std::equal(now.begin(), now.end(), rows.begin(), same))) { + rows = std::move(now); + update(); + } + } + + QMenuBar* bar; + std::function open_settings; + std::vector rows; + /// The chips show their batteries (they fit in the menu bar with them) + bool batteries = true; + QTimer poll; + QTimer long_press; + int pressed = -1; + double press_x = 0; + double drag_dx = 0; + bool dragging = false; +}; + +} // Anonymous namespace + MainWindow::MainWindow(bool has_broken_vulkan) : ui{std::make_unique()}, input_subsystem{std::make_shared()}, user_data_migrator{this} { @@ -421,6 +836,8 @@ MainWindow::MainWindow(bool has_broken_vulkan) SetDefaultUIGeometry(); RestoreUIState(); + FitToScreenUnderGamescope(this); + Gamescope::FitDialogsAndMenus(this); ConnectMenuEvents(); ConnectWidgetEvents(); @@ -448,10 +865,6 @@ MainWindow::MainWindow(bool has_broken_vulkan) // Gen keys if necessary OnCheckFirmwareDecryption(); -#ifdef __unix__ - OnCheckGraphicsBackend(); -#endif - // Check for orphaned profiles and reset profile data if necessary QtCommon::Content::FixProfiles(); @@ -470,6 +883,11 @@ MainWindow::MainWindow(bool has_broken_vulkan) mouse_hide_timer.setInterval(default_mouse_hide_timeout); connect(&mouse_hide_timer, &QTimer::timeout, this, &MainWindow::HideMouseCursor); connect(ui->menubar, &QMenuBar::hovered, this, &MainWindow::ShowMouseCursor); + // The players, after the last menu, in the automatic modes + new PlayerChips(ui->menubar, [this](int player) { + open_player_tab = player; + OnConfigure(); + }); update_input_timer.setInterval(default_input_update_timeout); connect(&update_input_timer, &QTimer::timeout, this, &MainWindow::UpdateInputDrivers); @@ -549,6 +967,9 @@ MainWindow::MainWindow(bool has_broken_vulkan) } MainWindow::~MainWindow() { + // The config saves itself on destruction: it must write the user's own players + RestoreConsoleProfile(); + // will get automatically deleted otherwise if (render_window->parent() == nullptr) { delete render_window; @@ -605,7 +1026,7 @@ void MainWindow::ControllerSelectorReconfigureControllers( // Don't forget to apply settings. QtCommon::system->HIDCore().DisableAllControllerConfiguration(); QtCommon::system->ApplySettings(); - config->SaveAllValues(); + SaveAllConfigValues(); UpdateStatusButtons(); @@ -917,6 +1338,7 @@ void MainWindow::WebBrowserRequestExit() { void MainWindow::InitializeWidgets() { render_window = new GRenderWindow(this, input_subsystem); + render_window->installEventFilter(this); render_window->hide(); game_list = new GameList(QtCommon::vfs, QtCommon::provider.get(), *play_time_manager, @@ -1288,6 +1710,8 @@ void MainWindow::InitializeHotkeys() { LinkActionShortcut(ui->action_Show_Status_Bar, QStringLiteral("Toggle Status Bar")); LinkActionShortcut(ui->action_Show_Performance_Overlay, QStringLiteral("Toggle Performance Overlay")); + LinkActionShortcut(ui->action_Show_Controller_Overlay, + QStringLiteral("Toggle Controller Overlay")); LinkActionShortcut(ui->action_Fullscreen, QStringLiteral("Fullscreen")); LinkActionShortcut(ui->action_Capture_Screenshot, QStringLiteral("Capture Screenshot")); LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"), true); @@ -1396,6 +1820,9 @@ void MainWindow::RestoreUIState() { ui->action_Show_Performance_Overlay->setChecked( UISettings::values.show_perf_overlay.GetValue()); + ui->action_Show_Controller_Overlay->setChecked( + Settings::values.console_debug_overlay.GetValue()); + ui->action_Show_Controller_Hints->setChecked(Settings::values.console_hints.GetValue()); if (perf_overlay) perf_overlay->setVisible(ui->action_Show_Performance_Overlay->isChecked()); Debugger::ToggleConsole(); @@ -1434,6 +1861,9 @@ void MainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) { } void MainWindow::ConnectWidgetEvents() { + ui->menu_Cheats->installEventFilter(this); + ui->menu_Cheats->menuAction()->setVisible(false); + connect(game_list, &GameList::BootGame, this, &MainWindow::BootGameFromList); connect(game_list, &GameList::GameChosen, this, &MainWindow::OnGameListLoadFile); connect(game_list, &GameList::OpenDirectory, this, &MainWindow::OnGameListOpenDirectory); @@ -1468,6 +1898,13 @@ void MainWindow::ConnectWidgetEvents() { // Software Keyboard Applet connect(this, &MainWindow::EmulationStarting, this, &MainWindow::SoftwareKeyboardExit); connect(this, &MainWindow::EmulationStopping, this, &MainWindow::SoftwareKeyboardExit); + connect(this, &MainWindow::EmulationStarting, this, &MainWindow::RefreshRuntimeCheats); + connect(this, &MainWindow::EmulationStopping, this, &MainWindow::ClearRuntimeCheats); + connect(&console_mode_timer, &QTimer::timeout, this, &MainWindow::ApplyConsoleControllerMode); + connect(&console_activity_timer, &QTimer::timeout, this, &MainWindow::PollControllerActivity); + console_activity_timer.start(std::chrono::milliseconds{40}); + // 250ms: instant to the user, negligible cost (the input reload only runs on changes) + console_mode_timer.start(std::chrono::milliseconds{250}); connect(&status_bar_update_timer, &QTimer::timeout, this, &MainWindow::UpdateStatusBar); @@ -1475,6 +1912,5239 @@ void MainWindow::ConnectWidgetEvents() { &MultiplayerState::UpdateThemedIcons); } +void MainWindow::RefreshRuntimeCheats() { + ClearRuntimeCheats(); + + const auto cheats = QtCommon::system->GetRuntimeCheats(); + auto* disable_all = ui->menu_Cheats->addAction(tr("Disable All Cheats")); + connect(disable_all, &QAction::triggered, this, [this] { + for (auto* action : runtime_cheat_actions) { + if (action->isEnabled()) { + action->setChecked(false); + } + } + }); + + auto* enable_all = ui->menu_Cheats->addAction(tr("Enable All Cheats")); + connect(enable_all, &QAction::triggered, this, [this] { + for (auto* action : runtime_cheat_actions) { + if (action->isEnabled()) { + action->setChecked(true); + } + } + }); + + ui->menu_Cheats->addSeparator(); + runtime_cheat_actions.reserve(cheats.size()); + for (const auto& cheat : cheats) { + const QString name = cheat.name.empty() ? tr("Unnamed Cheat") + : QString::fromUtf8(cheat.name); + auto* action = ui->menu_Cheats->addAction(name); + action->setCheckable(true); + action->setChecked(cheat.enabled || cheat.is_master); + action->setEnabled(!cheat.is_master); + connect(action, &QAction::toggled, this, [action, id = cheat.id](bool enabled) { + if (!QtCommon::system->SetCheatEnabled(id, enabled)) { + const QSignalBlocker blocker{action}; + action->setChecked(!enabled); + } + }); + runtime_cheat_actions.push_back(action); + } + + ui->menu_Cheats->menuAction()->setVisible(!runtime_cheat_actions.empty()); +} + +void MainWindow::ClearRuntimeCheats() { + ui->menu_Cheats->clear(); + runtime_cheat_actions.clear(); + ui->menu_Cheats->menuAction()->setVisible(false); +} + +namespace { + +/// The joystick API is shared with the input driver's threads (the rumble worker); +/// SDL_LockJoysticks is the official guard for calling into it elsewhere. +struct JoystickApiLock { + JoystickApiLock() { + SDL_LockJoysticks(); + } + ~JoystickApiLock() { + SDL_UnlockJoysticks(); + } +}; + +/// Calls `use` with the pad opened as a joystick for the call (under the lock); `fallback` when it +/// can't be opened +template +T WithJoystick(SDL_JoystickID id, T fallback, Use&& use) { + const JoystickApiLock lock; + SDL_Joystick* js = SDL_OpenJoystick(id); + if (!js) { + return fallback; + } + T result = use(js); + SDL_CloseJoystick(js); + return result; +} + +/// Calls `use` with the pad opened as a gamepad for the call (under the lock); `fallback` when it +/// can't be opened +template +T WithGamepad(SDL_JoystickID id, T fallback, Use&& use) { + const JoystickApiLock lock; + SDL_Gamepad* pad = SDL_OpenGamepad(id); + if (!pad) { + return fallback; + } + T result = use(pad); + SDL_CloseGamepad(pad); + return result; +} + +/// A pad's stable identity: its hardware serial when it reports one, else its model GUID (which +/// two pads can share: slots are keyed by connection, this only matches returning pads) +std::string PadIdentity(SDL_JoystickID id) { + const JoystickApiLock lock; + SDL_Joystick* js = SDL_OpenJoystick(id); + if (!js) { + return {}; + } + const char* serial = SDL_GetJoystickSerial(js); + if (serial && serial[0]) { + std::string out{"serial:"}; + out += serial; + SDL_CloseJoystick(js); + return out; + } + const SDL_GUID guid = SDL_GetJoystickGUID(js); + SDL_CloseJoystick(js); + char buf[33]{}; + for (int i = 0; i < 16; ++i) { + unsigned byte = guid.data[i]; + // Bytes 2-3 are a CRC of the name, which Steam changes on the same pad: zeroed, as + // SDLDriver::GetGUID does + if (i == 2 || i == 3) { + byte = 0; + } + std::snprintf(buf + i * 2, 3, "%02x", byte); + } + return std::string{"guid:"} + buf; +} + +/// What Steam says is in one of its virtual pads, from the file it writes for the game. SDL +/// reads it at most every 3 seconds, so a controller Steam just moved showed as the old one. +struct SteamSlot { + Uint64 handle = 0; + Uint16 vendor = 0; + Uint16 product = 0; + SDL_GamepadType type = SDL_GAMEPAD_TYPE_UNKNOWN; + QString name; +}; + +std::optional SteamSlotOf(SDL_JoystickID id); + +/// A pad's display name +QString PadName(SDL_JoystickID id) { + // (Steam names the Deck's controls with a translation key: not a name to show) + const auto slot = SteamSlotOf(id); + if (slot && !slot->name.isEmpty() && !slot->name.startsWith(QLatin1Char('#'))) { + return slot->name; + } + const Uint16 vendor = slot ? slot->vendor : SDL_GetJoystickVendorForID(id); + const Uint16 product = slot ? slot->product : SDL_GetJoystickProductForID(id); + if (vendor == 0x28DE && product == 0x1205) { + return QStringLiteral("Steam Deck"); + } + return WithJoystick(id, QStringLiteral("?"), [](SDL_Joystick* js) { + const char* name = SDL_GetJoystickName(js); + return name ? QString::fromUtf8(name) : QStringLiteral("?"); + }); +} + +/// True for Steam Input's virtual pads, whose GUID and serial aren't stable (Steam re-binds them) +bool IsSteamVirtualPad(SDL_JoystickID id) { + if (!Common::RunningUnderSteam()) { + return false; + } + // Every virtual pad's GUID carries Valve's vendor (0x28DE, bytes 4-5); the name isn't + // usable (one pad shows as "SteamDeck" and "Xbox" in a session) + // Valve makes real controllers too: the virtual gamepad product (0x11FF, bytes 8-9) marks them + return WithJoystick(id, false, [](SDL_Joystick* js) { + const SDL_GUID guid = SDL_GetJoystickGUID(js); + return guid.data[4] == 0xDE && guid.data[5] == 0x28 && guid.data[8] == 0xFF && + guid.data[9] == 0x11; + }); +} + +/// The OS device node of a pad (e.g. /dev/input/event5); empty where unsupported +QString PadPath(SDL_JoystickID id) { + return WithJoystick(id, QString{}, [](SDL_Joystick* js) { + const char* path = SDL_GetJoystickPath(js); + return path ? QString::fromUtf8(path) : QString{}; + }); +} + +/// A pad's slot as Steam says now (nothing outside Steam's pads); reread when Steam writes it +std::optional SteamSlotOf(SDL_JoystickID id) { +#ifdef __linux__ + static const QByteArray file = qgetenv("SteamVirtualGamepadInfo"); + if (file.isEmpty()) { + return std::nullopt; + } + // The pad's slot: Steam names its device "Microsoft X-Box 360 pad " (read once a pad) + static std::map slot_of_pad; + auto known = slot_of_pad.find(id); + if (known == slot_of_pad.end()) { + const QString node = QFileInfo{PadPath(id)}.fileName(); + if (node.isEmpty()) { + return std::nullopt; + } + int slot = -1; + QFile name_file{QStringLiteral("/sys/class/input/%1/device/name").arg(node)}; + if (name_file.open(QIODevice::ReadOnly)) { + const QString name = QString::fromUtf8(name_file.readAll()).trimmed(); + const QString prefix = QStringLiteral("Microsoft X-Box 360 pad "); + bool ok = false; + const int number = name.startsWith(prefix) ? name.mid(prefix.size()).toInt(&ok) : -1; + slot = ok ? number : -1; + } + known = slot_of_pad.emplace(id, slot).first; + } + if (known->second < 0) { + return std::nullopt; + } + // The file, read again when Steam writes it + static std::map said; + static timespec said_at{}; + struct ::stat st {}; + if (::stat(file.constData(), &st) != 0) { + return std::nullopt; + } + if (st.st_mtim.tv_sec != said_at.tv_sec || st.st_mtim.tv_nsec != said_at.tv_nsec) { + QFile in{QString::fromLocal8Bit(file)}; + if (!in.open(QIODevice::ReadOnly)) { + return std::nullopt; + } + said_at = st.st_mtim; + said.clear(); + SteamSlot* current = nullptr; + for (const QByteArray& raw : in.readAll().split('\n')) { + const QByteArray line = raw.trimmed(); + if (line.startsWith("[slot ") && line.endsWith(']')) { + current = &said[line.mid(6, line.size() - 7).toInt()]; + continue; + } + const auto at = line.indexOf('='); + if (!current || at < 0) { + continue; + } + const QByteArray key = line.left(at); + const QByteArray value = line.mid(at + 1); + if (key == "handle") { + current->handle = value.toULongLong(nullptr, 16); + } else if (key == "VID") { + current->vendor = static_cast(value.toUInt(nullptr, 16)); + } else if (key == "PID") { + current->product = static_cast(value.toUInt(nullptr, 16)); + } else if (key == "type") { + current->type = SDL_GetGamepadTypeFromString(value.constData()); + } else if (key == "name") { + current->name = QString::fromUtf8(value); + } + } + } + if (const auto slot = said.find(known->second); slot != said.end()) { + return slot->second; + } +#endif + return std::nullopt; +} + +/// A pad's USB vendor id (under Steam, its controller's, as Steam says now) +Uint16 PadVendor(SDL_JoystickID id) { + if (const auto slot = SteamSlotOf(id)) { + return slot->vendor; + } + return SDL_GetJoystickVendorForID(id); +} + +/// A pad's USB product id (under Steam, its controller's, as Steam says now) +Uint16 PadProduct(SDL_JoystickID id) { + if (const auto slot = SteamSlotOf(id)) { + return slot->product; + } + return SDL_GetJoystickProductForID(id); +} + +/// A pad's gamepad type (under Steam, its controller's, as Steam says now) +SDL_GamepadType PadType(SDL_JoystickID id) { + if (const auto slot = SteamSlotOf(id)) { + return slot->type; + } + return SDL_GetGamepadTypeForID(id); +} + +#ifdef __linux__ +/// The kernel's HID entry for a controller (bus, vendor, product, address), from its uevent +struct HidEntry { + unsigned bus = 0; + unsigned vendor = 0; + unsigned product = 0; + std::string address; +}; + +std::optional ReadHidEntry(const QString& dir) { + QFile file{dir + QStringLiteral("/uevent")}; + if (dir.isEmpty() || !file.open(QIODevice::ReadOnly)) { + return std::nullopt; + } + HidEntry entry; + bool has_id = false; + for (const QByteArray& line : file.readAll().split('\n')) { + if (line.startsWith("HID_ID=")) { + const QList parts = line.mid(7).split(':'); + if (parts.size() == 3) { + entry.bus = parts[0].toUInt(nullptr, 16); + entry.vendor = parts[1].toUInt(nullptr, 16); + entry.product = parts[2].toUInt(nullptr, 16); + has_id = true; + } + } else if (line.startsWith("HID_UNIQ=")) { + entry.address = line.mid(9).trimmed().toLower().toStdString(); + } + } + return has_id ? std::optional{entry} : std::nullopt; +} + +/// A controller as the kernel has it: address (or HID entry), Bluetooth or not, input nodes +struct RealController { + std::string key; + std::string address; + bool bluetooth = false; + std::vector events; +}; + +constexpr unsigned BusBluetooth = 0x5; + +/// The controllers of a model (one controller's several HID entries share its address) +std::vector ControllersOfModel(unsigned vendor, unsigned product) { + std::map found; + const QDir devices{QStringLiteral("/sys/bus/hid/devices")}; + for (const QString& name : devices.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { + const QString dir = devices.filePath(name); + const auto entry = ReadHidEntry(dir); + if (!entry || entry->vendor != vendor || entry->product != product) { + continue; + } + const std::string key = entry->address.empty() ? name.toStdString() : entry->address; + auto& controller = found[key]; + controller.key = key; + controller.address = entry->address; + controller.bluetooth = entry->bus == BusBluetooth && entry->address.size() == 17; + const QDir inputs{dir + QStringLiteral("/input")}; + for (const QString& input : inputs.entryList({QStringLiteral("input*")}, QDir::Dirs)) { + const QDir nodes{inputs.filePath(input)}; + for (const QString& event : nodes.entryList({QStringLiteral("event*")}, QDir::Dirs)) { + controller.events.push_back(QStringLiteral("/dev/input/") + event); + } + } + } + std::vector out; + for (auto& [key, controller] : found) { + out.push_back(std::move(controller)); + } + return out; +} + +/// Whether a pad's controller is on Bluetooth, and its address: from the HID device behind the +/// pad, else (under Steam) the only controller of its model. Unsure with several of the model +/// until a button press tells them apart, so Turn Off never hits the wrong one. +struct PadBluetooth { + std::string address; + bool unsure = false; +}; + +PadBluetooth FindPadBluetooth(SDL_JoystickID id) { + const QString node = QFileInfo{PadPath(id)}.fileName(); + if (!node.isEmpty()) { + const QString dir = + node.startsWith(QStringLiteral("hidraw")) + ? QFileInfo{QStringLiteral("/sys/class/hidraw/%1/device").arg(node)} + .canonicalFilePath() + : QFileInfo{QStringLiteral("/sys/class/input/%1/device/device").arg(node)} + .canonicalFilePath(); + if (const auto entry = ReadHidEntry(dir)) { + const bool bluetooth = entry->bus == BusBluetooth && entry->address.size() == 17; + return {bluetooth ? entry->address : std::string{}}; + } + } + const auto controllers = + ControllersOfModel(PadVendor(id), PadProduct(id)); + const bool any_bluetooth = std::any_of(controllers.begin(), controllers.end(), + [](const auto& c) { return c.bluetooth; }); + if (controllers.size() == 1) { + return {controllers[0].bluetooth ? controllers[0].address : std::string{}}; + } + return {{}, any_bluetooth}; +} + +/// How long a press read from a controller's input node counts (checks come every 100ms) +constexpr s64 RealPressWindowUs = 300'000; + +/// True while a controller has an input held, or had one in the last 300ms (a quick tap falls +/// between checks), read from its input nodes +bool RealButtonHeld(const RealController& controller) { + static std::map open_nodes; + // (Each node's axes, read when it is opened: their ranges, and where they rest then) + static std::map, input_absinfo> ranges; + // (Each node's last press, by the kernel's timestamp) + static std::map pressed_at_us; + timespec real{}; + clock_gettime(CLOCK_REALTIME, &real); + const s64 now_us = static_cast(real.tv_sec) * 1'000'000 + real.tv_nsec / 1000; + for (const QString& event : controller.events) { + auto it = open_nodes.find(event); + if (it == open_nodes.end()) { + const int fd = + ::open(event.toLocal8Bit().constData(), O_RDONLY | O_NONBLOCK | O_CLOEXEC); + // (A node that can't be opened yet, as it connects, is tried again next time) + if (fd < 0) { + continue; + } + it = open_nodes.emplace(event, fd).first; + for (u16 code = 0; code <= ABS_MAX; ++code) { + input_absinfo info{}; + if (ioctl(fd, EVIOCGABS(code), &info) == 0 && info.maximum > info.minimum) { + ranges[{event, code}] = info; + } + } + } + if (it->second < 0) { + continue; + } + // Its queue: the presses since the last check (and drained, so the kernel keeps nothing) + std::array events; + ssize_t got = 0; + while ((got = ::read(it->second, events.data(), sizeof(events))) > 0) { + for (std::size_t k = 0; k < static_cast(got) / sizeof(input_event); ++k) { + const input_event& e = events[k]; + bool pressed = e.type == EV_KEY && e.value == 1; + if (const auto range = ranges.find({event, e.code}); + e.type == EV_ABS && range != ranges.end()) { + // A quarter of its range away from rest + const auto& info = range->second; + const double moved = std::abs(static_cast(e.value - info.value)) / + static_cast(info.maximum - info.minimum); + pressed = moved > 0.25; + } + if (pressed) { + pressed_at_us[event] = static_cast(e.input_event_sec) * 1'000'000 + + static_cast(e.input_event_usec); + } + } + } + if (const auto pressed = pressed_at_us.find(event); + pressed != pressed_at_us.end() && now_us - pressed->second < RealPressWindowUs) { + return true; + } + std::array keys{}; + if (ioctl(it->second, EVIOCGKEY(keys.size()), keys.data()) < 0) { + ::close(it->second); + open_nodes.erase(it); + std::erase_if(ranges, [&](const auto& e) { return e.first.first == event; }); + continue; + } + if (std::any_of(keys.begin(), keys.end(), [](unsigned char b) { return b != 0; })) { + return true; + } + } + return false; +} + +/// A controller's BlueZ object paths, one per Bluetooth adapter +QStringList BluezDevicePaths(const std::string& address) { + QString device = QString::fromStdString(address).toUpper(); + device.replace(QLatin1Char(':'), QLatin1Char('_')); + QStringList paths; + const QDir adapters{QStringLiteral("/sys/class/bluetooth")}; + for (const QString& adapter : adapters.entryList({QStringLiteral("hci*")}, QDir::AllEntries)) { + if (!adapter.contains(QLatin1Char(':'))) { // (hci0:12 is a connection, not an adapter) + paths.push_back(QStringLiteral("/org/bluez/%1/dev_%2").arg(adapter, device)); + } + } + return paths; +} + +/// Asks BlueZ for a property of a controller without waiting: `answer` gets it on the GUI +/// thread (while `context` lives), or never +void AskBluezProperty(const std::string& address, const QString& interface, + const QString& property, QObject* context, + std::function answer) { + QDBusConnection bus = QDBusConnection::systemBus(); + if (!bus.isConnected()) { + return; + } + for (const QString& path : BluezDevicePaths(address)) { + QDBusMessage get = QDBusMessage::createMethodCall( + QStringLiteral("org.bluez"), path, QStringLiteral("org.freedesktop.DBus.Properties"), + QStringLiteral("Get")); + get << interface << property; + auto* watcher = new QDBusPendingCallWatcher(bus.asyncCall(get, 1000)); + QObject::connect(watcher, &QDBusPendingCallWatcher::finished, context, + [answer](QDBusPendingCallWatcher* w) { + const QDBusPendingReply reply = *w; + if (!reply.isError()) { + answer(reply.value().variant()); + } + w->deleteLater(); + }); + } +} + +/// Asks BlueZ whether a controller is connected, without waiting (see AskBluezProperty) +void AskBluezConnected(const std::string& address, QObject* context, + std::function answer) { + AskBluezProperty(address, QStringLiteral("org.bluez.Device1"), QStringLiteral("Connected"), + context, [answer](const QVariant& value) { answer(value.toBool()); }); +} + +/// Asks BlueZ to disconnect a controller, which turns most controllers off +void DisconnectBluetooth(const std::string& address) { + QDBusConnection bus = QDBusConnection::systemBus(); + if (!bus.isConnected()) { + LOG_WARNING(Frontend, "console-mode: no system bus to disconnect {}", address); + return; + } + for (const QString& path : BluezDevicePaths(address)) { + const QDBusMessage call = QDBusMessage::createMethodCall( + QStringLiteral("org.bluez"), path, QStringLiteral("org.bluez.Device1"), + QStringLiteral("Disconnect")); + auto* watcher = new QDBusPendingCallWatcher(bus.asyncCall(call)); + QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [address, path](auto* w) { + const QDBusPendingReply<> reply = *w; + if (reply.isError()) { + if (reply.error().type() != QDBusError::UnknownObject) { + LOG_WARNING(Frontend, "console-mode: disconnect {} failed: {}", address, + reply.error().message().toStdString()); + } + } else { + LOG_INFO(Frontend, "console-mode: disconnected {} ({})", address, + path.toStdString()); + } + w->deleteLater(); + }); + } +} +#endif + +/// True while any button of a pad is held: the Identify handshake reads this. +bool PadAnyButtonPressed(SDL_JoystickID id) { + return WithJoystick(id, false, [](SDL_Joystick* js) { + const int count = SDL_GetNumJoystickButtons(js); + for (int i = 0; i < count; ++i) { + if (SDL_GetJoystickButton(js, i)) { + return true; + } + } + return false; + }); +} + +/// True while a pad's + (Start, Menu, Options) is held +bool PadStartHeld(SDL_JoystickID id) { + return WithGamepad(id, false, [](SDL_Gamepad* pad) { + return SDL_GetGamepadButton(pad, SDL_GAMEPAD_BUTTON_START); + }); +} + +/// Steam's own player index for a pad (-1 when not assigned by Steam Input). +int PadPlayerIndex(SDL_JoystickID id) { + return WithJoystick(id, -1, [](SDL_Joystick* js) { return SDL_GetJoystickPlayerIndex(js); }); +} + +/// True when SDL reports a gyro on the pad +bool PadHasGyro(SDL_JoystickID id) { + return WithGamepad(id, false, + [](SDL_Gamepad* pad) { return SDL_GamepadHasSensor(pad, SDL_SENSOR_GYRO); }); +} + +/// True while a pad's accelerometer reads nothing (gravity always registers when on) +bool PadMotionSilent(SDL_JoystickID id) { + return WithGamepad(id, false, [](SDL_Gamepad* pad) { + std::array accel{}; + return SDL_GetGamepadSensorData(pad, SDL_SENSOR_ACCEL, accel.data(), 3) && + accel[0] == 0.0f && accel[1] == 0.0f && accel[2] == 0.0f; + }); +} + +/// Asks the Steam Deck's controller to turn its motion sensors on (Steam keeps them off unless +/// its layout uses the gyro): IMU mode 0x30 = 0x18 in feature report 0x87, as SDL sends it, on +/// a thread of its own +void EnableDeckMotion(const QString& path) { +#ifdef __linux__ + static std::atomic busy{false}; + if (!path.startsWith(QStringLiteral("/dev/hidraw")) || busy.exchange(true)) { + return; + } + std::thread([node = path.toStdString()] { + const int fd = ::open(node.c_str(), O_RDWR | O_CLOEXEC); + if (fd >= 0) { + std::array report{0x00, 0x87, 0x03, 0x30, 0x18, 0x00}; + if (ioctl(fd, HIDIOCSFEATURE(report.size()), report.data()) < 0 && + Common::ControllerProbes()) { + LOG_WARNING(Frontend, "console-mode: deck motion request failed on {}", node); + } + ::close(fd); + } + busy = false; + }).detach(); +#endif +} + +/// The controller applet modes, as the log names them +const char* AppletModeName(Settings::AppletMode mode) { + switch (mode) { + case Settings::AppletMode::HLE: + return "Custom Frontend"; + case Settings::AppletMode::LLE: + return "Real Hardware"; + case Settings::AppletMode::Disabled: + return "Disabled"; + case Settings::AppletMode::ConsoleMode: + return "Modern Console"; + case Settings::AppletMode::HandheldConsoleMode: + return "Handheld Console"; + default: + return "unknown"; + } +} + +/// A controller type, as the log names it +const char* StyleName(Core::HID::NpadStyleIndex style) { + using Core::HID::NpadStyleIndex; + switch (style) { + case NpadStyleIndex::Fullkey: + return "Pro Controller"; + case NpadStyleIndex::Handheld: + return "Handheld"; + case NpadStyleIndex::JoyconDual: + return "Dual Joycons"; + case NpadStyleIndex::JoyconLeft: + return "Left Joycon"; + case NpadStyleIndex::JoyconRight: + return "Right Joycon"; + case NpadStyleIndex::GameCube: + return "GameCube"; + default: + return "other"; + } +} + +/// Whether a game's supported controller types include one (as hid_core decides it) +bool StyleSupported(Core::HID::NpadStyleIndex style, const Core::HID::NpadStyleTag& tag) { + using Core::HID::NpadStyleIndex; + switch (style) { + case NpadStyleIndex::Fullkey: + return tag.fullkey; + case NpadStyleIndex::Handheld: + return tag.handheld; + case NpadStyleIndex::JoyconDual: + return tag.joycon_dual; + case NpadStyleIndex::JoyconLeft: + return tag.joycon_left; + case NpadStyleIndex::JoyconRight: + return tag.joycon_right; + case NpadStyleIndex::GameCube: + return tag.gamecube; + case NpadStyleIndex::Pokeball: + return tag.palma; + case NpadStyleIndex::NES: + return tag.lark; + case NpadStyleIndex::SNES: + return tag.lucia; + case NpadStyleIndex::N64: + return tag.lagoon; + case NpadStyleIndex::SegaGenesis: + return tag.lager; + default: + return false; + } +} + +/// A controller's short name, for a named player ("John (Xbox)") +QString ShortControllerName(SDL_JoystickID id, const QString& full) { + const Uint16 vendor = PadVendor(id); + const Uint16 product = PadProduct(id); + if (vendor == 0x28DE && product == 0x1205) { + return QStringLiteral("Steam Deck"); + } + // (The Steam Controller and the Steam Controller (2026), wired or through a dongle) + if (vendor == 0x28DE && (product == 0x1102 || product == 0x1142 || product == 0x1302 || + product == 0x1304 || product == 0x1305)) { + return QStringLiteral("Steam Controller"); + } + switch (PadType(id)) { + case SDL_GAMEPAD_TYPE_XBOX360: + case SDL_GAMEPAD_TYPE_XBOXONE: + return QStringLiteral("Xbox"); + case SDL_GAMEPAD_TYPE_PS3: + return QStringLiteral("DualShock 3"); + case SDL_GAMEPAD_TYPE_PS4: + return QStringLiteral("DualShock 4"); + case SDL_GAMEPAD_TYPE_PS5: + return QStringLiteral("DualSense"); + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO: + return QStringLiteral("Pro Controller"); + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT: + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT: + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR: + return QStringLiteral("Joy-Con"); + case SDL_GAMEPAD_TYPE_GAMECUBE: + return QStringLiteral("GameCube"); + default: + return full; + } +} + +/// A stick binding turned for a single Joy-Con held sideways (the right one a quarter clockwise, +/// the left one the other way); only SDL bindings turn +std::string TurnStickSideways(const std::string& raw, bool right) { + Common::ParamPackage param{raw}; + if (param.Get("engine", "") != "sdl" || !param.Has("axis_x") || !param.Has("axis_y")) { + return raw; + } + const int axis_x = param.Get("axis_x", 0); + const int axis_y = param.Get("axis_y", 1); + const std::string invert_x = param.Get("invert_x", "+"); + const std::string invert_y = param.Get("invert_y", "+"); + const auto flip = [](const std::string& sign) { + return sign == "-" ? std::string{"+"} : std::string{"-"}; + }; + param.Set("axis_x", axis_y); + param.Set("axis_y", axis_x); + // Right: its x is the push's -y, its y the push's x. Left: its x is y, its y is -x. + // (An SDL stick's y is read negated, after the axes are picked: SDL's y points down. So + // the new x, SDL's y as read, is already the push's -y, and the new y needs a flip of x; + // the left one the other way round.) + param.Set("invert_x", right ? invert_y : flip(invert_y)); + param.Set("invert_y", right ? flip(invert_x) : invert_x); + // (The centre offsets follow their axes; each is minus the axis's resting value as read, + // and the swap reads each axis with the other's sign) + if (param.Has("offset_x") || param.Has("offset_y")) { + const float offset_x = param.Get("offset_x", 0.0f); + const float offset_y = param.Get("offset_y", 0.0f); + param.Set("offset_x", -offset_y); + param.Set("offset_y", -offset_x); + } + return param.Serialize(); +} + +/// A stick binding the D-pad also moves (up, down, left, right: the D-pad buttons that push +/// the stick that way); an empty D-pad leaves the stick as it is +std::string StickWithDpad(const std::string& stick, const std::string& up, + const std::string& down, const std::string& left, + const std::string& right) { + if (up.empty() && down.empty() && left.empty() && right.empty()) { + return stick; + } + Common::ParamPackage param{{"engine", "analog_from_button"}}; + param.Set("up", up); + param.Set("down", down); + param.Set("left", left); + param.Set("right", right); + if (!stick.empty()) { + param.Set("stick", stick); + } + return param.Serialize(); +} + +/// A player's bindings for a single Joy-Con held upright: the right one's stick is the left +/// stick (the D-pad moves it too), L / ZL its SL / SR; the left one's SL / SR are R / ZR +void BindUprightJoyCon(Settings::PlayerInput& set, bool right) { + using namespace Settings::NativeButton; + const auto pad = set.buttons; + auto& out = set.buttons; + if (right) { + out[RStick] = pad[LStick]; + out[SLRight] = pad[L]; + out[SRRight] = pad[ZL]; + set.analogs[Settings::NativeAnalog::RStick] = + StickWithDpad(set.analogs[Settings::NativeAnalog::LStick], pad[DUp], pad[DDown], + pad[DLeft], pad[DRight]); + } else { + out[SLLeft] = pad[R]; + out[SRLeft] = pad[ZR]; + } +} + +/// A player's bindings for a single Joy-Con held sideways: face buttons by position, the +/// shoulders to SL / SR, the left stick to its stick (the D-pad moves it too), the motion +/// turned to the Joy-Con's own axes (a game turns a sideways Joy-Con's stick and motion itself) +void BindSidewaysJoyCon(Settings::PlayerInput& set, bool right) { + for (std::string& motion : set.motions) { + Common::ParamPackage param{motion}; + if (param.Has("motion")) { + param.Set("turn", right ? 1 : -1); + motion = param.Serialize(); + } + } + using namespace Settings::NativeButton; + const auto pad = set.buttons; + auto& out = set.buttons; + const std::string bottom = pad[B], east = pad[A], west = pad[Y], top = pad[X]; + if (right) { + // Turned a quarter clockwise: A below, X to the right, B to the left, Y on top + out[A] = bottom; + out[X] = east; + out[B] = west; + out[Y] = top; + out[SLRight] = pad[L]; + out[SRRight] = pad[R]; + out[RStick] = pad[LStick]; + // (The D-pad as the player sees it: up pushes the turned stick as the stick's up does) + set.analogs[Settings::NativeAnalog::RStick] = + StickWithDpad(TurnStickSideways(set.analogs[Settings::NativeAnalog::LStick], true), + pad[DRight], pad[DLeft], pad[DUp], pad[DDown]); + } else { + // Turned a quarter the other way + out[DLeft] = bottom; + out[DDown] = east; + out[DUp] = west; + out[DRight] = top; + out[SLLeft] = pad[L]; + out[SRLeft] = pad[R]; + set.analogs[Settings::NativeAnalog::LStick] = + StickWithDpad(TurnStickSideways(set.analogs[Settings::NativeAnalog::LStick], false), + pad[DLeft], pad[DRight], pad[DDown], pad[DUp]); + } +} + +/// A battery as Linux lists it (/sys/class/power_supply): charge and whether it charges +#ifdef __linux__ +std::optional> ReadPowerSupply(const QString& dir) { + const auto read = [&](const char* name) { + QFile file{dir + QLatin1Char('/') + QLatin1String(name)}; + return file.open(QIODevice::ReadOnly) ? QString::fromLatin1(file.readAll()).trimmed() + : QString{}; + }; + int percent = -1; + bool ok = false; + if (const int capacity = read("capacity").toInt(&ok); ok) { + percent = capacity; + } else { + const QString level = read("capacity_level"); + percent = level == QStringLiteral("Full") ? 100 + : level == QStringLiteral("High") ? 75 + : level == QStringLiteral("Normal") ? 50 + : level == QStringLiteral("Low") ? 15 + : level == QStringLiteral("Critical") ? 5 + : -1; + } + if (percent < 0) { + return std::nullopt; + } + const QString status = read("status"); + return std::pair{percent, + status == QStringLiteral("Charging") || status == QStringLiteral("Full")}; +} + +/// A Bluetooth controller's battery, by its address (hid-

-battery) +std::optional> BluetoothBattery(const std::string& address) { + const QDir supplies{QStringLiteral("/sys/class/power_supply")}; + const QString wanted = QString::fromStdString(address).toLower(); + for (const QString& name : supplies.entryList(QDir::AllEntries | QDir::NoDotAndDotDot)) { + const QString dir = supplies.filePath(name); + bool match = name.toLower().contains(wanted); + if (!match) { + if (const auto entry = + ReadHidEntry(QFileInfo{dir + QStringLiteral("/device")}.canonicalFilePath())) { + match = entry->address == address; + } + } + if (match) { + return ReadPowerSupply(dir); + } + } + return std::nullopt; +} + +/// Asks BlueZ for a Bluetooth LE controller's battery (Xbox Series controllers have no power +/// supply in Linux), without waiting: `answer` gets it on the GUI thread +void AskBluezBattery(const std::string& address, QObject* context, + std::function answer) { + AskBluezProperty(address, QStringLiteral("org.bluez.Battery1"), QStringLiteral("Percentage"), + context, [answer](const QVariant& value) { + bool ok = false; + const int percent = value.toInt(&ok); + if (ok && percent >= 0 && percent <= 100) { + answer(percent); + } + }); +} + +/// The system's own battery (the handheld's own controls run on it) +std::optional> SystemBattery() { + const QDir supplies{QStringLiteral("/sys/class/power_supply")}; + for (const QString& name : supplies.entryList({QStringLiteral("BAT*")}, QDir::AllEntries)) { + if (const auto battery = ReadPowerSupply(supplies.filePath(name))) { + return battery; + } + } + return std::nullopt; +} +#endif + +/// What SDL knows of a pad's battery: percent (-1 unknown), charging, wired +std::tuple SdlBattery(SDL_JoystickID id) { + const JoystickApiLock lock; + SDL_Joystick* js = SDL_OpenJoystick(id); + if (!js) { + return {-1, false, false}; + } + int percent = -1; + const SDL_PowerState state = SDL_GetJoystickPowerInfo(js, &percent); + SDL_CloseJoystick(js); + switch (state) { + case SDL_POWERSTATE_ON_BATTERY: + return {percent, false, false}; + case SDL_POWERSTATE_CHARGING: + case SDL_POWERSTATE_CHARGED: + return {percent, true, false}; + case SDL_POWERSTATE_NO_BATTERY: + return {-1, false, true}; + default: + return {-1, false, false}; + } +} + +/// True for Nintendo's controllers and look-alikes: their buttons already match the Switch's +bool IsNintendoPad(SDL_JoystickID id) { + switch (PadType(id)) { + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO: + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT: + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT: + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR: + case SDL_GAMEPAD_TYPE_GAMECUBE: + return true; + default: + return PadVendor(id) == 0x057E; + } +} + +/// The players controllers take in the console modes: a Switch's eight (a ninth controller +/// waits). The settings' players past them are the handheld's own and one more. +constexpr int ConsolePlayers = 8; + +/// Makers of standalone controllers: never a handheld's built-in controls, even when alone +bool IsControllerMaker(Uint16 vendor) { + switch (vendor) { + case 0x045E: // Microsoft + case 0x054C: // Sony + case 0x057E: // Nintendo + case 0x2DC8: // 8BitDo + case 0x046D: // Logitech + case 0x20D6: // PowerA + case 0x0E6F: // PDP + case 0x0F0D: // Hori + case 0x1532: // Razer + case 0x0738: // Mad Catz + case 0x146B: // Nacon + case 0x3537: // GameSir + return true; + default: + return false; + } +} + +/// Makers of handhelds with built-in controls: a pad from one is the handheld's own on a +/// direct launch +bool IsHandheldMaker(Uint16 vendor) { + return vendor == 0x28DE || vendor == 0x17EF || vendor == 0x0B05 || vendor == 0x0DB0; +} + +/// Whether a pad can be a handheld's own controls (of Valve's, only the Deck's) +bool CouldBeHandheld(Uint16 vendor, Uint16 product) { + if (vendor == 0x28DE) { + return product == 0x1205; + } + return !IsControllerMaker(vendor); +} + +/// Whether a pad is plainly a standalone controller, never a handheld's controls: Valve's other +/// controllers, controller-only makers, and wireless Xbox controllers (a wired Microsoft id +/// stays: some handhelds' controls report one, such as the ROG Xbox Ally) +bool IsPlainlyStandalone(SDL_JoystickID id) { + const Uint16 vendor = PadVendor(id); + const Uint16 product = PadProduct(id); + if (vendor == 0x28DE) { + return product != 0x1205; + } + if (vendor == 0x045E) { + switch (product) { + case 0x02E0: // Xbox One S, Bluetooth + case 0x02E6: // Xbox Wireless Adapter + case 0x02FD: // Xbox One S, Bluetooth + case 0x0719: // Xbox 360 wireless receiver + case 0x0B05: // Xbox Elite Series 2, Bluetooth + case 0x0B13: // Xbox Series X|S, Bluetooth + case 0x0B20: // Xbox Series X|S, Bluetooth + case 0x0B22: // Xbox Elite Series 2, Bluetooth + return true; + default: + break; + } + } else if (IsControllerMaker(vendor)) { + return true; + } + const JoystickApiLock lock; + SDL_Gamepad* pad = SDL_OpenGamepad(id); + if (!pad) { + return false; + } + const bool wireless = SDL_GetJoystickConnectionState(SDL_GetGamepadJoystick(pad)) == + SDL_JOYSTICK_CONNECTION_WIRELESS; + SDL_CloseGamepad(pad); + return wireless; +} + +/// True for the controller types Steam reports for standalone controllers +bool IsStandaloneControllerType(SDL_GamepadType type) { + return type != SDL_GAMEPAD_TYPE_UNKNOWN && type != SDL_GAMEPAD_TYPE_STANDARD; +} + +/// Steam Input's handle for the physical controller behind a pad (0 none): Steam refills its +/// virtual pads in its own order, so only the handle tells which controller came back +Uint64 PadSteamHandle(SDL_JoystickID id) { + // (As Steam says now: SDL's copy is up to 3 seconds old) + if (const auto slot = SteamSlotOf(id)) { + return slot->handle; + } + return WithGamepad(id, Uint64{0}, + [](SDL_Gamepad* pad) { return SDL_GetGamepadSteamHandle(pad); }); +} + +/// The key a pad's Bluetooth state is kept under: its Steam handle under Steam (it follows the +/// controller between virtual pads), else the connection instance +std::string BluetoothKey(SDL_JoystickID id) { + if (const Uint64 handle = PadSteamHandle(id)) { + return fmt::format("steamhandle:{:#x}", handle); + } + return fmt::format("inst:{}", id); +} + +/// How a pad is stored as the handheld's: Steam handle under Steam, else its identity +std::string PadKey(SDL_JoystickID id, const std::string& ident) { + if (Common::SteamPadsInUse()) { + if (const Uint64 handle = PadSteamHandle(id)) { + return fmt::format("steamhandle:{:#x}", handle); + } + } + return ident; +} + +/// True while a pad has an input held: any button, or a stick or trigger past half travel. +bool PadInputHeld(SDL_JoystickID id) { + return WithGamepad(id, false, [](SDL_Gamepad* pad) { + for (int b = 0; b < SDL_GAMEPAD_BUTTON_COUNT; ++b) { + if (SDL_GetGamepadButton(pad, static_cast(b))) { + return true; + } + } + for (int a = 0; a < SDL_GAMEPAD_AXIS_COUNT; ++a) { + const Sint16 value = SDL_GetGamepadAxis(pad, static_cast(a)); + if (value > 16384 || value < -16384) { + return true; + } + } + return false; + }); +} + +/// A short rumble pulse on a pad, if it supports rumble. +void PadRumble(SDL_JoystickID id, Uint16 strength, Uint32 duration_ms) { + const JoystickApiLock lock; + if (SDL_Gamepad* pad = SDL_OpenGamepad(id)) { + SDL_RumbleGamepad(pad, strength, strength, duration_ms); + SDL_CloseGamepad(pad); + } +} + +/// An SDL motion binding for a device, as InputCommon's auto-mapping builds it +std::string SdlMotionParam(const std::string& guid, int port) { + Common::ParamPackage param; + param.Set("engine", "sdl"); + param.Set("motion", 0); + param.Set("port", port); + param.Set("guid", guid); + return param.Serialize(); +} + +/// Points every SDL binding of a player at one device (guid + port), leaving other engines +/// alone. True when it changed. +bool RouteSdlBindings(Settings::PlayerInput& player, const std::string& guid, int port) { + bool routed = false; + const auto route = [&](auto& params) { + for (std::string& raw : params) { + Common::ParamPackage param{raw}; + if (param.Get("engine", "") != "sdl") { + continue; + } + const std::string old_guid = param.Get("guid", ""); + if (old_guid == guid && param.Get("port", -1) == port) { + continue; + } + param.Set("guid", guid); + param.Set("port", port); + if (param.Has("guid2") && param.Get("guid2", "") == old_guid) { + param.Set("guid2", guid); + } + raw = param.Serialize(); + routed = true; + } + }; + route(player.buttons); + route(player.analogs); + route(player.motions); + return routed; +} + +/// The binding sets the console modes start from: the user's players without mappings or +/// profiles (each controller gets its defaults or a picked profile). Only a DSU server's motion +/// stays: the console modes don't expose motion. +std::array ModernStartSets( + const std::array& user_players) { + auto sets = user_players; + for (auto& set : sets) { + set.buttons.fill({}); + set.analogs.fill({}); + for (std::string& motion : set.motions) { + if (Common::ParamPackage{motion}.Get("engine", "") != "cemuhookudp") { + motion.clear(); + } + } + set.profile_name.clear(); + } + return sets; +} + +} // Anonymous namespace + +void MainWindow::SaveAllConfigValues() { + if (!console_profile) { + config->SaveAllValues(); + return; + } + // A console mode drives the players at runtime; the file keeps the user's own + auto& players = Settings::values.players.GetValue(true); + std::swap(players, *console_profile); + config->SaveAllValues(); + std::swap(players, *console_profile); +} + +namespace { +/// The handheld set's motion bindings, to trace what clears the DSU gyro (Debug Probes) +std::string MotionTrace(const Settings::PlayerInput& player) { + std::string out; + for (const auto& motion : player.motions) { + out += '[' + motion + ']'; + } + return out; +} +} // Anonymous namespace + +void MainWindow::RestoreConsoleProfile() { + if (!console_profile) { + return; + } + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: restore, profile P1 motions {}", + MotionTrace((*console_profile)[0])); + } + // A running game has its own copy of the players, which the engine drove: both copies get + // the user's players back (the game's as read at boot) + Settings::values.players.GetValue(true) = *console_profile; + if (!Settings::values.players.UsingGlobal()) { + Settings::values.players.GetValue() = game_profiles ? *game_profiles : *console_profile; + } + console_profile.reset(); + game_profiles.reset(); + session_sets.reset(); +} + +Settings::PlayerInput& MainWindow::SessionSet(int set) { + if (game_profiles && !(*game_profiles)[set].profile_name.empty()) { + return (*game_profiles)[set]; + } + if (!session_sets) { + session_sets = ModernStartSets(*console_profile); + } + return (*session_sets)[set]; +} + +std::array MainWindow::ConsoleBindingSets() const { + auto sets = session_sets ? *session_sets : ModernStartSets(*console_profile); + if (game_profiles) { + for (size_t i = 0; i < sets.size(); ++i) { + if (!(*game_profiles)[i].profile_name.empty()) { + sets[i] = (*game_profiles)[i]; + } + } + } + return sets; +} + +namespace { + +/// A binding's mapping without its device (guid, port): what a Controls tab edit changes. +/// Order- and float-format-insensitive ("0.5" and "0.500000" are the same). +std::string BindingMapping(const std::string& raw) { + if (raw.empty()) { + return {}; + } + Common::ParamPackage param{raw}; + // Only an SDL binding's guid/port is routing (a DSU server's address is the mapping) + if (param.Get("engine", "") == "sdl") { + param.Erase("guid"); + param.Erase("guid2"); + param.Erase("port"); + } + std::vector fields; + std::string field; + for (const char c : param.Serialize() + ",") { + if (c != ',') { + field += c; + continue; + } + const auto colon = field.find(':'); + if (colon != std::string::npos) { + const std::string value = field.substr(colon + 1); + char* end = nullptr; + const float number = std::strtof(value.c_str(), &end); + if (!value.empty() && end && *end == '\0') { + field = field.substr(0, colon + 1) + fmt::format("{}", number); + } + } + fields.push_back(field); + field.clear(); + } + std::sort(fields.begin(), fields.end()); + std::string out; + for (const auto& f : fields) { + out += f + ','; + } + return out; +} + +/// Puts a profile's mappings on a binding set, keeping the set's controller on SDL bindings +void ApplyProfileMappings(Settings::PlayerInput& set, const Settings::PlayerInput& profile) { + const auto apply = [](auto& to, const auto& from) { + for (size_t i = 0; i < to.size(); ++i) { + Common::ParamPackage taken{from[i]}; + const Common::ParamPackage kept{to[i]}; + if (!from[i].empty() && !to[i].empty() && taken.Get("engine", "") == "sdl" && + kept.Get("engine", "") == "sdl") { + taken.Set("guid", kept.Get("guid", "")); + taken.Set("port", kept.Get("port", 0)); + if (kept.Has("guid2")) { + taken.Set("guid2", kept.Get("guid2", "")); + } else { + taken.Erase("guid2"); + } + to[i] = taken.Serialize(); + } else { + to[i] = from[i]; + } + } + }; + apply(set.buttons, profile.buttons); + apply(set.analogs, profile.analogs); + apply(set.motions, profile.motions); +} + +/// Brings edited mappings into the profile's, keeping the profile's own device on SDL bindings. +/// True when anything was taken. +template +bool MergeMappings(Array& profile, const Array& before, const Array& after) { + bool taken = false; + for (size_t i = 0; i < after.size(); ++i) { + if (BindingMapping(after[i]) == BindingMapping(before[i])) { + continue; + } + Common::ParamPackage edited{after[i]}; + const Common::ParamPackage original{profile[i]}; + if (!after[i].empty() && !profile[i].empty() && edited.Get("engine", "") == "sdl" && + original.Get("engine", "") == "sdl") { + edited.Set("guid", original.Get("guid", "")); + edited.Set("port", original.Get("port", 0)); + if (original.Has("guid2")) { + edited.Set("guid2", original.Get("guid2", "")); + } else { + edited.Erase("guid2"); + } + profile[i] = edited.Serialize(); + } else { + profile[i] = after[i]; + } + taken = true; + } + return taken; +} + +} // Anonymous namespace + +void MainWindow::ApplySeatProfiles() { + const std::string stored = Settings::values.modern_seat_profiles.GetValue(); + std::vector seats; + std::stringstream entries{stored}; + for (std::string entry; std::getline(entries, entry, ',');) { + seats.push_back(entry); + } + std::optional input_profiles; + for (size_t i = 0; i < seats.size() && i < 8; ++i) { + if (seats[i].empty()) { + continue; + } + if (!input_profiles) { + input_profiles.emplace(); + } + const auto read = input_profiles->PeekProfile(seats[i], i); + if (!read) { + LOG_INFO(Frontend, "console-mode: P{} seat profile \"{}\" is gone", i + 1, seats[i]); + SetSeatProfile(static_cast(i), {}); + continue; + } + ApplyProfileMappings((*session_sets)[i], *read); + (*session_sets)[i].profile_name = seats[i]; + LOG_INFO(Frontend, "console-mode: P{} starts with its seat profile \"{}\"", i + 1, + seats[i]); + } +} + +void MainWindow::SetSeatProfile(int player, const std::string& name) { + if (player < 0 || player >= 8) { + return; + } + std::vector seats; + std::stringstream entries{Settings::values.modern_seat_profiles.GetValue()}; + for (std::string entry; std::getline(entries, entry, ',');) { + seats.push_back(entry); + } + seats.resize(8); + seats[static_cast(player)] = name; + std::string joined; + for (size_t i = 0; i < seats.size(); ++i) { + joined += (i ? "," : "") + seats[i]; + } + // (Nothing stored when no seat has a profile) + if (joined.find_first_not_of(',') == std::string::npos) { + joined.clear(); + } + Settings::values.modern_seat_profiles.SetValue(joined); +} + +void MainWindow::MergeConsoleProfileEdits(const std::array& before) { + if (!console_profile) { + return; + } + // The Controls tab edits the global copy, whatever copy a running game uses + const auto& after = Settings::values.players.GetValue(true); + // The handheld's own non-SDL motion (a DSU server) must survive edits on players it doesn't + // hold: kept here and put back at the end + const auto handheld_motions_kept = SessionSet(0).motions; + const auto own_slot = pad_slots.find(builtin_pad_id); + // (Only a handheld without a player can't have edited its set) + const bool handheld_has_player = builtin_pad_id && own_slot != pad_slots.end(); + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, + "console-mode: merge start, profile P1 motions {} before {} after {} " + "handheld_has_player={}", + MotionTrace((*console_profile)[0]), MotionTrace(before[0]), MotionTrace(after[0]), + handheld_has_player); + } + // The SDL device (guid, port) a player's bindings point at + const auto sdl_device = [](const Settings::PlayerInput& player) { + for (const std::string& raw : player.buttons) { + const Common::ParamPackage param{raw}; + if (!raw.empty() && param.Get("engine", "") == "sdl") { + return std::optional>{ + {param.Get("guid", ""), param.Get("port", 0)}}; + } + } + return std::optional>{}; + }; + for (size_t i = 0; i < after.size(); ++i) { + const auto& a = after[i]; + const auto& b = before[i]; + // A device change is a controller swap (below), not an edit + if (const auto device = sdl_device(a); device && device != sdl_device(b)) { + continue; + } + // A single Joy-Con's mapping is arranged from the set, not the set itself (its player + // tab is read-only meanwhile): nothing there is an edit + if (i < joycon_auto_set.size() && joycon_auto_set[i] && + (*joycon_auto_set[i] == Settings::ControllerType::RightJoycon || + *joycon_auto_set[i] == Settings::ControllerType::LeftJoycon)) { + continue; + } + // Only mapping changes count as edits (connection and routing are the engine's). The + // handheld's own pad's edits go to player one's set. + const auto own = pad_slots.find(builtin_pad_id); + size_t target = static_cast(slot_set[i]); + // For this session only: the user's own setup is the manual modes' + auto& p = SessionSet(static_cast(target)); + bool remapped = MergeMappings(p.buttons, b.buttons, a.buttons); + remapped = MergeMappings(p.analogs, b.analogs, a.analogs) || remapped; + bool edited = remapped; + // An external pad never gets the handheld's non-SDL motion: its absence on another + // player is the engine's doing, not an edit, and must not wipe it from the set + auto edited_motions = a.motions; + if (target != 0 || + !(builtin_pad_id && own != pad_slots.end() && own->second == static_cast(i))) { + const auto& handheld_motions = SessionSet(0).motions; + for (size_t k = 0; k < edited_motions.size(); ++k) { + const std::string& kept = p.motions[k]; + const bool handheld_motion = + !kept.empty() && Common::ParamPackage{kept}.Get("engine", "") != "sdl" && + std::find(handheld_motions.begin(), handheld_motions.end(), kept) != + handheld_motions.end(); + if (handheld_motion && edited_motions[k].empty()) { + edited_motions[k] = b.motions[k]; + } + } + } + edited = MergeMappings(p.motions, b.motions, edited_motions) || edited; + // Remapped and not saved: the controls are no longer the profile's + if (remapped && !p.profile_name.empty()) { + InputProfiles input_profiles; + const auto saved = input_profiles.PeekProfile(p.profile_name, i); + bool same = saved.has_value(); + for (size_t k = 0; same && k < p.buttons.size(); ++k) { + same = BindingMapping(p.buttons[k]) == BindingMapping(saved->buttons[k]); + } + for (size_t k = 0; same && k < p.analogs.size(); ++k) { + same = BindingMapping(p.analogs[k]) == BindingMapping(saved->analogs[k]); + } + if (!same) { + LOG_INFO(Frontend, "console-mode: P{} remapped: profile \"{}\" let go", i + 1, + p.profile_name); + p.profile_name.clear(); + SetSeatProfile(static_cast(i), {}); + } + } + if (!edited) { + continue; + } + set_default_of[target] = 0; // (the user's own mapping now) + LOG_INFO(Frontend, "console-mode: Controls edit on P{} kept for the session in set P{}", + i + 1, target + 1); + } + + if (!handheld_has_player) { + auto& motions = SessionSet(0).motions; + for (size_t k = 0; k < motions.size(); ++k) { + const std::string& kept = handheld_motions_kept[k]; + if (motions[k].empty() && !kept.empty() && + Common::ParamPackage{kept}.Get("engine", "") != "sdl") { + motions[k] = kept; + LOG_INFO(Frontend, "console-mode: kept the handheld's motion {} on P1", kept); + } + } + } + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: merge end, profile P1 motions {}", + MotionTrace((*console_profile)[0])); + } + + // A swap from the Controls tab: a player whose device was changed to another player's pad + // trades slots with it; the routing pass re-points them next tick + if (!input_subsystem) { + return; + } + // The pads and their (guid, port); listed first, as GetSDLBinding can't run under the lock + std::vector instances; + { + const JoystickApiLock lock; + int count = 0; + SDL_JoystickID* ids = SDL_GetGamepads(&count); + for (int k = 0; k < count; ++k) { + instances.push_back(ids[k]); + } + SDL_free(ids); + } + std::map> bound; + for (const u32 inst : instances) { + if (const auto binding = input_subsystem->GetSDLBinding(inst)) { + bound[inst] = *binding; + } + } + // (The eight players only) + for (size_t i = 0; i < after.size() && i < static_cast(ConsolePlayers); ++i) { + const auto chosen = sdl_device(after[i]); + if (!chosen || chosen == sdl_device(before[i])) { + continue; + } + u32 pad = 0; + for (const auto& [inst, binding] : bound) { + if (binding == *chosen) { + pad = inst; + break; + } + } + if (!pad) { + continue; + } + if (pad == builtin_pad_id && Settings::values.controller_applet_mode.GetValue() == + Settings::AppletMode::HandheldConsoleMode) { + LOG_INFO(Frontend, "console-mode: Controls swap to P{} ignored: the handheld's own pad", + i + 1); + continue; + } + const auto pad_slot = pad_slots.find(pad); + if (pad_slot != pad_slots.end() && pad_slot->second == static_cast(i)) { + continue; + } + u32 holder = 0; + for (const auto& [inst, slot] : pad_slots) { + if (slot == static_cast(i) && bound.contains(inst)) { + holder = inst; + break; + } + } + const int from = pad_slot != pad_slots.end() ? pad_slot->second : -1; + if (holder) { + if (from >= 0) { + pad_slots[holder] = from; + } else { + pad_slots.erase(holder); + pad_identity.erase(holder); + } + } + pad_slots[pad] = static_cast(i); + LOG_INFO(Frontend, "console-mode: Controls swap: inst={} P{} -> P{}{}", pad, + from >= 0 ? from + 1 : 0, i + 1, + holder + ? fmt::format(", inst={} P{} -> P{}", holder, i + 1, from >= 0 ? from + 1 : 0) + : std::string{}); + } +} + +namespace { +/// The green/red flashes blink four times a second for their 1.5 seconds +bool BlinkOn(qint64 elapsed_ms) { + return elapsed_ms < 1500 && (elapsed_ms / 125) % 2 == 0; +} +} // Anonymous namespace + +void MainWindow::RenderControllerOverlay() { + // A row lights while its controller has an input held, or a moment after a tap. Never for + // motion: a resting gyro is never still. + const auto now = std::chrono::steady_clock::now(); + std::set active; + for (const auto& row : overlay_rows) { + if (row.pad == 0) { + continue; + } + const auto last = + input_subsystem ? input_subsystem->GetSDLLastActivity(row.pad) : std::nullopt; + if (PadInputHeld(row.pad) || (last && now - *last < std::chrono::milliseconds{250})) { + active.insert(row.pad); + } + } + overlay_active_pads = active; + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + for (auto& player : state.players) { + const auto row = std::find_if(overlay_rows.begin(), overlay_rows.end(), + [&](const auto& r) { return r.player == player.player; }); + player.active = row != overlay_rows.end() && active.contains(row->pad); + } + } + + const auto mode = Settings::values.controller_applet_mode.GetValue(); + const bool automatic = mode == Settings::AppletMode::ConsoleMode || + mode == Settings::AppletMode::HandheldConsoleMode; + const qint64 now_ms = QDateTime::currentMSecsSinceEpoch(); + const auto publish = [](Common::OverlayPanel& panel, const QImage* image) { + GameOverlay::Publish(panel, image); + }; + + const auto player_color = [](int player) { + return ConfigurePlayerAssignment::PlayerColor(player); + }; + const QFont badge_font = GameOverlay::Style::LabelFont(); + + // Hints: a controller that took or left a player, named for a few seconds at the bottom left + constexpr qint64 hint_ms = 3000; + for (const auto& row : overlay_rows) { + const int i = row.player; + if (row.flash == 1 && row.pad != 0 && row.flash_since > hinted_join[i]) { + hinted_join[i] = row.flash_since; + controller_hints.push_back({overlay_row_name[i], i, true, row.flash_since}); + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: hint \"{} joined\" P{}", + overlay_row_name[i].toStdString(), i + 1); + } + } else if (row.flash == 2 && row.flash_since > hinted_leave[i]) { + hinted_leave[i] = row.flash_since; + // (Removed on the tick it left) + const bool turned_off = std::abs(row.flash_since - turned_off_at[i]) < 1000; + // (Named after the controller that left: another may have the player already) + const QString& left_name = + overlay_left_name[i].isEmpty() ? overlay_row_name[i] : overlay_left_name[i]; + controller_hints.push_back({left_name, i, false, row.flash_since, turned_off}); + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: hint \"{} {}\" P{}", left_name.toStdString(), + turned_off ? "turned off" : "left", i + 1); + } + } + } + // (A pause's notice stays while the game is paused for it, and shows even with the hints off) + const bool hints_on = Settings::values.console_hints.GetValue(); + std::erase_if(controller_hints, [&](const auto& hint) { + if (hint.pause_notice && !disconnect_paused.empty()) { + return false; + } + return now_ms - hint.at >= hint_ms || (!hints_on && !hint.pause_notice); + }); + if (!automatic || controller_hints.empty()) { + publish(Common::GetOverlayPanel(Common::OverlayPanelId::Hints), nullptr); + } else { + QFont hint_font; + hint_font.setPixelSize(15); + hint_font.setBold(true); + const QFontMetrics hint_fm{hint_font}; + constexpr int hint_h = 30; + constexpr int hint_gap = 6; + constexpr int badge_w = 36; + const auto text_of = [](const ControllerHint& hint) { + if (!hint.note.isEmpty()) { + return hint.note; + } + if (hint.joined) { + return tr("%1 joined").arg(hint.name); + } + return hint.turned_off ? tr("%1 turned off").arg(hint.name) + : tr("%1 left").arg(hint.name); + }; + int width = 0; + for (const auto& hint : controller_hints) { + width = + (std::max)(width, 14 + hint_fm.horizontalAdvance(text_of(hint)) + 10 + badge_w + 6); + } + // The widest a hint can be, so the image keeps its size while hints come and go + width = (std::max)(width, 260) + 2; + const int count = static_cast(controller_hints.size()); + QImage image{width, count * (hint_h + hint_gap), QImage::Format_RGBA8888}; + image.fill(Qt::transparent); + QPainter painter{&image}; + painter.setRenderHint(QPainter::Antialiasing); + painter.setRenderHint(QPainter::TextAntialiasing); + // Newest at the bottom, nearest the corner + int y = 0; + for (const auto& hint : controller_hints) { + const QString text = text_of(hint); + const int w = 14 + hint_fm.horizontalAdvance(text) + 10 + badge_w + 6; + // (A pause's notice doesn't fade while the game is paused for it) + const qint64 left = hint.pause_notice && !disconnect_paused.empty() + ? hint_ms + : hint_ms - (now_ms - hint.at); + const int alpha = left < 500 ? static_cast(255 * (std::max)(left, qint64{0}) / 500) + : 255; + painter.setPen(Qt::NoPen); + painter.setBrush(hint.joined ? QColor(18, 18, 22, 215 * alpha / 255) + : QColor(96, 22, 28, 220 * alpha / 255)); + painter.drawRoundedRect(QRectF(1, y, w, hint_h), hint_h / 2.0, hint_h / 2.0); + painter.setFont(hint_font); + painter.setPen(QColor(255, 255, 255, alpha)); + painter.drawText(QRect(15, y, w, hint_h), Qt::AlignVCenter | Qt::AlignLeft, text); + QColor badge = player_color(hint.player); + badge.setAlpha(hint.joined ? alpha : alpha / 2); + painter.setPen(Qt::NoPen); + painter.setBrush(badge); + const QRectF badge_rect(1 + w - 6 - badge_w, y + 5, badge_w, hint_h - 10); + painter.drawRoundedRect(badge_rect, badge_rect.height() / 2, badge_rect.height() / 2); + painter.setFont(badge_font); + painter.setPen(QColor(255, 255, 255, alpha)); + painter.drawText(badge_rect, Qt::AlignCenter, + QStringLiteral("P%1").arg(hint.player + 1)); + y += hint_h + hint_gap; + } + painter.end(); + publish(Common::GetOverlayPanel(Common::OverlayPanelId::Hints), &image); + } + + overlay_blink.clear(); + for (const auto& row : overlay_rows) { + overlay_blink.push_back(row.flash != 0 && BlinkOn(now_ms - row.flash_since)); + } + if (!Settings::values.console_debug_overlay.GetValue() || !automatic || overlay_rows.empty()) { + publish(Common::GetOverlayPanel(Common::OverlayPanelId::Players), nullptr); + return; + } + + // The Switch buttons as chips: a label and a colour (stick moves: the stick and an arrow) + const auto chip = [](int button) -> std::pair { + using namespace Settings::NativeButton; + if (button >= StickMoveButton) { + static constexpr std::array arrows{u"\u2190", u"\u2191", u"\u2192", + u"\u2193"}; + const int stick = (button - StickMoveButton) / 4; + const int direction = (button - StickMoveButton) % 4; + return {(stick == 0 ? QStringLiteral("LS") : QStringLiteral("RS")) + + QString::fromUtf16(arrows[static_cast(direction)]), + QColor(52, 73, 94)}; + } + switch (button) { + case A: + return {QStringLiteral("A"), QColor(231, 76, 60)}; + case B: + return {QStringLiteral("B"), QColor(230, 180, 20)}; + case X: + return {QStringLiteral("X"), QColor(52, 152, 219)}; + case Y: + return {QStringLiteral("Y"), QColor(46, 184, 104)}; + case LStick: + return {QStringLiteral("L3"), QColor(70, 90, 112)}; + case RStick: + return {QStringLiteral("R3"), QColor(70, 90, 112)}; + case L: + return {QStringLiteral("L"), QColor(120, 132, 140)}; + case R: + return {QStringLiteral("R"), QColor(120, 132, 140)}; + case ZL: + return {QStringLiteral("ZL"), QColor(98, 108, 116)}; + case ZR: + return {QStringLiteral("ZR"), QColor(98, 108, 116)}; + case Plus: + return {QStringLiteral("+"), QColor(142, 88, 182)}; + case Minus: + return {QStringLiteral("−"), QColor(142, 88, 182)}; + case DLeft: + return {QStringLiteral("←"), QColor(84, 99, 116)}; + case DUp: + return {QStringLiteral("↑"), QColor(84, 99, 116)}; + case DRight: + return {QStringLiteral("→"), QColor(84, 99, 116)}; + case DDown: + return {QStringLiteral("↓"), QColor(84, 99, 116)}; + case Home: + return {QStringLiteral("⌂"), QColor(60, 60, 66)}; + case Screenshot: + return {QStringLiteral("◉"), QColor(60, 60, 66)}; + case SLLeft: + case SLRight: + return {QStringLiteral("SL"), QColor(120, 132, 140)}; + default: + return {QStringLiteral("SR"), QColor(120, 132, 140)}; + } + }; + const QFont name_font = GameOverlay::Style::TextFont(); + const QFont chip_font = GameOverlay::Style::SmallFont(); + const QFontMetrics name_fm{name_font}; + const QFontMetrics chip_fm{chip_font}; + + constexpr int row_h = 28; + constexpr int row_gap = 4; + constexpr int badge_w = 30; + constexpr int inner = 6; + constexpr int bubble_gap = 6; + constexpr int chip_h = 18; + constexpr int chip_gap = 3; + const auto chip_width = [&](const QString& text) { + return (std::max)(chip_h, chip_fm.horizontalAdvance(text) + 10); + }; + // The widest chip there can be (a stick move, "LS→", is wider than a button) + int widest_chip = 26; + for (int k = 0; k < 8; ++k) { + widest_chip = (std::max)(widest_chip, chip_width(chip(StickMoveButton + k).first)); + } + // An entry lives as long as set, then shrinks away + const bool show_history = Settings::values.console_history.GetValue(); + const bool show_gaps = Settings::values.console_history_gaps.GetValue(); + const int history_size = Settings::values.console_history_size.GetValue(); + const qint64 press_life_ms = Settings::values.console_history_seconds.GetValue() * 1000LL; + constexpr qint64 press_shrink_ms = 400; + // The time between inputs: a tag between their chips, in ms, or seconds from one ("1.2") + QFont gap_font; + gap_font.setPixelSize(8); + gap_font.setBold(true); + const QFontMetrics gap_fm{gap_font}; + const auto gap_text = [press_life_ms](qint64 ms) { + ms = (std::min)(ms, press_life_ms); + return ms < 1000 ? QString::number(ms) + : QStringLiteral("%1s").arg(static_cast(ms) / 1000.0, 0, 'f', + ms < 10000 ? 1 : 0); + }; + constexpr int gap_pad = 3; + const int widest_gap = gap_fm.horizontalAdvance(QStringLiteral("999")) + gap_pad * 2; + const auto press_scale = [now_ms, press_life_ms](const ButtonPress& press) { + const qint64 over = now_ms - press.at - press_life_ms; + if (over <= 0) { + return 1.0; + } + return (std::max)(0.0, 1.0 - static_cast(over) / press_shrink_ms); + }; + + int name_w = 0; + for (const auto& row : overlay_rows) { + name_w = (std::max)(name_w, name_fm.horizontalAdvance(overlay_row_name[row.player])); + } + // (A name being typed has room for its 16 characters) + if (overlay_edit_player >= 0) { + name_w = (std::max)(name_w, name_fm.horizontalAdvance(QString(16, QLatin1Char('M')))); + } + // Room for a battery after the name, when any controller tells its charge + const bool batteries = std::any_of(overlay_rows.begin(), overlay_rows.end(), + [](const auto& row) { return row.battery >= 0; }); + const int battery_w = + batteries ? 8 + chip_fm.horizontalAdvance(QStringLiteral("100%")) + 5 + 20 : 0; + const int controller_w = inner + badge_w + 8 + name_w + battery_w + inner + 4; + // Room for as many of the widest chips as the history keeps, so the image keeps its size + int history_room = show_history ? inner * 2 + history_size * (widest_chip + chip_gap) + + (show_gaps ? (history_size - 1) * widest_gap : 0) + : 200; + // Short of the panels at the top right: the oldest inputs drop off sooner + if (render_window) { + const auto& layout = render_window->GetFramebufferLayout(); + const int room = static_cast(Common::OverlayRoomTopLeft( + static_cast(layout.screen.right - layout.screen.left))) - + (controller_w + bubble_gap + 2); + history_room = (std::clamp)(room, inner * 2 + widest_chip, history_room); + } + const int width = controller_w + bubble_gap + history_room + 2; + const int count = static_cast(overlay_rows.size()); + const int height = count * row_h + (count - 1) * row_gap + 2; + + QImage image{width, height, QImage::Format_RGBA8888}; + image.fill(Qt::transparent); + QPainter painter{&image}; + painter.setRenderHint(QPainter::Antialiasing); + painter.setRenderHint(QPainter::TextAntialiasing); + painter.setPen(Qt::NoPen); + // The controller bubble: its state lights it (blue held, green joined, red left) + const auto controller_bubble = [&](const OverlayRow& row, bool blink, int at_y) { + const bool gone = row.pad == 0; + QColor fill = GameOverlay::Style::Fill; + if (row.flash == 2) { + if (blink) { + fill = GameOverlay::Style::Bad; + } + } else if (!gone && active.contains(row.pad)) { + fill = GameOverlay::Style::Active; + } else if (blink) { + fill = GameOverlay::Style::Good; + } + GameOverlay::Style::Pill(painter, QRectF(1, at_y, controller_w, row_h), fill); + QColor badge = player_color(row.player); + if (gone) { + badge.setAlpha(110); + } + painter.setBrush(badge); + const QRectF badge_rect(1 + inner, at_y + 5, badge_w, row_h - 10); + painter.drawRoundedRect(badge_rect, badge_rect.height() / 2, badge_rect.height() / 2); + painter.setFont(badge_font); + painter.setPen(Qt::white); + painter.drawText(badge_rect, Qt::AlignCenter, QStringLiteral("P%1").arg(row.player + 1)); + // On the badge's corner: ? for a reconnect's guess, else the starting player's colour + if (!gone && (row.guessed || row.origin >= 0)) { + const QPointF corner(badge_rect.right() - 1, badge_rect.top() + 1); + painter.setPen(QPen(QColor(14, 14, 18), 1.5)); + if (row.guessed) { + painter.setBrush(Qt::white); + painter.drawEllipse(corner, 6, 6); + QFont mark_font = badge_font; + mark_font.setPixelSize(9); + painter.setFont(mark_font); + painter.setPen(QColor(14, 14, 18)); + painter.drawText(QRectF(corner.x() - 6, corner.y() - 6, 12, 12), Qt::AlignCenter, + QStringLiteral("?")); + } else { + painter.setBrush(player_color(row.origin)); + painter.drawEllipse(corner, 4.5, 4.5); + } + painter.setPen(Qt::NoPen); + } + painter.setFont(name_font); + if (row.player == overlay_edit_player && !gone) { + // The name being typed: a field with its caret (blinking), or what to type + const QRectF field(1 + inner + badge_w + 4, at_y + 4, name_w + 10, row_h - 8); + painter.setPen(QPen(QColor(120, 170, 255, 230), 1.2)); + painter.setBrush(QColor(255, 255, 255, 30)); + painter.drawRoundedRect(field, 5, 5); + const QRectF text_rect = field.adjusted(5, 0, -5, 0); + painter.setPen(overlay_edit_text.isEmpty() ? QColor(255, 255, 255, 110) + : QColor(245, 245, 245)); + painter.drawText(text_rect, Qt::AlignVCenter | Qt::AlignLeft, + overlay_edit_text.isEmpty() ? tr("Name") : overlay_edit_text); + if ((QDateTime::currentMSecsSinceEpoch() / 500) % 2 == 0) { + const double caret = text_rect.left() + + (overlay_edit_text.isEmpty() + ? 0 + : name_fm.horizontalAdvance(overlay_edit_text)) + + 1; + painter.setPen(QPen(Qt::white, 1.2)); + painter.drawLine(QPointF(caret, field.top() + 4), QPointF(caret, field.bottom() - 4)); + } + painter.setPen(Qt::NoPen); + return; + } + painter.setPen(gone ? GameOverlay::Style::DimText : GameOverlay::Style::Text); + painter.drawText(QRect(1 + inner + badge_w + 8, at_y, name_w + 4, row_h), + Qt::AlignVCenter | Qt::AlignLeft, overlay_row_name[row.player]); + // The battery's percent, then its icon (the same as the tabs' and the menu bar's) + if (!gone && row.battery >= 0) { + const int percent_w = chip_fm.horizontalAdvance(QStringLiteral("100%")); + const double bx = 1 + inner + badge_w + 8 + name_w + 8 + percent_w + 5; + painter.drawPixmap(QPointF(bx, at_y + row_h / 2.0 - 6), + ConfigurePlayerAssignment::Battery(row.battery, row.charging)); + painter.setFont(chip_font); + painter.setPen(QColor(220, 220, 220)); + painter.drawText(QRectF(bx - 5 - percent_w, at_y, percent_w, row_h), + Qt::AlignVCenter | Qt::AlignRight, + QStringLiteral("%1%").arg(row.battery)); + } + painter.setPen(Qt::NoPen); + }; + // A name being typed: apply, remove and cancel, where the history goes + const auto edit_buttons = [&](std::size_t r, int at_y) { + const auto& row = overlay_rows[r]; + constexpr int round_w = 24; + const bool named = !overlay_custom_name[static_cast(row.player)].empty(); + const int buttons = named ? 3 : 2; + const double x0 = 1 + controller_w + bubble_gap; + painter.setPen(Qt::NoPen); + painter.setBrush(QColor(14, 14, 18, 200)); + painter.drawRoundedRect(QRectF(x0, at_y, 8 + buttons * (round_w + chip_gap) - chip_gap, + row_h), + row_h / 2.0, row_h / 2.0); + double x = x0 + 4; + const double h = row_h - 6; + const auto round = [&](int action, const QColor& fill) { + const QRectF rect(x, at_y + 3, round_w, h); + overlay_buttons.push_back({rect.toAlignedRect(), row.player, action, -1}); + x += round_w + chip_gap; + painter.setPen(Qt::NoPen); + painter.setBrush(fill); + painter.drawEllipse(rect.center(), h / 2.0, h / 2.0); + painter.setPen(QPen(Qt::white, 1.8, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + painter.setBrush(Qt::NoBrush); + return rect.center(); + }; + // Apply: a check + { + const QPointF c = round(4, QColor(45, 160, 80, 230)); + const QPointF check[3] = {QPointF(c.x() - 4.5, c.y()), QPointF(c.x() - 1.5, c.y() + 3), + QPointF(c.x() + 4.5, c.y() - 3.5)}; + painter.drawPolyline(check, 3); + } + // Remove the name: a bin + if (named) { + const QPointF c = round(5, QColor(200, 50, 50, 230)); + painter.drawLine(QPointF(c.x() - 4.5, c.y() - 3.5), QPointF(c.x() + 4.5, c.y() - 3.5)); + painter.drawLine(QPointF(c.x() - 1.5, c.y() - 5), QPointF(c.x() + 1.5, c.y() - 5)); + painter.drawRoundedRect(QRectF(c.x() - 3.5, c.y() - 3.5, 7, 8.5), 1, 1); + } + // Cancel: a cross + { + const QPointF c = round(6, QColor(255, 255, 255, 40)); + painter.drawLine(QPointF(c.x() - 3.5, c.y() - 3.5), QPointF(c.x() + 3.5, c.y() + 3.5)); + painter.drawLine(QPointF(c.x() + 3.5, c.y() - 3.5), QPointF(c.x() - 3.5, c.y() + 3.5)); + } + painter.setPen(Qt::NoPen); + }; + // The row under the mouse shows its buttons where its history goes + overlay_buttons.clear(); + const auto neighbour = [this](std::size_t r, int step) { + for (int k = static_cast(r) + step; + k >= 0 && k < static_cast(overlay_rows.size()); k += step) { + if (overlay_rows[static_cast(k)].pad != 0) { + return overlay_rows[static_cast(k)].player; + } + } + return -1; + }; + const auto row_buttons = [&](std::size_t r, int at_y) { + const auto& row = overlay_rows[r]; + const auto address = pad_bluetooth.find(BluetoothKey(row.pad)); + const bool turns_off = address != pad_bluetooth.end() && !address->second.empty(); + const QString label = tr("Turn Off"); + const QString config_label = tr("Config"); + constexpr int round_w = 24; + const int remove_w = turns_off ? 22 + chip_fm.horizontalAdvance(label) + 10 : 0; + const int config_w = chip_fm.horizontalAdvance(config_label) + 20; + const int above = neighbour(r, -1); + const int below = neighbour(r, 1); + const int count_round = (above >= 0 ? 1 : 0) + (below >= 0 ? 1 : 0); + const double x0 = 1 + controller_w + bubble_gap; + const double pill_w = 4 + (count_round + 1) * (round_w + chip_gap) + config_w + + (turns_off ? chip_gap + remove_w : 0) + 4; + painter.setPen(Qt::NoPen); + painter.setBrush(QColor(14, 14, 18, 200)); + painter.drawRoundedRect(QRectF(x0, at_y, pill_w, row_h), row_h / 2.0, row_h / 2.0); + double x = x0 + 4; + const double top = at_y + 3; + const double h = row_h - 6; + const auto add = [&](double w, int action, int target) { + const QRectF rect(x, top, w, h); + overlay_buttons.push_back({rect.toAlignedRect(), row.player, action, target}); + x += w + chip_gap; + return rect; + }; + const auto arrow = [&](int step, int target) { + const QRectF rect = add(round_w, step, target); + painter.setPen(Qt::NoPen); + painter.setBrush(QColor(255, 255, 255, 40)); + painter.drawEllipse(rect.center(), h / 2.0, h / 2.0); + const QPointF c = rect.center(); + const double d = step < 0 ? -1.0 : 1.0; + const QPointF tri[3] = {QPointF(c.x() - 5, c.y() - 2.5 * d), + QPointF(c.x() + 5, c.y() - 2.5 * d), + QPointF(c.x(), c.y() + 3.5 * d)}; + painter.setBrush(Qt::white); + painter.drawPolygon(tri, 3); + }; + if (above >= 0) { + arrow(-1, above); + } + if (below >= 0) { + arrow(1, below); + } + // Rename: a pencil, opening a small dialog for the name + { + const QRectF rect = add(round_w, 3, -1); + painter.setPen(Qt::NoPen); + painter.setBrush(QColor(255, 255, 255, 40)); + painter.drawEllipse(rect.center(), h / 2.0, h / 2.0); + const QPointF c = rect.center(); + painter.setPen(QPen(Qt::white, 1.6, Qt::SolidLine, Qt::RoundCap)); + painter.drawLine(QPointF(c.x() - 4, c.y() + 4), QPointF(c.x() + 3, c.y() - 3)); + painter.drawLine(QPointF(c.x() + 1.5, c.y() - 4.5), QPointF(c.x() + 4.5, c.y() - 1.5)); + painter.setPen(Qt::NoPen); + } + // Config: the player's tab in the controls settings + { + const QRectF config_rect = add(config_w, 2, -1); + painter.setPen(QPen(QColor(120, 170, 255, 230), 1.5)); + painter.setBrush(QColor(45, 95, 200, 120)); + painter.drawRoundedRect(config_rect.adjusted(0.75, 0.75, -0.75, -0.75), h / 2.0, + h / 2.0); + painter.setFont(chip_font); + painter.setPen(Qt::white); + painter.drawText(config_rect, Qt::AlignCenter, config_label); + painter.setPen(Qt::NoPen); + } + if (!turns_off) { + return true; + } + const QRectF rect = add(remove_w, 0, -1); + painter.setPen(Qt::NoPen); + painter.setBrush(QColor(200, 50, 50, 230)); + painter.drawRoundedRect(rect, h / 2.0, h / 2.0); + // A power symbol + const QPointF c(rect.left() + 12, rect.center().y()); + painter.setPen(QPen(Qt::white, 2, Qt::SolidLine, Qt::RoundCap)); + painter.setBrush(Qt::NoBrush); + painter.drawArc(QRectF(c.x() - 5, c.y() - 4.5, 10, 10), 125 * 16, 290 * 16); + painter.drawLine(QPointF(c.x(), c.y() - 6), QPointF(c.x(), c.y())); + painter.setFont(chip_font); + painter.setPen(Qt::white); + painter.drawText(rect.adjusted(22, 0, 0, 0), Qt::AlignVCenter | Qt::AlignLeft, label); + painter.setPen(Qt::NoPen); + return true; + }; + // Where each row is, for the mouse (a row drags onto another to swap them) + overlay_hits.clear(); + int drag_row = -1; + int drag_y = 0; + int y = 1; + for (std::size_t r = 0; r < overlay_rows.size(); ++r) { + const auto& row = overlay_rows[r]; + const bool blink = overlay_blink[r]; + overlay_hits.emplace_back(row.player, QRect(1, y, width - 2, row_h)); + if (overlay_dragging && row.player == overlay_drag_player) { + // Where the dragged row came from: an empty slot (the row follows the mouse) + QColor edge = player_color(row.player); + edge.setAlpha(150); + painter.setPen(QPen(edge, 1.5, Qt::DashLine)); + painter.setBrush(Qt::NoBrush); + painter.drawRoundedRect(QRectF(1.5, y + 0.5, controller_w - 1, row_h - 1), row_h / 2.0, + row_h / 2.0); + painter.setPen(Qt::NoPen); + drag_row = static_cast(r); + drag_y = y; + } else { + controller_bubble(row, blink, y); + } + if (row.player == overlay_edit_player && row.pad != 0) { + edit_buttons(r, y); + y += row_h + row_gap; + continue; + } + if (row.player == overlay_hover_player && row.pad != 0 && !overlay_dragging && + row_buttons(r, y)) { + y += row_h + row_gap; + continue; + } + + // The history bubble: the last inputs, newest first, shrinking away as they expire. + // Buttons pressed together share a capsule, joined by "+". + static const std::deque none; + const auto found = press_history.find(overlay_row_history[row.player]); + const auto& presses = show_history && found != press_history.end() ? found->second : none; + struct Input { + std::size_t first; + std::size_t count; + double scale; + double width; + double gap_w; ///< the time to the newer input, drawn before this one (0: none) + }; + constexpr double plus_w = 10; + constexpr double capsule_pad = 3; + std::vector inputs; // newest first + double chips_w = 0; + for (std::size_t end = presses.size(); end > 0;) { + std::size_t first = end - 1; + while (first > 0 && presses[first - 1].at == presses[end - 1].at) { + --first; + } + const double scale = press_scale(presses[first]); + double input_w = 0; + for (std::size_t k = first; k < end; ++k) { + input_w += chip_width(chip(presses[k].button).first); + } + if (end - first > 1) { + input_w += capsule_pad * 2 + plus_w * static_cast(end - first - 1); + } + input_w *= scale; + if (scale > 0.0) { + // The time from this input to the newer one before it + double gap_w = 0; + if (show_gaps && !inputs.empty()) { + gap_w = gap_fm.horizontalAdvance( + gap_text(presses[inputs.back().first].at - presses[first].at)) + + gap_pad * 2; + } + if (chips_w + gap_w + input_w > history_room - inner * 2) { + break; + } + inputs.push_back({first, end - first, scale, input_w, gap_w}); + chips_w += gap_w + input_w + chip_gap * scale; + } + end = first; + } + if (chips_w > 0.5) { + const double bubble_x = 1 + controller_w + bubble_gap; + const double bubble_w = inner * 2 + chips_w - chip_gap; + GameOverlay::Style::Pill( + painter, QRectF(bubble_x, y, (std::max)(bubble_w, double{row_h}), row_h), + GameOverlay::Style::Fill); + double cx = bubble_x + inner; + for (std::size_t g = 0; g < inputs.size(); ++g) { + const auto& input = inputs[g]; + const double scale = input.scale; + // (Older inputs fade a step each; past twenty they're transparent) + const int alpha = + (std::clamp)(static_cast((255 - static_cast(g) * 12) * scale), 0, 255); + const double h = chip_h * scale; + const bool together = input.count > 1; + if (input.gap_w > 0) { + // A tag sitting in the gap, overlapping the space around it + const QRectF tag(cx - chip_gap * scale, y + (row_h - 12) / 2.0, input.gap_w, + 12); + painter.setBrush(QColor(255, 255, 255, 22 * alpha / 255)); + painter.drawRoundedRect(tag, 6, 6); + painter.setFont(gap_font); + painter.setPen(QColor(190, 195, 202, alpha)); + painter.drawText( + tag, Qt::AlignCenter, + gap_text(presses[inputs[g - 1].first].at - presses[input.first].at)); + painter.setPen(Qt::NoPen); + cx += input.gap_w - chip_gap * scale; + } + double x = cx; + if (together) { + // The capsule: a light band with an outline around the buttons + const double ch = (chip_h + capsule_pad * 2) * scale; + const QRectF capsule(cx, y + (row_h - ch) / 2.0, input.width, ch); + painter.setBrush(QColor(255, 255, 255, 40 * alpha / 255)); + painter.setPen(QPen(QColor(255, 255, 255, 120 * alpha / 255), 1)); + painter.drawRoundedRect(capsule, ch / 2.0, ch / 2.0); + painter.setPen(Qt::NoPen); + x += capsule_pad * scale; + } + for (std::size_t k = input.first; k < input.first + input.count; ++k) { + const auto& [label, color] = chip(presses[k].button); + const double w = chip_width(label) * scale; + QColor chip_color = color; + chip_color.setAlpha(alpha); + const QRectF rect(x, y + (row_h - h) / 2.0, w, h); + painter.setBrush(chip_color); + painter.drawRoundedRect(rect, h / 2.0, h / 2.0); + if (scale > 0.6) { + painter.setFont(chip_font); + painter.setPen(QColor(255, 255, 255, alpha)); + painter.drawText(rect, Qt::AlignCenter, label); + painter.setPen(Qt::NoPen); + } + x += w; + if (k + 1 < input.first + input.count) { + if (scale > 0.6) { + painter.setFont(chip_font); + painter.setPen(QColor(255, 255, 255, alpha)); + painter.drawText(QRectF(x, y, plus_w * scale, row_h), Qt::AlignCenter, + QStringLiteral("+")); + painter.setPen(Qt::NoPen); + } + x += plus_w * scale; + } + } + cx += input.width + chip_gap * scale; + } + } + y += row_h + row_gap; + } + // The dragged row, last, over the others + if (drag_row >= 0) { + const int at_y = std::clamp(drag_y + overlay_drag_dy, 0, height - row_h - 1); + controller_bubble(overlay_rows[static_cast(drag_row)], + overlay_blink[static_cast(drag_row)], at_y); + } + painter.end(); + publish(Common::GetOverlayPanel(Common::OverlayPanelId::Players), &image); +} + +bool MainWindow::HandleOverlayMouse(QEvent* event) { + const auto type = event->type(); + // A name being typed in the overlay takes the keys + if (overlay_edit_player >= 0) { + bool shown_now = false; + { + auto& frame = Common::GetOverlayPanel(Common::OverlayPanelId::Players); + std::scoped_lock lock{frame.mutex}; + shown_now = frame.enabled; + } + const bool still_there = + std::any_of(overlay_rows.begin(), overlay_rows.end(), [this](const auto& row) { + return row.player == overlay_edit_player && row.pad != 0; + }); + if (!shown_now || !still_there) { + overlay_edit_player = -1; + } + } + if (overlay_edit_player >= 0 && + (type == QEvent::KeyPress || type == QEvent::KeyRelease || + type == QEvent::ShortcutOverride)) { + event->accept(); + if (type != QEvent::KeyPress) { + return true; + } + const auto* key = static_cast(event); + const int player = overlay_edit_player; + if (key->key() == Qt::Key_Return || key->key() == Qt::Key_Enter || + key->key() == Qt::Key_Escape) { + if (key->key() != Qt::Key_Escape) { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.rename_requests.emplace_back(player, + overlay_edit_text.trimmed().toStdString()); + } + overlay_edit_player = -1; + } else if (key->key() == Qt::Key_Backspace) { + overlay_edit_text.chop(1); + } else if (!key->text().isEmpty() && key->text().at(0).isPrint() && + overlay_edit_text.size() < 16) { + overlay_edit_text += key->text(); + } + RenderControllerOverlay(); + return true; + } + if (type == QEvent::Leave && overlay_hover_player >= 0) { + overlay_hover_player = -1; + RenderControllerOverlay(); + return false; + } + // (With no button held, the pointer's moves come as hover moves) + const bool hover_move = type == QEvent::HoverMove; + if (type != QEvent::MouseButtonPress && type != QEvent::MouseMove && + type != QEvent::MouseButtonRelease && !hover_move) { + return false; + } + bool shown = false; + { + auto& frame = Common::GetOverlayPanel(Common::OverlayPanelId::Players); + std::scoped_lock lock{frame.mutex}; + shown = frame.enabled; + } + if (!shown || overlay_hits.empty() || !render_window) { + overlay_drag_player = -1; + overlay_dragging = false; + overlay_hover_player = -1; + return false; + } + // The cursor in the overlay image + const QPoint at = + GameOverlay::CursorOn(Common::GetOverlayPanel(Common::OverlayPanelId::Players), + *render_window) + .at; + const auto row_at = [this](QPoint point) { + for (const auto& [player, rect] : overlay_hits) { + if (rect.contains(point)) { + return player; + } + } + return -1; + }; + const auto* mouse = static_cast(event); + // The row under the mouse shows its buttons (not while one is dragged) + if ((type == QEvent::MouseMove || hover_move) && !overlay_dragging) { + int hover = row_at(at); + if (hover >= 0 && + std::none_of(overlay_rows.begin(), overlay_rows.end(), + [&](const auto& row) { return row.player == hover && row.pad != 0; })) { + hover = -1; + } + if (hover != overlay_hover_player) { + overlay_hover_player = hover; + RenderControllerOverlay(); + } + } + if (hover_move) { + return false; // (the rest is the press, drag and release's) + } + // A button acts on its press; its release is the overlay's too + if (overlay_button_down && type == QEvent::MouseButtonRelease) { + overlay_button_down = false; + return true; + } + if (type == QEvent::MouseButtonPress && mouse->button() == Qt::LeftButton) { + const auto button = std::find_if(overlay_buttons.begin(), overlay_buttons.end(), + [&](const auto& b) { return b.rect.contains(at); }); + if (button != overlay_buttons.end()) { + overlay_button_down = true; + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + if (button->action == 3) { + // Name it in place: typing goes to the field (the window takes the keys) + overlay_edit_player = button->player; + overlay_edit_text = QString::fromStdString( + overlay_custom_name[static_cast(button->player)]); + render_window->setFocus(); + QTimer::singleShot(0, this, [this] { RenderControllerOverlay(); }); + } else if (button->action >= 4 && button->action <= 6) { + // Apply (4), remove the name (5), cancel (6) + if (button->action != 6) { + state.rename_requests.emplace_back( + button->player, button->action == 4 + ? overlay_edit_text.trimmed().toStdString() + : std::string{}); + } + overlay_edit_player = -1; + QTimer::singleShot(0, this, [this] { RenderControllerOverlay(); }); + } else if (button->action == 2) { + // (After the event: the dialog runs its own loop) + const int player = button->player; + QTimer::singleShot(0, this, [this, player] { + open_player_tab = player; + OnConfigure(); + }); + } else if (button->action == 0) { + LOG_INFO(Frontend, "console-mode: overlay turn off P{}", button->player + 1); + state.remove_requests.push_back(button->player); + } else { + LOG_INFO(Frontend, "console-mode: overlay swap P{} <-> P{}", button->player + 1, + button->target + 1); + state.swap_requests.emplace_back(button->player, button->target); + // The buttons follow the controller to its new row + overlay_hover_player = button->target; + } + return true; + } + } + if (type == QEvent::MouseButtonPress) { + if (mouse->button() != Qt::LeftButton) { + return false; + } + const int player = row_at(at); + if (player < 0) { + return false; // the game's + } + overlay_drag_player = player; + overlay_press = at; + overlay_drag_dy = 0; + overlay_dragging = false; + return true; + } + if (overlay_drag_player < 0) { + return false; + } + if (type == QEvent::MouseMove) { + const int dy = at.y() - overlay_press.y(); + if (!overlay_dragging && std::abs(dy) < QApplication::startDragDistance()) { + return true; + } + overlay_dragging = true; + overlay_drag_dy = dy; + RenderControllerOverlay(); + return true; + } + // Released: dropped on another row swaps the two players; a click rumbles the controller + const int player = overlay_drag_player; + const bool dragged = overlay_dragging; + overlay_drag_player = -1; + overlay_dragging = false; + overlay_drag_dy = 0; + if (dragged) { + const int target = row_at(QPoint(10, at.y())); + if (target >= 0 && target != player) { + LOG_INFO(Frontend, "console-mode: overlay swap P{} <-> P{}", player + 1, target + 1); + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.swap_requests.emplace_back(player, target); + } + RenderControllerOverlay(); + return true; + } + if (Settings::values.vibration_enabled.GetValue() && + Settings::values.players.GetValue()[player].vibration_enabled) { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.rumble_requests.push_back(player); + } + return true; +} + +bool MainWindow::OverlayAnimating() const { + const qint64 now_ms = QDateTime::currentMSecsSinceEpoch(); + if (!controller_hints.empty() || overlay_edit_player >= 0) { + return true; + } + const qint64 life_ms = Settings::values.console_history_seconds.GetValue() * 1000LL; + for (const auto& [ident, history] : press_history) { + if (!history.empty() && now_ms - history.front().at > life_ms - 100) { + return true; + } + } + return false; +} + +void MainWindow::LearnBluetoothPads() { +#ifdef __linux__ + // Pads with several controllers of their model: the one controller with a button held while + // just one of those pads has one is that pad's + if (pad_bt_pending.empty()) { + return; + } + // The pads now, each with the controller behind it now (Steam may have just moved one) + std::map, std::vector>> by_model; + { + const JoystickApiLock lock; + int count = 0; + SDL_JoystickID* ids = SDL_GetGamepads(&count); + for (int i = 0; i < count; ++i) { + const u32 id = ids[i]; + // (Not a real device Steam hid: its virtual pad is the player) + if (Common::SteamPadsInUse() && !IsSteamVirtualPad(id) && + Common::SteamHidModel(PadVendor(id), + PadProduct(id))) { + continue; + } + std::string key = BluetoothKey(id); + if (pad_bt_pending.contains(key)) { + by_model[{PadVendor(id), PadProduct(id)}] + .emplace_back(id, std::move(key)); + } + } + SDL_free(ids); + } + // Debug Probes: controllers waiting for a press whose pads can't be found (every 2 seconds) + if (Common::ControllerProbes()) { + std::size_t found = 0; + for (const auto& [model, pads] : by_model) { + found += pads.size(); + } + static auto last_missing = std::chrono::steady_clock::time_point{}; + const auto now = std::chrono::steady_clock::now(); + if (found < pad_bt_pending.size() && now - last_missing > std::chrono::seconds{2}) { + last_missing = now; + std::string keys; + for (const auto& key : pad_bt_pending) { + keys += " " + key; + } + LOG_INFO(Frontend, "console-mode: waiting for a press:{}, {} of them on a pad", keys, + found); + } + } + std::set taken; + for (const auto& [key, address] : pad_bluetooth) { + if (!address.empty()) { + taken.insert(address); + } + } + for (const auto& [model, pads] : by_model) { + std::vector controllers = ControllersOfModel(model.first, model.second); + std::erase_if(controllers, [&](const auto& c) { return taken.contains(c.address); }); + // The last of its model left to tell apart: that one is it + if (pads.size() == 1 && controllers.size() == 1) { + const auto& [id, key] = pads[0]; + pad_bluetooth[key] = controllers[0].bluetooth ? controllers[0].address : std::string{}; + pad_bt_pending.erase(key); + if (Common::ControllerProbes()) { + LOG_INFO( + Frontend, "console-mode: inst={} ({}) is the last of its model: bluetooth={}", + id, key, controllers[0].bluetooth ? controllers[0].address : std::string{"no"}); + } + continue; + } + // A pad's button held now, or pressed in the last 200ms (a quick tap) + const auto now_steady = std::chrono::steady_clock::now(); + std::vector> pressed_pads; + for (const auto& pad : pads) { + const auto last = + input_subsystem ? input_subsystem->GetSDLLastActivity(pad.first) : std::nullopt; + if (PadAnyButtonPressed(pad.first) || + (last && now_steady - *last < std::chrono::milliseconds{200})) { + pressed_pads.push_back(pad); + } + } + // (Every check reads the controllers' queues, so a press counts when it happened) + const RealController* pressed = nullptr; + int count = 0; + for (const auto& controller : controllers) { + if (RealButtonHeld(controller)) { + pressed = &controller; + ++count; + } + } + if (pressed_pads.size() != 1) { + // Debug Probes: presses that can't tell them apart (several pads at once) + if (pressed_pads.size() > 1 && Common::ControllerProbes()) { + static auto last_many = std::chrono::steady_clock::time_point{}; + if (now_steady - last_many > std::chrono::seconds{1}) { + last_many = now_steady; + std::string which; + for (const auto& [id, key] : pressed_pads) { + which += fmt::format(" inst={}({})", id, key); + } + LOG_INFO(Frontend, + "console-mode: {} pads of model {:04x}:{:04x} pressed at once, " + "{} of {} controllers show one held:{}", + pressed_pads.size(), model.first, model.second, count, + controllers.size(), which); + } + } + continue; + } + // Debug Probes: why a press didn't tell them apart (at most once a second) + if (count != 1 && Common::ControllerProbes()) { + static auto last = std::chrono::steady_clock::time_point{}; + if (const auto now = std::chrono::steady_clock::now(); + now - last > std::chrono::seconds{1}) { + last = now; + std::string nodes; + for (const auto& controller : controllers) { + nodes += fmt::format(" {}[{}]", controller.address, + controller.events.empty() + ? std::string{"no input node"} + : controller.events.front().toStdString()); + } + LOG_INFO(Frontend, + "console-mode: {} pressed a button, {} of {} controllers of its model " + "show one held:{}", + pressed_pads.front().second, count, controllers.size(), nodes); + } + } + if (count != 1) { + continue; + } + const auto& [id, key] = pressed_pads[0]; + // (The controller behind the pad must not have changed while it was read) + if (BluetoothKey(id) != key) { + continue; + } + pad_bluetooth[key] = pressed->bluetooth ? pressed->address : std::string{}; + pad_bt_pending.erase(key); + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, + "console-mode: inst={} ({}) told apart by a button press: bluetooth={}", id, + key, pressed->bluetooth ? pressed->address : std::string{"no"}); + } + } +#endif +} + +#ifdef __linux__ +namespace { + +/// The presses since the last look: the pads that just got input, and the real controllers +/// with input in the last 150ms, read from their input nodes +struct FreshPresses { + std::set pads; + std::set controllers; +}; + +/// Reads the pads' and the real controllers' presses (a pad's is SDL's record of its input) +FreshPresses WatchControllerPresses(InputCommon::InputSubsystem* input) { + FreshPresses fresh; + // The pads with a button down, and the models behind them + std::vector pads; + std::set> models; + { + const JoystickApiLock lock; + int count = 0; + SDL_JoystickID* ids = SDL_GetGamepads(&count); + for (int i = 0; i < count; ++i) { + pads.push_back(ids[i]); + models.emplace(PadVendor(ids[i]), PadProduct(ids[i])); + } + SDL_free(ids); + } + // (A pad's input newer than at the last look) + static std::map pads_seen; + for (const SDL_JoystickID id : pads) { + const auto last = input ? input->GetSDLLastActivity(id) : std::nullopt; + if (!last) { + continue; + } + auto& seen = pads_seen[id]; + if (*last != seen) { + const bool first = seen == std::chrono::steady_clock::time_point{}; + seen = *last; + if (!first) { + fresh.pads.insert(id); + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: probe: pad inst={} ({}) input", id, + BluetoothKey(id)); + } + } + } + } + // The controllers' input nodes, listed again every 2 seconds + struct Node { + int fd; + std::string controller; + /// Its axes' ranges and where they rested when it was opened + std::map axes; + }; + static std::map nodes; + static std::map pressed_at; + static auto listed = std::chrono::steady_clock::time_point{}; + const auto now = std::chrono::steady_clock::now(); + if (now - listed > std::chrono::seconds{2}) { + listed = now; + for (const auto& [vendor, product] : models) { + for (const auto& controller : ControllersOfModel(vendor, product)) { + for (const QString& event : controller.events) { + if (!nodes.contains(event)) { + const int fd = ::open(event.toLocal8Bit().constData(), + O_RDONLY | O_NONBLOCK | O_CLOEXEC); + // (Not a motion sensor's node: its axes move all the time) + std::array props{}; + if (fd >= 0 && ioctl(fd, EVIOCGPROP(props.size()), props.data()) >= 0 && + (props[INPUT_PROP_ACCELEROMETER / 8] & + (1 << (INPUT_PROP_ACCELEROMETER % 8)))) { + ::close(fd); + continue; + } + std::map axes; + for (u16 code = 0; fd >= 0 && code <= ABS_MAX; ++code) { + input_absinfo info{}; + if (ioctl(fd, EVIOCGABS(code), &info) == 0 && + info.maximum > info.minimum) { + axes[code] = info; + } + } + nodes[event] = {fd, controller.key, std::move(axes)}; + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, + "console-mode: probe: watching {} of {} ({:04x}:{:04x}){}", + event.toStdString(), controller.key, vendor, product, + nodes[event].fd < 0 ? " - can't open" : ""); + } + } + } + } + } + } + for (auto it = nodes.begin(); it != nodes.end();) { + std::array events; + ssize_t got = 0; + while (it->second.fd >= 0 && + (got = ::read(it->second.fd, events.data(), sizeof(events))) > 0) { + for (std::size_t k = 0; k < static_cast(got) / sizeof(input_event); ++k) { + const input_event& e = events[k]; + bool pressed = e.type == EV_KEY && e.value == 1; + if (const auto axis = it->second.axes.find(e.code); + e.type == EV_ABS && axis != it->second.axes.end()) { + const auto& info = axis->second; + pressed = std::abs(static_cast(e.value - info.value)) / + static_cast(info.maximum - info.minimum) > + 0.25; + } + if (!pressed) { + continue; + } + pressed_at[it->second.controller] = now; + // (Logged once a burst: a stick held out sends events all the time) + static std::map logged_at; + auto& logged = logged_at[it->second.controller]; + const bool burst = now - logged < std::chrono::milliseconds{500}; + logged = now; + if (Common::ControllerProbes() && !burst) { + LOG_INFO(Frontend, "console-mode: probe: controller {} input ({} {:#x})", + it->second.controller, e.type == EV_KEY ? "button" : "axis", + e.code); + } + } + } + // (Gone: listed again if it comes back) + if (it->second.fd < 0 || (got < 0 && errno == ENODEV)) { + if (it->second.fd >= 0) { + ::close(it->second.fd); + } + it = nodes.erase(it); + } else { + ++it; + } + } + for (auto it = pressed_at.begin(); it != pressed_at.end();) { + if (now - it->second < std::chrono::milliseconds{150}) { + fresh.controllers.insert(it->first); + ++it; + } else { + it = pressed_at.erase(it); + } + } + return fresh; +} + +} // Anonymous namespace +#endif + +void MainWindow::WatchSteamPadInputs() { +#ifdef __linux__ + // (Read under Steam, and for Debug Probes) + if (!Common::SteamPadsInUse() && !Common::ControllerProbes()) { + return; + } + const FreshPresses fresh = WatchControllerPresses(input_subsystem.get()); + // A pad's input together with exactly one real controller's: when Steam then moves a + // controller to that pad, that is the one + if (Common::SteamPadsInUse() && fresh.pads.size() == 1 && fresh.controllers.size() == 1) { + last_lone_input = LoneInput{*fresh.pads.begin(), *fresh.controllers.begin(), + std::chrono::steady_clock::now()}; + } +#endif +} + +void MainWindow::PollControllerActivity() { + // (The automatic modes only) + const auto mode = Settings::values.controller_applet_mode.GetValue(); + if (mode == Settings::AppletMode::ConsoleMode || + mode == Settings::AppletMode::HandheldConsoleMode) { + WatchSteamPadInputs(); + LearnBluetoothPads(); + } + // Redrawn faster than the 250ms tick, only when who is active changes or while animating + if (overlay_rows.empty()) { + if (!controller_hints.empty()) { + RenderControllerOverlay(); + } + return; + } + const auto now = std::chrono::steady_clock::now(); + std::set active; + for (const auto& row : overlay_rows) { + if (row.pad == 0) { + continue; + } + const auto last = + input_subsystem ? input_subsystem->GetSDLLastActivity(row.pad) : std::nullopt; + if (PadInputHeld(row.pad) || (last && now - *last < std::chrono::milliseconds{250})) { + active.insert(row.pad); + } + } + // ...and when a green/red flash blinks + const qint64 now_ms = QDateTime::currentMSecsSinceEpoch(); + std::vector blink; + for (const auto& row : overlay_rows) { + blink.push_back(row.flash != 0 && BlinkOn(now_ms - row.flash_since)); + } + const bool pressed = PollButtonHistory(); + const auto& layout = render_window->GetFramebufferLayout(); + const float room = Common::OverlayRoomTopLeft( + static_cast(layout.screen.right - layout.screen.left)); + const bool room_changed = std::exchange(overlay_room, room) != room; + if (pressed || OverlayAnimating() || active != overlay_active_pads || blink != overlay_blink || + room_changed) { + RenderControllerOverlay(); + } +} + +bool MainWindow::PollButtonHistory() { + if (!QtCommon::system || !QtCommon::system->IsPoweredOn()) { + return false; + } + auto& hid = QtCommon::system->HIDCore(); + const qint64 now_ms = QDateTime::currentMSecsSinceEpoch(); + bool pressed = false; + const qint64 life_ms = Settings::values.console_history_seconds.GetValue() * 1000LL; + const std::size_t size = + static_cast(Settings::values.console_history_size.GetValue()); + // A controller that left takes its history with it (back, it starts over) + std::erase_if(press_history, [this, &pressed](const auto& entry) { + const bool kept = + std::any_of(overlay_rows.begin(), overlay_rows.end(), [&](const auto& row) { + return row.pad != 0 && overlay_row_history[row.player] == entry.first; + }); + pressed |= !kept; + return !kept; + }); + for (const auto& row : overlay_rows) { + if (row.pad == 0 || row.player < 0 || row.player >= 8 || + overlay_row_history[row.player].empty()) { + continue; + } + const int i = row.player; + const std::string& ident = overlay_row_history[i]; + const bool fresh = history_ident[i] != ident; + history_ident[i] = ident; + const auto& player = Settings::values.players.GetValue()[i]; + auto* controller = i == 0 && player.controller_type == Settings::ControllerType::Handheld + ? hid.GetEmulatedController(Core::HID::NpadIdType::Handheld) + : hid.GetEmulatedControllerByIndex(i); + if (!controller) { + continue; + } + // Entries gone through their life and shrink leave the history + auto& history = press_history[ident]; + while (!history.empty() && now_ms - history.front().at > life_ms + 400) { + history.pop_front(); + pressed = true; + } + // Presses within 50ms of an input's first (about three frames) are one input + constexpr qint64 together_ms = 50; + const auto record = [&](int button) { + qint64 at = now_ms; + if (!history.empty() && now_ms - history.back().at <= together_ms) { + const qint64 group = history.back().at; + // (A stick turning again is a new input, not a second press) + const bool same_stick = + button >= StickMoveButton && + std::any_of(history.begin(), history.end(), [&](const ButtonPress& p) { + return p.at == group && p.button >= StickMoveButton && + (p.button - StickMoveButton) / 4 == (button - StickMoveButton) / 4; + }); + if (!same_stick) { + at = group; + } + } + history.push_back({button, at}); + std::set inputs; + for (const auto& press : history) { + inputs.insert(press.at); + } + while (inputs.size() > size) { + const qint64 oldest = history.front().at; + while (!history.empty() && history.front().at == oldest) { + history.pop_front(); + } + inputs.erase(oldest); + } + pressed = true; + }; + // A stick counts when it leaves the middle, and again when it turns another way + const auto sticks = controller->GetSticksValues(); + for (int s = 0; s < 2; ++s) { + const float x = sticks[static_cast(s)].x.value; + const float y = sticks[static_cast(s)].y.value; + const float reach = std::hypot(x, y); + auto& pointing = stick_direction[i][static_cast(s)]; + if (reach > 0.6f) { + const int direction = std::abs(x) > std::abs(y) ? (x < 0 ? 0 : 2) : (y > 0 ? 1 : 3); + if (direction + 1 != pointing) { + pointing = direction + 1; + if (!fresh) { + record(StickMoveButton + s * 4 + direction); + } + } + } else if (reach < 0.3f) { + pointing = 0; + } + } + const auto values = controller->GetButtonsValues(); + auto& down = buttons_down[i]; + for (int b = 0; b < Settings::NativeButton::NumButtons; ++b) { + const bool held = values[b].value; + if (held && !down[b] && !fresh) { + record(b); + } + down[b] = held; + } + } + return pressed; +} + +void MainWindow::ApplyConsoleControllerMode() { + // (Closing: the controllers' inputs are unloaded; a reload now would outlive the input + // engines and crash at exit) + if (closing) { + return; + } + // A tick longer than 250ms means a controller or the system held Eden up: always logged + struct SlowCheckWarning { + std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); + ~SlowCheckWarning() { + const auto ms = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count(); + if (ms > 250) { + LOG_WARNING(Frontend, "console-mode: controller check took {} ms", ms); + } + } + } slow_check_warning; + const auto mode = Settings::values.controller_applet_mode.GetValue(); + const bool handheld = mode == Settings::AppletMode::HandheldConsoleMode; + const bool console = mode == Settings::AppletMode::ConsoleMode; + // The mode, when it changes (from the Controllers tab or System > Applets): always logged + if (mode != logged_mode) { + LOG_INFO(Frontend, "console-mode: mode {} -> {}", + logged_mode ? AppletModeName(*logged_mode) : "(start)", AppletModeName(mode)); + logged_mode = mode; + // Debug Probes: what every report needs, once per mode + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, + "console-mode: setup steam={} bypass={} overlay={} hints={} history={} " + "inputs={} expire={}s gaps={} seat_profiles=\"{}\"", + Common::RunningUnderSteam(), + Common::GetControllerConsoleState().steam_bypassed.load(), + Settings::values.console_debug_overlay.GetValue(), + Settings::values.console_hints.GetValue(), + Settings::values.console_history.GetValue(), + Settings::values.console_history_size.GetValue(), + Settings::values.console_history_seconds.GetValue(), + Settings::values.console_history_gaps.GetValue(), + Settings::values.modern_seat_profiles.GetValue()); + } + } + // The handheld's own pad is stored per way of launching: the Steam handle under Steam, the + // raw pad's identity otherwise. A Steam virtual pad's GUID stored as the identity (older + // builds) never matches a raw pad: dropped, so auto-detection works again. + if (!Common::SteamPadsInUse()) { + const std::string identity = Settings::values.builtin_pad_identity.GetValue(); + if (identity.size() >= 25 && identity.starts_with("guid:") && + identity.compare(5 + 8, 4, "de28") == 0 && identity.compare(5 + 16, 4, "ff11") == 0) { + Settings::values.builtin_pad_identity.SetValue(std::string{}); + Settings::values.builtin_pad_manual.SetValue(false); + LOG_INFO(Frontend, + "console-mode: stored handheld was a Steam virtual pad ({}), " + "back to auto-detect for direct launches", + identity); + } + } + // A declaration with no identity (older builds) would pin "no handheld" forever: undone + if (Settings::values.builtin_pad_manual.GetValue() && + Settings::values.builtin_pad_identity.GetValue().empty()) { + Settings::values.builtin_pad_manual.SetValue(false); + LOG_INFO(Frontend, "console-mode: declared handheld had no identity, back to auto"); + } + + // The live gamepads, keyed by connection instance (always unique); pad_identity keeps the + // stable identity used to reclaim slots. + // + // Under Steam the virtual pads share one GUID and Steam moves controllers between them, so + // the Steam handle (which follows the controller) is the identity. Steam fills it in a + // moment after a pad appears: until then the pad isn't live (at most 3 seconds). + std::map live; + /// Under Steam: real devices unhidden for their motion (never players) + std::vector motion_devices; + { + static std::map first_seen; + const auto now = std::chrono::steady_clock::now(); + std::set present; + const JoystickApiLock lock; + int count = 0; + SDL_JoystickID* ids = SDL_GetGamepads(&count); + // Steam's virtual pads around (none when Steam Input is off for Eden) + Common::GetControllerConsoleState().steam_pads_present = + std::any_of(ids, ids + count, [](SDL_JoystickID id) { return IsSteamVirtualPad(id); }); + for (int i = 0; i < count; ++i) { + const u32 id = ids[i]; + present.insert(id); + first_seen.try_emplace(id, now); + // Bypassed: the real controllers play, Steam's virtual pads are left alone + if (Common::GetControllerConsoleState().steam_bypassed && IsSteamVirtualPad(id)) { + continue; + } + // A real device Steam hid, opened again for its motion: never a player + if (Common::SteamPadsInUse() && !IsSteamVirtualPad(id) && + Common::SteamHidModel(PadVendor(id), + PadProduct(id))) { + motion_devices.push_back(id); + // (Only marked once logged: Debug Probes turned on later still describes it) + static std::set probed; + if (Common::ControllerProbes() && probed.insert(id).second) { + std::string twins; + const Uint16 vendor = PadVendor(id); + const Uint16 product = PadProduct(id); + for (int k = 0; k < count; ++k) { + if (ids[k] != id && IsSteamVirtualPad(ids[k]) && + PadVendor(ids[k]) == vendor && + PadProduct(ids[k]) == product) { + twins += fmt::format("{} ", ids[k]); + } + } + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, + "console-mode: real device inst={} {:04x}:{:04x} name={} " + "gyro={} path={} same model as virtual inst=[{}]", + id, vendor, product, PadName(id).toStdString(), PadHasGyro(id), + PadPath(id).toStdString(), twins); + } + } + continue; + } + std::string ident = PadIdentity(id); + if (Common::SteamPadsInUse() && IsSteamVirtualPad(id)) { + if (const Uint64 handle = PadSteamHandle(id)) { + ident = fmt::format("steamhandle:{:#x}", handle); + } else if (now - first_seen[id] < std::chrono::seconds{3}) { + continue; + } + } + // (For identifying a user's handheld from their log) + static std::set described; + if (Common::ControllerProbes() && described.insert(ident).second) { + const Uint16 vendor = PadVendor(id); + // (SDL has no name for an unknown type: null, which fmt refuses) + const char* type = SDL_GetGamepadStringForType(PadType(id)); + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, + "console-mode: device {:04x}:{:04x} name=\"{}\" type={} steam={} " + "gyro={} handheld_maker={} controller_maker={} ident={}", + vendor, PadProduct(id), PadName(id).toStdString(), + type ? type : "unknown", IsSteamVirtualPad(id), PadHasGyro(id), + IsHandheldMaker(vendor), IsControllerMaker(vendor), ident); + } + } + live[id] = std::move(ident); + } + SDL_free(ids); + std::erase_if(first_seen, [&present](const auto& e) { return !present.contains(e.first); }); + } + + // The Deck's controller only reports motion while its sensors are on, which Steam leaves off + // unless its layout uses the gyro (in Desktop Mode too): when it goes silent, ask again (at + // most every 2 seconds). Under Steam it is a motion device, else one of the pads. + { + const auto is_deck = [](u32 id) { + return PadVendor(id) == 0x28DE && PadProduct(id) == 0x1205; + }; + std::optional deck; + if (const auto it = std::find_if(motion_devices.begin(), motion_devices.end(), is_deck); + it != motion_devices.end()) { + deck = *it; + } else if (!Common::SteamPadsInUse()) { + for (const auto& [id, ident] : live) { + if (is_deck(id) && PadPath(id).startsWith(QStringLiteral("/dev/hidraw"))) { + deck = id; + break; + } + } + } + const qint64 now_ms = QDateTime::currentMSecsSinceEpoch(); + if (deck && now_ms - deck_motion_asked_at >= 2000 && PadMotionSilent(*deck)) { + deck_motion_asked_at = now_ms; + const QString path = PadPath(*deck); + EnableDeckMotion(path); + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: deck motion silent, asked for it via {}", + path.toStdString()); + } + } + } + + // A controller Steam moved to another virtual pad takes its slot along + if (Common::SteamPadsInUse()) { + static std::map handle_inst; + std::map moves; // to <- from + for (const auto& [id, ident] : live) { + if (!ident.starts_with("steamhandle:")) { + continue; + } + const auto it = handle_inst.find(ident); + if (it != handle_inst.end() && it->second != id) { + moves[id] = it->second; + } + } + if (!moves.empty()) { + std::map old_slot; + std::set involved; + for (const auto& [to, from] : moves) { + involved.insert(to); + involved.insert(from); + } + for (const u32 inst : involved) { + if (const auto it = pad_slots.find(inst); it != pad_slots.end()) { + old_slot[inst] = it->second; + pad_slots.erase(it); + } + pad_identity.erase(inst); + } + u32 new_builtin = builtin_pad_id; + const std::set benched_before = benched_pads; + const auto address_before = inst_address; + const auto origin_before = pad_origin; + const auto guessed_before = pad_guessed; + for (const auto& [to, from] : moves) { + const auto slot = old_slot.find(from); + LOG_INFO(Frontend, "console-mode: Steam moved {} from inst={} to inst={} (P{})", + live[to], from, to, slot != old_slot.end() ? slot->second + 1 : 0); + // Steam moves a controller on its first use and says so later, so its input + // already came on the new pad: the one controller that had input with this pad + // just before is the one moved (a match made meanwhile is put right) + const std::string key = BluetoothKey(to); + if (last_lone_input && last_lone_input->pad == to && + std::chrono::steady_clock::now() - last_lone_input->at < + std::chrono::seconds{5} && + last_lone_input->controller.size() == 17 && pad_bluetooth.contains(key)) { + const std::string& address = last_lone_input->controller; + const auto had = pad_bluetooth.find(key); + if (had->second != address) { + // (The controller it was taken for is unsure again) + for (auto& [other, other_address] : pad_bluetooth) { + if (other != key && other_address == address) { + other_address.clear(); + pad_bt_pending.insert(other); + } + } + LOG_INFO(Frontend, + "console-mode: inst={} ({}) told apart by the input Steam moved " + "it for: bluetooth={}{}", + to, key, address, + had->second.empty() ? std::string{} + : " (was " + had->second + ")"); + had->second = address; + pad_bt_pending.erase(key); + } + } + if (slot != old_slot.end()) { + pad_slots[to] = slot->second; + pad_identity[to] = live[to]; + } + if (builtin_pad_id == from) { + new_builtin = to; + } + // (From the state before the moves: two pads can trade instances) + if (benched_before.contains(from)) { + benched_pads.insert(to); + } else { + benched_pads.erase(to); + } + const auto carry = [from, to](auto& now_map, const auto& before) { + if (const auto it = before.find(from); it != before.end()) { + now_map[to] = it->second; + } else { + now_map.erase(to); + } + }; + carry(inst_address, address_before); + carry(pad_origin, origin_before); + if (guessed_before.contains(from)) { + pad_guessed.insert(to); + } else { + pad_guessed.erase(to); + } + } + builtin_pad_id = new_builtin; + } + handle_inst.clear(); + for (const auto& [id, ident] : live) { + if (ident.starts_with("steamhandle:")) { + handle_inst[ident] = id; + } + } + } + + // Publish the live pads to the settings UI, and serve Identify: the next pad with a button + // held becomes the handheld's own. Whatever the mode (the tab declares it before OK). + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.pads.clear(); + // Every pad is offered, possible handheld controls first (they can pose as a + // standalone controller, such as an emulated DualSense) + std::vector> standalone; + for (const auto& [id, ident] : live) { + // Under Steam the entries carry the Steam handle (every pad shares one GUID) + const Uint64 handle = Common::SteamPadsInUse() ? PadSteamHandle(id) : 0; + auto entry = std::pair{PadName(id).toStdString(), + handle ? fmt::format("steamhandle:{:#x}", handle) : ident}; + if (IsPlainlyStandalone(id)) { + standalone.push_back(std::move(entry)); + } else { + state.pads.push_back(std::move(entry)); + } + } + state.builtin_pads = state.pads.size(); + state.pads.insert(state.pads.end(), standalone.begin(), standalone.end()); + // A tap is shorter than 250ms: poll faster while Identify waits, while twins wait for + // a press, and while paused for a disconnect (for +) + console_mode_timer.start(std::chrono::milliseconds{ + state.identify_armed || !disconnect_paused.empty() ? 50 + : pad_bt_pending.empty() ? 250 + : 100}); + if (state.identify_armed) { + const auto now = std::chrono::steady_clock::now(); + if (now - state.identify_armed_at > std::chrono::seconds{15}) { + state.identify_armed = false; + } else { + for (const auto& [id, ident] : live) { + // (Any pad: the user presses on the handheld's own on purpose) + if (PadAnyButtonPressed(id)) { + state.identify_armed = false; + builtin_pad_id = id; + builtin_identity = ident; + builtin_seen_first = true; + builtin_warned = false; + // Each way of launching keeps its own: the other one's stays + const Uint64 handle = Common::SteamPadsInUse() ? PadSteamHandle(id) : 0; + if (Common::SteamPadsInUse()) { + if (handle) { + Settings::values.builtin_pad_steam_handle.SetValue( + fmt::format("{:#x}", handle)); + Settings::values.builtin_pad_steam_manual.SetValue(true); + } + } else { + Settings::values.builtin_pad_identity.SetValue(ident); + Settings::values.builtin_pad_manual.SetValue(true); + } + LOG_INFO(Frontend, + "console-mode: identify captured inst={} ident={} " + "steam_handle={:#x}", + id, ident, handle); + break; + } + } + } + } + } + + // Under Steam the picker declares a pad by its Steam handle + { + const std::string declared = Settings::values.builtin_pad_identity.GetValue(); + constexpr std::string_view prefix = "steamhandle:"; + if (declared.starts_with(prefix)) { + const std::string handle = declared.substr(prefix.size()); + for (const auto& [id, ident] : live) { + if (fmt::format("{:#x}", PadSteamHandle(id)) == handle) { + builtin_pad_id = id; + break; + } + } + // The identity is the direct launches' own: a Steam pick only sets the handle + Settings::values.builtin_pad_steam_handle.SetValue(handle); + Settings::values.builtin_pad_steam_manual.SetValue(true); + Settings::values.builtin_pad_identity.SetValue(std::string{}); + Settings::values.builtin_pad_manual.SetValue(false); + LOG_INFO(Frontend, "console-mode: picker declared Steam handle {} inst={}", handle, + builtin_pad_id); + } + } + + // The overlay and hints only exist in the automatic modes: so do their View menu toggles + ui->action_Show_Controller_Overlay->setVisible(handheld || console); + ui->action_Show_Controller_Hints->setVisible(handheld || console); + if (!handheld && !console) { + if (!overlay_rows.empty()) { + overlay_rows.clear(); + RenderControllerOverlay(); + } + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.engine_active = false; + state.players.clear(); + state.handheld_name.clear(); + state.handheld_has_player = false; + state.swap_requests.clear(); + state.remove_requests.clear(); + } + benched_pads.clear(); + if (console_profile) { + // Leaving the console modes: the user's own players come back exactly as they were + RestoreConsoleProfile(); + pad_slots.clear(); + pad_identity.clear(); + pad_sets.clear(); + address_origin.clear(); + address_claims.clear(); + slot_set = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + set_default_of.fill(0); + set_before_profile.clear(); + LOG_INFO(Frontend, "console-mode: left, the user's players are restored"); + if (QtCommon::system && QtCommon::system->IsPoweredOn()) { + QtCommon::system->HIDCore().ReloadInputDevices(); + } + } + if (builtin_seen_first) { + // Leaving forgets the auto-detected handheld; a declared one stays + builtin_pad_id = 0; + builtin_identity.clear(); + builtin_seen_first = false; + builtin_warned = false; + // (The Steam handle stays: it is the same controller in every session) + if (!Settings::values.builtin_pad_manual.GetValue()) { + Settings::values.builtin_pad_identity.SetValue(std::string{}); + } + } + return; + } + if (!console_profile) { + // Entering a console mode: the user's players are kept aside; the engine's changes stay + // runtime only (see SaveAllConfigValues) + console_profile = Settings::values.players.GetValue(true); + game_profiles.reset(); + session_sets = ModernStartSets(*console_profile); + ApplySeatProfiles(); + LOG_INFO(Frontend, "console-mode: entered, the user's players are kept aside"); + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: entered with profile P1 motions {}", + MotionTrace((*console_profile)[0])); + } + } + // A game with input profiles of its own: those players' sets are the profile's + if (Settings::values.players.UsingGlobal()) { + game_profiles.reset(); + } else if (!game_profiles) { + game_profiles = Settings::values.players.GetValue(); + for (size_t i = 0; i < game_profiles->size(); ++i) { + if (!(*game_profiles)[i].profile_name.empty()) { + LOG_INFO(Frontend, "console-mode: P{} uses the game's input profile \"{}\"", i + 1, + (*game_profiles)[i].profile_name); + } + } + } + if (builtin_identity.empty()) { + // Console Mode also needs to know the handheld's own pad: it carries player one's set + builtin_identity = Settings::values.builtin_pad_identity.GetValue(); + } + + // Names as the Controls tab lists them, by the device the pad is bound as + std::vector input_devices; + if (input_subsystem) { + input_devices = input_subsystem->GetInputDevices(); + } + const auto label_of = [&](u32 id, const std::string&) { + QString display; + if (input_subsystem) { + if (const auto binding = input_subsystem->GetSDLBinding(id)) { + for (const auto& device : input_devices) { + if (device.Get("engine", "") == "sdl" && + device.Get("guid", "") == binding->first && + device.Get("port", -1) == binding->second) { + display = QString::fromStdString(device.Get("display", "")); + break; + } + } + } + } + // Under Steam, SDL's names lag up to 3 seconds behind a move: until SDL has Steam's + // controller type, the name is Steam's controller's + if (const auto slot = SteamSlotOf(id); + slot && SDL_GetGamepadTypeForID(id) != slot->type) { + switch (slot->type) { + case SDL_GAMEPAD_TYPE_XBOX360: + display = QStringLiteral("Xbox 360 Controller"); + break; + case SDL_GAMEPAD_TYPE_XBOXONE: + display = QStringLiteral("Xbox One Controller"); + break; + case SDL_GAMEPAD_TYPE_PS4: + display = QStringLiteral("PS4 Controller"); + break; + case SDL_GAMEPAD_TYPE_PS5: + display = QStringLiteral("DualSense Wireless Controller"); + break; + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO: + display = QStringLiteral("Nintendo Switch Pro Controller"); + break; + default: + display = slot->name.startsWith(QLatin1Char('#')) ? PadName(id) : slot->name; + break; + } + } + // (Steam's names can be translation keys: not a name to show) + if (display.startsWith(QLatin1Char('#'))) { + display = PadName(id); + } + return std::pair{display, PadName(id)}; + }; + + // Debug Probes: the pad identities and the slot mapping, every tick + if (Common::ControllerProbes()) { + std::string trace; + for (const auto& [id, ident] : live) { + const auto it = pad_slots.find(id); + trace += fmt::format("\n pad inst={} slot={} idx={} name={} path={} ident={}", id, + it == pad_slots.end() ? -1 : static_cast(it->second), + PadPlayerIndex(id), PadName(id).toStdString(), + PadPath(id).toStdString(), ident); + } + LOG_INFO(Frontend, "console-mode: live={}{}, builtin={}{}", trace, + live.empty() ? " (none)" : "", builtin_pad_id, + builtin_seen_first ? "" : " (unlatched)"); + } + { + // Steam fills a virtual pad's handle, type and name a moment after it appears: traced + static std::map traced_steam; + for (const auto& [id, ident] : live) { + const std::string desc = fmt::format( + "steam_handle={:#x} type={} name={}", PadSteamHandle(id), + static_cast(PadType(id)), PadName(id).toStdString()); + auto& last = traced_steam[id]; + if (last != desc) { + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: pad inst={} slot={} {}", id, + pad_slots.contains(id) ? pad_slots.at(id) + 1 : 0, desc); + } + last = desc; + } + } + + static std::set traced_insts; + for (const auto& [id, ident] : live) { + if (traced_insts.insert(id).second) { + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, + "console-mode: pad connected inst={} ident={} name={} idx={} gyro={} " + "steam_handle={:#x} type={} real_type={}", + id, ident, PadName(id).toStdString(), PadPlayerIndex(id), + PadHasGyro(id), PadSteamHandle(id), + static_cast(PadType(id)), + static_cast(SDL_GetRealGamepadTypeForID(id))); + } + } + } + for (auto it = traced_insts.begin(); it != traced_insts.end();) { + if (live.find(*it) == live.end()) { + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: pad disconnected inst={}", *it); + } + it = traced_insts.erase(it); + } else { + ++it; + } + } + } + + // Turn Off: Eden disconnects a Bluetooth controller (most turn off); it sits out until it + // reconnects, and the next controller to connect takes the player + { + // (By the controller, see BluetoothKey) + std::map keys; + std::set live_keys; + for (const auto& [id, ident] : live) { + keys[id] = BluetoothKey(id); + live_keys.insert(keys[id]); + } + std::erase_if(pad_bluetooth, [&](const auto& e) { return !live_keys.contains(e.first); }); + std::erase_if(pad_bt_pending, [&](const auto& key) { return !live_keys.contains(key); }); +#ifdef __linux__ + for (const auto& [id, ident] : live) { + if (!pad_bluetooth.contains(keys[id])) { + const PadBluetooth found = FindPadBluetooth(id); + pad_bluetooth[keys[id]] = found.address; + if (found.unsure) { + pad_bt_pending.insert(keys[id]); + } + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: inst={} bluetooth={}", id, + found.unsure ? std::string{"unsure until a button press"} + : found.address.empty() ? std::string{"no"} + : found.address); + } + } + } +#endif + std::vector removals; + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + removals.swap(state.remove_requests); + } + for (const int player : removals) { + const auto held = std::find_if(pad_slots.begin(), pad_slots.end(), [&](const auto& e) { + return e.second == player && live.contains(e.first); + }); + if (player < 0 || player >= 10 || held == pad_slots.end()) { + continue; + } + const u32 id = held->first; + if (pad_bluetooth[keys[id]].empty()) { + continue; // (Only a Bluetooth controller is turned off) + } + pad_slots.erase(held); + pad_identity.erase(id); + benched_pads.insert(id); + turned_off_at[player] = QDateTime::currentMSecsSinceEpoch(); + const std::string address = pad_bluetooth[keys[id]]; +#ifdef __linux__ + DisconnectBluetooth(address); +#endif + LOG_INFO(Frontend, "console-mode: P{} turned off, inst={} {}", player + 1, id, address); + } + std::erase_if(benched_pads, [&](u32 id) { return !live.contains(id); }); + std::erase_if(live, [&](const auto& e) { return benched_pads.contains(e.first); }); + } + + // The handheld's controller removed with its ✕: auto-detect leaves it alone until it is + // allowed again (or picked, or identified) + { + bool remove = false; + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + remove = std::exchange(state.builtin_remove_request, false); + } + if (remove && builtin_pad_id && live.contains(builtin_pad_id)) { + const std::string key = PadKey(builtin_pad_id, live[builtin_pad_id]); + Settings::values.builtin_pad_blocked.SetValue(key); + Settings::values.builtin_pad_steam_handle.SetValue(std::string{}); + Settings::values.builtin_pad_steam_manual.SetValue(false); + Settings::values.builtin_pad_identity.SetValue(std::string{}); + Settings::values.builtin_pad_manual.SetValue(false); + builtin_pad_id = 0; + builtin_identity.clear(); + LOG_INFO(Frontend, "console-mode: handheld controller {} removed: auto-detect skips it", + key); + } + } + const std::string blocked_key = Settings::values.builtin_pad_blocked.GetValue(); + const auto is_blocked = [&](u32 id) { + return !blocked_key.empty() && live.contains(id) && PadKey(id, live[id]) == blocked_key; + }; + // The handheld's rules apply only to the pad proven to be its own: the latched instance + // still alive, its Steam handle under Steam, or a unique identity match. Otherwise none. + u32 builtin_match_id = 0; + bool builtin_valid = false; + const bool steam_handle_known = + Common::SteamPadsInUse() && !Settings::values.builtin_pad_steam_handle.GetValue().empty(); + if (builtin_pad_id && live.find(builtin_pad_id) != live.end() && !steam_handle_known && + !is_blocked(builtin_pad_id)) { + builtin_match_id = builtin_pad_id; + builtin_valid = true; + } else if (Common::SteamPadsInUse()) { + // Under Steam neither the GUID nor Steam's player index tells the Deck's pad: its Steam + // handle, stable across sessions, does. With none stored yet, a lone pad is latched. + const std::string want = Settings::values.builtin_pad_steam_handle.GetValue(); + int count = 0; + u32 holder = 0; + if (!want.empty()) { + for (const auto& [id, ident] : live) { + if (fmt::format("{:#x}", PadSteamHandle(id)) != want || is_blocked(id)) { + continue; + } + if (!Settings::values.builtin_pad_steam_manual.GetValue() && + !CouldBeHandheld(PadVendor(id), PadProduct(id))) { + // A standalone controller stored as the handheld's (older builds) is dropped, + // unless the user declared it + LOG_INFO(Frontend, + "console-mode: stored handheld {} is a {:04x}:{:04x} " + "controller, not a handheld's: forgotten", + want, PadVendor(id), PadProduct(id)); + Settings::values.builtin_pad_steam_handle.SetValue(std::string{}); + continue; + } + ++count; + holder = id; + } + } + bool adopted = false; + if (count == 0) { + // No pad holds the stored handle (it can change after a reboot or update): the + // Deck's controller is the only one Steam reports with no gamepad type. Adopted when + // exactly one pad fits. + int fits = 0; + u32 fit = 0; + for (const auto& [id, ident] : live) { + if (PadType(id) == SDL_GAMEPAD_TYPE_UNKNOWN && + PadSteamHandle(id) != 0 && CouldBeHandheld(PadVendor(id), PadProduct(id)) && + !is_blocked(id)) { + ++fits; + fit = id; + } + } + if (fits == 1) { + count = 1; + holder = fit; + adopted = true; + } else if (want.empty() && live.size() == 1 && + !IsStandaloneControllerType(PadType(live.begin()->first)) && + CouldBeHandheld(PadVendor(live.begin()->first), + PadProduct(live.begin()->first)) && + !is_blocked(live.begin()->first)) { + count = 1; + holder = live.begin()->first; + } + } + if (adopted) { + const std::string handle = fmt::format("{:#x}", PadSteamHandle(holder)); + if (handle != want) { + Settings::values.builtin_pad_steam_handle.SetValue(handle); + Settings::values.builtin_pad_steam_manual.SetValue(false); + LOG_INFO(Frontend, + "console-mode: builtin adopted inst={} as the deck's controller, " + "Steam handle {} -> {}", + holder, want.empty() ? std::string{"(none)"} : want, handle); + } + } + static std::string last_resolved; + const std::string resolved = + count == 1 ? fmt::format("inst={}", holder) : fmt::format("{} matches", count); + if (resolved != last_resolved) { + last_resolved = resolved; + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: builtin by Steam handle {}: {}", + want.empty() ? std::string{"(none stored)"} : want, resolved); + } + } + if (count == 1) { + builtin_match_id = holder; + builtin_valid = true; + } + } else if (!builtin_identity.empty()) { + int identity_count = 0; + u32 identity_holder = 0; + for (const auto& [id, ident] : live) { + if (ident == builtin_identity && !is_blocked(id)) { + ++identity_count; + identity_holder = id; + } + } + if (identity_count == 1) { + builtin_match_id = identity_holder; + builtin_valid = true; + } + if (!builtin_valid) { + static int last_count = -1; + if (identity_count != last_count) { + last_count = identity_count; + LOG_INFO(Frontend, + "console-mode: builtin unresolved ({} pads match identity {}), " + "built-in rules paused", + identity_count, builtin_identity); + } + } + } + if (builtin_valid) { + builtin_pad_id = builtin_match_id; + if (Common::SteamPadsInUse() && + Settings::values.builtin_pad_steam_handle.GetValue().empty()) { + // Latch the handheld's Steam handle as soon as Steam has filled it in + if (const Uint64 handle = PadSteamHandle(builtin_match_id)) { + Settings::values.builtin_pad_steam_handle.SetValue(fmt::format("{:#x}", handle)); + LOG_INFO(Frontend, "console-mode: builtin Steam handle latched {:#x} inst={}", + handle, builtin_match_id); + } + } + } + + if (handheld) { + const std::string stored{Settings::values.builtin_pad_identity.GetValue()}; + const bool manual = Settings::values.builtin_pad_manual.GetValue(); + if (manual) { + // A declared pad (picker or Identify): resolve its current instance + builtin_identity = stored; + builtin_seen_first = true; + builtin_pad_id = 0; + if (builtin_valid) { + builtin_pad_id = builtin_match_id; + } + } else if (!builtin_pad_id && !stored.empty() && !Common::SteamPadsInUse()) { + // (Under Steam the stored GUID is every pad's: the Steam handle resolves it) + for (const auto& [id, ident] : live) { + if (ident == stored) { + builtin_pad_id = id; + builtin_identity = ident; + builtin_seen_first = true; + builtin_match_id = id; + builtin_valid = true; + break; + } + } + } + // (Direct launches only: under Steam the handle resolves it above) + if (!builtin_pad_id && !manual && !Common::SteamPadsInUse()) { + auto handheld_candidate = [&]() -> u32 { + std::vector makers; + std::vector decks; + for (const auto& [id, ident] : live) { + if (IsSteamVirtualPad(id) || is_blocked(id)) { + // (A virtual pad carries Valve's vendor: no evidence) + continue; + } + const Uint16 vendor = PadVendor(id); + if (IsHandheldMaker(vendor) && CouldBeHandheld(vendor, PadProduct(id))) { + makers.push_back(id); + // Valve also makes standalone controllers: the deck's own wins + if (vendor == 0x28DE && PadProduct(id) == 0x1205) { + decks.push_back(id); + } + } + } + if (makers.size() == 1) { + return makers.front(); + } + return decks.size() == 1 ? decks.front() : 0; + }; + const u32 candidate = handheld_candidate(); + // The handheld's own from this tick on: the claims below must already skip it, or + // with externals on at launch it takes P1 and leaves it empty a tick later + if (candidate) { + LOG_INFO(Frontend, "console-mode: handheld {:04x}:{:04x} detected by its maker", + PadVendor(candidate), PadProduct(candidate)); + builtin_pad_id = candidate; + builtin_identity = live[candidate]; + builtin_seen_first = true; + Settings::values.builtin_pad_identity.SetValue(live[candidate]); + builtin_warned = false; + builtin_match_id = candidate; + builtin_valid = true; + } else if (live.size() == 1 && !IsControllerMaker(PadVendor(live.begin()->first)) && + !is_blocked(live.begin()->first)) { + LOG_INFO(Frontend, "console-mode: handheld {:04x}:{:04x} assumed: the only pad", + PadVendor(live.begin()->first), PadProduct(live.begin()->first)); + builtin_match_id = live.begin()->first; + builtin_valid = true; + builtin_pad_id = live.begin()->first; + builtin_identity = live.begin()->second; + builtin_seen_first = true; + Settings::values.builtin_pad_identity.SetValue(live.begin()->second); + // (A lone Steam virtual pad is the handheld's own: only unknown raw hardware is + // noted) + if (!builtin_warned && !IsSteamVirtualPad(live.begin()->first)) { + QMessageBox::information( + this, tr("Assign Handheld Controller"), + tr("Unknown handheld detected.\n\n" + "Careful: a less popular controller could be labeled as a handheld.")); + builtin_warned = true; + } + } + // Nothing identified: this tick works like Modern; the next looks again + } + } + + auto& players = Settings::values.players.GetValue(); + bool changed = false; + + // A disconnected pad keeps its reservation so a quick blip reclaims its player, for a grace + // period only (a different controller must not leave a player dead) + { + static std::map pad_last_seen; + const auto now = std::chrono::steady_clock::now(); + for (const auto& [id, ident] : live) { + pad_last_seen[id] = now; + } + for (auto it = pad_slots.begin(); it != pad_slots.end();) { + const bool is_live = live.find(it->first) != live.end(); + const auto seen = pad_last_seen.find(it->first); + const bool expired = !is_live && seen != pad_last_seen.end() && + now - seen->second > std::chrono::seconds{45}; + if (expired) { + LOG_INFO(Frontend, "console-mode: reservation expired inst={} (slot {} free again)", + it->first, it->second); + pad_identity.erase(it->first); + pad_last_seen.erase(it->first); + it = pad_slots.erase(it); + changed = true; + } else { + ++it; + } + } + } + + // The handheld's own pad takes no player while external controllers are around: released, + // so they fill from player one. It claims player one again when they leave. + if (handheld && builtin_valid && live.size() > 1) { + for (auto it = pad_slots.begin(); it != pad_slots.end();) { + if (it->first == builtin_match_id) { + pad_identity.erase(it->first); + it = pad_slots.erase(it); + changed = true; + } else { + ++it; + } + } + } + + // Alone, the handheld's own pad is player one: the departed externals' reservations are + // dropped (they would push it down), and returning externals fill from player one + if (handheld && builtin_valid && live.size() == 1) { + for (auto it = pad_slots.begin(); it != pad_slots.end();) { + const bool own = it->first == builtin_match_id; + if (!own || it->second != 0) { + if (!own) { + LOG_INFO(Frontend, + "console-mode: handheld alone, dropping reservation inst={} " + "(slot {})", + it->first, it->second); + } + pad_identity.erase(it->first); + it = pad_slots.erase(it); + changed = true; + } else { + ++it; + } + } + } + + // The addresses of the Bluetooth controllers holding players; promises to away controllers + // last as long as a reservation (45 seconds) + const auto now_steady = std::chrono::steady_clock::now(); + for (const auto& [id, ident] : live) { + if (const auto known = pad_bluetooth.find(BluetoothKey(id)); + known != pad_bluetooth.end() && !known->second.empty()) { + // A controller just told apart: its battery is read now + if (auto& address = inst_address[id]; address != known->second) { + address = known->second; + battery_read.erase(id); + } + if (const auto origin = pad_origin.find(id); origin != pad_origin.end()) { + address_origin.try_emplace(known->second, origin->second); + } + } + } + std::erase_if(address_claims, [&](const auto& e) { + return now_steady - e.second.at > std::chrono::seconds{45}; + }); + + // New pads claim the lowest free slot (the handheld's own skipped while others are around), + // in player index order where there is one + std::set used; + for (const auto& [id, slot] : pad_slots) { + used.insert(slot); + } + std::vector claim_order; + claim_order.reserve(live.size()); + for (const auto& [id, ident] : live) { + claim_order.push_back(id); + } + std::sort(claim_order.begin(), claim_order.end(), [](u32 a, u32 b) { + const int ia = PadPlayerIndex(a); + const int ib = PadPlayerIndex(b); + if (ia != ib) { + return ia >= 0 && (ib < 0 || ia < ib); + } + return a < b; + }); + for (const u32 id : claim_order) { + const std::string& ident = live.at(id); + // The handheld's own is excluded by identity: its instance changes when it cycles + if (handheld && builtin_valid && id == builtin_match_id && live.size() > 1) { + continue; + } + // Steam's player index only orders the claims; slots fill lowest-free + if (pad_slots.find(id) == pad_slots.end()) { + // How many controllers are away (with several, an untold return is a guess) + const auto away = std::count_if(pad_slots.begin(), pad_slots.end(), + [&](const auto& e) { return !live.contains(e.first); }); + // A Bluetooth controller comes back to its player by address (Steam's handles don't + // survive a reconnect) + const std::string bt_key = BluetoothKey(id); + const auto known = pad_bluetooth.find(bt_key); + const std::string address = + known != pad_bluetooth.end() ? known->second : std::string{}; + if (!address.empty()) { + const auto own = + std::find_if(pad_slots.begin(), pad_slots.end(), [&](const auto& e) { + if (live.contains(e.first)) { + return false; + } + const auto held = inst_address.find(e.first); + return held != inst_address.end() && held->second == address; + }); + int slot = -1; + int origin = -1; + if (own != pad_slots.end()) { + slot = own->second; + const auto from = pad_origin.find(own->first); + origin = from != pad_origin.end() ? from->second : slot; + pad_identity.erase(own->first); + pad_slots.erase(own); + } else if (const auto claim = address_claims.find(address); + claim != address_claims.end() && !used.contains(claim->second.slot)) { + // (Its player was taken by a guess, then given back) + slot = claim->second.slot; + origin = claim->second.origin; + address_claims.erase(claim); + } + if (slot >= 0) { + LOG_INFO(Frontend, "console-mode: {} back as P{} by its Bluetooth address", + address, slot + 1); + pad_slots[id] = slot; + pad_identity[id] = ident; + pad_origin[id] = origin; + used.insert(slot); + changed = true; + continue; + } + } else if (pad_bt_pending.contains(bt_key) && away > 1) { + // Its address is about to be known: wait a moment rather than guess + const auto since = claim_wait_since.try_emplace(id, now_steady).first->second; + if (now_steady - since < std::chrono::seconds{3}) { + continue; + } + } + // Reclaim a reservation with a matching identity. Identical pads share one, so an + // ambiguous pad takes the lowest of them (one the game is paused for first), or a + // lower free slot + const auto before = [&](int slot, int other) { + const bool waited = disconnect_paused.contains(slot); + if (waited != disconnect_paused.contains(other)) { + return waited; + } + return slot < other; + }; + auto match = pad_slots.end(); + int matches = 0; + for (auto it = pad_slots.begin(); it != pad_slots.end(); ++it) { + if (live.find(it->first) == live.end() && pad_identity[it->first] == ident) { + if (match == pad_slots.end() || before(it->second, match->second)) { + match = it; + } + ++matches; + } + } + if (matches == 0 && Common::SteamPadsInUse()) { + // A new Steam handle on return: no reservation is provably its own, the lowest + // is taken + for (auto it = pad_slots.begin(); it != pad_slots.end(); ++it) { + if (live.find(it->first) == live.end() && + (match == pad_slots.end() || before(it->second, match->second))) { + match = it; + } + } + if (match != pad_slots.end()) { + matches = 2; + } + } + if (matches > 1) { + int lowest_free = -1; + for (int slot = 0; slot < ConsolePlayers; ++slot) { + if (used.find(slot) == used.end()) { + lowest_free = slot; + break; + } + } + if (lowest_free < 0 || match->second < lowest_free || + disconnect_paused.contains(match->second)) { + LOG_INFO(Frontend, + "console-mode: ambiguous reclaim inst={} ident={} ({} candidates) " + "takes the lowest, slot {} from dead inst={}", + id, ident, matches, match->second, match->first); + matches = 1; + } else { + match = pad_slots.end(); + matches = 0; + } + } + if (matches == 1) { + // A guess (several away): marked (?) until its address proves it. The player + // stays promised to its controller's address + const bool guessed = away > 1; + LOG_INFO(Frontend, + "console-mode: reclaim inst={} ident={} takes slot {} from dead inst={}{}", + id, ident, match->second, match->first, guessed ? " (a guess)" : ""); + const auto from = pad_origin.find(match->first); + pad_origin[id] = from != pad_origin.end() ? from->second : match->second; + if (guessed) { + pad_guessed.insert(id); + if (const auto held = inst_address.find(match->first); + held != inst_address.end()) { + address_claims[held->second] = {match->second, pad_origin[id], now_steady}; + } + } + // Its own set comes back at once (kept by the address, learned only later) + if (const auto held = inst_address.find(match->first); + !guessed && held != inst_address.end() && !pad_sets.contains(ident)) { + if (const auto set = pad_sets.find("bt:" + held->second); + set != pad_sets.end()) { + pad_sets[ident] = set->second; + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: inst={} carries its own P{} set back", + id, set->second + 1); + } + } + } + pad_slots[id] = match->second; + pad_identity[id] = ident; + pad_identity.erase(match->first); + pad_slots.erase(match); + changed = true; + continue; + } + // Claim the lowest free slot + bool assigned = false; + for (int slot = 0; slot < ConsolePlayers && !assigned; ++slot) { + if (used.find(slot) == used.end()) { + LOG_INFO(Frontend, "console-mode: claim inst={} ident={} -> slot {}", id, ident, + slot); + pad_slots[id] = slot; + pad_identity[id] = ident; + // (A known Bluetooth controller keeps the player it started as) + const auto first = address_origin.find(address); + pad_origin[id] = first != address_origin.end() ? first->second : slot; + used.insert(slot); + assigned = true; + changed = true; + } + } + if (!assigned) { + // Retire reservations and retry, never a live pad's slot + for (auto it = pad_slots.begin(); it != pad_slots.end();) { + const bool live_pad = live.find(it->first) != live.end(); + if (!live_pad) { + pad_identity.erase(it->first); + it = pad_slots.erase(it); + } else { + ++it; + } + } + used.clear(); + for (const auto& [k, slot] : pad_slots) { + used.insert(slot); + } + for (int slot = 0; slot < ConsolePlayers; ++slot) { + if (used.find(slot) == used.end()) { + LOG_INFO(Frontend, "console-mode: claim inst={} ident={} -> slot {}", id, + ident, slot); + pad_slots[id] = slot; + pad_identity[id] = ident; + pad_origin[id] = slot; + used.insert(slot); + changed = true; + break; + } + } + } + } + } + + // What is kept per connection lasts while the pad is live or its player is held for it + { + const auto kept = [&](u32 id) { return live.contains(id) || pad_slots.contains(id); }; + std::erase_if(inst_address, [&](const auto& e) { return !kept(e.first); }); + std::erase_if(pad_origin, [&](const auto& e) { return !kept(e.first); }); + std::erase_if(pad_guessed, [&](u32 id) { return !kept(id); }); + std::erase_if(claim_wait_since, [&](const auto& e) { + return !live.contains(e.first) || pad_slots.contains(e.first); + }); + } + + // A guessed controller whose address became known stays, or moves to its real player + for (auto it = pad_guessed.begin(); it != pad_guessed.end();) { + const u32 id = *it; + const auto known = pad_bluetooth.find(BluetoothKey(id)); + const auto at = pad_slots.find(id); + if (!live.contains(id) || at == pad_slots.end() || known == pad_bluetooth.end() || + known->second.empty()) { + ++it; + continue; + } + const std::string& address = known->second; + const auto own = std::find_if(pad_slots.begin(), pad_slots.end(), [&](const auto& e) { + const auto held = inst_address.find(e.first); + return !live.contains(e.first) && held != inst_address.end() && held->second == address; + }); + if (own != pad_slots.end()) { + LOG_INFO(Frontend, "console-mode: {} was guessed as P{}: moved back to P{}", address, + at->second + 1, own->second + 1); + const auto from = pad_origin.find(own->first); + pad_origin[id] = from != pad_origin.end() ? from->second : own->second; + at->second = own->second; + pad_identity.erase(own->first); + pad_slots.erase(own); + changed = true; + } else { + address_claims.erase(address); // (the guess was right) + } + it = pad_guessed.erase(it); + } + + // Swaps from the settings or the overlay: the pads trade slots, for this session + { + std::vector> requests; + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + requests.swap(state.swap_requests); + } + for (const auto& [a, b] : requests) { + if (a < 0 || b < 0 || a >= ConsolePlayers || b >= ConsolePlayers || a == b) { + continue; + } + u32 pad_a = 0; + u32 pad_b = 0; + for (const auto& [id, slot] : pad_slots) { + if (live.find(id) == live.end()) { + continue; + } + if (slot == a) { + pad_a = id; + } + if (slot == b) { + pad_b = id; + } + } + if (!pad_a && !pad_b) { + continue; + } + // Everything on the two players changes places, held players too (else a returning + // controller could find its player taken) + for (auto& [id, slot] : pad_slots) { + if (slot == a) { + slot = b; + } else if (slot == b) { + slot = a; + } + } + // (A swap is the user's say: a guess is settled) + pad_guessed.erase(pad_a); + pad_guessed.erase(pad_b); + LOG_INFO(Frontend, "console-mode: swap P{} <-> P{} (inst={} inst={})", a + 1, b + 1, + pad_a, pad_b); + changed = true; + } + } + + // Profiles picked in the Controls page go on the set the player's controller carries + { + std::vector picks; + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + picks.swap(state.profile_requests); + } + std::optional input_profiles; + for (const auto& [player, name, restore] : picks) { + if (!console_profile || player < 0 || player >= static_cast(players.size())) { + continue; + } + const int set = slot_set[player]; + const bool game_set = game_profiles && !(*game_profiles)[set].profile_name.empty(); + auto& target = SessionSet(set); + if (name.empty() && restore) { + if (const auto before = set_before_profile.find(set); + before != set_before_profile.end()) { + target.buttons = before->second.buttons; + target.analogs = before->second.analogs; + target.motions = before->second.motions; + set_before_profile.erase(before); + } + } + if (!name.empty()) { + set_before_profile.try_emplace(set, target); + if (!input_profiles) { + input_profiles.emplace(); + } + const auto read = input_profiles->PeekProfile(name, player); + if (!read) { + LOG_WARNING(Frontend, "console-mode: input profile \"{}\" not found", name); + continue; + } + ApplyProfileMappings(target, *read); + } + target.profile_name = name; + // The seat remembers it: the next session's P{player} starts with it + SetSeatProfile(player, name); + LOG_INFO(Frontend, "console-mode: P{} input profile \"{}\" on the P{} set{}", + player + 1, name, set + 1, game_set ? " (the game's)" : ""); + changed = true; + } + } + + // Rumble requested from the Controllers tab: a short pulse on the player's controller + { + std::vector rumbles; + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + rumbles.swap(state.rumble_requests); + } + for (const int player : rumbles) { + for (const auto& [id, slot] : pad_slots) { + if (slot != player || live.find(id) == live.end()) { + continue; + } + // Sent twice: a single request through Steam's virtual pads is sometimes lost + const u32 pad = id; + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: rumble P{} inst={}", player + 1, pad); + } + PadRumble(pad, 0xC000, 300); + QTimer::singleShot(150, this, [pad] { PadRumble(pad, 0xC000, 200); }); + break; + } + } + } + + // Each live pad's player gets the pad's binding set, pointed at the pad (bindings address + // pads by guid and port, which follow attach order, so the slot map alone isn't the + // routing). The handheld's own pad carries player one's set; an external pad its own set, + // without the handheld's non-SDL motion, plus its SDL gyro when the set has no motion. + slot_set = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + // Use Any Controller as Joy-Cons: a game that doesn't take Pro Controllers gets Dual + // Joy-Cons, else a single one held sideways. Only a Pro Controller player is changed (and + // put back), never a type set by hand. + { + std::optional supported; + bool horizontal = true; + if (QtCommon::system && QtCommon::system->IsPoweredOn() && + Settings::values.console_joycon_auto.GetValue()) { + supported = QtCommon::system->HIDCore().GetSupportedStyleTag(); + horizontal = QtCommon::system->HIDCore().IsJoyHoldHorizontal(); + } + for (int i = 0; i < static_cast(players.size()) && i < 8; ++i) { + auto& player = players[i]; + auto& from = joycon_auto_from[static_cast(i)]; + auto& set = joycon_auto_set[static_cast(i)]; + if (set && player.controller_type != *set) { + from.reset(); // (changed by hand since) + set.reset(); + } + const auto base = from ? *from : player.controller_type; + if (base != Settings::ControllerType::ProController) { + continue; + } + auto want = base; + if (supported && player.connected && supported->raw != Core::HID::NpadStyleSet::None && + !supported->fullkey) { + if (supported->joycon_dual) { + want = Settings::ControllerType::DualJoyconDetached; + } else if (supported->joycon_right) { + want = Settings::ControllerType::RightJoycon; + } else if (supported->joycon_left) { + want = Settings::ControllerType::LeftJoycon; + } + } + // A single Joy-Con is held as the game holds it: sideways or upright + const bool single = want == Settings::ControllerType::RightJoycon || + want == Settings::ControllerType::LeftJoycon; + const bool sideways = single && horizontal; + auto& was_sideways = joycon_auto_sideways[static_cast(i)]; + const auto say = [&](const QString& note) { + if (player.connected) { + controller_hints.push_back( + {QString{}, i, true, QDateTime::currentMSecsSinceEpoch(), false, note}); + } + }; + if (want == player.controller_type) { + // (The game turned its Joy-Cons: the bindings follow on the routing pass) + if (set && single && was_sideways != sideways) { + was_sideways = sideways; + LOG_INFO(Frontend, "console-mode: P{} now holds its Joy-Con {}", i + 1, + sideways ? "sideways" : "upright"); + say(sideways ? tr("P%1 plays as a sideways Joy-Con").arg(i + 1) + : tr("P%1 plays as an upright Joy-Con").arg(i + 1)); + } + continue; + } + player.controller_type = want; + changed = true; + if (want == base) { + from.reset(); + set.reset(); + was_sideways = false; + LOG_INFO(Frontend, "console-mode: P{} back to a Pro Controller", i + 1); + say(tr("P%1 plays as a Pro Controller again").arg(i + 1)); + continue; + } + from = base; + set = want; + was_sideways = sideways; + LOG_INFO(Frontend, "console-mode: P{} plays as {} (the game takes no Pro Controller)", + i + 1, + !single ? "Dual Joy-Cons" + : sideways ? "a sideways Joy-Con" + : "an upright Joy-Con"); + say(!single ? tr("P%1 plays as Dual Joy-Cons").arg(i + 1) + : sideways ? tr("P%1 plays as a sideways Joy-Con").arg(i + 1) + : tr("P%1 plays as an upright Joy-Con").arg(i + 1)); + } + // (For the player tabs: a single Joy-Con's mapping is the engine's) + std::array held{}; + for (std::size_t i = 0; i < held.size(); ++i) { + const auto& set = joycon_auto_set[i]; + if (set && (*set == Settings::ControllerType::RightJoycon || + *set == Settings::ControllerType::LeftJoycon)) { + held[i] = joycon_auto_sideways[i] ? 1 : 2; + } + } + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.joycon_held = held; + } + + if (input_subsystem && console_profile) { + const auto profile = ConsoleBindingSets(); + const auto is_handheld_motion = [&profile](const std::string& raw) { + if (raw.empty() || Common::ParamPackage{raw}.Get("engine", "") == "sdl") { + return false; + } + return std::find(profile[0].motions.begin(), profile[0].motions.end(), raw) != + profile[0].motions.end(); + }; + for (const auto& [id, ident] : live) { + const auto it = pad_slots.find(id); + if (it == pad_slots.end() || it->second < 0 || + it->second >= static_cast(players.size())) { + continue; + } + const auto binding = input_subsystem->GetSDLBinding(id); + if (!binding) { + continue; + } + const int slot = it->second; + const bool is_builtin = builtin_valid && id == builtin_match_id; + // The set's key: a Bluetooth controller's address (so its set follows it through + // reconnects), else its identity; a set made before the address is known moves to it + const auto address = inst_address.find(id); + const std::string set_key = + address != inst_address.end() ? "bt:" + address->second : ident; + if (set_key != ident && !pad_sets.contains(set_key) && pad_sets.contains(ident)) { + pad_sets[set_key] = pad_sets[ident]; + pad_sets.erase(ident); + } else if (set_key != ident && pad_sets.contains(set_key) && + pad_sets.contains(ident) && pad_sets[ident] == pad_sets[set_key]) { + // (Lent to it on a reclaim, until its address was known) + pad_sets.erase(ident); + } + // A controller keeps the set it first got: its slot's, else the first set nobody has + if (!is_builtin && !pad_sets.contains(set_key)) { + std::set taken; + for (const auto& [other, set] : pad_sets) { + taken.insert(set); + } + int set = slot; + for (int k = 0; taken.contains(set) && k < static_cast(players.size()); ++k) { + set = k; + } + if (taken.contains(set)) { + set = slot; + } + pad_sets[set_key] = set; + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: inst={} carries the P{} set", id, set + 1); + } + } + // A set with no controller mappings gives the pad its default mapping, below + const auto has_sdl = [](const Settings::PlayerInput& p) { + return std::any_of(p.buttons.begin(), p.buttons.end(), [](const std::string& b) { + return !b.empty() && Common::ParamPackage{b}.Get("engine", "") == "sdl"; + }); + }; + const int set_index = is_builtin ? 0 : pad_sets[set_key]; + slot_set[slot] = set_index; + Settings::PlayerInput want = players[slot]; + // A set holding only a gone controller's default mapping is rebuilt for this one (an + // Xbox pad's has no gyro or back buttons). Not while that controller is connected: + // identical ones without an address share a set. + const u32 defaults_of = set_default_of[static_cast(set_index)]; + const bool others_defaults = defaults_of != 0 && defaults_of != id && + !live.contains(defaults_of) && + profile[set_index].profile_name.empty(); + if (others_defaults && Common::ControllerProbes()) { + LOG_INFO(Frontend, + "console-mode: P{} set holds inst={}'s defaults: rebuilt for inst={}", + set_index + 1, defaults_of, id); + } + if (has_sdl(profile[set_index]) && !others_defaults) { + const auto& own = profile[set_index]; + want.buttons = own.buttons; + want.analogs = own.analogs; + want.motions = own.motions; + want.profile_name = own.profile_name; + RouteSdlBindings(want, binding->first, binding->second); + } else { + // No controller mappings: the controller's default mapping, for this session + Common::ParamPackage device; + device.Set("engine", "sdl"); + device.Set("guid", binding->first); + device.Set("port", binding->second); + // A DSU server's motion stays; only SDL motion is the device's to fill + const auto kept_motions = profile[set_index].motions; + const bool motion_kept = + std::any_of(kept_motions.begin(), kept_motions.end(), [](const auto& m) { + return !m.empty() && + Common::ParamPackage{m}.Get("engine", "") == "cemuhookudp"; + }); + want.buttons.fill({}); + want.analogs.fill({}); + want.motions.fill({}); + for (const auto& [index, param] : + input_subsystem->GetButtonMappingForDevice(device)) { + want.buttons[index] = param.Serialize(); + } + for (const auto& [index, param] : + input_subsystem->GetAnalogMappingForDevice(device)) { + want.analogs[index] = param.Serialize(); + } + if (motion_kept) { + want.motions = kept_motions; + } else { + for (const auto& [index, param] : + input_subsystem->GetMotionMappingForDevice(device)) { + want.motions[index] = param.Serialize(); + } + } + want.profile_name.clear(); + // Kept for the session: rebuilt every tick, it would differ once a game polls the + // sensors and reload the input four times a second + auto& own = SessionSet(set_index); + own.buttons = want.buttons; + own.analogs = want.analogs; + own.motions = want.motions; + set_default_of[static_cast(set_index)] = id; + static std::set defaulted; + if (defaulted.insert(id).second) { + LOG_INFO(Frontend, + "console-mode: P{} set has no controller mappings: inst={} " + "gets its default mapping{}", + set_index + 1, id, motion_kept ? " (its set's motion kept)" : ""); + } + } + // Under Steam the virtual pad has no motion: take the paired real device's (the Deck, + // or the only one of a model) + u32 motion_source = 0; + if (Common::SteamPadsInUse()) { + const Uint16 vendor = is_builtin ? 0x28DE : PadVendor(id); + const Uint16 product = is_builtin ? 0x1205 : PadProduct(id); + const auto same_model = [vendor, product](u32 other) { + return PadVendor(other) == vendor && + PadProduct(other) == product; + }; + const auto real = + std::count_if(motion_devices.begin(), motion_devices.end(), same_model); + const auto virtuals = std::count_if( + live.begin(), live.end(), [&](const auto& e) { return same_model(e.first); }); + if (real == 1 && (is_builtin || virtuals == 1)) { + const u32 device = + *std::find_if(motion_devices.begin(), motion_devices.end(), same_model); + if (PadHasGyro(device)) { + motion_source = device; + } + } + } + if (motion_source != overlay_motion_source[slot]) { + overlay_motion_source[slot] = motion_source; + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: P{} motion from real device inst={}", + slot + 1, motion_source); + } + } + if (motion_source) { + if (const auto source = input_subsystem->GetSDLBinding(motion_source)) { + want.motions.fill(SdlMotionParam(source->first, source->second)); + } + } else { + if (!is_builtin) { + for (std::string& motion : want.motions) { + if (is_handheld_motion(motion)) { + motion.clear(); + } + } + } + // (The handheld's own pad too: its set may have been an external's) + const bool no_motion = std::all_of(want.motions.begin(), want.motions.end(), + [](const std::string& m) { return m.empty(); }); + if (no_motion && PadHasGyro(id)) { + want.motions.fill(SdlMotionParam(binding->first, binding->second)); + } + } + auto& player = players[slot]; + // A single Joy-Con (set above): the buttons and stick arranged to fit, sideways or + // upright as the game holds it + const bool single = + joycon_auto_set[static_cast(slot)] && + (player.controller_type == Settings::ControllerType::RightJoycon || + player.controller_type == Settings::ControllerType::LeftJoycon); + const bool right_joycon = + player.controller_type == Settings::ControllerType::RightJoycon; + if (single && joycon_auto_sideways[static_cast(slot)]) { + BindSidewaysJoyCon(want, right_joycon); + } else { + if (Settings::values.console_button_labels.GetValue() && !IsNintendoPad(id)) { + // Button Layout by label: the controller's A is the Switch's A + using namespace Settings::NativeButton; + std::swap(want.buttons[A], want.buttons[B]); + std::swap(want.buttons[X], want.buttons[Y]); + } + if (single) { + BindUprightJoyCon(want, right_joycon); + } + } + player.profile_name = want.profile_name; + if (player.buttons != want.buttons || player.analogs != want.analogs || + player.motions != want.motions) { + player.buttons = want.buttons; + player.analogs = want.analogs; + player.motions = want.motions; + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: P{} <- inst={} guid={} port={} set=P{}{}", + slot + 1, id, binding->first, binding->second, set_index + 1, + is_builtin ? " (handheld)" : ""); + } + changed = true; + } + } + } + + // Only the players with a live pad are connected + for (int i = 0; i < static_cast(players.size()); ++i) { + bool want = false; + for (const auto& [id, ident] : live) { + const auto it = pad_slots.find(id); + if (it != pad_slots.end() && it->second == i) { + want = true; + break; + } + } + if (players[i].connected != want) { + players[i].connected = want; + changed = true; + } + } + + // A game running with no controller is told so once (keyboard and mouse are Manual's) + { + const bool running = QtCommon::system && QtCommon::system->IsPoweredOn(); + const bool any_player = std::any_of(players.begin(), players.end(), + [](const auto& player) { return player.connected; }); + const qint64 now_ms = QDateTime::currentMSecsSinceEpoch(); + if (!running) { + no_controller_told = false; + no_controller_since = 0; + } else if (any_player) { + no_controller_since = 0; + } else if (!no_controller_told) { + if (no_controller_since == 0) { + no_controller_since = now_ms; + } else if (now_ms - no_controller_since >= 3000) { + no_controller_told = true; + controller_hints.push_back( + {QString{}, 0, false, now_ms, false, + tr("No controller: connect one, or use Manual for keyboard and mouse")}); + LOG_INFO(Frontend, "console-mode: a game runs with no controller"); + } + } + } + + if (changed) { + std::string out; + for (int i = 0; i < static_cast(players.size()); ++i) { + out += players[i].connected ? "1" : "0"; + } + + static std::string last_written; + if (out != last_written) { + for (size_t i = 0; i < out.size(); ++i) { + if (last_written.size() != out.size() || last_written[i] != out[i]) { + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: player {} {}", i + 1, + out[i] == '1' ? "activated" : "deactivated"); + } + } + } + last_written = out; + } + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: players written={}", out); + } + } + + // A live pad holds at most one slot, in range, never shared: if this logs, it's a bug + { + std::set seen_slots; + for (const auto& [id, slot] : pad_slots) { + const bool in_range = slot >= 0 && slot < ConsolePlayers; + const bool unique = in_range && seen_slots.insert(slot).second; + if (live.find(id) != live.end() && (!in_range || !unique)) { + LOG_ERROR(Frontend, + "console-mode: INVARIANT BROKEN inst={} slot={} in_range={} " + "unique={} - two pads fighting over one player or a corrupt slot", + id, slot, in_range, unique); + } + } + } + + // Pause When a Controller Disconnects: a player whose controller left and didn't come back + // within 3 seconds pauses the game; it resumes when they all have a controller again, or + // with + on another controller (those players are then let go) + { + const qint64 now_ms = QDateTime::currentMSecsSinceEpoch(); + for (int i = 0; i < static_cast(players.size()) && i < 10; ++i) { + const bool held = std::any_of(pad_slots.begin(), pad_slots.end(), + [&](const auto& e) { return e.second == i; }); + const bool here = std::any_of(pad_slots.begin(), pad_slots.end(), [&](const auto& e) { + return e.second == i && live.contains(e.first); + }); + auto& since = waiting_since[static_cast(i)]; + since = held && !here ? (since ? since : now_ms) : 0; + if (since == 0) { + pause_done.erase(i); // (a new wait may pause again) + } + } + // Who holds each player now (0 nobody), and whether that is an external controller + std::array holder{}; + for (const auto& [id, slot] : pad_slots) { + if (slot >= 0 && slot < 10 && live.contains(id)) { + holder[static_cast(slot)] = id; + } + } + const auto on_handheld = [&](u32 id) { + return id != 0 && builtin_valid && id == builtin_match_id; + }; + const auto was_external = held_by_external; + for (std::size_t i = 0; i < holder.size(); ++i) { + held_by_external[i] = holder[i] != 0 && !on_handheld(holder[i]); + } + const bool handheld_took_over = + !std::exchange(handheld_was_playing, + std::any_of(holder.begin(), holder.end(), on_handheld)) && + handheld_was_playing; + const bool running = + emulation_running && QtCommon::emu_thread && QtCommon::emu_thread->IsRunning(); + // (Pausing takes a moment: running again counts as a resume by hand only once seen paused) + if (!disconnect_paused.empty() && !running && !disconnect_pause_pending) { + disconnect_pause_seen = true; + } + if (!disconnect_paused.empty() && running && disconnect_pause_seen) { + disconnect_paused.clear(); // (resumed by hand) + disconnect_continue_held = false; + disconnect_pause_seen = false; + handover_paused = -1; + handover_pressed = false; + } + // The overlay is drawn into frames: the notice first, the pause a moment later + const auto pause_with_notice = [&](int player, const QString& notice) { + controller_hints.push_back({QString{}, player, false, now_ms, false, notice, true}); + RenderControllerOverlay(); + disconnect_pause_pending = true; + disconnect_pause_seen = false; + QTimer::singleShot(150, this, [this] { + disconnect_pause_pending = false; + if (!disconnect_paused.empty() && emulation_running && QtCommon::emu_thread && + QtCommon::emu_thread->IsRunning()) { + OnPauseGame(); + } + }); + }; + if (Settings::values.console_pause_disconnect.GetValue() && running && + !disconnect_pause_pending) { + // A disconnect that is surely real (Turn Off, or BlueZ says disconnected) pauses at + // once; any other waits 3 seconds, as Steam briefly drops its pads now and then + const auto surely_gone = [&](int player) { + if (now_ms - turned_off_at[static_cast(player)] < 5000) { + return true; + } +#ifdef __linux__ + // (BlueZ is asked without waiting, at most every half second; an answer counts if + // it came after the controller left) + for (const auto& [id, slot] : pad_slots) { + if (slot != player || live.contains(id)) { + continue; + } + const auto address = inst_address.find(id); + if (address == inst_address.end()) { + continue; + } + auto& known = bluez_connected[address->second]; + if (known.asked_ms == 0 || now_ms - known.asked_ms >= 500) { + known.asked_ms = now_ms; + AskBluezConnected(address->second, this, + [this, key = address->second](bool on) { + auto& entry = bluez_connected[key]; + entry.connected = on; + entry.answered_ms = + QDateTime::currentMSecsSinceEpoch(); + }); + } + if (!known.connected && known.answered_ms >= + waiting_since[static_cast(player)]) { + return true; + } + } +#endif + return false; + }; + std::set gone; + for (int i = 0; i < 10; ++i) { + // (Each wait pauses once: resumed by hand, the game keeps running) + const qint64 since = waiting_since[static_cast(i)]; + if (since && !pause_done.contains(i) && + (now_ms - since >= 3000 || surely_gone(i))) { + gone.insert(i); + } + } + // A handover: the last external controller left (whichever player it held) and the + // handheld's controls took over. Paused until someone picks the handheld up or + // reconnects. + int handover = -1; + const bool externals_left = + std::any_of(was_external.begin(), was_external.end(), [](bool b) { return b; }) && + std::none_of(held_by_external.begin(), held_by_external.end(), + [](bool b) { return b; }); + if (gone.empty() && disconnect_paused.empty() && externals_left && + handheld_took_over) { + for (std::size_t i = 0; i < holder.size() && handover < 0; ++i) { + if (on_handheld(holder[i])) { + handover = static_cast(i); + } + } + } + if (handover >= 0) { + disconnect_paused = {handover}; + handover_paused = handover; + handover_pressed = PadInputHeld(holder[static_cast(handover)]); + LOG_INFO(Frontend, "console-mode: paused, P{} handed over to the built-in controls", + handover + 1); + pause_with_notice(handover, + tr("P%1 is on the built-in controls now: press a button on " + "them, or reconnect a controller, to go on") + .arg(handover + 1)); + } else if (!gone.empty()) { + disconnect_paused = gone; + pause_done.insert(gone.begin(), gone.end()); + LOG_INFO(Frontend, "console-mode: paused, P{}'s controller disconnected", + *gone.begin() + 1); + QStringList names; + for (const int player : gone) { + names.push_back(QStringLiteral("P%1").arg(player + 1)); + } + const QString who = names.join(QStringLiteral(", ")); + // (Said once: the pause's notice takes the place of their "left" hints) + std::erase_if(controller_hints, [&](const auto& hint) { + return !hint.joined && !hint.pause_notice && gone.contains(hint.player); + }); + // (The leave is stamped a moment later, when the overlay draws it: a margin) + for (const int player : gone) { + auto& said = hinted_leave[static_cast(player)]; + said = (std::max)(said, now_ms + 2'000); + } + // (With no other controller left, reconnecting is the only way on) + pause_with_notice(*gone.begin(), + live.empty() + ? tr("%1 disconnected: reconnect to go on").arg(who) + : tr("%1 disconnected: reconnect, or press + on another " + "controller to go on without %1") + .arg(who)); + } + } else if (!disconnect_paused.empty() && !running && emulation_running && + !disconnect_pause_pending) { + // Paused for a disconnect when the last external controller left too: the handheld's + // controls took a player, and the pause becomes a handover (not a resume) + if (handover_paused < 0 && handheld_took_over && + std::none_of(held_by_external.begin(), held_by_external.end(), + [](bool b) { return b; })) { + for (std::size_t i = 0; i < holder.size(); ++i) { + if (on_handheld(holder[i])) { + handover_paused = static_cast(i); + handover_pressed = PadInputHeld(holder[i]); + disconnect_paused = {handover_paused}; + LOG_INFO(Frontend, + "console-mode: pause handed over to the built-in controls (P{})", + i + 1); + // (The disconnect's notice gives way; running a moment, so the new + // one is drawn into a frame) + std::erase_if(controller_hints, + [](const auto& hint) { return hint.pause_notice; }); + OnStartGame(); + pause_with_notice(handover_paused, + tr("P%1 is on the built-in controls now: press a button " + "on them, or reconnect a controller, to go on") + .arg(handover_paused + 1)); + break; + } + } + } + bool all_back = + std::all_of(disconnect_paused.begin(), disconnect_paused.end(), [&](int player) { + return std::any_of(pad_slots.begin(), pad_slots.end(), [&](const auto& e) { + return e.second == player && live.contains(e.first); + }); + }); + // A handover goes on when an external controller takes the player back, or at a + // press on the handheld (once let go, so the game never sees it) + if (handover_paused >= 0) { + const u32 at = holder[static_cast(handover_paused)]; + all_back = at != 0 && !on_handheld(at); + if (on_handheld(at)) { + if (PadInputHeld(at)) { + handover_pressed = true; + } else if (std::exchange(handover_pressed, false)) { + all_back = true; + } + } + } + // (+ counts once let go, so the game never sees it on resuming) + const bool plus = std::any_of(live.begin(), live.end(), + [](const auto& e) { return PadStartHeld(e.first); }); + if (all_back) { + LOG_INFO(Frontend, "console-mode: resumed, the controllers are back"); + disconnect_paused.clear(); + disconnect_continue_held = false; + handover_paused = -1; + OnStartGame(); + } else if (plus) { + disconnect_continue_held = true; + } else if (std::exchange(disconnect_continue_held, false)) { + // On without them: their players are no longer held for their controllers + for (auto it = pad_slots.begin(); it != pad_slots.end();) { + if (disconnect_paused.contains(it->second) && !live.contains(it->first)) { + pad_identity.erase(it->first); + it = pad_slots.erase(it); + } else { + ++it; + } + } + QStringList names; + for (const int player : disconnect_paused) { + names.push_back(QStringLiteral("P%1").arg(player + 1)); + } + LOG_INFO(Frontend, "console-mode: resumed without {}", + names.join(QStringLiteral(", ")).toStdString()); + controller_hints.push_back({QString{}, *disconnect_paused.begin(), false, now_ms, + false, + tr("Going on without %1") + .arg(names.join(QStringLiteral(", ")))}); + disconnect_paused.clear(); + handover_paused = -1; + handover_pressed = false; + OnStartGame(); + } + } + } + + // Player Lights: each controller shows its player in the player's colour (not under Steam, + // which sets them) + if (Settings::values.console_player_lights.GetValue() && + !(Common::RunningUnderSteam() && Common::GetControllerConsoleState().steam_pads_present)) { + std::erase_if(lights_player, [&](const auto& e) { return !live.contains(e.first); }); + for (const auto& [id, slot] : pad_slots) { + if (!live.contains(id) || IsSteamVirtualPad(id)) { + continue; + } + auto& shown = lights_player[id]; + if (shown == slot + 1) { + continue; + } + shown = slot + 1; + const JoystickApiLock lock; + if (SDL_Gamepad* pad = SDL_OpenGamepad(id)) { + SDL_SetGamepadPlayerIndex(pad, slot); + const QColor color = ConfigurePlayerAssignment::PlayerColor(slot); + SDL_SetGamepadLED(pad, static_cast(color.red()), + static_cast(color.green()), + static_cast(color.blue())); + SDL_CloseGamepad(pad); + } + if (Common::ControllerProbes()) { + LOG_INFO(Frontend, "console-mode: inst={} lights show P{}", id, slot + 1); + } + } + } + + // A player whose controller type the game doesn't support: logged once per change + if (QtCommon::system && QtCommon::system->IsPoweredOn()) { + auto& hid = QtCommon::system->HIDCore(); + const auto supported = hid.GetSupportedStyleTag(); + for (int i = 0; i < static_cast(players.size()) && i < 8; ++i) { + // (A handheld P1 is the handheld's own controller, as the game sees it) + const auto* controller = + i == 0 && players[0].controller_type == Settings::ControllerType::Handheld + ? hid.GetEmulatedController(Core::HID::NpadIdType::Handheld) + : hid.GetEmulatedControllerByIndex(static_cast(i)); + if (!controller || !players[i].connected) { + refused_logged[static_cast(i)].clear(); + continue; + } + const auto style = controller->GetNpadStyleIndex(); + const bool taken = StyleSupported(style, supported); + const std::string what = taken ? std::string{} + : fmt::format("{}/{:#x}", static_cast(style), + static_cast(supported.raw)); + auto& logged = refused_logged[static_cast(i)]; + if (what != logged) { + if (!taken) { + LOG_WARNING(Frontend, + "console-mode: P{} is a {} controller, which the game doesn't " + "support (supported styles {:#x})", + i + 1, StyleName(style), static_cast(supported.raw)); + } + logged = what; + } + } + } + + // The controller overlay is drawn into the presented frame (as an overlay panel): no Qt + // window can composite over the game under gamescope + { + // One row per player: green when its pad connects, red when it leaves, then gone. The + // name drops InputCommon's port number, which shifts as Steam moves controllers. + constexpr qint64 flash_ms = 1500; + const qint64 now_ms = QDateTime::currentMSecsSinceEpoch(); + static const QRegularExpression port_number{QStringLiteral(" \\d+(?=( \\(Steam\\))?$)")}; + static const QRegularExpression steam_suffix{QStringLiteral(" \\(Steam\\)$")}; + // A controller's name, or the one given to it with its short name ("John (Xbox)") + const auto name_key = [&](u32 pad) { + if (builtin_valid && pad == builtin_match_id) { + return std::string{"handheld"}; + } + if (const auto address = inst_address.find(pad); address != inst_address.end()) { + return "bt:" + address->second; + } + return "id:" + live[pad]; + }; + // Names given from the Controllers tab belong to the controller + { + std::vector> renames; + { + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + renames.swap(state.rename_requests); + } + for (const auto& [player, given] : renames) { + const auto held = + std::find_if(pad_slots.begin(), pad_slots.end(), [&](const auto& e) { + return e.second == player && live.contains(e.first); + }); + if (held == pad_slots.end()) { + continue; + } + const std::string key = name_key(held->first); + if (given.empty()) { + controller_names.erase(key); + } else { + controller_names[key] = given; + } + LOG_INFO(Frontend, "console-mode: P{} named \"{}\"", player + 1, given); + } + } + std::array custom_names{}; + overlay_rows.clear(); + std::erase_if(battery_read, [&](const auto& e) { return !live.contains(e.first); }); + // (A controller that leaves starts afresh when it connects again) + const auto left = [&](const std::string& key) { + return std::none_of(live.begin(), live.end(), [&](const auto& pad) { + const auto address = inst_address.find(pad.first); + return address != inst_address.end() && address->second == key; + }); + }; + std::erase_if(bluez_first, [&](const auto& e) { return left(e.first); }); + std::erase_if(bluez_battery, [&](const auto& e) { return left(e.first); }); + std::erase_if(battery_whose, [&](const auto& e) { return !live.contains(e.first); }); + std::vector tab_rows; + // Flashes follow the controller behind a player (in handheld mode P1 stays connected + // while it changes): green when one takes a player, red when one leaves + for (int i = 0; i < static_cast(players.size()); ++i) { + u32 pad = 0; + for (const auto& [id, slot] : pad_slots) { + if (slot == i && live.find(id) != live.end()) { + pad = id; + break; + } + } + auto& since = overlay_row_since[i]; + auto& gone = overlay_row_gone[i]; + auto& flash = overlay_flash[i]; + auto& flash_since = overlay_flash_since[i]; + auto& green_at = overlay_green_at[i]; + if (players[i].connected && pad) { + const auto [display, raw] = label_of(pad, std::string{}); + QString name = display.isEmpty() ? raw : display; + name.remove(port_number); + name.remove(steam_suffix); + if (name == QStringLiteral("SteamDeck")) { + name = QStringLiteral("Steam Deck"); // (Steam's name for the Deck's own) + } + // (The name of the controller that had the player, should it have just left) + const QString previous = overlay_row_name[i]; + // (A name given before the address was known moves to it, like the bindings) + if (const std::string key = name_key(pad); key.starts_with("bt:")) { + const auto earlier = controller_names.find("id:" + live[pad]); + if (earlier != controller_names.end()) { + controller_names[key] = earlier->second; + controller_names.erase(earlier); + } + } + const auto given = controller_names.find(name_key(pad)); + // Handheld Console: the controller that took P1 from the handheld's controls + // carries the handheld's name when it has none (the same person, docked) + const auto handed = controller_names.find("handheld"); + const bool inherits = given == controller_names.end() && i == 0 && handheld && + builtin_valid && pad != builtin_match_id && + !pad_slots.contains(builtin_match_id) && + handed != controller_names.end(); + if (given != controller_names.end()) { + custom_names[static_cast(i)] = given->second; + name = QStringLiteral("%1 (%2)").arg(QString::fromStdString(given->second), + ShortControllerName(pad, name)); + } else if (inherits) { + name = QStringLiteral("%1 (%2)").arg(QString::fromStdString(handed->second), + ShortControllerName(pad, name)); + } + overlay_row_name[i] = name; + if (since == 0 || gone != 0) { + since = now_ms; + gone = 0; + flash = 1; + flash_since = now_ms; + green_at = 0; + } else if (live[pad] != overlay_row_ident[i]) { + const bool old_left = + std::none_of(live.begin(), live.end(), [&](const auto& entry) { + return entry.second == overlay_row_ident[i]; + }); + if (old_left) { + flash = 2; + flash_since = now_ms; + green_at = now_ms + flash_ms / 2; + overlay_left_name[i] = previous; + } else { + flash = 1; + flash_since = now_ms; + green_at = 0; + } + } + overlay_row_ident[i] = live[pad]; + // The input history's key: the controller's own (its address, else its + // connection too when identical controllers share an identity) + std::string history_key = name_key(pad); + if (history_key.starts_with("id:") && + std::any_of(live.begin(), live.end(), [&](const auto& entry) { + return entry.first != pad && entry.second == live[pad]; + })) { + history_key += fmt::format("#{}", pad); + } + overlay_row_history[i] = std::move(history_key); + } else if (since != 0 && gone == 0) { + gone = now_ms; + flash = 2; + flash_since = now_ms; + green_at = 0; + overlay_left_name[i] = overlay_row_name[i]; + } + if (since == 0) { + continue; + } + if (gone != 0 && now_ms - gone > flash_ms) { + since = 0; + gone = 0; + flash = 0; + overlay_row_ident[i].clear(); + overlay_row_history[i].clear(); + continue; + } + if (green_at != 0 && now_ms >= green_at) { + flash = 1; + flash_since = green_at; + green_at = 0; + } + if (flash != 0 && gone == 0 && green_at == 0 && now_ms - flash_since >= flash_ms) { + flash = 0; + } + // The controller's battery: by its Bluetooth address, the system's for the handheld's + // own controls, else SDL's (never a Steam virtual pad's). Read every 10 seconds, more + // often while a new controller's value settles. + Battery battery; + if (pad) { + auto& read = battery_read[pad]; + // Whose reading it is: Steam reshuffles its pads, so another controller is read + // afresh + const bool own = builtin_valid && pad == builtin_match_id; + const std::string whose = (own ? "handheld:" : "") + BluetoothKey(pad); + if (auto& was = battery_whose[pad]; was != whose) { + was = whose; + read = {}; + } + if (read.first == 0 || now_ms - read.first > 10'000) { + Battery fresh; + const char* source = "sdl"; + if (!IsSteamVirtualPad(pad)) { + const auto [percent, charging, wired] = SdlBattery(pad); + fresh = {percent, charging, wired}; + } +#ifdef __linux__ + std::optional> found; + bool by_address = false; + bool settling = false; + if (builtin_valid && pad == builtin_match_id) { + found = SystemBattery(); + source = "system"; + } else if (const auto address = inst_address.find(pad); + address != inst_address.end()) { + by_address = true; + found = BluetoothBattery(address->second); + source = "power supply"; + if (!found) { + // (Asked without waiting: a new answer triggers a reread) + const std::string& key = address->second; + auto& bluez = bluez_battery[key]; + if (bluez.asked_ms == 0 || now_ms - bluez.asked_ms >= 500) { + bluez.asked_ms = now_ms; + AskBluezBattery(key, this, [this, key](int percent) { + auto& entry = bluez_battery[key]; + const bool moved = entry.percent != percent; + entry.percent = percent; + if (moved) { + for (const auto& [inst, at] : inst_address) { + if (at == key) { + battery_read[inst].first = 0; + } + } + } + }); + } + if (bluez.percent >= 0) { + found = std::pair{bluez.percent, false}; + } + source = "bluez"; + // BlueZ first reads 50% for a new controller (the real charge + // comes about 10 seconds later): a first 50% counts once it changes, + // or after 12 seconds + if (found) { + // (By controller: Steam reshuffling its pads is no new connection) + const auto [first, added] = + bluez_first.try_emplace(address->second, now_ms, found->first); + // (Only its placeholder: a first value of anything else is real) + if (first->second.second == 50 && + now_ms - first->second.first < 12'000 && + found->first == first->second.second) { + found.reset(); + settling = true; + } + } + } + } + if (!found && !settling && fresh.percent < 0 && !fresh.wired && + Common::ControllerProbes()) { + const auto address = inst_address.find(pad); + LOG_INFO(Frontend, "console-mode: P{} inst={} battery unknown (address {})", + i + 1, pad, + address != inst_address.end() ? address->second : "none"); + } + if (found) { + fresh = {found->first, found->second, false}; + } + // (No value yet, or BlueZ's first one settling: read again sooner) + const qint64 read_at = settling ? now_ms - 9'000 + : by_address && !found ? now_ms - 8'000 + : now_ms; +#else + const qint64 read_at = now_ms; +#endif + if (Common::ControllerProbes() && fresh.percent >= 0 && + (fresh.percent != read.second.percent || + fresh.charging != read.second.charging)) { + LOG_INFO(Frontend, "console-mode: P{} inst={} battery {}%{} ({})", i + 1, + pad, fresh.percent, fresh.charging ? " charging" : "", source); + } + read = {read_at, fresh}; + } + battery = read.second; + // A low battery, once a session per controller: named on screen + const std::string key = name_key(pad); + if (battery.percent >= 0 && battery.percent <= 15 && !battery.charging && + battery_low_told.insert(key).second) { + controller_hints.push_back({QString{}, i, false, now_ms, false, + tr("%1: battery low (%2%)") + .arg(overlay_row_name[i]) + .arg(battery.percent)}); + LOG_INFO(Frontend, "console-mode: P{} battery low ({}%)", i + 1, + battery.percent); + } + } + const auto started = pad ? pad_origin.find(pad) : pad_origin.end(); + const int origin = + started != pad_origin.end() && started->second != i ? started->second : -1; + const bool guessed = pad && pad_guessed.contains(pad); + overlay_rows.push_back({i, + QStringLiteral("P%1: %2").arg(i + 1).arg(overlay_row_name[i]), + gone != 0 ? 0u : pad, flash, flash_since, origin, guessed, + battery.percent, battery.charging}); + const std::string key = pad ? BluetoothKey(pad) : std::string{}; + const auto address = pad_bluetooth.find(key); + const int turn_off = address != pad_bluetooth.end() && !address->second.empty() ? 2 + : pad_bt_pending.contains(key) ? 1 + : 0; + overlay_custom_name[static_cast(i)] = + custom_names[static_cast(i)]; + tab_rows.push_back({i, overlay_row_name[i].toStdString(), false, gone != 0, flash, + flash_since, ConsoleBindingSets()[slot_set[i]].profile_name, + turn_off, origin, guessed, + custom_names[static_cast(i)], battery.percent, + battery.charging, battery.wired}); + } + { + std::string handheld_name; + bool handheld_has_player = false; + if (builtin_valid && live.find(builtin_match_id) != live.end()) { + const auto [display, raw] = label_of(builtin_match_id, std::string{}); + QString name = display.isEmpty() ? raw : display; + name.remove(port_number); + handheld_name = name.toStdString(); + handheld_has_player = pad_slots.contains(builtin_match_id); + } + // The removed controller, by name while it is connected + std::string blocked_name; + for (const auto& [id, ident] : live) { + if (is_blocked(id)) { + blocked_name = PadName(id).toStdString(); + } + } + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + state.engine_active = true; + state.players = std::move(tab_rows); + state.handheld_name = std::move(handheld_name); + state.handheld_has_player = handheld_has_player; + state.handheld_blocked_name = std::move(blocked_name); + } + RenderControllerOverlay(); + } + + if (!changed) { + return; + } + // Reloaded whether a game runs or not: the Controls tab reads the players back from the + // emulated controllers, and stale ones would be taken for the user's edits + if (QtCommon::system) { + QtCommon::system->HIDCore().ReloadInputDevices(); + } + auto& state = Common::GetControllerConsoleState(); + std::scoped_lock lock{state.mutex}; + ++state.generation; +} + +bool MainWindow::eventFilter(QObject* watched, QEvent* event) { + // The controller overlay takes the mouse over its rows (drag to swap, click to rumble) + if (watched == render_window && HandleOverlayMouse(event)) { + return true; + } + if (watched == ui->menu_Cheats && event->type() == QEvent::MouseButtonRelease) { + const auto* mouse_event = static_cast(event); + auto* action = ui->menu_Cheats->actionAt(mouse_event->pos()); + if (mouse_event->button() == Qt::LeftButton && action && action->isEnabled() && + action->isCheckable()) { + action->trigger(); + return true; + } + } + return QMainWindow::eventFilter(watched, event); +} + void MainWindow::ConnectMenuEvents() { const auto connect_menu = [&](QAction* action, const Fn& event_fn) { connect(action, &QAction::triggered, this, event_fn); @@ -1506,6 +7176,10 @@ void MainWindow::ConnectMenuEvents() { connect_menu(ui->action_Show_Filter_Bar, &MainWindow::OnToggleFilterBar); connect_menu(ui->action_Show_Status_Bar, &MainWindow::OnToggleStatusBar); connect_menu(ui->action_Show_Performance_Overlay, &MainWindow::OnTogglePerfOverlay); + connect(ui->action_Show_Controller_Overlay, &QAction::toggled, this, + [](bool shown) { Settings::values.console_debug_overlay.SetValue(shown); }); + connect(ui->action_Show_Controller_Hints, &QAction::toggled, this, + [](bool shown) { Settings::values.console_hints.SetValue(shown); }); #ifdef HAS_RESHADE connect_menu(ui->action_Post_Processing_Shaders, &MainWindow::OnPostProcessingShaders); #else @@ -1786,7 +7460,11 @@ bool MainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPar QtCommon::system->SetFrontendAppletSet({ std::make_unique(*this), // Amiibo Settings - (Settings::values.controller_applet_mode.GetValue() == Settings::AppletMode::Disabled) + // The console modes own the controllers and suppress the applet, like Disabled + (Settings::values.controller_applet_mode.GetValue() == Settings::AppletMode::Disabled || + Settings::values.controller_applet_mode.GetValue() == Settings::AppletMode::ConsoleMode || + Settings::values.controller_applet_mode.GetValue() == + Settings::AppletMode::HandheldConsoleMode) ? nullptr : std::make_unique(*this), // Controller Selector std::make_unique(*this), // Error Display @@ -1899,7 +7577,7 @@ void MainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletPa // Save configurations UpdateUISettings(); game_list->SaveInterfaceLayout(); - config->SaveAllValues(); + SaveAllConfigValues(); u64 title_id{0}; @@ -2745,7 +8423,7 @@ void MainWindow::OnLinkToRyujinx(const u64& program_id) { UISettings::values.ryujinx_link_paths.remove(program_id); } - config->SaveAllValues(); + SaveAllConfigValues(); } void MainWindow::OnMenuLoadFile() { @@ -2797,9 +8475,9 @@ void MainWindow::IncrementInstallProgress() { void MainWindow::OnMenuInstallToNAND() { const QString file_filter = - tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive " - "(*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge " - "Image (*.xci)"); + tr("Installable Switch File (*.nca *.nsp *.nsz *.xci *.xcz);;Nintendo Content Archive " + "(*.nca);;Nintendo Submission Package (*.nsp *.nsz);;NX Cartridge " + "Image (*.xci *.xcz)"); QStringList filenames = QFileDialog::getOpenFileNames( this, tr("Install Files"), QString::fromStdString(UISettings::values.roms_path), @@ -2856,7 +8534,10 @@ void MainWindow::OnMenuInstallToNAND() { QFuture future; ContentManager::InstallResult result; - if (file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { + if (file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive) || + file.endsWith(QStringLiteral("nsz"), Qt::CaseInsensitive) || + file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) || + file.endsWith(QStringLiteral("xcz"), Qt::CaseInsensitive)) { const auto progress_callback = [this](size_t size, size_t progress) { emit UpdateInstallProgress(); if (install_progress->wasCanceled()) { @@ -3115,7 +8796,7 @@ void MainWindow::OnExit() { void MainWindow::OnSaveConfig() { QtCommon::system->ApplySettings(); - config->SaveAllValues(); + SaveAllConfigValues(); } void MainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { @@ -3266,6 +8947,7 @@ void MainWindow::HideFullscreen() { statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked()); ui->menubar->show(); + FitToScreenUnderGamescope(this); } else { if (UsingExclusiveFullscreen()) { render_window->showNormal(); @@ -3280,6 +8962,21 @@ void MainWindow::HideFullscreen() { } } +void MainWindow::FitToScreenUnderGamescope(QWidget* window) { + // Under gamescope a window is scaled to fit together with any tooltip reaching past it, so + // a smaller window grows and shrinks on hover: filling the screen keeps them inside + if (!Gamescope::IsRunningUnder()) { + return; + } + if (window->isFullScreen()) { + return; + } + QScreen* screen = window->screen() ? window->screen() : QGuiApplication::primaryScreen(); + if (screen) { + window->setGeometry(screen->geometry()); + } +} + void MainWindow::ToggleWindowMode() { if (ui->action_Single_Window_Mode->isChecked()) { // Render in the main window... @@ -3397,14 +9094,19 @@ void MainWindow::OnConfigure() { const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue(); const auto old_language_index = Settings::values.language_index.GetValue(); const bool old_gamemode = UISettings::values.enable_gamemode.GetValue(); -#ifdef __unix__ - const bool old_force_x11 = UISettings::values.gui_force_x11.GetValue(); -#endif + // Taken before the dialog exists (its Controls tab writes the players), from the copy in + // use: during a game the global copy holds stale routing, which would invent swaps + const auto players_before = Settings::values.players.GetValue(); Settings::SetConfiguringGlobal(true); ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), vk_device_records, *QtCommon::system, !multiplayer_state->IsHostingPublicRoom()); + // Opened from a player chip: straight to that player's tab + if (open_player_tab >= 0) { + configure_dialog.OpenPlayerTab(open_player_tab); + open_player_tab = -1; + } connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this, &MainWindow::OnLanguageChanged); connect(&configure_dialog, &ConfigureDialog::ExternalContentDirsChanged, this, @@ -3442,6 +9144,7 @@ void MainWindow::OnConfigure() { Settings::values.disabled_addons.clear(); + RestoreConsoleProfile(); config = std::make_unique(); UISettings::values.reset_to_defaults = false; @@ -3453,6 +9156,10 @@ void MainWindow::OnConfigure() { SetDefaultUIGeometry(); RestoreUIState(); } + MergeConsoleProfileEdits(players_before); + ui->action_Show_Controller_Overlay->setChecked( + Settings::values.console_debug_overlay.GetValue()); + ui->action_Show_Controller_Hints->setChecked(Settings::values.console_hints.GetValue()); InitializeHotkeys(); if (UISettings::values.theme != old_theme) { @@ -3464,11 +9171,6 @@ void MainWindow::OnConfigure() { if (UISettings::values.enable_gamemode.GetValue() != old_gamemode) { SetGamemodeEnabled(UISettings::values.enable_gamemode.GetValue()); } -#ifdef __unix__ - if (UISettings::values.gui_force_x11.GetValue() != old_force_x11) { - GraphicsBackend::SetForceX11(UISettings::values.gui_force_x11.GetValue()); - } -#endif if (!multiplayer_state->IsHostingPublicRoom()) { multiplayer_state->UpdateCredentials(); @@ -3483,7 +9185,7 @@ void MainWindow::OnConfigure() { UISettings::values.configuration_applied = false; - config->SaveAllValues(); + SaveAllConfigValues(); if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) { render_window->installEventFilter(render_window); @@ -3703,7 +9405,26 @@ void MainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file_ Settings::RestoreGlobalState(QtCommon::system->IsPoweredOn()); return; } else if (result == QDialog::Accepted) { + // A game with its own controller config keeps its own in the file, not the engine's + // runtime players (as a global save does, see SaveAllConfigValues) + std::optional> engine_players; + if (console_profile && game_profiles && QtCommon::system->IsPoweredOn() && + QtCommon::system->GetApplicationProcessProgramID() == title_id && + !Settings::values.players.UsingGlobal()) { + auto& game_players = Settings::values.players.GetValue(); + engine_players = game_players; + game_players = *game_profiles; + } dialog.ApplyConfiguration(); + if (engine_players && !Settings::values.players.UsingGlobal()) { + Settings::values.players.GetValue() = *engine_players; + } + // (The running game's own value; otherwise the View menu keeps showing the global one) + if (QtCommon::system->IsPoweredOn()) { + ui->action_Show_Controller_Overlay->setChecked( + Settings::values.console_debug_overlay.GetValue()); + ui->action_Show_Controller_Hints->setChecked(Settings::values.console_hints.GetValue()); + } } const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false); @@ -3719,7 +9440,7 @@ void MainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file_ UISettings::values.configuration_applied = false; if (!is_powered_on) { - config->SaveAllValues(); + SaveAllConfigValues(); } } @@ -4352,56 +10073,6 @@ void MainWindow::OnCheckFirmwareDecryption() { UpdateMenuState(); } -#ifdef __unix__ -void MainWindow::OnCheckGraphicsBackend() { - const QString platformName = QGuiApplication::platformName(); - const QByteArray qtPlatform = qgetenv("QT_QPA_PLATFORM"); - - if (platformName == QStringLiteral("xcb") || qtPlatform == "xcb") - return; - - const bool isWayland = - platformName.startsWith(QStringLiteral("wayland"), Qt::CaseInsensitive) || - qtPlatform.startsWith("wayland"); - if (!isWayland) - return; - - const bool currently_hidden = UISettings::values.gui_hide_backend_warning.GetValue(); - if (currently_hidden) - return; - - QMessageBox msgbox(this); - msgbox.setWindowTitle(tr("Wayland Detected!")); - msgbox.setText( - tr("Wayland is known to have significant performance issues and mysterious bugs.\n" - "It's recommended to use X11 instead.\n\n" - "Would you like to force it for future launches?")); - msgbox.setIcon(QMessageBox::Warning); - - QPushButton* okButton = msgbox.addButton(tr("Use X11"), QMessageBox::AcceptRole); - msgbox.addButton(tr("Continue with Wayland"), QMessageBox::RejectRole); - msgbox.setDefaultButton(okButton); - - QCheckBox* cb = new QCheckBox(tr("Don't show again"), &msgbox); - cb->setChecked(currently_hidden); - msgbox.setCheckBox(cb); - - msgbox.exec(); - - const bool hide = cb->isChecked(); - if (hide != currently_hidden) { - UISettings::values.gui_hide_backend_warning.SetValue(hide); - } - - if (msgbox.clickedButton() == okButton) { - UISettings::values.gui_force_x11.SetValue(true); - GraphicsBackend::SetForceX11(true); - QMessageBox::information(this, tr("Restart Required"), - tr("Restart Eden to apply the X11 backend.")); - } -} -#endif - bool MainWindow::CheckFirmwarePresence() { return FirmwareManager::CheckFirmwarePresence(*QtCommon::system.get()); } @@ -4525,6 +10196,21 @@ void MainWindow::closeEvent(QCloseEvent* event) { event->ignore(); return; } + // Debug Probes: who was which player when Eden closed + if (Common::ControllerProbes() && !overlay_rows.empty()) { + std::string players_now; + for (const auto& row : overlay_rows) { + players_now += fmt::format("\n P{} {} ident={} profile=\"{}\"{}", row.player + 1, + overlay_row_name[row.player].toStdString(), + overlay_row_ident[row.player], + ConsoleBindingSets()[slot_set[row.player]].profile_name, + row.pad == 0 ? " (left)" : ""); + } + LOG_INFO(Frontend, "console-mode: closing, mode {}, players:{}", + AppletModeName(Settings::values.controller_applet_mode.GetValue()), players_now); + } + closing = true; + console_mode_timer.stop(); UpdateUISettings(); game_list->SaveInterfaceLayout(); diff --git a/src/yuzu/main_window.h b/src/yuzu/main_window.h index 8aedeec721..ea02fd48f9 100644 --- a/src/yuzu/main_window.h +++ b/src/yuzu/main_window.h @@ -9,7 +9,16 @@ #include #include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include #include #include @@ -19,6 +28,7 @@ #include "common/common_types.h" #include "common/settings_enums.h" +#include "common/settings_input.h" #include "frontend_common/content_manager.h" #include "input_common/drivers/tas_input.h" #include "qt_common/config/qt_config.h" @@ -49,6 +59,7 @@ class LoadingScreen; class OverlayDialog; class ControllerDialog; class QLabel; +class QShortcut; class MultiplayerState; class QPushButton; class QProgressDialog; @@ -264,6 +275,8 @@ private: void ConnectWidgetEvents(); void ConnectMenuEvents(); void UpdateMenuState(); + void RefreshRuntimeCheats(); + void ClearRuntimeCheats(); void SetupPrepareForSleep(); @@ -422,9 +435,6 @@ private slots: void OnCreateHomeMenuApplicationMenuShortcut(); void OnCaptureScreenshot(); void OnCheckFirmwareDecryption(); -#ifdef __unix__ - void OnCheckGraphicsBackend(); -#endif void OnLanguageChanged(const QString& locale); void OnMouseActivity(); bool OnShutdownBegin(); @@ -552,6 +562,257 @@ private: QString startup_icon_theme; QActionGroup* game_size_actions; + std::vector runtime_cheat_actions; + + /// The console modes' engine: assigns the connected controllers to players, on a timer + QTimer console_mode_timer; + /// Eden is closing: the engine stops (it would reload the inputs closeEvent unloaded) + bool closing = false; + void ApplyConsoleControllerMode(); + /// connection instance -> player slot; kept after a disconnect so the pad reclaims its player + std::map pad_slots; + /// Per connection: its controller's Bluetooth address, the player it started as, and + /// whether its player was a guess on a reconnect + std::map inst_address; + std::map pad_origin; + std::set pad_guessed; + /// Returning pads waiting a moment for their Bluetooth address before they claim a player + std::map claim_wait_since; + /// Players taken by a guess, kept for the Bluetooth controller that held them + struct AddressClaim { + int slot; + int origin; + std::chrono::steady_clock::time_point at; + }; + std::map address_claims; + /// Each Bluetooth controller's starting player, by address: kept through Turn Off and + /// reconnects + std::map address_origin; + /// Names given to controllers ("bt:
", "handheld" or "id:"). Never saved: + /// owners can't tell identical controllers apart in a later session + std::map controller_names; + /// The mode and each player's refused controller type as last logged + std::optional logged_mode; + std::array refused_logged{}; + /// When the deck's controller was last asked to turn its motion sensors back on + qint64 deck_motion_asked_at = 0; + /// Pads whose player was removed: they sit out until they reconnect (connection instance) + std::set benched_pads; + /// When each player's controller was last turned off (Turn Off) + std::array turned_off_at{}; + /// Each pad's Bluetooth address by BluetoothKey ("" none or unknown), and the pads not yet + /// told apart from others of their model + std::map pad_bluetooth; + std::set pad_bt_pending; + void LearnBluetoothPads(); + /// Reads the pads' and the real controllers' inputs + void WatchSteamPadInputs(); + /// The last time a pad had input together with exactly one real controller: when Steam + /// then moves a controller to that pad, that is the one + struct LoneInput { + u32 pad; + std::string controller; + std::chrono::steady_clock::time_point at; + }; + std::optional last_lone_input; + /// connection instance -> stable identity (serial, else model GUID), to match a returning pad + std::map pad_identity; + /// identity -> the binding set the controller carries, so its mappings follow it + std::map pad_sets; + /// player -> the set its controller carries, as of the last tick + std::array slot_set{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + /// set -> the controller whose default mapping it holds (0: the user's, or empty); a set + /// holding a gone controller's defaults is rebuilt for the one taking it + std::array set_default_of{}; + /// This session's binding sets: profiles and remaps stay here, so the user's own setup + /// (the manual modes') is never touched + std::optional> session_sets; + /// The set a change goes to: the session's, or a game's own profile set + Settings::PlayerInput& SessionSet(int set); + /// The profile each seat (player number) starts a session with + void ApplySeatProfiles(); + void SetSeatProfile(int player, const std::string& name); + /// A set's mappings before this session's first profile on it, for taking the profile off + std::map set_before_profile; + /// The handheld's own pad: never a player while other pads are connected + u32 builtin_pad_id = 0; + /// The built-in's stable identity: the exclusion must survive its instance changing + std::string builtin_identity; + /// Latched once the built-in has been identified + bool builtin_seen_first = false; + /// Warn once per engagement when the built-in cannot be identified + bool builtin_warned = false; + /// Overlay rows per player: when it appeared, when its pad left, and its name + std::array overlay_row_since{}; + std::array overlay_row_gone{}; + std::array overlay_row_name{}; + /// Per player: the controller behind the row (its identity), and its flash (1 green, 2 red) + /// with when it began; a red then green keeps the green's start in overlay_green_at + std::array overlay_row_ident{}; + /// The key each player's input history is kept under (identical controllers can share an + /// identity) + std::array overlay_row_history{}; + std::array overlay_flash{}; + std::array overlay_flash_since{}; + std::array overlay_green_at{}; + /// Per player: the real device its motion comes from under Steam (0: none) + std::array overlay_motion_source{}; + /// The overlay's rows as the last assignment tick left them: flash 1 green, 2 red + struct OverlayRow { + int player; + QString text; + u32 pad; + int flash; + qint64 flash_since; + /// The player its controller started as (-1: this one), and whether it was a guess + int origin = -1; + bool guessed = false; + /// Its controller's battery (percent, -1 unknown) and whether it charges + int battery = -1; + bool charging = false; + }; + std::vector overlay_rows; + std::vector overlay_blink; + /// The room the players panel had last: redrawn when a top-right panel changes + float overlay_room = 0.0f; + std::set overlay_active_pads; + /// Polls controller input faster than the assignment tick, for the blue highlight + QTimer console_activity_timer; + /// The overlay's player rows as drawn, for the mouse + std::vector> overlay_hits; + int overlay_drag_player = -1; + int overlay_drag_dy = 0; + bool overlay_dragging = false; + QPoint overlay_press; + /// The row under the mouse (-1: none) and its buttons as drawn: swap above (-1) or below + /// (1), Turn Off (0), Config (2), rename (3); while naming apply (4), remove (5), cancel (6) + int overlay_hover_player = -1; + bool overlay_button_down = false; + struct OverlayButton { + QRect rect; + int player; + int action; + int target; + }; + std::vector overlay_buttons; + bool HandleOverlayMouse(QEvent* event); + /// Each player's given name as shown, and the name being typed (player -1: none) + std::array overlay_custom_name{}; + /// The name of the controller that last left each player, for its hint + std::array overlay_left_name{}; + /// Batteries, read at most every 10 seconds, and the controllers already warned of a low one + struct Battery { + int percent = -1; + bool charging = false; + bool wired = false; + }; + std::map> battery_read; + /// A controller's first BlueZ battery reading and when, by address (BlueZ says 50% at first) + std::map> bluez_first; + /// Whose controller each pad's battery reading is (Steam handle or identity, handheld or not) + std::map battery_whose; + std::set battery_low_told; + /// Use Any Controller as Joy-Cons: each player's type before the engine changed it, and the + /// type it set + std::array, 10> joycon_auto_from{}; + std::array, 10> joycon_auto_set{}; + /// A single Joy-Con set by it: held sideways (else upright), as the game holds it + std::array joycon_auto_sideways{}; + /// Pause When a Controller Disconnects: since when each player waits (0 none), and the + /// players a pause is for + std::array waiting_since{}; + std::set disconnect_paused; + /// A handover pause: the player (-1 none) the handheld's controls took over mid-game when + /// the last external controller left (it may be docked). Goes on at a press on the handheld + /// or when an external controller returns. Also who held each player at the last tick. + int handover_paused = -1; + bool handover_pressed = false; + std::array held_by_external{}; + /// Whether the handheld's controls held a player at the last tick (in Modern Console they + /// may have played all along: no handover) + bool handheld_was_playing = false; + /// What BlueZ last said of a controller (by address): connected, and when asked and answered + struct BluezConnection { + bool connected = true; + qint64 asked_ms = 0; + qint64 answered_ms = 0; + }; + std::map bluez_connected; + /// What BlueZ last said of a controller's battery (by address; -1 nothing yet), and when + struct BluezBattery { + int percent = -1; + qint64 asked_ms = 0; + }; + std::map bluez_battery; + /// The pause for a disconnect is about to come (its notice is drawn first) + bool disconnect_pause_pending = false; + /// The game was seen paused (until then, running isn't a resume by hand) + bool disconnect_pause_seen = false; + /// + is held on another controller during that pause: on without those players once let go + bool disconnect_continue_held = false; + std::set pause_done; + /// Player Lights: the player each controller's lights were last set to (by connection) + std::map lights_player; + int overlay_edit_player = -1; + QString overlay_edit_text; + /// The player whose tab the next settings dialog opens on (-1: as usual) + int open_player_tab = -1; + /// Under gamescope, makes a window fill the screen (see the definition) + void FitToScreenUnderGamescope(QWidget* window); + void RenderControllerOverlay(); + void PollControllerActivity(); + /// The last buttons each controller pressed, as the game sees them, newest last; by + /// controller, so the history follows a swap + struct ButtonPress { + int button; + qint64 at; + }; + std::map> press_history; + /// The controller each player's buttons were last read for (a new one records no presses) + std::array history_ident{}; + std::array, 10> buttons_down{}; + /// Stick moves in the history: StickMoveButton + stick * 4 + direction (left, up, right, + /// down), stick 0 the left one + static constexpr int StickMoveButton = 64; + /// The direction each player's sticks point, plus one (0 at rest) + std::array, 10> stick_direction{}; + /// Reads the players' buttons; true when the history changed (a press, or one expiring) + bool PollButtonHistory(); + /// A controller named on screen for a moment: it joined as a player, or left one + struct ControllerHint { + QString name; + int player; + bool joined; + qint64 at; + /// Left because Turn Off turned its controller off + bool turned_off = false; + /// Said instead of joined / left ("" none): how the player's controller changed + QString note; + /// Says the game is paused for a disconnect: kept while it is, shown with hints off too + bool pause_notice = false; + }; + std::vector controller_hints; + /// A game running with no controller: since when (0 none), and whether it was said + qint64 no_controller_since = 0; + bool no_controller_told = false; + /// The flashes already turned into hints, per player (green, red) + std::array hinted_join{}; + std::array hinted_leave{}; + /// True while the overlay animates (hints fading, history entries shrinking away) + bool OverlayAnimating() const; + /// The user's own players while a console mode drives them: what the config file sees, and + /// what leaving the mode puts back + std::optional> console_profile; + /// The running game's own players, when it has input profiles of its own + std::optional> game_profiles; + /// The binding sets the pads carry: the user's own, with a game's input profiles on top + std::array ConsoleBindingSets() const; + /// Saves the configuration, writing the user's own players while a console mode runs + void SaveAllConfigValues(); + /// Puts the user's own players back (leaving a console mode, or before the config saves) + void RestoreConsoleProfile(); + /// Folds edits made in the Controls tab during a console mode into the user's profile + void MergeConsoleProfileEdits(const std::array& before); // Debugger panes ControllerDialog* controller_dialog = nullptr; @@ -600,6 +861,7 @@ private: std::string arguments, const bool needs_title); protected: + bool eventFilter(QObject* watched, QEvent* event) override; void dropEvent(QDropEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override; void dragMoveEvent(QDragMoveEvent* event) override; diff --git a/src/yuzu/overlay_panel.cpp b/src/yuzu/overlay_panel.cpp new file mode 100644 index 0000000000..b518377c3e --- /dev/null +++ b/src/yuzu/overlay_panel.cpp @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include +#include +#include +#include + +#include "yuzu/bootmanager.h" +#include "yuzu/overlay_panel.h" + +namespace GameOverlay { + +void Publish(Common::OverlayPanel& panel, const QImage* image) { + std::scoped_lock lock{panel.mutex}; + if (!image) { + if (panel.enabled) { + panel.enabled = false; + ++panel.version; + } + return; + } + panel.width = static_cast(image->width()); + panel.height = static_cast(image->height()); + panel.pixels.resize(static_cast(image->sizeInBytes())); + std::memcpy(panel.pixels.data(), image->constBits(), + static_cast(image->sizeInBytes())); + panel.enabled = true; + ++panel.version; +} + +Cursor CursorOn(Common::OverlayPanel& panel, const GRenderWindow& window) { + const auto& layout = window.GetFramebufferLayout(); + Common::OverlayRect place{}; + { + std::scoped_lock lock{panel.mutex}; + place = Common::PlaceOverlayPanel( + panel, static_cast(layout.screen.left), static_cast(layout.screen.top), + static_cast(layout.screen.right), static_cast(layout.screen.bottom)); + } + // The panel is drawn at its own size, in the framebuffer's pixels + const qreal ratio = window.devicePixelRatioF(); + const QPointF logical = window.mapFromGlobal(QCursor::pos()); + const QPoint at(static_cast(logical.x() * ratio) - static_cast(place.x), + static_cast(logical.y() * ratio) - static_cast(place.y)); + const bool inside = at.x() >= 0 && at.y() >= 0 && at.x() < static_cast(place.width) && + at.y() < static_cast(place.height); + return {at, inside}; +} + +namespace Style { + +QFont TextFont() { + QFont font; + font.setPixelSize(13); + return font; +} + +QFont LabelFont() { + QFont font; + font.setPixelSize(12); + font.setBold(true); + return font; +} + +QFont SmallFont() { + QFont font; + font.setPixelSize(11); + font.setBold(true); + return font; +} + +void Pill(QPainter& painter, const QRectF& rect, const QColor& fill) { + painter.setPen(Qt::NoPen); + painter.setBrush(fill); + painter.drawRoundedRect(rect, rect.height() / 2.0, rect.height() / 2.0); +} + +} // namespace Style + +} // namespace GameOverlay diff --git a/src/yuzu/overlay_panel.h b/src/yuzu/overlay_panel.h new file mode 100644 index 0000000000..8a8e05e077 --- /dev/null +++ b/src/yuzu/overlay_panel.h @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include + +#include "common/overlay_panels.h" + +class GRenderWindow; +class QImage; +class QPainter; +class QRectF; +class QString; + +/// The frontend's side of the in-game overlay panels (common/overlay_panels.h) +namespace GameOverlay { + +/// Shows an image as the panel (copied), or hides the panel (nullptr) +void Publish(Common::OverlayPanel& panel, const QImage* image); + +/// The cursor in a panel's image, and whether it is over the panel (which must be shown) +struct Cursor { + QPoint at; + bool inside = false; +}; +[[nodiscard]] Cursor CursorOn(Common::OverlayPanel& panel, const GRenderWindow& window); + +/// The overlay's look, shared by its panels +namespace Style { + +/// A panel's dark, see-through fill +inline const QColor Fill{14, 14, 18, 175}; +/// A held, hovered or active item +inline const QColor Active{45, 95, 200, 200}; +/// Something that joined or turned on +inline const QColor Good{45, 160, 80, 200}; +/// Something that left or failed +inline const QColor Bad{190, 50, 50, 200}; +inline const QColor Text{240, 240, 240}; +inline const QColor DimText{255, 255, 255, 120}; + +/// The fonts: names and lines, labels (bold), small labels (bold) +[[nodiscard]] QFont TextFont(); +[[nodiscard]] QFont LabelFont(); +[[nodiscard]] QFont SmallFont(); + +/// A pill: a rounded rectangle with fully round ends +void Pill(QPainter& painter, const QRectF& rect, const QColor& fill); + + +} // namespace Style + +} // namespace GameOverlay diff --git a/src/yuzu/util/controller_navigation.cpp b/src/yuzu/util/controller_navigation.cpp index 0dbfca243e..5d9ed7e2f2 100644 --- a/src/yuzu/util/controller_navigation.cpp +++ b/src/yuzu/util/controller_navigation.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -70,6 +73,12 @@ void ControllerNavigation::ControllerUpdateButton() { case Core::HID::NpadStyleIndex::JoyconDual: case Core::HID::NpadStyleIndex::Handheld: case Core::HID::NpadStyleIndex::GameCube: + if ((button_values[Settings::NativeButton::Minus].value && + !button_values[Settings::NativeButton::Minus].locked) || + (button_values[Settings::NativeButton::Plus].value && + !button_values[Settings::NativeButton::Plus].locked)) { + emit TriggerContextMenu(); + } TriggerButton(Settings::NativeButton::A, Qt::Key_Enter); TriggerButton(Settings::NativeButton::B, Qt::Key_Escape); TriggerButton(Settings::NativeButton::DDown, Qt::Key_Down); @@ -78,10 +87,18 @@ void ControllerNavigation::ControllerUpdateButton() { TriggerButton(Settings::NativeButton::DUp, Qt::Key_Up); break; case Core::HID::NpadStyleIndex::JoyconLeft: + if (button_values[Settings::NativeButton::Minus].value && + !button_values[Settings::NativeButton::Minus].locked) { + emit TriggerContextMenu(); + } TriggerButton(Settings::NativeButton::DDown, Qt::Key_Enter); TriggerButton(Settings::NativeButton::DLeft, Qt::Key_Escape); break; case Core::HID::NpadStyleIndex::JoyconRight: + if (button_values[Settings::NativeButton::Plus].value && + !button_values[Settings::NativeButton::Plus].locked) { + emit TriggerContextMenu(); + } TriggerButton(Settings::NativeButton::X, Qt::Key_Enter); TriggerButton(Settings::NativeButton::A, Qt::Key_Escape); break; diff --git a/src/yuzu/util/controller_navigation.h b/src/yuzu/util/controller_navigation.h index 86e210368f..d0bd8f5898 100644 --- a/src/yuzu/util/controller_navigation.h +++ b/src/yuzu/util/controller_navigation.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -29,6 +32,7 @@ public: signals: void TriggerKeyboardEvent(Qt::Key key); + void TriggerContextMenu(); private: void TriggerButton(Settings::NativeButton::Values native_button, Qt::Key key); diff --git a/src/yuzu/util/gamescope.cpp b/src/yuzu/util/gamescope.cpp new file mode 100644 index 0000000000..d79ec6863a --- /dev/null +++ b/src/yuzu/util/gamescope.cpp @@ -0,0 +1,449 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/logging.h" +#include "common/settings.h" +#include "yuzu/util/gamescope.h" + +namespace Gamescope { +namespace { + +// Under gamescope (installed on the application only there). Gamescope shows one window at a +// time, scaled to fit the screen, with no title bar, and only one popup over it: +// - A dialog takes the whole screen as it shows, before it's mapped, so it's never scaled up +// (blurry, and a tooltip past its edge rescaled it). A smaller dialog keeps its own size, +// centred. Its own show handling runs first (a message box fixes its size +// there), then its size is freed. +// - A dialog with no buttons of its own to leave it gets a Close button. +// - A closing menu can leave the mouse grabbed by the main window: taps then reach the main +// window, which the open dialog blocks, so the dialog never gets them. A modal window shown +// with no menu open lets go of any such grab. +// - A submenu's popup would hide its parent menu, which still took the mouse unseen: a +// submenu opens in its menu's place instead. +// - A smaller dialog is a card on a darker screen, like its own window on a desktop, with an +// Expand button to fill the screen (Shrink to go back). +class GamescopeDialogs final : public QObject { +public: + explicit GamescopeDialogs(QWidget* main_) : QObject(main_), main{main_} { + // The menu bar's menus got their actions before this was installed + for (QMenu* menu : main->findChildren()) { + PrepareMenu(menu); + } + } + + bool eventFilter(QObject* watched, QEvent* event) override { + if (auto* menu = qobject_cast(watched)) { + if (event->type() == QEvent::ActionAdded) { + PrepareMenu(menu); + return false; + } + return TurnPage(menu, event); + } + if (event->type() == QEvent::LayoutRequest && watched->isWidgetType() && + watched->property("gamescope_fit").isValid()) { + // A message box fixes its own size on every layout change: it lays itself out, then + // takes the whole screen again + // (Taken over here, so the layout is activated first, as Qt would before event()) + auto* widget = static_cast(watched); + if (QLayout* layout = widget->layout()) { + layout->activate(); + } + static_cast(widget)->event(event); + if (QScreen* screen = widget->screen(); screen && widget->geometry() != screen->geometry()) { + widget->setMinimumSize(0, 0); + widget->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + widget->setGeometry(screen->geometry()); + } + return true; + } + if (event->type() != QEvent::Show || !watched->isWidgetType()) { + return false; + } + auto* widget = static_cast(watched); + if (widget == main || !widget->isWindow()) { + return false; + } + if (widget->windowModality() != Qt::NonModal) { + QTimer::singleShot(0, this, [this] { + if (QApplication::activePopupWidget() || !main->windowHandle()) { + return; + } + main->windowHandle()->setMouseGrabEnabled(false); + if (Settings::values.console_debug_probes.GetValue()) { + LOG_INFO(Frontend, "gamescope: dialog shown, mouse grab released"); + } + }); + } + // Eden's own overlays over the game (software keyboard, applet messages) size and place + // themselves over it + if (widget->windowType() != Qt::Dialog || widget->isFullScreen() || + (widget->windowFlags() & Qt::FramelessWindowHint)) { + return false; + } + static_cast(widget)->event(event); + FitDialog(widget); + return true; + } + +private: + static void FitDialog(QWidget* dialog) { + QScreen* screen = dialog->screen() ? dialog->screen() : QGuiApplication::primaryScreen(); + if (!screen) { + return; + } + const QRect area = screen->geometry(); + const QSize natural = dialog->size(); + const bool first = !dialog->property("gamescope_fit").isValid(); + dialog->setProperty("gamescope_fit", true); + dialog->setMinimumSize(0, 0); + dialog->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + dialog->setGeometry(area); + QLayout* layout = dialog->layout(); + if (!first || !layout) { + return; + } + // A smaller dialog keeps its size, a card in the middle; it can be expanded to fill the + // screen and shrunk back (each time it opens it starts as a card) + const bool centred = natural.width() < area.width() * 85 / 100 && + natural.height() < area.height() * 85 / 100; + QList corner; + if (NeedsClose(dialog)) { + auto* close = new QPushButton(tr("Close"), dialog); + connect(close, &QPushButton::clicked, dialog, &QWidget::close); + corner.append(close); + } + QPushButton* expand = nullptr; + if (centred && !IsSmallPrompt(dialog)) { + expand = new QPushButton(tr("Expand"), dialog); + expand->setToolTip(tr("Fill the screen")); + corner.prepend(expand); + } + int strip = 0; + for (QPushButton* button : corner) { + button->setCursor(Qt::PointingHandCursor); + button->adjustSize(); + strip = (std::max)(strip, button->height() + 8); + } + const QMargins own = layout->contentsMargins(); + const QRect card_area((area.width() - natural.width()) / 2, + (area.height() - natural.height()) / 2, natural.width(), + natural.height()); + QFrame* card = centred ? AddCard(dialog, card_area) : nullptr; + // Card: margins around the dialog's own size, buttons above its top right corner. + // Full: the buttons in a strip at the top right of the screen. + // (The dialog's current layout each time, and guarded pointers: a message box rebuilds + // its layout on a style change, so AddCard's style sheet already deleted the one read + // above; the kept pointer crashed in QLayout::setContentsMargins) + QList> corner_buttons; + for (QPushButton* button : corner) { + corner_buttons.append(button); + } + const auto place = [dialog_ptr = QPointer{dialog}, own, area, card_area, + card_ptr = QPointer{card}, corner_buttons, strip, + expand_ptr = QPointer{expand}](bool full) { + QWidget* const target = dialog_ptr.data(); + QLayout* const target_layout = target ? target->layout() : nullptr; + if (!target_layout) { + return; + } + QFrame* const target_card = card_ptr.data(); + QPushButton* const target_expand = expand_ptr.data(); + QList buttons; + for (const QPointer& button : corner_buttons) { + if (button) { + buttons.append(button.data()); + } + } + if (full || !target_card) { + target_layout->setContentsMargins(own + + QMargins(0, buttons.isEmpty() ? 0 : strip, 0, 0)); + } else { + target_layout->setContentsMargins(own + + QMargins(card_area.left(), card_area.top(), + area.width() - card_area.right() - 1, + area.height() - card_area.bottom() - 1)); + } + if (target_card) { + target_card->setVisible(!full); + } + if (target_expand) { + target_expand->setText(full ? tr("Shrink") : tr("Expand")); + target_expand->setToolTip(full ? tr("Back to its own size") + : tr("Fill the screen")); + target_expand->adjustSize(); + } + if (buttons.isEmpty()) { + target->update(); + return; + } + int right = full || !target_card ? area.width() - 8 : card_area.right() + 1; + const int top = + full || !target_card + ? 6 + : (std::max)(6, card_area.top() - 14 - buttons.first()->height() - 6); + for (auto it = buttons.rbegin(); it != buttons.rend(); ++it) { + (*it)->move(right - (*it)->width(), top); + (*it)->raise(); + (*it)->show(); + right -= (*it)->width() + 6; + } + target->update(); + }; + if (expand) { + connect(expand, &QPushButton::clicked, dialog, [place, expand] { + // (The connection ends with the button, so expand is alive here) + const bool full = !expand->property("gamescope_full").toBool(); + expand->setProperty("gamescope_full", full); + place(full); + }); + } + // File pickers, per-game settings and the room browser open expanded (Shrink: a card) + const bool starts_full = expand && (qobject_cast(dialog) || + dialog->inherits("ConfigurePerGame") || + dialog->inherits("Lobby")); + if (starts_full) { + expand->setProperty("gamescope_full", true); + } + place(starts_full); + } + + // A prompt or short form: a few lines and fields, nothing to gain from filling the screen + static bool IsSmallPrompt(QWidget* dialog) { + static constexpr const char* small[] = { + "QMessageBox", "QInputDialog", "AboutDialog", + "DataDialog", "DirectConnectWindow", "HostRoomWindow", + "RyujinxDialog", "LimitableInputDialog", "SetPlayTimeDialog", + "SequenceDialog", "NewUserDialog", "ConfigureProfileManagerDeleteDialog", + "MigrationDialog", "CalibrationConfigurationDialog", + }; + for (const char* name : small) { + if (dialog->inherits(name)) { + return true; + } + } + return false; + } + + // A dialog leaves through its button row; without one (the room browser, Create Room) it + // has no way out + static bool NeedsClose(QWidget* dialog) { + for (auto* box : dialog->findChildren()) { + if (!box->buttons().isEmpty()) { + return false; + } + } + return true; + } + + // The dialog's own area is a card on a darker screen, so it doesn't float edgeless + static QFrame* AddCard(QWidget* dialog, const QRect& inner) { + const QColor base = dialog->palette().color(QPalette::Window); + if (dialog->objectName().isEmpty()) { + dialog->setObjectName(QStringLiteral("gamescopeDialog")); + } + dialog->setStyleSheet(dialog->styleSheet() + + QStringLiteral("\n#%1 { background-color: %2; }") + .arg(dialog->objectName(), base.darker(160).name())); + auto* card = new QFrame(dialog); + card->setObjectName(QStringLiteral("gamescopeCard")); + card->setStyleSheet(QStringLiteral("#gamescopeCard { background-color: %1; border: 1px " + "solid %2; border-radius: 10px; }") + .arg(base.name(), base.lighter(150).name())); + card->setGeometry(inner.adjusted(-14, -14, 14, 14)); + card->lower(); + return card; + } + + // A submenu opens in its menu's place: the menu swaps its entries for the submenu's, with + // ‹ Back on top, so only one menu is ever up. Set up as a menu gets its first action, so + // it's in place before the menu first measures itself. + static void PrepareMenu(QMenu* menu) { + if (menu->property("gamescope_menu").isValid()) { + return; + } + menu->setProperty("gamescope_menu", true); + connect(menu, &QMenu::aboutToShow, menu, [menu] { + menu->setProperty("gamescope_pages", QVariantList{}); + ShowPage(menu, nullptr); + }); + } + + // A tap (or Enter / Right) on a submenu's entry or on Back turns the page, the menu kept open + static bool TurnPage(QMenu* menu, QEvent* event) { + if (event->type() == QEvent::KeyPress) { + const int key = static_cast(event)->key(); + if (key != Qt::Key_Return && key != Qt::Key_Enter && key != Qt::Key_Right && + key != Qt::Key_Left) { + return false; + } + } else if (event->type() != QEvent::MouseButtonRelease) { + return false; + } + QAction* active = menu->activeAction(); + if (!active || !active->isEnabled()) { + return false; + } + QVariantList pages = menu->property("gamescope_pages").toList(); + const bool is_left = event->type() == QEvent::KeyPress && + static_cast(event)->key() == Qt::Key_Left; + if (active->property("gamescope_back").isValid() || (is_left && !pages.isEmpty())) { + pages.removeLast(); + } else if (auto* sub = qobject_cast(active->property("gamescope_sub").value()); + sub && !is_left) { + pages.append(QVariant::fromValue(sub)); + } else { + return false; + } + menu->setProperty("gamescope_pages", pages); + auto* page = pages.isEmpty() ? nullptr : qobject_cast(pages.last().value()); + ShowPage(menu, page); + return true; + } + + // Shows the menu's own entries (page null) or a submenu's, submenus as entries ending in › + static void ShowPage(QMenu* menu, QMenu* page) { + for (QAction* action : menu->actions()) { + if (action->property("gamescope_added").isValid()) { + menu->removeAction(action); + action->deleteLater(); + } else if (action->property("gamescope_hidden").isValid()) { + action->setVisible(true); + action->setProperty("gamescope_hidden", QVariant{}); + } + } + const QList own = menu->actions(); + QAction* first = own.isEmpty() ? nullptr : own.first(); + const auto add = [menu](QAction* added, QAction* before) { + added->setProperty("gamescope_added", true); + menu->insertAction(before, added); + }; + if (page) { + for (QAction* action : own) { + if (action->isVisible()) { + action->setVisible(false); + action->setProperty("gamescope_hidden", true); + } + } + QMetaObject::invokeMethod(page, "aboutToShow"); + auto* back = new QAction(QStringLiteral("‹ ") + tr("Back"), menu); + back->setProperty("gamescope_back", true); + add(back, first); + auto* separator = new QAction(menu); + separator->setSeparator(true); + add(separator, first); + for (QAction* original : page->actions()) { + if (!original->isVisible()) { + continue; + } + QAction* copy = nullptr; + if (original->isSeparator()) { + copy = new QAction(menu); + copy->setSeparator(true); + } else if (QMenu* sub = original->menu()) { + copy = new QAction(original->icon(), original->text() + QStringLiteral(" ›"), menu); + copy->setEnabled(original->isEnabled()); + copy->setProperty("gamescope_sub", QVariant::fromValue(sub)); + } else { + copy = new QAction(original->icon(), original->text(), menu); + copy->setEnabled(original->isEnabled()); + copy->setCheckable(original->isCheckable()); + copy->setChecked(original->isChecked()); + connect(copy, &QAction::triggered, original, [original] { original->trigger(); }); + } + add(copy, first); + } + } else { + for (QAction* action : own) { + QMenu* sub = action->menu(); + if (!sub || !action->isVisible()) { + continue; + } + // (A hidden action reads as disabled: its state is taken first) + const bool enabled = action->isEnabled(); + action->setVisible(false); + action->setProperty("gamescope_hidden", true); + auto* entry = new QAction(action->icon(), action->text() + QStringLiteral(" ›"), menu); + entry->setEnabled(enabled); + entry->setProperty("gamescope_sub", QVariant::fromValue(sub)); + add(entry, action); + } + } + if (!menu->isVisible()) { + return; + } + // An open menu turning its page: sized again and kept on the screen + menu->adjustSize(); + if (QScreen* screen = menu->screen()) { + const QRect area = screen->availableGeometry(); + QPoint at = menu->pos(); + at.setX((std::max)(area.left(), (std::min)(at.x(), area.right() - menu->width()))); + at.setY((std::max)(area.top(), (std::min)(at.y(), area.bottom() - menu->height()))); + menu->move(at); + } + } + + QWidget* main; +}; +} // namespace + +bool IsRunningUnder() { + return qEnvironmentVariableIsSet("GAMESCOPE_WAYLAND_DISPLAY") || + qgetenv("XDG_CURRENT_DESKTOP") == "gamescope"; +} + +// Opening a folder starts the desktop's file manager, which can't show under gamescope (in Game +// Mode it doesn't even reach a display): folders and files open in Eden's own file browser +class FolderBrowser final : public QObject { + Q_OBJECT + +public: + explicit FolderBrowser(QWidget* main_) : QObject(main_), main{main_} {} + +public slots: + void Open(const QUrl& url) { + const QFileInfo info(url.toLocalFile()); + const QString folder = info.isDir() ? info.absoluteFilePath() : info.absolutePath(); + QWidget* parent = QApplication::activeWindow() ? QApplication::activeWindow() : main; + QFileDialog browser(parent, folder); + browser.setOption(QFileDialog::DontUseNativeDialog); + browser.setFileMode(QFileDialog::ExistingFiles); + browser.setLabelText(QFileDialog::Reject, tr("Close")); + browser.setDirectory(folder); + if (!info.isDir()) { + browser.selectFile(info.fileName()); + } + browser.exec(); + } + +private: + QWidget* main; +}; + +void FitDialogsAndMenus(QWidget* main) { + if (IsRunningUnder()) { + qApp->installEventFilter(new GamescopeDialogs(main)); + QDesktopServices::setUrlHandler(QStringLiteral("file"), new FolderBrowser(main), "Open"); + } +} + +} // namespace Gamescope + +#include "gamescope.moc" diff --git a/src/yuzu/util/gamescope.h b/src/yuzu/util/gamescope.h new file mode 100644 index 0000000000..fd6e9c95cd --- /dev/null +++ b/src/yuzu/util/gamescope.h @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +class QWidget; + +// Steam's Game Mode runs Eden under gamescope, which shows one window at a time, scaled to fit +// the screen, with no title bars, and only one popup over it +namespace Gamescope { + +/// Whether Eden runs under gamescope +bool IsRunningUnder(); + +/// Under gamescope only: fits Eden's dialogs and menus to how gamescope shows windows +/// (see gamescope.cpp). `main` is the main window. +void FitDialogsAndMenus(QWidget* main); + +} // namespace Gamescope diff --git a/src/yuzu/util/overlay_dialog.cpp b/src/yuzu/util/overlay_dialog.cpp index 2d50f22acb..da74fc3772 100644 --- a/src/yuzu/util/overlay_dialog.cpp +++ b/src/yuzu/util/overlay_dialog.cpp @@ -12,6 +12,7 @@ #include "hid_core/hid_types.h" #include "ui_overlay_dialog.h" #include "yuzu/util/overlay_dialog.h" +#include "yuzu/util/gamescope.h" namespace { @@ -29,8 +30,12 @@ OverlayDialog::OverlayDialog(QWidget* parent, Core::System& system, const QStrin : QDialog(parent), ui{std::make_unique()}, use_rich_text{use_rich_text_} { ui->setupUi(this); + // Under gamescope only one normal window shows at a time: a window bypassing the window + // manager is drawn over the game instead of in its place + const bool gamescope = Gamescope::IsRunningUnder(); setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowTitleHint | - Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint); + Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint | + (gamescope ? Qt::X11BypassWindowManagerHint : Qt::WindowFlags{})); setWindowModality(Qt::WindowModal); setAttribute(Qt::WA_TranslucentBackground); diff --git a/tools/optimize-assets.sh b/tools/optimize-assets.sh index a9b2888648..7f0a17e7ac 100755 --- a/tools/optimize-assets.sh +++ b/tools/optimize-assets.sh @@ -8,3 +8,8 @@ NPROC=$(nproc 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n # shellcheck disable=SC2038 find . -type f -iname '*.png' | xargs -P "$NPROC" -I {} optipng -o7 {} + +which svgo || exit + +# shellcheck disable=SC2038 +find . -type f -iname '*.svg' | xargs -P "$NPROC" -I {} svgo {}