Compare commits

..

42 Commits

Author SHA1 Message Date
PavelBARABANOV a72d30642f Fixed Sacred 2 Remaster - added indexed texture handles support 2026-11-01 06:09:38 +01:00
PavelBARABANOV 05b4d7f4cc Fixed Civilization VII - added TIR mixed samples support 2026-11-01 06:09:38 +01:00
PavelBARABANOV 5ac896fbd7 lic 2026-11-01 06:09:38 +01:00
PavelBARABANOV 53e7a51d2e Fixed Disco Elysium - bug in swapped abs/neg bits in F2I decoding 2026-11-01 06:09:38 +01:00
crueter db83070bf2 [meta] Add FUNDING.yml (#4613)
Forgejo 17.0.0 adds support for FUNDING.yml, this also shows up on
GitHub.

Signed-off-by: crueter <crueter@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.
- [x] I have read and followed the [website policy](https://git.eden-emu.dev/eden-emu/site-policy).
- [x] 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.
- [x] I affirm that, by submitting this pull request, I am responsible for all of the changes contained within these commits.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4613
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-11-01 05:16:02 +01:00
crueter e903d70d9e [docs] Add site policy, disallow AI-written PRs/issues and spam (#4612)
The spam got a little out of hand.

Site policy also disallows things such as asking for donations without
giving back to us, piracy, large file uploads, illegal stuff, and more.

Signed-off-by: crueter <crueter@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.
- [x] I have read and followed the [website policy](https://git.eden-emu.dev/eden-emu/site-policy).
- [x] 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.
- [x] I affirm that, by submitting this pull request, I am responsible for all of the changes contained within these commits.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4612
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: John <john@eden-emu.dev>
2026-11-01 03:19:27 +01:00
lizzie 802531c457 [ports/*] Fix cross-compilation issues (#4493)
OpenSSL needs a patch to properly cross compile under rv64; fix infinite recursion with A32 thunks.
Updated cross build guide as well.

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4493
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-11-01 03:12:55 +01:00
lizzie bd071e3464 [dynarmic] Add A64:SM4/SM3 tests (#4513)
Trivial change for upcoming work.

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4513
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-11-01 03:12:03 +01:00
lizzie a845100bf0 [cmake] Cleanup dynarmic's CMake (#4365)
Removes a handful of unused/untested features (like disabling CPU detection)
and brings the CMake of dynarmic more in line with the rest of the build system.

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4365
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-11-01 03:11:26 +01:00
PavelBARABANOV 943f1fc760 [gpu_thread] drop affinity pinning, fix BOTW perf regression (#4603)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4603
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-30 19:55:35 +01:00
crueter 072da77516 [android] Replace GitHub Icon with Forgejo icon in About page (#4535)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Authored-by: Nathantendo <204940629+Nathantendo@users.noreply.github.com>

Co-authored-by: Nathantendo <204940629+Nathantendo@users.noreply.github.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4535
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-10-30 16:45:11 +01:00
PavelBARABANOV 035f4611cb [vk_rasterizer] Fix viewport Y flip for negative scale_y (#4558)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
credit: ReiKatari

Aggelos 1/2 viewport fix

https://github.com/ReiKatari/STORM_SWITCH/commit/ff269fbb49388c1b90cd97b944365629e0fcc164
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4558
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2026-10-30 05:05:24 +01:00
PavelBARABANOV ea92c081b7 [core] Speed up NCZBLOCK reads and skip double AES for pre-decrypted NCZ (#4582)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
- Use a 32-slot direct-mapped block cache and reuse one ZSTD_DCtx per
  BlockReader instead of re-creating it per block.
- Find the covering section with std::lower_bound instead of a linear scan
  (helps BKTR updates with thousands of sections).
- Mark BlockNczFile as HasDecryptedSections() and drop its CTR pass; NCZ
  body is stored decrypted, so NcaFileSystemDriver now skips its AES layers
  for these files (no double decryption).
- Recognize .xcz as XCZ in AppLoader_XCI::IdentifyType.

thanks Reikatari

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4582
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-10-30 04:40:15 +01:00
Soar Qin 69665063a9 [cheats] add runtime cheats toggles with master code support (#4334)
add per-cheat runtime toggles (thread-safe).
add master code handling (master code cannot be disabled, as noted in Atmosphere's implementation).
add configurable global / per-game initial states for cheat entries.
remove fixed opcode limits and do some fixes to text parsing / file loading.
do not run debug log while cheat logging is not enabled, to reduce performance impacts.
update the `Using Cheats` document to reflect the changes.

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4334
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: John <john@eden-emu.dev>
2026-10-30 03:47:38 +01:00
xbzk b4d5760014 [video_core] Revert 4490 and 4531 (#4584)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
Reverting NCE Invalidation readbacks. Me and Maran had discussed the risk of this be costly without alternative before.
After 2 or 3 weeks, a new regression has shown up: Pavel's device gets slow as fuck in DKCR.

I've prolly tackled that one too, but i don't like the solution anymore.
I had to infiltrate so much stuff that the weight of be working on the symptom instead of the root cause has grown way too much.

I'm reverting so we can get a clean base, then i will research deeper so we can maybe find a more surgical yet wider fix.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4584
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: Pavel Barabanov <pavelbarabanov94@gmail.com>
2026-10-30 03:26:33 +01:00
PavelBARABANOV 0731f40f4d [video_core/host1x] VP9 Video Playback Fixes (#4590)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
https://git.eden-emu.dev/eden-emu/eden/pulls/4542

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4590
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: John <john@eden-emu.dev>
2026-10-30 03:06:33 +01:00
PavelBARABANOV 3e6a5566cf [vk] handles unreachable unknown format 255 error (#4591)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
https://git.eden-emu.dev/eden-emu/eden/pulls/4529

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4591
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-10-30 02:47:10 +01:00
PavelBARABANOV d89e02d3ac [emit_spirv_image] remove the fix for LA/EOW (#4589)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
this is no longer needed; https://github.com/StevenMXZ/Adreno-Tools-Drivers/releases/tag/gamesir completely fixes these games

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4589
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-10-30 02:26:33 +01:00
crueter a2aa4d97e1 [docs] Remove AI restrictions, and adapt to new open registration (#4585)
Registration is now open. Enjoy

Signed-off-by: crueter <crueter@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4585
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-10-29 17:10:37 +01:00
John 26a03d2473 Revert "[video_core] Improve asynchronous shader building (#2560)" (#4512)
Restores performance but need to check TOTK item icons and Jamboree graphic issues.

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4512
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2026-10-26 17:26:32 +01:00
xbzk b7c1ded159 [file_sys] added log for newer keys needed error (#4519)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
One log line which could have spared me from a lot of trouble.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4519
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2026-10-26 17:26:07 +01:00
John cbd4cf2d8c [hle][core] Hang Freeze Fix - Video Fixes - Revert Microsleep (#4316) (#4525)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Credit: amicuchu
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

- Fixes Mario Strikers Intro Freezing from legacy.
- Microsleep no longer needed for Absolum Video freezing and other videos freezing.
- Revert `[service, nvhost] added machinery to allow microsleep between nvdec read requests to avoid guest panic in some games #4316`
- Tested with CPU/GPU decoding on Linux/Windows.
Special thanks to xbzk

<video src="/attachments/9f4a4494-78ee-4b65-ad26-628e83d5c83b" title="strikers" controls></video>

Co-authored-by: Your Name <John@John.localdomain>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4525
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2026-10-26 17:25:47 +01:00
PavelBARABANOV a3debcf731 [buffer_cashe] use old logic when Optimized Vertex Buffers is disabled (#4528)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
Fixes vertex explosions on Turnip. Fixes Celeste on QCOM. Fixes new issues discovered after #3579

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4528
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2026-10-26 17:25:24 +01:00
xbzk 5239cbe2a7 [nce] handles duplicate NCE interrupts (#4530)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
Another crash observed in Ender Magnolia: A deadlock caused between CPUCore_0/GPU/GPUFencingThread.

CPUCore_0 waits for GPU work inside the NCE fault handler
GPU waits for the syncpoint mutex
GPUFencingThread holds that mutex while waiting for CPUCore_0 NCE interrupt lock

The fix makes duplicate interrupts return before acquiring the lock, while the first request keeps its original behavior.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4530
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2026-10-26 17:24:45 +01:00
xbzk 0e11fe8b5e [video_core, settings] readback for nce invalidations (#4490) optimization and nuke toggles (#4502) (#4531)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Follow up for #4490: Originally i was racing locks between dirty and clean invalidations, but +94% were clean so it was causing useless locks. Solutioin was to share locks between both.

P.S.: THIS IS INTENDED TO FIX RANDOM CRASHES IN UE, OBJECTIVELY REPRODUCIBLE IN ENDER MAGNOLIA IN ANDROID.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4531
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2026-10-26 17:24:28 +01:00
xbzk 0689f73147 [ir] resolve conditional Phi inputs when tracking bindless texture handles (#4551)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
Aimed to fix Ender Magnolia missing shader textures. Main example is Yolvan character bullets.

By using windows version of the game, dxvk lib to make it vulkan, and renderdoc, it was possible to capture bullets, and by tracking backward composition and comparing with a similar scene from eden with missing bullets, it was possible to unveil the missing functionality: conditional Phi inputs resolve for bindless handles.
By ignoring the boolean predicate register in the shader, handles for these shaders were resolving to some old value instead of proper live conditional ones.

TESTS:
-Compare Yolvan bullets
-Usual roam on main titles for regression check.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4551
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2026-10-26 17:24:00 +01:00
wildcard a95efaf18f [vulkan] Fix TOTK dark squares (#4565)
Qualcomm and Turnip use different subpixel rounding for Vulkan texture
gather coordinates than the Switch's Maxwell GPU. This can select the
wrong texels near texture boundaries, producing large black squares in TOTK

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4565
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2026-10-26 17:23:45 +01:00
PavelBARABANOV 58968bd127 [core] Support block-compressed NSZ and XCZ (#4552)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
- Add NCZBLOCK (nsz -B / .xcz) reader: each read decodes only the covered blocks and re-encrypts CTR sections, no disk output.
- Allow installing solid .nsz to NAND via DecompressNCZForInstall (lazy, incremental decode with frontier, O(n) instead of O(n^2)).
- Accept BKTR updates with thousands of sections (MaxSectionCount = 0x10000).
- Wire .nsz/.xcz into loader, registered cache, scanner, and NAND install (content_manager.h), and reject solid NCZ from the game list.
- Bump the pinned zstd to 33618c8 in cpmfile.json, which includes the upstream AArch64 revert ([33618c89](https://github.com/facebook/zstd/commit/33618c89e511637f8a6ef955b3501766d71feb53)) for a ZSTD_decodeSequence branch optimization that could corrupt data on ARM64; without it, solid NCZ decoding on Android fails with "Data corruption detected".

NCZ format and CTR counter semantics follow the reference nsz tool and its
Rust port:
- https://github.com/nicoboss/nsz (Decompressor.py, BlockDecompressorReader.py)
- https://docs.rs/nsz-rs/0.3.0/src/nsz_rs/decompress.rs.html

The last-block edge case (decompressed size is an exact multiple of block
size) is handled as described in https://github.com/nicoboss/nsz/issues/210

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4552
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2026-10-26 17:23:18 +01:00
PavelBARABANOV 05f36d990c [chore] re-add out/ to .gitignore (#4578)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4578
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-26 16:23:23 +01:00
PavelBARABANOV eb88a40a8e [qt] fix graphics API toggle getting stuck on OpenGL_GLSL (#4577)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4577
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-25 16:06:46 +01:00
PavelBARABANOV 305f40100d Fix aarch and android builds (#4576)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
credit: John and Crueter

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4576
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-10-25 10:03:16 +01:00
John 989768aa46 Fix [core, gpu, threads] Multithreading refactor (#4254) (#4548)
Performance loss regression fixed in Link's Awakening, Castlevania, Super Mario RPG, etc

Tested by Mr. Knobs on Android and myself on Linux

Multicore ON may be fixed for some users using Intel CPUs.
Games include: FF Tactics, Shredder's Revenge, Unity Engine Games.

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4548
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-10-19 15:58:04 +02:00
John de7e6e01d4 Revert [input_common/joycon] Enumerate SDL devices iff SDL signals change (#4486) (#4545)
Due to causing the platform windows to crash when a controller is activated.

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Co-authored-by: Your Name <John@John.localdomain>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4545
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-10-18 00:17:28 +02:00
crueter e0d47f2790 [cmake] fix macOS compilation by forcing lz4 to be static (#4540)
Signed-off-by: crueter <crueter@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4540
2026-10-16 21:41:11 +02:00
PavelBARABANOV d8c6c59b67 Fix Check Strings after 4523 (#4534)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4534
2026-10-16 01:17:53 +02:00
xbzk aaa0bcb9bf [patcher, ro, settings] runtime tls patch (#4492) optimization and nuke toggle (#4502) (#4523)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
This is a follow up for the biomutant fix. By the time i knew it was shallow, coz i was running patchtext routine even for svc and modules, causing a routine which were needed to run 14 times to run 4000+ instead.
Since some perf loss was reported in 30 sep nightly, and it caused ac3r to not boot, we had added a temp toggle, which is now being removed as optimizations + fix are in.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4523
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-10-15 12:13:17 +02:00
PavelBARABANOV e255c20db4 Revert "[hle] constexpr handler dispatch maps, introduce version gating (#4480)" (#4532)
This reverts commit 218c6705d9.

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4532
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-10-15 08:45:15 +02:00
lizzie 14da4482a4 [input_common/joycon] Enumerate SDL devices iff SDL signals change (#4486)
As per SDL documentation this is the "desired" loop.

> Enumerating the HID devices is an expensive operation, so you can call this to see if there have been any system device changes since the last call to this function. A change in the counter returned doesn't necessarily mean that anything has changed, but you can call SDL_hid_enumerate() to get an updated device list.

https://wiki.libsdl.org/SDL3/SDL_hid_device_change_count

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4486
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-14 21:24:58 +02:00
lizzie fb51a12534 [input/sdl] nuke SDL_Vibration thread (#4299)
Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

isn't it net faster to just...send things, serially?
especially since vibration occurs so non-often...
i dont think it would cause any issues

TEST: if this causes ANY sort of perf regression on games
when the thing vibrates WITH AN SDL CONFIGURED GAMEPAD OR WHATEVER

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4299
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-14 21:24:35 +02:00
CamilleLaVey a594c8d60e [shader_recompiler, vulkan, qcom, tu] Provide handling to missing shader subgroups on QCOM (#4508)
This works provides better emulation on certain GS missing for shader invocation data + geometry pass fallback in qcom/turnip drivers, some of those were provided as community patch by @a.kamaltdinov; which was refined to address the requirements on forced gpu reads; which used to kill some performance on low end devices; now, the stability with some of the graphical problems have been addressed and balanced. Shuffle shaders (SHFFL) are not actually provided on QCOM and turnip drivers, so any game that previously required this stage draw, will now avoid being ignored and tax some performance based on the complexity of the stage draw from now on. This will also address partially some tessellation problems as well.

_Special Thanks:_

1.- @a.kamaltdinov (for the initial patch "early fix for nier" provided for #4325)
2.- @PavelBARABANOV (because the making the cherry-pick easier for a new PR)

Co-authored-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4508
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-10-14 00:04:16 +02:00
crueter 6b3cb5772b [docs] revise AI policy (#4522)
spent 2 hours on a document award

This is a revised version of our original AI policy that is cautiously
permissive to skilled developers using AI responsibly, while hopefully
keeping out the script kiddies spamming their mom's credit card on
Claude tokens.

This will be trialed for at least a week once merged, any
revisions/changes should be made within the next few months

Signed-off-by: crueter <crueter@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4522
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-10-13 23:54:51 +02:00
lizzie 218c6705d9 [hle] constexpr handler dispatch maps, introduce version gating (#4480)
This PR primarily focuses on upbringing constexpr maps for handlers.

Each time an HLE object of a service is construed, it registers it's own handlers, over and over.
Regardless of whetever it needs them at the moment or not.
Additionally we don't require to keep track of different function pointers amongst each object.
This can be done by overriding the given function instead, as opposed to having a separate
hash map for every given object.

In other words: Remove handlers (and handlers_tipc) map for every instance
then read from a static defined per-class.

- [x] Migrate all HLE functions to new `frozen::map` constexpr time finder
- [ ] Measure if this approach actually makes better codegen

Optional:
- [x] Properly gate all functions (that have versions commented next to them)
- [x] Maybe store `HandlerFnP<>` and `const char*` separately, version gating can go in a different map as well

Information such as name can be used on debug builds, but doesn't particularly help on release as one can consult an external reference (or have an annotated IPC map)

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Co-authored-by: Maufeat <sahyno1996@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4480
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-10-13 04:38:36 +02:00
527 changed files with 3941 additions and 947 deletions
+2
View File
@@ -0,0 +1,2 @@
liberapay: crueter
custom: 'https://www.paypal.biz/edenemulator'
+4 -1
View File
@@ -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 [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 [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.
------------------- -------------------
+1
View File
@@ -7,6 +7,7 @@
# Build directory # Build directory
/[Bb]uild*/ /[Bb]uild*/
doc-build/ doc-build/
out/
AppDir/ AppDir/
uruntime uruntime
@@ -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}
+10 -1
View File
@@ -1 +1,10 @@
AI and LLM use is *strictly* prohibited within our codebase and surrounding community, including issues and comments. This includes using AI or LLMs to write docs/commit messages, debug issues, brainstorm ideas, research concepts, or search the codebase. # AGENTS
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, 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.
-1
View File
@@ -1 +0,0 @@
AI and LLM use is *strictly* prohibited within our codebase and surrounding community, including issues and comments. This includes using AI or LLMs to write docs/commit messages, debug issues, brainstorm ideas, research concepts, or search the codebase.
+1 -1
View File
@@ -24,7 +24,7 @@ else()
endif() endif()
if (lz4_FOUND AND NOT TARGET lz4::lz4) if (lz4_FOUND AND NOT TARGET lz4::lz4)
if (TARGET LZ4::lz4_shared) if (TARGET LZ4::lz4_shared AND NOT YUZU_STATIC_BUILD)
add_library(lz4::lz4 ALIAS LZ4::lz4_shared) add_library(lz4::lz4 ALIAS LZ4::lz4_shared)
elseif (TARGET LZ4::lz4_static) elseif (TARGET LZ4::lz4_static)
add_library(lz4::lz4 ALIAS LZ4::lz4_static) add_library(lz4::lz4 ALIAS LZ4::lz4_static)
+33 -37
View File
@@ -1,9 +1,5 @@
# Contributing # Contributing
<!--
This document is not to be perused by AI models.
-->
Eden has lots of different ways that you can contribute to its efforts, even without knowing how to write code: Eden has lots of different ways that you can contribute to its efforts, even without knowing how to write code:
- Donate! This will help us live our lives, pay for infrastructure/testing hardware, and more - Donate! This will help us live our lives, pay for infrastructure/testing hardware, and more
@@ -20,18 +16,38 @@ Eden is free, open-source, copyleft software, licensed under the terms of the [G
### Policies ### Policies
- No LLM or AI usage, *period*, for patches, pull requests, issues, comments, debugging, brainstorming, etc. - 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:
- For details on why, see the [detailed AI policy](docs/policies/AI.md). - As a common courtesy, please disclose your AI usage under the PR description, as `Assisted-by: <AI model> (<how it helped>)`.
- Usage of any form of profanity or otherwise unsavory language is generally discouraged. - All PR descriptions, issue bodies, and comments **must** be written by you, in your own words.
- This is primarily because it rarely helps to actually understand what's going on. - 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.
- Remember that your comments should be focused and actually address what's happening. With very few exceptions, expletives are actively detrimental at best. - 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.
- New code must follow the same general style as the surrounding codebase. Exceptions may be granted in certain cases. - 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. - 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. - 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. - 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. - 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? ### 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. 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.
@@ -43,7 +59,10 @@ You may also search for open issues on [GitHub](https://github.com/eden-emulator
There are five primary ways to contribute. There are five primary ways to contribute.
- Submit pull requests directly to our source tree - 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) - 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. - 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) - Submit pull requests to our [Codeberg mirror](https://codeberg.org/eden-emu/eden)
@@ -53,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. - 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. - 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. 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.
### How do I sign up?
<details>
<summary>To sign up and begin contributing... (click to open)</summary>
Email [crueter@crueter.xyz](mailto:crueter@crueter.xyz) with the following format:
```txt
Subject: [Eden Git] Registration Request
Username: <Your Desired Username>
Email: <Your Desired Email>
I wish to sign up because... <your reason here>
```
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.
</details>
## Non-code Contributions ## 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. 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).
+4 -3
View File
@@ -202,7 +202,8 @@
"0001-cpmutil-compat.patch", "0001-cpmutil-compat.patch",
"0002-use-ccache.patch", "0002-use-ccache.patch",
"0003-use-cmake-compiler-flags.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", "repo": "jimmy-park/openssl-cmake",
"version": "3.6.2" "version": "3.6.2"
@@ -351,13 +352,13 @@
}, },
"zstd": { "zstd": {
"find_args": "MODULE", "find_args": "MODULE",
"hash": "cc5ad4b119a9c2ea57f0b71eeff01113bb506e0d17000159c5409cb8236d22e38c52d5e9e97e7947a4bf1b2dfc44b6c503ab2d9aedbd59458435c6a2849cb029", "hash": "2b006c3c110c38bd2f5896b42d36a38931c8eae261f30552f9a9fd04458d218d8f1a1425f117fd12af545ed77042e4b2d1a1a9b6286c4d0b9d74ef79f20a8f08",
"min_version": "1.5", "min_version": "1.5",
"options": [ "options": [
"ZSTD_BUILD_SHARED OFF" "ZSTD_BUILD_SHARED OFF"
], ],
"repo": "facebook/zstd", "repo": "facebook/zstd",
"source_subdir": "build/cmake", "source_subdir": "build/cmake",
"version": "b8d6101fba" "version": "33618c8"
} }
} }
+25 -4
View File
@@ -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. 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` ```sh
- Download Debian 13: `wget https://cdimage.debian.org/debian-cd/current/arm64/iso-cd/debian-13.0.0-arm64-netinst.iso` #!/bin/sh
- Create a system disk: `qemu-img create -f qcow2 debian-13-arm64-ci.qcow2 30G` ISO_FILE="debian-13.0.0-arm64-netinst.iso"
- 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` 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 ## Gentoo
-19
View File
@@ -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`. 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 ## 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). 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).
-116
View File
@@ -1,116 +0,0 @@
# AI Policy
AI and LLM use is *strictly* prohibited within our codebase and surrounding community, including issues and comments. This includes using AI or LLMs to write docs/commit messages, debug issues, brainstorm ideas, research concepts, or search the codebase.
- [AI Policy](#ai-policy)
- [Low-quality code](#low-quality-code)
- [Licensing concerns](#licensing-concerns)
- [Vibe-coding](#vibe-coding)
- [Commit messages](#commit-messages)
- [Miscellaneous concerns](#miscellaneous-concerns)
- [Unacceptable Use Examples](#unacceptable-use-examples)
- [Addendum: Commit Messages](#addendum-commit-messages)
## Low-quality code
AI is notorious for producing low-quality code; be it:
- nonfunctional,
- verbose/inefficient,
- breaking other parts of the codebase,
- or writing/architecting in a completely different style
All code, AI or not, is held under a **strict standard of excellence**. AI/LLM-generated code will fail this test 10 times out of 10.
## Licensing concerns
This is an area of ongoing litigation, and as such, is still very iffy. For the time being, know that allowing AI to ingest the codebase may end up with its copyleft code regurgitated into incompatibly-licensed proprietary or permissive software. For you, this means to **not** feed code into LLMs.
AI models may have also ingested AGPLv3 code, which is license-incompatible with our codebase.
## Vibe-coding
Just don't. If you're not going to put the effort in to understand every line of code you wrote, neither will we, and your patch or pull request will be ignored.
## Commit messages
AI-generated commit messages are absolutely terrible, and your pull request or patch will immediately be rejected if you choose to do this. They are, quite simply, actively detrimental to our understanding of your changes, and if you're not willing to summarize the intent behind your changes, then we're not going to bother reading the code you wrote.
Write concise, simple, and descriptive commit messages that actually convey the proper intent behind what your change is trying to do.
See the [Addendum](#addendum-commit-messages) for an instance of how bad AI models are at commit messages.
## Miscellaneous concerns
- While many environmental concerns about AI are typically blown out of proportion, it *is* a legitimate issue, and should be taken into account.
- Many people have significant concerns over the ethics of AI usage due to inhumane and predatory behavior by large AI companies, particularly Anthropic and OpenAI. This can technically be avoided through the usage of local LLMs.
- LLMs have a tendency to add unicode characters (such as the arrow → and the em-dash — symbols) to their output, which can make viewing code or documents harder on command-line editors and viewers.
- Dedicated coding models--namely Claude--also like to add a lot of comments to overexplain every individual line of code it produces. This actually makes it *harder* to understand the code!
## Unacceptable Use Examples
Here are a few examples of unacceptable use:
- Solving problems
- Slapping a few files and a "please fix bug XYZ" into an LLM is a recipe for disaster that will pretty much never work.
- Fully AI-generated code, aka "vibecoding"
- Writing code based on pseudo-instructions
- If you don't know how to write code, don't. If you've figured out the root cause (preferably without feeding random files into an LLM) and actively know what's going on, provide information to other developers or friends of yours who have knowledge of the language and/or the codebase.
## Addendum: Commit Messages
The patchset for pull request [#3422](https://git.eden-emu.dev/eden-emu/eden/pulls/3422) was fed into several LLMs to generate a commit message. One LLM 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
Another (code-oriented) LLM output the following:
```txt
profile(manager/ui): switch to index-based deletion and unify removal logic
- Make ConfigureProfileManagerDeleteDialog emit a deleteUser(int) signal instead of taking a callback. Store the target index in the dialog (m_index) and emit it on acceptance.
- Change ConfigureProfileManager to pass an index to SetInfo and to accept an index in DeleteUser. Wire the dialog signal to the new DeleteUser slot.
- Update headers: add the signal and m_index, add TODO to move dialog to a .ui file, and update slot/signature declarations.
- Add ProfileManager::RemoveProfileAtIndex(std::size_t) and refactor RemoveUser(UUID) to call RemoveProfileAtIndex to avoid duplicated removal logic. Ensure the removal path marks saves as needed and writes the user save file.
- Ensure the profile list updates immediately after deletes by calling profile_manager.ResetUserSaveFile() when populating the user list (qlaunch fix).
- Misc: update SPDX copyright year and fix build breakages caused by the API changes.
This consolidates profile removal behavior, fixes potential race conditions in the profile dialog, and removes duplicated removal code.
```
This has all of the same problems as the other one. Needlessly verbose, doesn't address *what* it actually fixes ("consolidates profile removal behavior"... okay, why? What does it fix?), etc. It even has the bonus of totally hallucinating the addition of a method!
On a more "philosophical" note, LLMs tend to be geared towards *corporate language*, as that's what they're trained on. This is why AI-generated commit messages feel like "word salad", and typically pad out the commit message to make it *look* like a lot of things were changed (trust me, it's like that in the corporate world). They typically also drift towards unneeded buzzwords and useless implementation details.
+13 -4
View File
@@ -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. ***INFO***: Make sure you select the correct directory or it will not work, the screen should show the **cheats** sub-directory.
</aside> </aside>
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 ### 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. 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 ### 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. 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. 3. *Select/Deselect* the name of the cheat you wish to enable/disable.
4. Click **OK** to close the window. 4. Click **OK** to close the window.
5. Launch the game to confirm the cheat is/is not active. 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.
+5 -5
View File
@@ -101,6 +101,11 @@ endfunction()
# ia64 exists # ia64 exists
# the rest exist, but are probably less popular than ia64 # the rest exist, but are probably less popular than ia64
detect_architecture_symbols(
ARCH wasm
SYMBOLS
"__EMSCRIPTEN__")
detect_architecture_symbols( detect_architecture_symbols(
ARCH arm64 ARCH arm64
SYMBOLS SYMBOLS
@@ -203,11 +208,6 @@ detect_architecture_symbols(
"__loongarch__" "__loongarch__"
"__loongarch64") "__loongarch64")
detect_architecture_symbols(
ARCH wasm
SYMBOLS
"__EMSCRIPTEN__")
# "generic" target # "generic" target
# If you have reached this point, you're on some as-of-yet unsupported architecture. # If you have reached this point, you're on some as-of-yet unsupported architecture.
# See the docs up above for known unsupported architectures # See the docs up above for known unsupported architectures
+1 -1
View File
@@ -259,7 +259,7 @@ android {
externalNativeBuild { externalNativeBuild {
cmake { cmake {
version = "3.31.6" version = "3.31.5"
path = file("${edenDir}/CMakeLists.txt") path = file("${edenDir}/CMakeLists.txt")
} }
} }
@@ -34,6 +34,13 @@ import org.yuzu.yuzu_emu.applets.web.WebBrowser
* with the native side of the Yuzu code. * with the native side of the Yuzu code.
*/ */
object NativeLibrary { object NativeLibrary {
@Keep
class RuntimeCheat(
val id: Int,
val name: String,
val enabled: Boolean,
val isMaster: Boolean
)
@Keep @Keep
data class UpdateResult( data class UpdateResult(
var tag: String = "", var tag: String = "",
@@ -197,6 +204,9 @@ object NativeLibrary {
*/ */
external fun isPaused(): Boolean external fun isPaused(): Boolean
external fun getRuntimeCheats(): Array<RuntimeCheat>
external fun setRuntimeCheatEnabled(id: Int, enabled: Boolean): Boolean
/** /**
* Returns the performance stats for the current game * Returns the performance stats for the current game
*/ */
@@ -13,11 +13,10 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
FASTMEM("cpuopt_fastmem"), FASTMEM("cpuopt_fastmem"),
FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives"), FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives"),
CORE_SYNC_CORE_SPEED("sync_core_speed"), CORE_SYNC_CORE_SPEED("sync_core_speed"),
ENABLE_CHEATS_BY_DEFAULT("enable_cheats_by_default"),
RENDERER_USE_SPEED_LIMIT("use_speed_limit"), RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"), USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"), SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
NCE_INVALIDATION_GPU_READBACK("nce_invalidation_gpu_readback"),
NCE_RUNTIME_NRO_PATCH("nce_runtime_nro_patch"),
FIX_BLOOM_EFFECTS("fix_bloom_effects"), FIX_BLOOM_EFFECTS("fix_bloom_effects"),
EMULATE_BGR565("emulate_bgr565"), EMULATE_BGR565("emulate_bgr565"),
RESCALE_HACK("rescale_hack"), RESCALE_HACK("rescale_hack"),
@@ -95,7 +94,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
ENABLE_QUICK_SETTINGS("enable_quick_settings"); ENABLE_QUICK_SETTINGS("enable_quick_settings");
// external fun isFrameSkippingEnabled(): Boolean //external fun isFrameSkippingEnabled(): Boolean
external fun isFrameInterpolationEnabled(): Boolean external fun isFrameInterpolationEnabled(): Boolean
override fun getBoolean(needsGlobal: Boolean): Boolean = override fun getBoolean(needsGlobal: Boolean): Boolean =
@@ -316,6 +316,13 @@ abstract class SettingsItem(
descriptionId = R.string.use_sync_core_description 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( put(
SingleChoiceSetting( SingleChoiceSetting(
IntSetting.REGION_INDEX, IntSetting.REGION_INDEX,
@@ -859,20 +866,6 @@ abstract class SettingsItem(
descriptionId = R.string.skip_cpu_inner_invalidation_description 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.NCE_RUNTIME_NRO_PATCH,
titleId = R.string.nce_runtime_nro_patch,
descriptionId = R.string.nce_runtime_nro_patch_description
)
)
put( put(
SwitchSetting( SwitchSetting(
BooleanSetting.FIX_BLOOM_EFFECTS, BooleanSetting.FIX_BLOOM_EFFECTS,
@@ -510,6 +510,7 @@ class SettingsFragmentPresenter(
add(IntSetting.FAST_CPU_TIME.key) add(IntSetting.FAST_CPU_TIME.key)
add(IntSetting.FAST_GPU_TIME.key) add(IntSetting.FAST_GPU_TIME.key)
add(BooleanSetting.CORE_SYNC_CORE_SPEED.key) add(BooleanSetting.CORE_SYNC_CORE_SPEED.key)
add(BooleanSetting.ENABLE_CHEATS_BY_DEFAULT.key)
add(IntSetting.MEMORY_LAYOUT.key) add(IntSetting.MEMORY_LAYOUT.key)
add(BooleanSetting.USE_CUSTOM_CPU_TICKS.key) add(BooleanSetting.USE_CUSTOM_CPU_TICKS.key)
@@ -554,8 +555,6 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.hacks)) add(HeaderSetting(R.string.hacks))
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key) add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
add(BooleanSetting.NCE_INVALIDATION_GPU_READBACK.key)
add(BooleanSetting.NCE_RUNTIME_NRO_PATCH.key)
add(BooleanSetting.FIX_BLOOM_EFFECTS.key) add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
add(BooleanSetting.EMULATE_BGR565.key) add(BooleanSetting.EMULATE_BGR565.key)
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key) add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
@@ -734,6 +734,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.inGameMenu.menu.findItem(R.id.menu_quick_settings)?.isVisible = binding.inGameMenu.menu.findItem(R.id.menu_quick_settings)?.isVisible =
BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean() BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean()
binding.inGameMenu.menu.findItem(R.id.menu_cheats)?.isVisible = false
binding.pausedIcon.setOnClickListener { binding.pausedIcon.setOnClickListener {
if (this::emulationState.isInitialized && emulationState.isPaused) { if (this::emulationState.isInitialized && emulationState.isPaused) {
@@ -817,6 +818,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
R.id.menu_load_amiibo -> handleLoadAmiiboSelection() R.id.menu_load_amiibo -> handleLoadAmiiboSelection()
R.id.menu_cheats -> {
binding.drawerLayout.closeDrawer(binding.inGameMenu)
showRuntimeCheatDialog()
true
}
R.id.menu_controls -> { R.id.menu_controls -> {
val action = HomeNavigationDirections.actionGlobalSettingsActivity( val action = HomeNavigationDirections.actionGlobalSettingsActivity(
null, null,
@@ -962,6 +969,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
emulationState.updateSurface() emulationState.updateSurface()
binding.inGameMenu.menu.findItem(R.id.menu_cheats)?.isVisible =
NativeLibrary.getRuntimeCheats().isNotEmpty()
updateShowStatsOverlay() updateShowStatsOverlay()
updateSocOverlay() updateSocOverlay()
@@ -987,6 +996,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) { emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) {
if (it) { if (it) {
binding.inGameMenu.menu.findItem(R.id.menu_cheats)?.isVisible = false
binding.loadingText.setText(R.string.shutting_down) binding.loadingText.setText(R.string.shutting_down)
ViewUtils.showView(binding.loadingIndicator) ViewUtils.showView(binding.loadingIndicator)
ViewUtils.hideView(binding.inputContainer) ViewUtils.hideView(binding.inputContainer)
@@ -1119,6 +1129,45 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
NativePostProcessing.persist() 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() { private fun addQuickSettings() {
binding.quickSettingsSheet.apply { binding.quickSettingsSheet.apply {
val container = binding.quickSettingsSheet.findViewById<ViewGroup>(R.id.quick_settings_container) val container = binding.quickSettingsSheet.findViewById<ViewGroup>(R.id.quick_settings_container)
@@ -100,7 +100,7 @@ class Game(
companion object { companion object {
val extensions: Set<String> = HashSet( val extensions: Set<String> = HashSet(
listOf("xci", "nsp", "nca", "nro") listOf("xci", "nsp", "nca", "nro", "nsz", "xcz")
) )
} }
} }
@@ -109,7 +109,7 @@ object GameHelper {
// File extensions considered as external content, buuut should // File extensions considered as external content, buuut should
// be done better imo. // be done better imo.
private val externalContentExtensions = setOf("nsp", "xci") private val externalContentExtensions = setOf("nsp", "xci", "nsz", "xcz")
private fun scanContentContainersRecursive( private fun scanContentContainersRecursive(
files: Array<MinimalDocumentFile>, files: Array<MinimalDocumentFile>,
@@ -76,7 +76,9 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobj
auto const file_type = loader->GetFileType(); auto const file_type = loader->GetFileType();
if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error)
return false; 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; return false;
u64 program_id = 0; u64 program_id = 0;
return loader->ReadProgramId(program_id) == Loader::ResultStatus::Success; return loader->ReadProgramId(program_id) == Loader::ResultStatus::Success;
+26
View File
@@ -67,6 +67,7 @@ extern "C" {
#include "core/file_sys/submission_package.h" #include "core/file_sys/submission_package.h"
#include "core/file_sys/vfs/vfs.h" #include "core/file_sys/vfs/vfs.h"
#include "core/file_sys/vfs/vfs_real.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/cabinet.h"
#include "core/frontend/applets/controller.h" #include "core/frontend/applets/controller.h"
#include "core/frontend/applets/error.h" #include "core/frontend/applets/error.h"
@@ -946,6 +947,31 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused(JNIEnv* env, jclass claz
return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused()); return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused());
} }
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getRuntimeCheats(JNIEnv* env, jclass clazz) {
const auto cheats = EmulationSession::GetInstance().System().GetRuntimeCheats();
const auto runtime_cheat_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary$RuntimeCheat");
const auto constructor = env->GetMethodID(runtime_cheat_class, "<init>", "(ILjava/lang/String;ZZ)V");
auto result = env->NewObjectArray(static_cast<jsize>(cheats.size()), runtime_cheat_class, nullptr);
for (jsize i = 0; i < static_cast<jsize>(cheats.size()); ++i) {
const auto& cheat = cheats[i];
const auto name = Common::Android::ToJString(env, cheat.name);
const auto item = env->NewObject(runtime_cheat_class, constructor, static_cast<jint>(cheat.id), name,
static_cast<jboolean>(cheat.enabled),
static_cast<jboolean>(cheat.is_master));
env->SetObjectArrayElement(result, i, item);
env->DeleteLocalRef(name);
env->DeleteLocalRef(item);
}
env->DeleteLocalRef(runtime_cheat_class);
return result;
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setRuntimeCheatEnabled(JNIEnv* env, jclass clazz,
jint id, jboolean enabled) {
return static_cast<jboolean>(EmulationSession::GetInstance().System().SetCheatEnabled(
static_cast<u32>(id), static_cast<bool>(enabled)));
}
jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletCaptureBuffer(JNIEnv* env, jclass clazz) { jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletCaptureBuffer(JNIEnv* env, jclass clazz) {
using namespace VideoCore::Capture; using namespace VideoCore::Capture;
@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="212"
android:viewportHeight="212"
android:width="212dp"
android:height="212dp">
<group
android:translateX="6"
android:translateY="6">
<path
android:pathData="M58 168v-98a50 50 0 0 1 50 -50h20"
android:strokeColor="#FFFFFF"
android:strokeWidth="25" />
<path
android:pathData="M58 168v-30a50 50 0 0 1 50 -50h20"
android:strokeColor="#FFFFFF"
android:strokeWidth="25" />
<path
android:pathData="M160 20A18 18 0 0 1 124 20A18 18 0 0 1 160 20Z"
android:strokeColor="#FFFFFF"
android:strokeWidth="15" />
<path
android:pathData="M160 88A18 18 0 0 1 124 88A18 18 0 0 1 160 88Z"
android:strokeColor="#FFFFFF"
android:strokeWidth="15" />
<path
android:pathData="M76 180A18 18 0 0 1 40 180A18 18 0 0 1 76 180Z"
android:strokeColor="#FFFFFF"
android:strokeWidth="15" />
</group>
</vector>
@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="98dp"
android:height="96dp"
android:viewportWidth="98"
android:viewportHeight="96">
<path
android:fillColor="?attr/colorControlNormal"
android:fillType="evenOdd"
android:pathData="M48.854,0C21.839,0 0,22 0,49.217c0,21.756 13.993,40.172 33.405,46.69 2.427,0.49 3.316,-1.059 3.316,-2.362 0,-1.141 -0.08,-5.052 -0.08,-9.127 -13.59,2.934 -16.42,-5.867 -16.42,-5.867 -2.184,-5.704 -5.42,-7.17 -5.42,-7.17 -4.448,-3.015 0.324,-3.015 0.324,-3.015 4.934,0.326 7.523,5.052 7.523,5.052 4.367,7.496 11.404,5.378 14.235,4.074 0.404,-3.178 1.699,-5.378 3.074,-6.6 -10.839,-1.141 -22.243,-5.378 -22.243,-24.283 0,-5.378 1.94,-9.778 5.014,-13.2 -0.485,-1.222 -2.184,-6.275 0.486,-13.038 0,0 4.125,-1.304 13.426,5.052a46.97,46.97 0,0 1,12.214 -1.63c4.125,0 8.33,0.571 12.213,1.63 9.302,-6.356 13.427,-5.052 13.427,-5.052 2.67,6.763 0.97,11.816 0.485,13.038 3.155,3.422 5.015,7.822 5.015,13.2 0,18.905 -11.404,23.06 -22.324,24.283 1.78,1.548 3.316,4.481 3.316,9.126 0,6.6 -0.08,11.897 -0.08,13.526 0,1.304 0.89,2.853 3.316,2.364 19.412,-6.52 33.405,-24.935 33.405,-46.691C97.707,22 75.788,0 48.854,0z" />
</vector>
@@ -250,7 +250,7 @@
style="@style/EdenButton.Secondary" style="@style/EdenButton.Secondary"
android:layout_width="56dp" android:layout_width="56dp"
android:layout_height="56dp" android:layout_height="56dp"
app:icon="@drawable/ic_github" app:icon="@drawable/ic_forgejo"
app:iconGravity="textStart" app:iconGravity="textStart"
app:iconSize="24dp" app:iconSize="24dp"
app:iconPadding="0dp" /> app:iconPadding="0dp" />
@@ -259,7 +259,7 @@
android:layout_height="56dp" android:layout_height="56dp"
android:layout_weight="1" android:layout_weight="1"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
app:icon="@drawable/ic_github" app:icon="@drawable/ic_forgejo"
app:iconSize="24dp" app:iconSize="24dp"
app:iconGravity="textStart" app:iconGravity="textStart"
app:iconPadding="0dp" app:iconPadding="0dp"
@@ -43,6 +43,10 @@
android:icon="@drawable/ic_nfc" android:icon="@drawable/ic_nfc"
android:title="@string/load_amiibo" /> android:title="@string/load_amiibo" />
<item
android:id="@+id/menu_cheats"
android:icon="@drawable/ic_code"
android:title="@string/cheats" />
<item <item
android:id="@+id/menu_overlay_controls" android:id="@+id/menu_overlay_controls"
@@ -587,10 +587,6 @@
<string name="fast_gpu_time_description">يجعل اللعبة تعتقد أن عمل وحدة معالجة الرسومات ينتهي بشكل أسرع مما هو عليه في الواقع، لذلك تتوقف عن خفض الدقة ومسافة العرض لتتناسب مع سرعات جهاز Switch.</string> <string name="fast_gpu_time_description">يجعل اللعبة تعتقد أن عمل وحدة معالجة الرسومات ينتهي بشكل أسرع مما هو عليه في الواقع، لذلك تتوقف عن خفض الدقة ومسافة العرض لتتناسب مع سرعات جهاز Switch.</string>
<string name="skip_cpu_inner_invalidation">تخطي إبطال صلاحية وحدة المعالجة المركزية الداخلية</string> <string name="skip_cpu_inner_invalidation">تخطي إبطال صلاحية وحدة المعالجة المركزية الداخلية</string>
<string name="skip_cpu_inner_invalidation_description">يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة من جانب وحدة المعالجة المركزية أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسن أداءها. قد يتسبب ذلك في حدوث أعطال أو تعطل في بعض الألعاب.</string> <string name="skip_cpu_inner_invalidation_description">يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة من جانب وحدة المعالجة المركزية أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسن أداءها. قد يتسبب ذلك في حدوث أعطال أو تعطل في بعض الألعاب.</string>
<string name="nce_invalidation_gpu_readback">إعادة قراءة وحدة معالجة الرسومات قبل إبطال صلاحية NCE</string>
<string name="nce_invalidation_gpu_readback_description">إصلاح مؤقت. يعالج مشكلة تعطل لعبة Ender Magnolia (وغيرها من ألعاب UE). قد يؤدي إلى انخفاض في الأداء. يجري العمل على تحسينه.</string>
<string name="nce_runtime_nro_patch">تصحيح حالات NRO في وقت التشغيل لـ NCE</string>
<string name="nce_runtime_nro_patch_description">حل مؤقت. إصلاح مشكلة تشغيل لعبة Biomutant. قد يؤثر ذلك على الأداء. يجري العمل على تحسينه.</string>
<string name="fix_bloom_effects">إصلاح تأثيرات التوهج</string> <string name="fix_bloom_effects">إصلاح تأثيرات التوهج</string>
<string name="fix_bloom_effects_description">يقلل من ضبابية التوهج في LA/EOW (Adreno A6XX - A7XX/ Turnip)، ويزيل التوهج في Burnout. تحذير: قد يسبب تشوهات رسومية في ألعاب أخرى.</string> <string name="fix_bloom_effects_description">يقلل من ضبابية التوهج في LA/EOW (Adreno A6XX - A7XX/ Turnip)، ويزيل التوهج في Burnout. تحذير: قد يسبب تشوهات رسومية في ألعاب أخرى.</string>
<string name="emulate_bgr565">محاكاة BGR565</string> <string name="emulate_bgr565">محاكاة BGR565</string>
@@ -577,10 +577,6 @@
<string name="fast_gpu_time_description">讓遊戲誤以為 GPU 工作能更快完成,避免遊戲為了配合 Switch 的時脈而降低解析度與渲染距離</string> <string name="fast_gpu_time_description">讓遊戲誤以為 GPU 工作能更快完成,避免遊戲為了配合 Switch 的時脈而降低解析度與渲染距離</string>
<string name="skip_cpu_inner_invalidation">跳過 CPU 內部失效處理</string> <string name="skip_cpu_inner_invalidation">跳過 CPU 內部失效處理</string>
<string name="skip_cpu_inner_invalidation_description">在記憶體更新期間跳過某些 CPU 端快取的失效處理,減少 CPU 使用率並提高其性能。可能會導致某些遊戲出現故障或當機</string> <string name="skip_cpu_inner_invalidation_description">在記憶體更新期間跳過某些 CPU 端快取的失效處理,減少 CPU 使用率並提高其性能。可能會導致某些遊戲出現故障或當機</string>
<string name="nce_invalidation_gpu_readback">在 NCE 無效化前進行 GPU 回讀</string>
<string name="nce_invalidation_gpu_readback_description">(暫時性功能)修復 \"終結者瑪格諾莉亞:霧中綻放\" 及其它使用虛幻引擎之遊戲中的當機問題,可能會降低效能。此功能正在改善中</string>
<string name="nce_runtime_nro_patch">對 NCE Runtime 的 NRO 檔案進行修補</string>
<string name="nce_runtime_nro_patch_description">(暫時性功能)修復 \"Biomutant\" 的啟動問題,可能會對效能造成影響。此功能正在改善中</string>
<string name="fix_bloom_effects">修正光暈特效</string> <string name="fix_bloom_effects">修正光暈特效</string>
<string name="fix_bloom_effects_description">在 \"薩爾達傳說:織夢島\" 和 \"薩爾達傳說:智慧的再現\" 中減少光暈模糊的問題並移除 \"橫衝直撞:狂飆樂園重製版\" 中的光暈效果(適用於 Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string> <string name="fix_bloom_effects_description">在 \"薩爾達傳說:織夢島\" 和 \"薩爾達傳說:智慧的再現\" 中減少光暈模糊的問題並移除 \"橫衝直撞:狂飆樂園重製版\" 中的光暈效果(適用於 Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string>
<string name="emulate_bgr565">模擬 BGR565</string> <string name="emulate_bgr565">模擬 BGR565</string>
@@ -593,12 +593,8 @@
<string name="fast_gpu_time_description">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.</string> <string name="fast_gpu_time_description">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.</string>
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string> <string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
<string name="skip_cpu_inner_invalidation_description">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.</string> <string name="skip_cpu_inner_invalidation_description">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.</string>
<string name="nce_invalidation_gpu_readback">GPU Readback Before NCE Invalidation</string>
<string name="nce_invalidation_gpu_readback_description">Temporary. Fix Ender Magnolia (and other UE titles) crashes. May reduce performance. Improvement in progress.</string>
<string name="nce_runtime_nro_patch">Patch Runtime NROs for NCE</string>
<string name="nce_runtime_nro_patch_description">Temporary. Fix Biomutant boot. May impact performance. Improvement in progress.</string>
<string name="fix_bloom_effects">Fix Bloom Effects</string> <string name="fix_bloom_effects">Fix Bloom Effects</string>
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string> <string name="fix_bloom_effects_description">Removes bloom in Burnout.</string>
<string name="emulate_bgr565">Emulate BGR565</string> <string name="emulate_bgr565">Emulate BGR565</string>
<string name="emulate_bgr565_description">Fixes problems with inverted colors in games or strange artifacts or strange shadows.</string> <string name="emulate_bgr565_description">Fixes problems with inverted colors in games or strange artifacts or strange shadows.</string>
<string name="rescale_hack">Enable Legacy Rescale Pass</string> <string name="rescale_hack">Enable Legacy Rescale Pass</string>
@@ -844,6 +840,12 @@
<string name="preferences_graphics">Graphics</string> <string name="preferences_graphics">Graphics</string>
<string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string> <string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string>
<string name="quick_settings">Quick Settings</string> <string name="quick_settings">Quick Settings</string>
<string name="cheats">Cheats</string>
<string name="enable_all_cheats">Enable All Cheats</string>
<string name="disable_all_cheats">Disable All Cheats</string>
<string name="unnamed_cheat">Unnamed Cheat</string>
<string name="enable_cheats_by_default">Enable cheats by default</string>
<string name="enable_cheats_by_default_description">Enable regular cheats when a game starts</string>
<string name="enable_quick_settings">Enable Quick Settings</string> <string name="enable_quick_settings">Enable Quick Settings</string>
<string name="enable_quick_settings_description">Allow access to quick settings menu via swipe and menu button</string> <string name="enable_quick_settings_description">Allow access to quick settings menu via swipe and menu button</string>
<string name="preferences_audio">Audio</string> <string name="preferences_audio">Audio</string>
+4
View File
@@ -418,6 +418,10 @@ void SetGlobalFilter(const Filter& filter) {
logging_instance->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) { void SetColorConsoleBackendEnabled(bool enabled) {
if (logging_instance) if (logging_instance)
logging_instance->color_console_backend.enabled = enabled; logging_instance->color_console_backend.enabled = enabled;
+1
View File
@@ -138,6 +138,7 @@ void Stop();
/// The global filter will prevent any messages from even being processed if they are filtered. /// The global filter will prevent any messages from even being processed if they are filtered.
void SetGlobalFilter(const Filter& filter); void SetGlobalFilter(const Filter& filter);
[[nodiscard]] bool IsMessageEnabled(Class log_class, Level log_level);
void SetColorConsoleBackendEnabled(bool enabled); void SetColorConsoleBackendEnabled(bool enabled);
} // namespace Common::Log } // namespace Common::Log
+1 -4
View File
@@ -247,6 +247,7 @@ struct Values {
SwitchableSetting<bool> sync_core_speed{linkage, false, "sync_core_speed", Category::Core, SwitchableSetting<bool> sync_core_speed{linkage, false, "sync_core_speed", Category::Core,
Specialization::Default}; Specialization::Default};
SwitchableSetting<bool> enable_cheats_by_default{linkage, true, "enable_cheats_by_default", Category::Core};
// Cpu // Cpu
SwitchableSetting<CpuBackend, true> cpu_backend{linkage, SwitchableSetting<CpuBackend, true> cpu_backend{linkage,
@@ -639,10 +640,6 @@ struct Values {
Specialization::Default, Specialization::Default,
true, true,
true}; true};
SwitchableSetting<bool> nce_invalidation_gpu_readback{
linkage, false, "nce_invalidation_gpu_readback", Category::RendererHacks};
SwitchableSetting<bool> nce_runtime_nro_patch{
linkage, false, "nce_runtime_nro_patch", Category::RendererHacks};
SwitchableSetting<bool> async_presentation{linkage, SwitchableSetting<bool> async_presentation{linkage,
#ifdef __ANDROID__ #ifdef __ANDROID__
true, true,
+9
View File
@@ -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-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -46,4 +49,10 @@ std::vector<u8> DecompressDataZSTD(std::span<const u8> compressed) {
return decompressed; return decompressed;
} }
std::size_t DecompressDataZSTD(std::span<const u8> compressed, std::span<u8> 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 } // namespace Common::Compression
+14
View File
@@ -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-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -42,4 +45,15 @@ namespace Common::Compression {
*/ */
[[nodiscard]] std::vector<u8> DecompressDataZSTD(std::span<const u8> compressed); [[nodiscard]] std::vector<u8> DecompressDataZSTD(std::span<const u8> 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<const u8> compressed, std::span<u8> output);
} // namespace Common::Compression } // namespace Common::Compression
+2
View File
@@ -33,6 +33,8 @@ add_library(core STATIC
crypto/encryption_layer.h crypto/encryption_layer.h
crypto/key_manager.cpp crypto/key_manager.cpp
crypto/key_manager.h crypto/key_manager.h
crypto/ncz_decompressor.cpp
crypto/ncz_decompressor.h
crypto/partition_data_manager.cpp crypto/partition_data_manager.cpp
crypto/partition_data_manager.h crypto/partition_data_manager.h
crypto/xts_encryption_layer.cpp crypto/xts_encryption_layer.cpp
+2 -2
View File
@@ -369,8 +369,8 @@ void ArmNce::SetContext(const Kernel::Svc::ThreadContext& ctx) {
} }
void ArmNce::SignalInterrupt(Kernel::KThread* thread) { void ArmNce::SignalInterrupt(Kernel::KThread* thread) {
// Add break loop condition. constexpr u64 break_loop = static_cast<u64>(HaltReason::BreakLoop);
m_guest_ctx.esr_el1.fetch_or(static_cast<u64>(HaltReason::BreakLoop)); if ((m_guest_ctx.esr_el1.fetch_or(break_loop) & break_loop) != 0) return;
auto* params = &thread->GetNativeExecutionParameters(); auto* params = &thread->GetNativeExecutionParameters();
LockThreadParameters(params); LockThreadParameters(params);
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project */ /* SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project */
/* SPDX-License-Identifier: GPL-2.0-or-later */ /* SPDX-License-Identifier: GPL-2.0-or-later */
@@ -5,9 +8,22 @@
#define __ASSEMBLY__ #define __ASSEMBLY__
// Newer Linux UAPI headers check __ASSEMBLER__ instead of __ASSEMBLY__ to hide C declarations.
// Without it, asm-generic/signal.h redeclares sigset_t and clashes with glibc's. Only define it
// around these includes, since glibc headers also look at __ASSEMBLER__.
#ifndef __ASSEMBLER__
#define __ASSEMBLER__
#define EDEN_NCE_UNDEF_ASSEMBLER
#endif
#include <asm-generic/signal.h> #include <asm-generic/signal.h>
#include <asm-generic/unistd.h> #include <asm-generic/unistd.h>
#ifdef EDEN_NCE_UNDEF_ASSEMBLER
#undef __ASSEMBLER__
#undef EDEN_NCE_UNDEF_ASSEMBLER
#endif
#define ReturnToRunCodeByExceptionLevelChangeSignal SIGUSR2 #define ReturnToRunCodeByExceptionLevelChangeSignal SIGUSR2
#define BreakFromRunCodeSignal SIGURG #define BreakFromRunCodeSignal SIGURG
#define GuestAccessFaultSignal SIGSEGV #define GuestAccessFaultSignal SIGSEGV
+42
View File
@@ -45,6 +45,23 @@ Patcher::Patcher() : c(m_patch_instructions), c_pre(m_patch_instructions_pre) {
WriteLoadContext(c_pre); WriteLoadContext(c_pre);
} }
Patcher::Patcher(std::span<const u8> text) : c(m_patch_instructions), c_pre(m_patch_instructions_pre) {
modules.emplace_back();
curr_patch = &modules.back();
const auto words = std::span<const u32>{reinterpret_cast<const u32*>(text.data()), text.size() / sizeof(u32)};
for (u32 i = ModuleCodeIndex; i < static_cast<u32>(words.size()); ++i) {
const uintptr_t offset = i * sizeof(u32);
if (auto mrs = MRS{words[i]}; mrs.Verify() && mrs.GetRt() != 31 && (mrs.GetSystemReg() == TpidrEl0 || mrs.GetSystemReg() == TpidrroEl0)) {
BranchToPatch(offset);
const auto src_reg = mrs.GetSystemReg() == TpidrroEl0 ? oaknut::SystemReg::TPIDRRO_EL0 : oaknut::SystemReg::TPIDR_EL0;
WriteMrsHandler(offset + sizeof(u32), oaknut::XReg{static_cast<int>(mrs.GetRt())}, src_reg);
} else if (auto msr = MSR{words[i]}; msr.Verify() && msr.GetSystemReg() == TpidrEl0) {
BranchToPatch(offset);
WriteMsrHandler(offset + sizeof(u32), oaknut::XReg{static_cast<int>(msr.GetRt())});
}
}
}
Patcher::~Patcher() = default; Patcher::~Patcher() = default;
bool Patcher::PatchText(std::span<const u8> program_image, const Kernel::CodeSet::Segment& code) { bool Patcher::PatchText(std::span<const u8> program_image, const Kernel::CodeSet::Segment& code) {
@@ -182,6 +199,31 @@ bool Patcher::PatchText(std::span<const u8> program_image, const Kernel::CodeSet
return true; return true;
} }
std::span<const u32> Patcher::RelocateRuntimeTls(
s64 patch_offset, std::vector<InstructionPatch>& out_patches) {
const auto& patch = modules.front();
const auto can_branch = [](s64 offset) {
return offset % 4 == 0 && offset >= -static_cast<s64>(MaxRelativeBranch) && offset < static_cast<s64>(MaxRelativeBranch);
};
out_patches.clear();
out_patches.reserve(patch.m_branch_to_patch_relocations.size());
for (const auto& rel : patch.m_branch_to_patch_relocations) {
const s64 offset = patch_offset + rel.patch_offset - static_cast<s64>(rel.module_offset);
if (!can_branch(offset)) {return {};}
u32 replacement;
oaknut::CodeGenerator rc{&replacement};
rc.B(offset);
out_patches.push_back({rel.module_offset, replacement});
}
for (const auto& rel : patch.m_branch_to_module_relocations) {
const s64 offset = static_cast<s64>(rel.module_offset) - patch_offset - rel.patch_offset;
if (!can_branch(offset)) {return {};}
oaknut::CodeGenerator rc{m_patch_instructions.data() + rel.patch_offset / sizeof(u32)};
rc.B(offset);
}
return m_patch_instructions;
}
bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, std::vector<u8>& program_image, EntryTrampolines* out_trampolines) { bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, std::vector<u8>& program_image, EntryTrampolines* out_trampolines) {
const size_t patch_size = GetSectionSize(); const size_t patch_size = GetSectionSize();
const size_t pre_patch_size = GetPreSectionSize(); const size_t pre_patch_size = GetPreSectionSize();
+7
View File
@@ -48,15 +48,22 @@ using ModuleTextAddress = u64;
using PatchTextAddress = u64; using PatchTextAddress = u64;
using EntryTrampolines = ::Common::unordered_map<ModuleTextAddress, PatchTextAddress>; using EntryTrampolines = ::Common::unordered_map<ModuleTextAddress, PatchTextAddress>;
struct InstructionPatch {
u64 offset;
u32 replacement;
};
class Patcher { class Patcher {
public: public:
void SetModuleID(const ModuleID& id) { void SetModuleID(const ModuleID& id) {
module_id = id; module_id = id;
} }
explicit Patcher(); explicit Patcher();
explicit Patcher(std::span<const u8> text);
~Patcher(); ~Patcher();
bool PatchText(std::span<const u8> program_image, const Kernel::CodeSet::Segment& code); bool PatchText(std::span<const u8> program_image, const Kernel::CodeSet::Segment& code);
bool RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, std::vector<u8>& program_image, EntryTrampolines* out_trampolines); bool RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, std::vector<u8>& program_image, EntryTrampolines* out_trampolines);
std::span<const u32> RelocateRuntimeTls(s64 patch_offset, std::vector<InstructionPatch>& out_patches);
size_t GetSectionSize() const noexcept; size_t GetSectionSize() const noexcept;
size_t GetPreSectionSize() const noexcept; size_t GetPreSectionSize() const noexcept;
+17 -34
View File
@@ -4,7 +4,6 @@
#include <array> #include <array>
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <unordered_map>
#include <utility> #include <utility>
#include "game_settings.h" #include "game_settings.h"
@@ -249,30 +248,12 @@ struct System::Impl {
} }
} }
void NotifyNVDECChannelOpen(u64 process_id) { void SetNVDECActive(bool is_nvdec_active) {
std::scoped_lock lock{nvdec_active_mutex}; nvdec_active = is_nvdec_active;
++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);
}
} }
bool GetNVDECActive() { bool GetNVDECActive() {
std::scoped_lock lock{nvdec_active_mutex}; return nvdec_active;
return !nvdec_active_channels.empty();
}
bool IsNVDECActiveForProcess(u64 process_id) {
std::scoped_lock lock{nvdec_active_mutex};
return nvdec_active_channels.contains(process_id);
} }
void InitializeDebugger(System& system, u16 port) { void InitializeDebugger(System& system, u16 port) {
@@ -528,8 +509,6 @@ struct System::Impl {
mutable std::mutex suspend_guard; mutable std::mutex suspend_guard;
std::mutex general_channel_mutex; std::mutex general_channel_mutex;
std::mutex nvdec_active_mutex;
std::unordered_map<u64, u32> nvdec_active_channels;
std::atomic_bool is_paused{}; std::atomic_bool is_paused{};
std::atomic_bool is_shutting_down{}; std::atomic_bool is_shutting_down{};
std::atomic_bool is_powered_on{}; std::atomic_bool is_powered_on{};
@@ -537,6 +516,7 @@ struct System::Impl {
bool extended_memory_layout : 1 = false; bool extended_memory_layout : 1 = false;
bool exit_locked : 1 = false; bool exit_locked : 1 = false;
bool exit_requested : 1 = false; bool exit_requested : 1 = false;
bool nvdec_active : 1 = false;
void EnsureGeneralChannelInitialized(System& system) { void EnsureGeneralChannelInitialized(System& system) {
if (!general_channel_event) { if (!general_channel_event) {
@@ -600,22 +580,14 @@ void System::UnstallApplication() {
impl->UnstallApplication(); impl->UnstallApplication();
} }
void System::NotifyNVDECChannelOpen(u64 process_id) { void System::SetNVDECActive(bool is_nvdec_active) {
impl->NotifyNVDECChannelOpen(process_id); impl->SetNVDECActive(is_nvdec_active);
}
void System::NotifyNVDECChannelClose(u64 process_id) {
impl->NotifyNVDECChannelClose(process_id);
} }
bool System::GetNVDECActive() { bool System::GetNVDECActive() {
return impl->GetNVDECActive(); return impl->GetNVDECActive();
} }
bool System::IsNVDECActiveForProcess(u64 process_id) {
return impl->IsNVDECActiveForProcess(process_id);
}
void System::InitializeDebugger() { void System::InitializeDebugger() {
impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue()); impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue());
} }
@@ -814,6 +786,17 @@ void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size); impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size);
} }
std::vector<Memory::RuntimeCheatInfo> 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) { void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) {
impl->frontend_applets.SetFrontendAppletSet(std::move(set)); impl->frontend_applets.SetFrontendAppletSet(std::move(set));
} }
+4 -3
View File
@@ -46,6 +46,7 @@ enum class ResultStatus : u16;
namespace Core::Memory { namespace Core::Memory {
struct CheatEntry; struct CheatEntry;
struct RuntimeCheatInfo;
class Memory; class Memory;
} // namespace Core::Memory } // namespace Core::Memory
@@ -191,10 +192,8 @@ public:
std::unique_lock<std::mutex> StallApplication(); std::unique_lock<std::mutex> StallApplication();
void UnstallApplication(); void UnstallApplication();
void NotifyNVDECChannelOpen(u64 process_id); void SetNVDECActive(bool is_nvdec_active);
void NotifyNVDECChannelClose(u64 process_id);
[[nodiscard]] bool GetNVDECActive(); [[nodiscard]] bool GetNVDECActive();
[[nodiscard]] bool IsNVDECActiveForProcess(u64 process_id);
/** /**
* Initialize the debugger. * Initialize the debugger.
@@ -344,6 +343,8 @@ public:
void RegisterCheatList(const std::vector<Memory::CheatEntry>& list, void RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
const std::array<u8, 0x20>& build_id, u64 main_region_begin, const std::array<u8, 0x20>& build_id, u64 main_region_begin,
u64 main_region_size); u64 main_region_size);
[[nodiscard]] std::vector<Memory::RuntimeCheatInfo> GetRuntimeCheats() const;
bool SetCheatEnabled(u32 cheat_id, bool enabled);
void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set); void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set);
+472
View File
@@ -0,0 +1,472 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <algorithm>
#include <array>
#include <cstring>
#include <memory>
#include <mutex>
#include <optional>
#include <span>
#include <string>
#include <vector>
#include <zstd.h>
#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<u8, 8> SectionsMagic{'N', 'C', 'Z', 'S', 'E', 'C', 'T', 'N'};
constexpr std::array<u8, 8> 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<u32> 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<u8>(blk & 0xFF); blk >>= 8; }
}
// Parse header + section table + optional block header. Returns payload_start.
std::optional<std::pair<std::vector<Section>, std::optional<BlockHeader>>> 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<Section> 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<s64>(Le(e, 8));
s.size = static_cast<s64>(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<BlockHeader> 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<s32>(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<u64>(n) * 4, block_start + BlockFixed);
if (sizes.size() != static_cast<u64>(n) * 4) return std::nullopt;
b.sizes.resize(n);
for (s32 i = 0; i < n; ++i) b.sizes[i] = static_cast<u32>(Le(sizes.data() + i * 4, 4));
payload_start = block_start + BlockFixed + static_cast<u64>(n) * 4;
bh = std::move(b);
} else {
payload_start = block_start;
}
if (!sections.empty() && sections[0].offset > static_cast<s64>(HeaderSize)) {
Section fake{};
fake.offset = static_cast<s64>(HeaderSize);
fake.size = sections[0].offset - static_cast<s64>(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<u8> 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<u8>* 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::size_t>(
std::min<u64>(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<u8> data;
};
const std::vector<u8>* GetBlock(u64 id) {
Slot& slot = cache[id % CacheSlots];
if (slot.id == id) {
return &slot.data; // O(1) hit
}
std::vector<u8> 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<u8>& 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<std::size_t>(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<u64> offsets;
std::vector<u32> sizes;
u64 decompressed_size;
ZSTD_DCtx* dctx = nullptr;
std::vector<Slot> cache; // direct-mapped, CacheSlots entries
};
class BlockNczFile final : public FileSys::VfsFile {
public:
BlockNczFile(std::string name_, std::vector<u8> hdr_, std::vector<Section> sections_,
std::unique_ptr<BlockReader> 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<u64>(nca_size, static_cast<u64>(s.offset + s.size));
}
std::string GetName() const override { return name; }
std::size_t GetSize() const override { return static_cast<std::size_t>(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::size_t>(std::min<u64>(len, nca_size - off));
const u64 end = off + len;
u64 pos = off;
if (pos < HeaderSize) {
const u64 n = std::min<u64>(end, HeaderSize) - pos;
std::memcpy(data, hdr.data() + pos, static_cast<std::size_t>(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<u64>(static_cast<u64>(s.offset), HeaderSize);
const u64 e = std::max<u64>(static_cast<u64>(s.offset) + static_cast<u64>(s.size), b);
return e <= p;
});
for (; it != sections.end() && pos < end; ++it) {
const auto& s = *it;
const u64 begin = std::max<u64>(static_cast<u64>(s.offset), HeaderSize);
const u64 stop = std::max<u64>(static_cast<u64>(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<std::size_t>(g - pos));
pos = g;
if (pos >= end) break;
}
const u64 pe = std::min(end, stop);
const std::span<u8> piece(data + (pos - off), static_cast<std::size_t>(pe - pos));
if (body->ReadAt(pos - HeaderSize, piece) != piece.size())
return static_cast<std::size_t>(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<u8> hdr;
const std::vector<Section> sections;
const std::unique_ptr<BlockReader> 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<Section> 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<u64>(size, static_cast<u64>(s.offset + s.size));
return static_cast<std::size_t>(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::size_t>(std::min<u64>(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<u8> out_buf(Chunk);
std::size_t index = 0;
for (; index < sections.size(); ++index) {
const auto& s = sections[index];
const u64 begin = std::max<u64>(static_cast<u64>(s.offset), HeaderSize);
const u64 end = std::max<u64>(static_cast<u64>(s.offset) + static_cast<u64>(s.size),
begin);
if (end > frontier) break;
}
for (; index < sections.size() && frontier < needed; ++index) {
const auto& s = sections[index];
const u64 begin = std::max<u64>(static_cast<u64>(s.offset), HeaderSize);
const u64 end = std::max<u64>(static_cast<u64>(s.offset) + static_cast<u64>(s.size),
begin);
if (end <= frontier) continue;
u64 pos = std::max<u64>(begin, frontier);
std::optional<AESCipher<Key128>> cipher;
if (s.Ctr()) cipher.emplace(s.key, Mode::CTR);
while (pos < end && frontier < needed) {
const u64 want = std::min<u64>(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::size_t>(
std::min<u64>(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<Section> sections;
const u64 payload_start;
mutable std::mutex mutex;
mutable std::vector<u8> data;
mutable ZSTD_DStream* stream = nullptr;
mutable u64 read_pos = 0;
mutable u64 frontier = 0;
mutable std::vector<u8> 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<BlockReader> body;
try { body = std::make_unique<BlockReader>(f, *block, ps); }
catch (const std::exception& e) {
LOG_ERROR(Crypto, "Failed to open NCZBLOCK: {}", e.what());
return nullptr;
}
return std::make_shared<BlockNczFile>(std::string{name}, std::move(hdr),
std::move(sections), std::move(body));
}
if (allow_solid) {
return std::make_shared<SolidNczFile>(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
+35
View File
@@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <string_view>
#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. "<id>.ncz" entry from an NSZ/XCZ PFS0).
* @param output_name Name to give the returned VirtualFile (e.g. "<id>.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
+1
View File
@@ -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. // Ensure we have the proper key area keys to continue.
const u8 master_key_id = MasterKeyIdForKeyGeneration(reader->GetKeyGeneration()); const u8 master_key_id = MasterKeyIdForKeyGeneration(reader->GetKeyGeneration());
if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, reader->GetKeyIndex())) { 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; status = Loader::ResultStatus::ErrorMissingKeyAreaKey;
return; return;
} }
@@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // 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. // Initialize our header reader for the fs index.
R_TRY(out_header_reader->Initialize(*m_reader, 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. // Declare the storage we're opening.
VirtualFile storage; VirtualFile storage;
@@ -158,7 +163,7 @@ Result NcaFileSystemDriver::OpenStorageImpl(VirtualFile* out, NcaFsHeaderReader*
out_header_reader->GetPatchMetaDataHashDataInfo())); out_header_reader->GetPatchMetaDataHashDataInfo()));
} }
if (patch_info.HasAesCtrExTable()) { if (patch_info.HasAesCtrExTable() && !is_pre_decrypted) {
// Check the encryption type. // Check the encryption type.
ASSERT(out_header_reader->GetEncryptionType() == NcaFsHeader::EncryptionType::None || ASSERT(out_header_reader->GetEncryptionType() == NcaFsHeader::EncryptionType::None ||
out_header_reader->GetEncryptionType() == NcaFsHeader::EncryptionType::AesCtrEx || out_header_reader->GetEncryptionType() == NcaFsHeader::EncryptionType::AesCtrEx ||
@@ -196,32 +201,34 @@ Result NcaFileSystemDriver::OpenStorageImpl(VirtualFile* out, NcaFsHeaderReader*
} }
} else { } else {
// Create the appropriate storage for the encryption type. // Create the appropriate storage for the encryption type.
switch (out_header_reader->GetEncryptionType()) { if (!is_pre_decrypted) {
case NcaFsHeader::EncryptionType::None: switch (out_header_reader->GetEncryptionType()) {
// If there's no encryption, use the base storage we made previously. case NcaFsHeader::EncryptionType::None:
break; // If there's no encryption, use the base storage we made previously.
case NcaFsHeader::EncryptionType::AesXts: break;
R_TRY(this->CreateAesXtsStorage(std::addressof(storage), std::move(storage), case NcaFsHeader::EncryptionType::AesXts:
fs_data_offset)); R_TRY(this->CreateAesXtsStorage(std::addressof(storage), std::move(storage),
break; fs_data_offset));
case NcaFsHeader::EncryptionType::AesCtr: break;
R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage), case NcaFsHeader::EncryptionType::AesCtr:
fs_data_offset, out_header_reader->GetAesCtrUpperIv(), R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage),
AlignmentStorageRequirement::None)); fs_data_offset, out_header_reader->GetAesCtrUpperIv(),
break; AlignmentStorageRequirement::None));
case NcaFsHeader::EncryptionType::AesCtrSkipLayerHash: { break;
// Create the aes ctr storage. case NcaFsHeader::EncryptionType::AesCtrSkipLayerHash: {
VirtualFile aes_ctr_storage; // Create the aes ctr storage.
R_TRY(this->CreateAesCtrStorage(std::addressof(aes_ctr_storage), storage, VirtualFile aes_ctr_storage;
fs_data_offset, out_header_reader->GetAesCtrUpperIv(), R_TRY(this->CreateAesCtrStorage(std::addressof(aes_ctr_storage), storage,
AlignmentStorageRequirement::None)); fs_data_offset, out_header_reader->GetAesCtrUpperIv(),
AlignmentStorageRequirement::None));
// Create region switch storage. // Create region switch storage.
R_TRY(this->CreateRegionSwitchStorage(std::addressof(storage), out_header_reader, R_TRY(this->CreateRegionSwitchStorage(std::addressof(storage), out_header_reader,
std::move(storage), std::move(aes_ctr_storage))); std::move(storage), std::move(aes_ctr_storage)));
} break; } break;
default: default:
R_THROW(ResultInvalidNcaFsHeaderEncryptionType); R_THROW(ResultInvalidNcaFsHeaderEncryptionType);
}
} }
// Potentially save storages to our context. // Potentially save storages to our context.
@@ -382,21 +389,25 @@ Result NcaFileSystemDriver::OpenIndirectableStorageAsOriginal(
} }
// Create the appropriate storage for the encryption type. // Create the appropriate storage for the encryption type.
switch (header_reader->GetEncryptionType()) { const bool is_pre_decrypted =
case NcaFsHeader::EncryptionType::None: m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections();
// If there's no encryption, use the base storage we made previously. if (!is_pre_decrypted) {
break; switch (header_reader->GetEncryptionType()) {
case NcaFsHeader::EncryptionType::AesXts: case NcaFsHeader::EncryptionType::None:
R_TRY( // If there's no encryption, use the base storage we made previously.
this->CreateAesXtsStorage(std::addressof(storage), std::move(storage), fs_data_offset)); break;
break; case NcaFsHeader::EncryptionType::AesXts:
case NcaFsHeader::EncryptionType::AesCtr: R_TRY(this->CreateAesXtsStorage(std::addressof(storage), std::move(storage),
R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage), fs_data_offset, fs_data_offset));
header_reader->GetAesCtrUpperIv(), break;
AlignmentStorageRequirement::CacheBlockSize)); case NcaFsHeader::EncryptionType::AesCtr:
break; R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage),
default: fs_data_offset, header_reader->GetAesCtrUpperIv(),
R_THROW(ResultInvalidNcaFsHeaderEncryptionType); AlignmentStorageRequirement::CacheBlockSize));
break;
default:
R_THROW(ResultInvalidNcaFsHeaderEncryptionType);
}
} }
// Set output storage. // Set output storage.
@@ -432,6 +443,11 @@ Result NcaFileSystemDriver::CreateAesCtrStorage(
ASSERT(out != nullptr); ASSERT(out != nullptr);
ASSERT(base_storage != nullptr); ASSERT(base_storage != nullptr);
if (m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections()) {
*out = std::move(base_storage);
R_SUCCEED();
}
// Create the iv. // Create the iv.
std::array<u8, AesCtrStorage::IvSize> iv{}; std::array<u8, AesCtrStorage::IvSize> iv{};
AesCtrStorage::MakeIv(iv.data(), sizeof(iv), upper_iv.value, offset); 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(out != nullptr);
ASSERT(base_storage != nullptr); ASSERT(base_storage != nullptr);
if (m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections()) {
*out = std::move(base_storage);
R_SUCCEED();
}
// Create the iv. // Create the iv.
std::array<u8, AesXtsStorage::IvSize> iv{}; std::array<u8, AesXtsStorage::IvSize> iv{};
AesXtsStorage::MakeAesXtsIv(iv.data(), sizeof(iv), offset, NcaHeader::XtsBlockSize); AesXtsStorage::MakeAesXtsIv(iv.data(), sizeof(iv), offset, NcaHeader::XtsBlockSize);
@@ -809,6 +830,12 @@ Result NcaFileSystemDriver::CreateAesCtrExStorageMetaStorage(
// Validate preconditions. // Validate preconditions.
ASSERT(out != nullptr); ASSERT(out != nullptr);
ASSERT(base_storage != 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 || ASSERT(encryption_type == NcaFsHeader::EncryptionType::None ||
encryption_type == NcaFsHeader::EncryptionType::AesCtrEx || encryption_type == NcaFsHeader::EncryptionType::AesCtrEx ||
encryption_type == NcaFsHeader::EncryptionType::AesCtrExSkipLayerHash); encryption_type == NcaFsHeader::EncryptionType::AesCtrExSkipLayerHash);
@@ -871,6 +898,11 @@ Result NcaFileSystemDriver::CreateAesCtrExStorage(
ASSERT(meta_storage != nullptr); ASSERT(meta_storage != nullptr);
ASSERT(patch_info.HasAesCtrExTable()); ASSERT(patch_info.HasAesCtrExTable());
if (m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections()) {
*out = std::move(base_storage);
R_SUCCEED();
}
// Read the bucket tree header. // Read the bucket tree header.
BucketTree::Header header; BucketTree::Header header;
std::memcpy(std::addressof(header), patch_info.aes_ctr_ex_header.data(), sizeof(header)); std::memcpy(std::addressof(header), patch_info.aes_ctr_ex_header.data(), sizeof(header));
@@ -104,6 +104,7 @@ public:
const NcaCompressionConfiguration& compression_cfg); const NcaCompressionConfiguration& compression_cfg);
VirtualFile GetSharedBodyStorage(); VirtualFile GetSharedBodyStorage();
VirtualFile GetStorage() const { return m_body_storage; }
u32 GetMagic() const; u32 GetMagic() const;
NcaHeader::DistributionType GetDistributionType() const; NcaHeader::DistributionType GetDistributionType() const;
NcaHeader::ContentType GetContentType() const; NcaHeader::ContentType GetContentType() const;
+4 -3
View File
@@ -503,10 +503,11 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildI
for (const auto& subdir : patch_dirs) { for (const auto& subdir : patch_dirs) {
if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) == disabled.cend()) { if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) == disabled.cend()) {
if (auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats"); cheats_dir != nullptr) { if (auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats"); cheats_dir != nullptr) {
if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true)) 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))
std::copy(res->begin(), res->end(), std::back_inserter(out)); 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));
}
} }
} }
} }
+43 -3
View File
@@ -16,6 +16,7 @@
#include "common/random.h" #include "common/random.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/crypto/key_manager.h" #include "core/crypto/key_manager.h"
#include "core/crypto/ncz_decompressor.h"
#include "core/file_sys/card_image.h" #include "core/file_sys/card_image.h"
#include "core/file_sys/common_funcs.h" #include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h" #include "core/file_sys/content_archive.h"
@@ -158,6 +159,25 @@ static std::shared_ptr<NSP> OpenContainerAsNsp(const VirtualFile& file, Loader::
return nullptr; 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>& 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 <typename Callback> template <typename Callback>
bool ForEachContainerEntry(const std::shared_ptr<NSP>& nsp, bool only_content, bool ForEachContainerEntry(const std::shared_ptr<NSP>& nsp, bool only_content,
std::optional<u64> base_program_id, Callback&& on_entry) { std::optional<u64> base_program_id, Callback&& on_entry) {
@@ -811,7 +831,14 @@ std::vector<ContentProviderEntry> RegisteredCache::ListEntriesFilter(
} }
static std::shared_ptr<NCA> GetNCAFromNSPForID(const NSP& nsp, const NcaID& id) { static std::shared_ptr<NCA> 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) { if (file == nullptr) {
return nullptr; return nullptr;
} }
@@ -1273,6 +1300,12 @@ bool ManualContentProvider::AddEntriesFromContainer(VirtualFile file, bool only_
return false; 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( return ForEachContainerEntry(
nsp, only_content, base_program_id, nsp, only_content, base_program_id,
[this](TitleType title_type, ContentRecordType content_type, u64 title_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)); const auto extension = Common::ToLower(filename.substr(dot_pos + 1));
// .xcz is an XCI container, but its updates only work through the NSP/PFS0 path
if (extension == "nsp") { // (DecompressNCZ), not ProcessXCI. So route .xcz here on purpose.
if (extension == "nsp" || extension == "nsz" || extension == "xcz") {
ProcessNSP(file); ProcessNSP(file);
} else if (extension == "xci") { } else if (extension == "xci") {
ProcessXCI(file); ProcessXCI(file);
@@ -1434,6 +1468,12 @@ void ExternalContentProvider::ProcessNSP(const VirtualFile& file) {
return; 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()); LOG_DEBUG(Service_FS, "Processing NSP file: {}", file->GetName());
AddExternalEntriesFromContainer(nsp, entries, versions, multi_version_entries); AddExternalEntriesFromContainer(nsp, entries, versions, multi_version_entries);
} }
+12
View File
@@ -12,6 +12,7 @@
#include "common/hex_util.h" #include "common/hex_util.h"
#include "common/logging.h" #include "common/logging.h"
#include "core/crypto/key_manager.h" #include "core/crypto/key_manager.h"
#include "core/crypto/ncz_decompressor.h"
#include "core/file_sys/common_funcs.h" #include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h" #include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h" #include "core/file_sys/nca_metadata.h"
@@ -246,6 +247,17 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
const auto id_string = Common::HexToString(rec.nca_id, false); const auto id_string = Common::HexToString(rec.nca_id, false);
auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string)); 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 (next_file == nullptr) {
if (rec.type != ContentRecordType::DeltaFragment) { if (rec.type != ContentRecordType::DeltaFragment) {
LOG_WARNING(Service_FS, LOG_WARNING(Service_FS,
+3
View File
@@ -112,6 +112,9 @@ public:
// Returns whether or not the file can be read from. // Returns whether or not the file can be read from.
virtual bool IsReadable() const = 0; 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 // The primary method of reading from the file. Reads length bytes into data starting at offset
// into file. Returns number of bytes successfully read. // 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; virtual std::size_t Read(u8* data, std::size_t length, std::size_t offset = 0) const = 0;
+7
View File
@@ -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-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -37,6 +40,10 @@ public:
std::size_t GetOffset() const; std::size_t GetOffset() const;
bool HasDecryptedSections() const override {
return file && file->HasDecryptedSections();
}
private: private:
std::size_t TrimToFit(std::size_t r_size, std::size_t r_offset) const; std::size_t TrimToFit(std::size_t r_size, std::size_t r_offset) const;
+3
View File
@@ -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-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
+3
View File
@@ -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-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
+3
View File
@@ -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-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
+1 -1
View File
@@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
@@ -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-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-License-Identifier: GPL-3.0-or-later
#pragma once #pragma once
@@ -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-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
+1 -1
View File
@@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/am/service/common_state_getter.h" #include "core/hle/service/am/service/common_state_getter.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-License-Identifier: GPL-3.0-or-later
#pragma once #pragma once
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later

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