From 252b2b11af5306dc4c1a58bbc984e990a71971b0 Mon Sep 17 00:00:00 2001 From: Spectranator Date: Sat, 1 Jun 2024 14:05:11 +0000 Subject: [PATCH 01/13] Uploaded my PGP public key You can use this public key to verify an e-mail has actually been sent by me or to encrypt messages Signed-off-by: Spectranator --- public_pgp/Litucks_0x5BB626CB_public.asc | 41 ++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 public_pgp/Litucks_0x5BB626CB_public.asc diff --git a/public_pgp/Litucks_0x5BB626CB_public.asc b/public_pgp/Litucks_0x5BB626CB_public.asc new file mode 100644 index 0000000000..21691652e8 --- /dev/null +++ b/public_pgp/Litucks_0x5BB626CB_public.asc @@ -0,0 +1,41 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=fXHE +-----END PGP PUBLIC KEY BLOCK----- From fa84e4a2a445712174f311f0f83327a2af1100ae Mon Sep 17 00:00:00 2001 From: Spectranator Date: Sun, 2 Jun 2024 11:01:28 +0000 Subject: [PATCH 02/13] Created first blog entry --- blog/000-intro.md.sig | Bin 0 -> 438 bytes blog/001-arm-emulation.md | 203 ++++++++++++++++++++++++++++++++++ blog/001-arm-emulation.md.sig | Bin 0 -> 438 bytes 3 files changed, 203 insertions(+) create mode 100644 blog/000-intro.md.sig create mode 100644 blog/001-arm-emulation.md create mode 100644 blog/001-arm-emulation.md.sig diff --git a/blog/000-intro.md.sig b/blog/000-intro.md.sig new file mode 100644 index 0000000000000000000000000000000000000000..3669b52589480e44bf0158ef4b9482ece4102fdc GIT binary patch literal 438 zcmV;n0ZIOe0kZ@E0SW*e79j-nIq#}j(h9gW$EU9z9_jO2wkFF30%lxL!vG2i5FQ@s z^INti%LyC|0GhF)#L&{VT17Xgiq+4%$H+APFlFPxT*c7Ap$B>J7n zm&|Ve2(2BA)h7P=395Ep`(8Y$Vl2A*@j@#pk1arYcgS?Vi!XJ!t1&b5edt3keZVz7 z&rdy6vU`!}t|xSQ*;dFr6+C|ywE%skafL98SZ;9YL*GGimjd&kp*d0Qwn39-Tn0CgwQ^)2*LxG gyNB6xI4snoDlvIw7f6)%6k%8bN!*L)w&QKFLs+BHDF6Tf literal 0 HcmV?d00001 diff --git a/blog/001-arm-emulation.md b/blog/001-arm-emulation.md new file mode 100644 index 0000000000..b993dfcbf7 --- /dev/null +++ b/blog/001-arm-emulation.md @@ -0,0 +1,203 @@ +# Blog Entry 1: ARM CPU emulation + +I've been studying the ARM recompiler used by Yuzu (Dynarmic) for quite a while now, and have learnt a lot on the way there. + +This is going to be a rather technical post, but I hope it might help people like me understand what goes on under the hood. + +## Native code execution + +Let me start by giving a greatly simplified explaination of what happens on actual ARM hardware (like the Nintendo Switch) when an application is started: + +1. Initial address space is set up +2. Stack pointer and finally program counter and are set +3. CPU goes into a loop where instructions are fetched, decoded, then executed + +The first step includes loading the executable into memory and allocating stack space. The stack is basically a piece of memory that is used to store local variables and hold information about what address to return execution to when a routine ("function") finishes execution. +The second step here sets (at least) 2 registers, the stack pointer which tells the CPU where the stack is and the program counter which tells the CPU where to execute code from. It would point to a specific routine inside the executable. +The third step is to just let the CPU execute the application. In reality this step is much more complex but this explaination will do the job here. + +Yuzu is able to run ARM64 code natively on ARM64 CPUs through "NCE", sidestepping the need for recompilation. + +## Code recompilation + +Now, what would this look like when emulating an ARM CPU with Dynarmic? In fact, the first 2 steps are exactly the same, except that the register values are stored in memory at first. +But then it gets interesting since the instructions at the program counter can't be "just executed". Instead, they have to go through a transformation from the architecture that is being emulated (like ARM64) to the architecture of the host CPU (like x64). + +Let's take a look at this function: +```c +unsigned long add(unsigned long a, unsigned long b) { + return a + b; +} +``` + +When compiled to ARM64, it looks like this: +```arm64 +add x0, x0, x1 +ret +``` + +This could very easily be translated into x64 like this: +```x64 +add rdi,rsi +mov rax,rdi +ret +``` + +And further optimized down like this: +```x64 +lea rax,[rdi+rsi*1] +ret +``` + +### Register mapping + +#### Static register map + +As you can see, I have directly mapped ARM64 registers to x64 registers: + + - `x0` -> `rax` + - `x1` -> `rdi` + - `x2` -> `rsi` + +But if you know the differences between ARM64 and x64 well enough, you've probably already notices that this won't always work! +The reason is that ARM64 has *way more* general purpose registers than x64! This unfortunately throws up a number of issues. + +#### Dynamic register map + +The closest we get to a good solution is to **dynamically allocate** the registers on the host machine. +This means that instead of creating a fixed mapping between registers, we do what C compilers do when there are more local variables in a function than registers available: Just store the least frequently used registers in memory instead and load them into a register (discarding *its* value into memory) as needed. + +This sounds pretty cool, doesn't it? It's not that easy. +Dynarmic operates in **blocks of code**. That means that instead of recompiling the whole application right from the start, only recently executed code is recompiled and kept in memory. There are multiple reasons for this: + +1. Startup time (recompiling everything can take a long time) +2. Memory usage (a limit for how much recompiled code to keep in memory can be defined) +3. Dynamic code generation (the guest application could overwrite and replace its own code at any time) + +It is what makes Dynarmic a **dynamic** recompiler. + +This comes with a pitfall in combination with dynamic register allocation though: Each block must be able to pick up execution from where the previous block stopped. This means that all registers must be stored in a predefined (fixed) location so that a block can be entered from different places. +For example, if block A expects the `x27` register to be in memory, but block B expects the same register to be in an actual register things would go horribly wrong. + +This is typically solved by either storing all or a fixed set of registers at specific locations in memory and the rest of the registers in actual registers at the end of a block, and loading the registers back from memory into actual registers as needed at the start of another block. +This brings quite an unfortunate performance penalty but there is no real way around this. + +More details on that later. + +### Intermediate representation + +So far, I've made it seem like the code transformation happens *directly* from the guest to the host architecture. This isn't actually true: There is something called an "intermediate representation" (short "IR") inbetween. +Pretty much all recompilers including Dynarmic have these 3 main components: + +1. Frontend ("lifts" guest instructions into IR) +2. Middleend (runs transformations like optimization, more on that later) +3. Backend ("lowers" IR into host instructions) + +This system has the major advantage that frontend and backend can be replaced individually and makes many different combinations possible. +Dynarmic has 2 frontends: + + - ARM32 + - ARM64 + +And 3 backend: + + - ARM64 + - RISCV64 + - x64 + +Specifically the RISCV64 backend does not implement all IR instructions so it only works with the ARM32 backend. +In theory there could be many more frontends and backends though, LLVM is great example for such a system but there are no frontends available that lift instructions to its IR, likely because its IR is too high level (too far away from machine instructions). Instead it has frontends for actual programming languages like C, C++ and Rust and many many backends, even some for GPUs. + +Typically, one guest instruction turns into one or more IR instructions and a couple of IR instructions turn into one or more host instructions. + +Let's take a look at the example from the beginning again: +```arm64 +add x0, x0, x1 +ret +``` + +And convert it as a whole block into IR: +```c +%0 = load_general_register 0 +%1 = load_general_register 1 +%2 = integer_add %0 %1 +store_general_register 0 %2 +%3 = load_general_register 30 +return branch_to(%3) +``` + +This is not what any actual IR looks like but you can see the entire process of loading the register values into IR registers, performing the addition and storing the result back into a register. Finally, the block ends by performing a branch to the address in the `x30` register (which is what the `ret` instruction actually does). + +#### Dynamic register allocation + +You might've noticed that instead of "overwriting" the IR register `0`, a new IR register `2` is created. This is because IR registers are actually constant values and only a concept needed to generate human readable IR code. In reality, the `integer_add` instruction arguments here simply "use" the results of the `load_general_register` instructions. + +The backend itself is then responsible for making sure the value returned by the used instruction is still available when the instruction user needs it. This can be achieved by either: + +1. Just keeping the value in an available host register if possible +2. Executing the instruction later, when it's actually needed +3. Moving the value into memory until it's used + +And this is actually how dynamic register allocation works under the hood! This concept of an intermediate representation makes it incredibly easy. + +#### Optimization + +One important optimization is known as "constant folding". This optimization pass figures out values at compile time. Take this piece of IR for example: +``` +%0 = integer_add 3 4 +%1 = integer_sub %0 1 +store_general_register 7 %1 +``` + +Through constant folding, this IR can be optimized down to just: +``` +store_general_register 7 6 +``` + +Another optimization pass known as "dead code elimination" is able to remove code that can be removed without changing the outcome. For example this piece of IR: +``` +%0 = integer_add 3 4 +%1 = integer_sub %0 1 +store_general_register 7 %0 +``` + +Would be optimized into just: +``` +%0 = integer_add 3 4 +store_general_register 7 %0 +``` + +By this pass. + +There are a couple more optimization passes in Dynarmic that aren't as easy to explain, but I guess you get the point. +Optimization passes are usually chained together to generate the most optimal code. + +### Other issues + +What happens if the backend architecture does not support an instruction the frontend architure does *at all*? +One example for this is the **exclusive monitor**. It's a multithreading-related feature on ARM CPUs that can not be accurately replicated on x86_64 CPUs at all, and even the way Dynarmic implements it is extremely slow compared to an actual ARM CPU. + +Sometimes, hard to emulate stuff like that can be emulated with less accurately to improve performance. In Torzu, such optimizations are enabled by setting the CPU accuracy to "unsafe". Some games may work fine with this, others may crash the entire emulator. Use at your own risk. + +### Possible performance improvements in Dynarmic + +#### Code caching + +The idea is to cache generated IR on disk (and OS filesystem cache) to avoid reoptimizing the same blocks over and over again. This is not particularly useful for hot blocks (blocks with code that is executed very often in a loop) though since such blocks would most likely always stay in memory anyways. +It would improve startup time though and generally works very similarly to the disk shader cache. + +#### Branch caching + +One other idea I've had to avoid calling into the recompiler while the game is running works very similar to **profile guided optimization**. Basically, all branches that can't be resolved at compile time could fill kind of a "branch cache" so that next time that branch is recompiled the path to previous branch locations could be shorter. + +#### More optimization passes + +LLVM has a big collection of optimization passes that may be worthwhile checking out. + +## Conclusion + +While Dynarmic is already very fast there are still possible improvements to be made. +I'd love to get started with those right away, but the Dynarmic code base is quite complex and hard to learn and I don't want to dedicate *all* my time to Dynarmic. +Who knows, maybe the mentioned optimizations are completely worthless? I'll keep you updated whenever something interesting happens! + +If you see any mistakes in this post, please feel free to create an issue. I have only proofread this post myself since I am a one-man team. diff --git a/blog/001-arm-emulation.md.sig b/blog/001-arm-emulation.md.sig new file mode 100644 index 0000000000000000000000000000000000000000..6127d3f58617bfe2878afea819283b912e8707f8 GIT binary patch literal 438 zcmV;n0ZIOe0kZ@E0SW*e79j-nIq#}j(h9gW$EU9z9_jO2wkFF30%lxL!vG2i5FQ@s z^INti%j!f6{SjjnD{j99_DPF1irhN4j%4rh^;SiNbVzn0hF*7CudV+Uh$T=A2Lct~mBa-MU?C+;JFDJwq2^_0-EB+GW7$?%xRU2-MCydaau_D(Ns zf654tDb|yc{76wx`A4Oe1O*;w#orhz1JF;^J{pzo8O{d!Ovca|;qf+z^6BJg1TY7@t3wI`=C{YBFEJAk$ zw&;v=QyY1G_dLTzBZ?$0M(!@*t%bM4X|gYhHVc-!&3NKW+uj!5ZXpFPj|<&5qK@)( zSQ`$j1B5}z@{1qr6@UlV<&Hp?O<3@y!wo#J?kBV`eOlm?H=^9Dgi`aeTe}7Hpx|vO g=-Doyz Date: Mon, 10 Jun 2024 13:39:40 +0000 Subject: [PATCH 03/13] Update README.md --- README.md | 55 +++++++++++++++++++++++-------------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 3fe00a8f85..7f3f368260 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,27 @@ SPDX-License-Identifier: GPL-2.0-or-later It is written in C++ with portability in mind, and I plan to actively maintain builds for Linux, Android and Windows. -

- Compatibility | - Development | - Building | - Download | - License -

+## !!! Limited public development !!! + +I feel like working publicly on this has taken away the fun. You may not understand, but it's quite stressful to have the public eye on a project. +Keep in mind, this is just a hobby project. I feel like I always have to keep updating so I don't disappoint you. It's just not a good situation for a hobby project to be in. +Turns out: running an open source project takes a lot more time than I have. +And then stupid and unnecessary issues like Windows Defender flagging the emulator as malware ruin the rest. I am grateful for all your bug reports, help and support, but all that has distracted me from taking the project into the direction I would've liked. + +Today I've accidentally locked myself out of the Tor site out pure stupidity and one of the things I didn't make a backup of for whatever reason was the key required to get the same Tor site set back up. + +For this reason, I have decided to limit public development. +It is not all over though. My plan is to: + - continue the blog + - move the blog into a seperate repository + - keep this repository updated just enough so it stays compilable on Linux and Windows + - keep the externals updated + - push some bigger updates from my private upstream whenever I feel like (no promises) + - set up a new Tor site (I'll keep you updated here and via the blog!) + - NOT publish releases. If someone feels like publishing builds they should feel free to do that + - NOT offer support in any way + +Again, thanks to everyone who has supported me in any way (even by creating bug reports), I really appreciate it. ## Compatibility @@ -30,19 +44,6 @@ The emulator is capable of running most commercial games at full speed, provided It runs most Nintendo Switch games released until the date of the Yuzu takedown. -## Changes - -Following are the changes made since forking from Yuzu: - - - Added option to optimize generated SPIR-V shaders via spirv-opt - - Added option to synchronize CPU clock to render speed limit - - Added option to launch home menu from Switch firmware - - Fixed crash when switching away from null graphics per-game - - Fixed controller UI being cut off at the bottom - - Removed analytics and authentication as they'd be useless (perhaps even outright dangerous) now - - Ported fixes from Sudachi and Suyu - - Minor improvements and additions - ## Goals The first and foremost goal is long-term maintenance. Even if I stop commiting new features I will always do my best to keep the emulator functional and third party dependencies updated. This also means most of the changes made will eventually be bug fixes. @@ -55,12 +56,10 @@ Android support is low priority but would be a nice bonus. ## Development +**The Tor site mentioned here has stopped working, I'll update this once a new one is up.** + Most of the development happens on [Dark Git](http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/). It's also where [our central repository](http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu) is hosted. -Currently, development is somewhat limited to external commits as I'm working on improvements in dynarmic! This will increase emulation speed in CPU-bound scenarios. - -If you want to contribute, please take a look at the [Contributor's Guide](http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu/wiki/Contributing) and [Developer Information](http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu/wiki/Developer-Information). - To clone this git repository, you can use these commands given tor is installed and running: git -c http.proxy=socks5h://127.0.0.1:9050 clone http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu.git @@ -79,14 +78,6 @@ This project incorporates several commits from the [Suyu](https://suyu.dev) and * __Linux__: [Linux Build](http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu/wiki/Building-for-Linux) * __Windows__: [Windows Build](http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu/wiki/Building-for-Windows) -* ~~__Android__: [Android Build](http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu/wiki/Building-For-Android)~~ -* ~~__macOS__: [macOS Build](http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu/wiki/Building-for-macOS)~~ - -(Only Linux and Windows builds are available for now. Android is planned eventually.) - -## Download - -Precompiled build are available **in the releases section**. ## License From 002d0559f261a2b55cf2569aeff5bd9667baf097 Mon Sep 17 00:00:00 2001 From: spectranator Date: Mon, 10 Jun 2024 19:41:41 +0200 Subject: [PATCH 04/13] Updated onion site links --- README.md | 17 ++++++++--------- README.md.sig | Bin 0 -> 438 bytes dist/onion.torzu_emu.torzu.metainfo.xml | 4 ++-- src/yuzu/aboutdialog.ui | 2 +- src/yuzu/main.cpp | 4 ++-- 5 files changed, 13 insertions(+), 14 deletions(-) create mode 100644 README.md.sig diff --git a/README.md b/README.md index 7f3f368260..539c284d17 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ SPDX-License-Identifier: GPL-2.0-or-later


- torzu + torzu
torzu
@@ -23,16 +23,15 @@ Keep in mind, this is just a hobby project. I feel like I always have to keep up Turns out: running an open source project takes a lot more time than I have. And then stupid and unnecessary issues like Windows Defender flagging the emulator as malware ruin the rest. I am grateful for all your bug reports, help and support, but all that has distracted me from taking the project into the direction I would've liked. -Today I've accidentally locked myself out of the Tor site out pure stupidity and one of the things I didn't make a backup of for whatever reason was the key required to get the same Tor site set back up. +Today I've accidentally locked myself out of the Tor site out of pure stupidity and one of the things I didn't make a backup of for was the key required to get the same Tor site set back up. -For this reason, I have decided to limit public development. +For these reasons, I have decided to limit public development. It is not all over though. My plan is to: - continue the blog - move the blog into a seperate repository - keep this repository updated just enough so it stays compilable on Linux and Windows - keep the externals updated - push some bigger updates from my private upstream whenever I feel like (no promises) - - set up a new Tor site (I'll keep you updated here and via the blog!) - NOT publish releases. If someone feels like publishing builds they should feel free to do that - NOT offer support in any way @@ -56,13 +55,13 @@ Android support is low priority but would be a nice bonus. ## Development -**The Tor site mentioned here has stopped working, I'll update this once a new one is up.** +**The Tor site has recently changed. You can make sure this README has actually been written by me by verifying against the `README.md.sig` file using the key in `public_pgp/`.** -Most of the development happens on [Dark Git](http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/). It's also where [our central repository](http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu) is hosted. +Most of the development happens on [Dark Git](http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/). It's also where [our central repository](http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu) is hosted. To clone this git repository, you can use these commands given tor is installed and running: - git -c http.proxy=socks5h://127.0.0.1:9050 clone http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu.git + git -c http.proxy=socks5h://127.0.0.1:9050 clone http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu.git cd torzu git submodule update --init --depth 1 --recursive @@ -76,8 +75,8 @@ This project incorporates several commits from the [Suyu](https://suyu.dev) and ## Building -* __Linux__: [Linux Build](http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu/wiki/Building-for-Linux) -* __Windows__: [Windows Build](http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu/wiki/Building-for-Windows) +* __Linux__: [Linux Build](http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu/wiki/Building-for-Linux) +* __Windows__: [Windows Build](http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu/wiki/Building-for-Windows) ## License diff --git a/README.md.sig b/README.md.sig new file mode 100644 index 0000000000000000000000000000000000000000..1d363dc22598c82c6854f14fa86cde6e82647ea7 GIT binary patch literal 438 zcmV;n0ZIOe0kZ@E0SW*e79j-nIq#}j(h9gW$EU9z9_jO2wkFF30%m7AbN~to5FQ@s z^INti%T%8W|5QfHcDp=hz3ClwB33*)t=Fo)ER*t{j*vAdoyMswitch emulator - http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu/issues - http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu + http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu/issues + http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu onion.torzu_emu.torzu.desktop yuzu diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui index 9ea07f7884..fcd84e24e6 100644 --- a/src/yuzu/aboutdialog.ui +++ b/src/yuzu/aboutdialog.ui @@ -129,7 +129,7 @@ li.checked::marker { content: "\2612"; } - <html><head/><body><p><a href="http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/litucks/torzu/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="http://y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> + <html><head/><body><p><a href="http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/litucks/torzu/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu/src/branch/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html> true diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a08172416e..5fc77ed6bf 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3531,9 +3531,9 @@ void GMainWindow::OnOpenMirrorRepo() { "Please either try again later, through a VPN or access the main
" "repository via the Tor Browser:
" "http://" - "y2nlvhmmk5jnsvechppxnbyzmmv3vbl7dvzn6ltwcdbpgxixp3clkgqd.onion/torzu-emu/torzu")); } From 35fe455e5c4e2ed80a0109c4519f38846410c399 Mon Sep 17 00:00:00 2001 From: mateomaui <148507115+mateomaui@users.noreply.github.com> Date: Tue, 11 Jun 2024 05:13:25 -1000 Subject: [PATCH 05/13] Replace URLs for precompiled windows binaries --- CMakeLists.txt | 4 ++-- CMakeModules/DownloadExternals.cmake | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b23d135a1..52e0afe715 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,7 +126,7 @@ if (YUZU_USE_BUNDLED_VCPKG) set(VCPKG_DOWNLOADS_PATH ${PROJECT_SOURCE_DIR}/externals/vcpkg/downloads) set(NASM_VERSION "2.16.01") set(NASM_DESTINATION_PATH ${VCPKG_DOWNLOADS_PATH}/nasm-${NASM_VERSION}-win64.zip) - set(NASM_DOWNLOAD_URL "https://github.com/yuzu-emu/ext-windows-bin/raw/master/nasm/nasm-${NASM_VERSION}-win64.zip") + set(NASM_DOWNLOAD_URL "https://github.com/litucks/ext-windows-bin/raw/master/nasm/nasm-${NASM_VERSION}-win64.zip") if (NOT EXISTS ${NASM_DESTINATION_PATH}) file(DOWNLOAD ${NASM_DOWNLOAD_URL} ${NASM_DESTINATION_PATH} SHOW_PROGRESS STATUS NASM_STATUS) @@ -622,7 +622,7 @@ if (NOT CLANG_FORMAT) message(STATUS "Clang format not found! Downloading...") set(CLANG_FORMAT "${PROJECT_BINARY_DIR}/externals/clang-format${CLANG_FORMAT_POSTFIX}.exe") file(DOWNLOAD - https://github.com/yuzu-emu/ext-windows-bin/raw/master/clang-format${CLANG_FORMAT_POSTFIX}.exe + https://github.com/litucks/ext-windows-bin/raw/master/clang-format${CLANG_FORMAT_POSTFIX}.exe "${CLANG_FORMAT}" SHOW_PROGRESS STATUS DOWNLOAD_SUCCESS) if (NOT DOWNLOAD_SUCCESS EQUAL 0) diff --git a/CMakeModules/DownloadExternals.cmake b/CMakeModules/DownloadExternals.cmake index 95e27c8545..620e033eb8 100644 --- a/CMakeModules/DownloadExternals.cmake +++ b/CMakeModules/DownloadExternals.cmake @@ -7,7 +7,7 @@ # prefix_var: name of a variable which will be set with the path to the extracted contents function(download_bundled_external remote_path lib_name prefix_var) -set(package_base_url "https://github.com/torzu/") +set(package_base_url "https://github.com/litucks/") set(package_repo "no_platform") set(package_extension "no_platform") if (WIN32) From 1e8ea3af21e68b52f93f2273a758b38ee2e8077b Mon Sep 17 00:00:00 2001 From: mateomaui <148507115+mateomaui@users.noreply.github.com> Date: Sun, 16 Jun 2024 02:55:11 -1000 Subject: [PATCH 06/13] Remove MSVC compiler version upper limit for QT and SDL to allow compiling with latest version of Visual Studio (#21) * Update CMakeLists.txt Commented out the upper limit of 1940 for the MSVC version for QT and SDL. The current version of the MSVC compiler is 19.40.XXXX, so it needs to be "LESS 1941" or higher to work now. * removed explanatory comments for less clutter --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 52e0afe715..30b8c773ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -502,7 +502,8 @@ if(ENABLE_QT) set(YUZU_QT_NO_CMAKE_SYSTEM_PATH) if(YUZU_USE_BUNDLED_QT) - if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64) + ## if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64) + if ((MSVC_VERSION GREATER_EQUAL 1920) AND ARCHITECTURE_x86_64) set(QT_BUILD qt-5.15.2-msvc2019_64) elseif ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND NOT MINGW AND ARCHITECTURE_x86_64) set(QT_BUILD qt5_5_15_2) @@ -531,7 +532,8 @@ endif() if (ENABLE_SDL2) if (YUZU_USE_BUNDLED_SDL2) # Detect toolchain and platform - if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64) + ## if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64) + if ((MSVC_VERSION GREATER_EQUAL 1920) AND ARCHITECTURE_x86_64) set(SDL2_VER "SDL2-2.28.2") else() message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.") From 4afc30545848b95b7adacdbaa14bac65ff4f2c48 Mon Sep 17 00:00:00 2001 From: spectranator Date: Sun, 16 Jun 2024 15:07:47 +0200 Subject: [PATCH 07/13] Added note about pull requests to README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 539c284d17..277f45ab7f 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,9 @@ It is not all over though. My plan is to: - push some bigger updates from my private upstream whenever I feel like (no promises) - NOT publish releases. If someone feels like publishing builds they should feel free to do that - NOT offer support in any way + - accept pull requests as long as they are of reasonable quality -Again, thanks to everyone who has supported me in any way (even by creating bug reports), I really appreciate it. +Again, thanks to everyone who has supported my efforts so far in any way (even by creating bug reports), I really appreciate it. ## Compatibility From a7d7aa0a5b9a6c3c23e7db39fad20199862a3a09 Mon Sep 17 00:00:00 2001 From: spectranator Date: Wed, 19 Jun 2024 21:09:54 +0200 Subject: [PATCH 08/13] Updated ffmpeg submodule --- externals/ffmpeg/ffmpeg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/ffmpeg/ffmpeg b/externals/ffmpeg/ffmpeg index 65c1c83ca4..e0db1f51d6 160000 --- a/externals/ffmpeg/ffmpeg +++ b/externals/ffmpeg/ffmpeg @@ -1 +1 @@ -Subproject commit 65c1c83ca42540415516c37e21c9aeb7dd2c96d1 +Subproject commit e0db1f51d6ddf9eb2c1314c23d063a29255b607a From 4208203ea4f79d6a4072a85e557bbb7d905e9f95 Mon Sep 17 00:00:00 2001 From: spectranator Date: Sun, 23 Jun 2024 23:43:15 +0200 Subject: [PATCH 09/13] Possible pending Github takedown --- README.md | 9 ++++++--- README.md.sig | Bin 438 -> 0 bytes 2 files changed, 6 insertions(+), 3 deletions(-) delete mode 100644 README.md.sig diff --git a/README.md b/README.md index 277f45ab7f..61cf5d119e 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,12 @@ SPDX-License-Identifier: GPL-2.0-or-later It is written in C++ with portability in mind, and I plan to actively maintain builds for Linux, Android and Windows.

-## !!! Limited public development !!! +## POSSIBLE PENDING GITHUB MIRROR TAKEDOWN + +I have received emails about takedowns on the release binaries hosted at mega (no worries I'll find another place to reupload them). +If the GitHub mirror gets taken down too, the next mirror repository is going to be: https://codeberg.org/litucks/torzu unless anything comes in the way. You can use the button in the "About" menu of the emulator to get to the current mirror repository or simply check out the [main repository](http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu). Please note that this is a manual process that could take me up to 2 days (worst case). + +## Limited public development I feel like working publicly on this has taken away the fun. You may not understand, but it's quite stressful to have the public eye on a project. Keep in mind, this is just a hobby project. I feel like I always have to keep updating so I don't disappoint you. It's just not a good situation for a hobby project to be in. @@ -56,8 +61,6 @@ Android support is low priority but would be a nice bonus. ## Development -**The Tor site has recently changed. You can make sure this README has actually been written by me by verifying against the `README.md.sig` file using the key in `public_pgp/`.** - Most of the development happens on [Dark Git](http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/). It's also where [our central repository](http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu) is hosted. To clone this git repository, you can use these commands given tor is installed and running: diff --git a/README.md.sig b/README.md.sig deleted file mode 100644 index 1d363dc22598c82c6854f14fa86cde6e82647ea7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 438 zcmV;n0ZIOe0kZ@E0SW*e79j-nIq#}j(h9gW$EU9z9_jO2wkFF30%m7AbN~to5FQ@s z^INti%T%8W|5QfHcDp=hz3ClwB33*)t=Fo)ER*t{j*vAdoyM Date: Sun, 30 Jun 2024 16:24:35 +0200 Subject: [PATCH 10/13] Decreased urgency of possible pending mirror takedown message as nothing has happened within a week --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 61cf5d119e..0bedde17d7 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,6 @@ SPDX-License-Identifier: GPL-2.0-or-later It is written in C++ with portability in mind, and I plan to actively maintain builds for Linux, Android and Windows. -## POSSIBLE PENDING GITHUB MIRROR TAKEDOWN - -I have received emails about takedowns on the release binaries hosted at mega (no worries I'll find another place to reupload them). -If the GitHub mirror gets taken down too, the next mirror repository is going to be: https://codeberg.org/litucks/torzu unless anything comes in the way. You can use the button in the "About" menu of the emulator to get to the current mirror repository or simply check out the [main repository](http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu). Please note that this is a manual process that could take me up to 2 days (worst case). - ## Limited public development I feel like working publicly on this has taken away the fun. You may not understand, but it's quite stressful to have the public eye on a project. @@ -43,6 +38,11 @@ It is not all over though. My plan is to: Again, thanks to everyone who has supported my efforts so far in any way (even by creating bug reports), I really appreciate it. +## Possible pending GitHub mirror takedown + +I have received emails about takedowns on the release binaries hosted at mega (no worries I'll find another place to reupload them). +If the GitHub mirror gets taken down too, the next mirror repository is going to be at: https://codeberg.org/litucks/torzu (repo privatized until then) unless anything comes in the way. You can use the button in the "About" menu of the emulator to get to the current mirror repository or simply check out the [main repository](http://vub63vv26q6v27xzv2dtcd25xumubshogm67yrpaz2rculqxs7jlfqad.onion/torzu-emu/torzu). Please note that setting the new mirror repo to public is a manual process that could take me up to 2 days depending on how long it takes me to notice that the GitHub mirror has been taken down (specially mid-week). + ## Compatibility The emulator is capable of running most commercial games at full speed, provided you meet the [necessary hardware requirements](http://web.archive.org/web/20240130133811/https://yuzu-emu.org/help/quickstart/#hardware-requirements). From cc81504195cded2e4442c6bc85d3149754316c63 Mon Sep 17 00:00:00 2001 From: spectranator Date: Sun, 30 Jun 2024 16:50:56 +0200 Subject: [PATCH 11/13] Added note about main repo having open issues again --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0bedde17d7..e121d8ff45 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ It is not all over though. My plan is to: - push some bigger updates from my private upstream whenever I feel like (no promises) - NOT publish releases. If someone feels like publishing builds they should feel free to do that - NOT offer support in any way + - feel free to open issues on the main repository though if you feel like an issue REALLY needs my attention - accept pull requests as long as they are of reasonable quality Again, thanks to everyone who has supported my efforts so far in any way (even by creating bug reports), I really appreciate it. From 39af5e51ffa2028e07ce02384241edb2e9820373 Mon Sep 17 00:00:00 2001 From: spectranator Date: Sun, 30 Jun 2024 16:54:56 +0200 Subject: [PATCH 12/13] Revert "Removed web service reminiscents" in preparation to fix multiplayer lobby list This reverts commit ffc907460f422e4ee69b54767ce35c755cc468b9. --- .gitmodules | 3 ++ CMakeLists.txt | 10 +++- externals/CMakeLists.txt | 10 +++- externals/cpp-jwt | 1 + src/CMakeLists.txt | 4 ++ src/core/CMakeLists.txt | 5 ++ src/dedicated_room/CMakeLists.txt | 4 ++ src/dedicated_room/yuzu_room.cpp | 9 ++++ src/network/CMakeLists.txt | 4 ++ src/network/announce_multiplayer_session.cpp | 16 ++++++ src/yuzu/CMakeLists.txt | 4 ++ src/yuzu/applets/qt_amiibo_settings.cpp | 52 ++++++++++++++++++++ src/yuzu/applets/qt_amiibo_settings.h | 1 + src/yuzu/multiplayer/chat_room.cpp | 35 +++++++++++++ src/yuzu/multiplayer/host_room.cpp | 23 +++++++++ src/yuzu/multiplayer/lobby.cpp | 17 +++++++ 16 files changed, 196 insertions(+), 2 deletions(-) create mode 160000 externals/cpp-jwt diff --git a/.gitmodules b/.gitmodules index 9dfd6df00f..9a53460c49 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,6 +28,9 @@ [submodule "vcpkg"] path = externals/vcpkg url = https://github.com/microsoft/vcpkg.git +[submodule "cpp-jwt"] + path = externals/cpp-jwt + url = https://github.com/arun11299/cpp-jwt.git [submodule "libadrenotools"] path = externals/libadrenotools url = https://github.com/bylaws/libadrenotools.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 30b8c773ad..55b514a102 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,8 @@ set(QT6_LOCATION "" CACHE PATH "Additional Location to search for Qt6 libraries option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF) CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF) +option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) + option(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" "${WIN32}") option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON) @@ -141,6 +143,9 @@ if (YUZU_USE_BUNDLED_VCPKG) if (YUZU_TESTS) list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests") endif() + if (ENABLE_WEB_SERVICE) + list(APPEND VCPKG_MANIFEST_FEATURES "web-service") + endif() if (ANDROID) list(APPEND VCPKG_MANIFEST_FEATURES "android") endif() @@ -340,7 +345,10 @@ if (USE_DISCORD_PRESENCE) find_package(DiscordRPC MODULE) endif() -find_package(httplib 0.12 MODULE COMPONENTS OpenSSL) +if (ENABLE_WEB_SERVICE) + find_package(cpp-jwt 1.4 CONFIG) + find_package(httplib 0.12 MODULE COMPONENTS OpenSSL) +endif() if (YUZU_TESTS) find_package(Catch2 3.0.1 REQUIRED) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 50d3190e29..2421fc234a 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -133,11 +133,19 @@ endif() add_subdirectory(sirit) # httplib -if (NOT TARGET httplib::httplib) +if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib) set(HTTPLIB_REQUIRE_OPENSSL ON) add_subdirectory(cpp-httplib) endif() +# cpp-jwt +if (ENABLE_WEB_SERVICE AND NOT TARGET cpp-jwt::cpp-jwt) + set(CPP_JWT_BUILD_EXAMPLES OFF) + set(CPP_JWT_BUILD_TESTS OFF) + set(CPP_JWT_USE_VENDORED_NLOHMANN_JSON OFF) + add_subdirectory(cpp-jwt) +endif() + # Opus if (NOT TARGET Opus::opus) set(OPUS_BUILD_TESTING OFF) diff --git a/externals/cpp-jwt b/externals/cpp-jwt new file mode 160000 index 0000000000..10ef5735d8 --- /dev/null +++ b/externals/cpp-jwt @@ -0,0 +1 @@ +Subproject commit 10ef5735d842b31025f1257ae78899f50a40fb14 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c4357ecbd..8615a0ca8b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -208,6 +208,10 @@ if (ENABLE_QT) add_subdirectory(yuzu) endif() +if (ENABLE_WEB_SERVICE) + add_subdirectory(web_service) +endif() + if (ANDROID) add_subdirectory(android/app/src/main/jni) target_include_directories(yuzu-android PRIVATE android/app/src/main) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index cf427ed2a0..d67ca881b9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1165,6 +1165,11 @@ if (MINGW) target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY}) endif() +if (ENABLE_WEB_SERVICE) + target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) + target_link_libraries(core PRIVATE web_service) +endif() + if (HAS_NCE) enable_language(C ASM) set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp") diff --git a/src/dedicated_room/CMakeLists.txt b/src/dedicated_room/CMakeLists.txt index 1d26e00bfd..c0dcc0241f 100644 --- a/src/dedicated_room/CMakeLists.txt +++ b/src/dedicated_room/CMakeLists.txt @@ -8,6 +8,10 @@ add_executable(yuzu-room ) target_link_libraries(yuzu-room PRIVATE common network) +if (ENABLE_WEB_SERVICE) + target_compile_definitions(yuzu-room PRIVATE -DENABLE_WEB_SERVICE) + target_link_libraries(yuzu-room PRIVATE web_service) +endif() target_link_libraries(yuzu-room PRIVATE mbedtls mbedcrypto) if (MSVC) diff --git a/src/dedicated_room/yuzu_room.cpp b/src/dedicated_room/yuzu_room.cpp index ae483830db..93038f161b 100644 --- a/src/dedicated_room/yuzu_room.cpp +++ b/src/dedicated_room/yuzu_room.cpp @@ -33,6 +33,10 @@ #include "network/room.h" #include "network/verify_user.h" +#ifdef ENABLE_WEB_SERVICE +#include "web_service/verify_user_jwt.h" +#endif + #undef _UNICODE #include #ifndef _MSC_VER @@ -347,9 +351,14 @@ int main(int argc, char** argv) { std::unique_ptr verify_backend; if (announce) { +#ifdef ENABLE_WEB_SERVICE + verify_backend = + std::make_unique(Settings::values.web_api_url.GetValue()); +#else LOG_INFO(Network, "yuzu Web Services is not available with this build: validation is disabled."); verify_backend = std::make_unique(); +#endif } else { verify_backend = std::make_unique(); } diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 47bafee801..8e306219fb 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -20,6 +20,10 @@ add_library(network STATIC create_target_directory_groups(network) target_link_libraries(network PRIVATE common enet::enet Boost::headers) +if (ENABLE_WEB_SERVICE) + target_compile_definitions(network PRIVATE -DENABLE_WEB_SERVICE) + target_link_libraries(network PRIVATE web_service) +endif() if (YUZU_USE_PRECOMPILED_HEADERS) target_precompile_headers(network PRIVATE precompiled_headers.h) diff --git a/src/network/announce_multiplayer_session.cpp b/src/network/announce_multiplayer_session.cpp index c61141efdc..1f83ae0849 100644 --- a/src/network/announce_multiplayer_session.cpp +++ b/src/network/announce_multiplayer_session.cpp @@ -9,6 +9,10 @@ #include "common/assert.h" #include "network/network.h" +#ifdef ENABLE_WEB_SERVICE +#include "web_service/announce_room_json.h" +#endif + namespace Core { // Time between room is announced to web_service @@ -16,7 +20,13 @@ static constexpr std::chrono::seconds announce_time_interval(15); AnnounceMultiplayerSession::AnnounceMultiplayerSession(Network::RoomNetwork& room_network_) : room_network{room_network_} { +#ifdef ENABLE_WEB_SERVICE + backend = std::make_unique(Settings::values.web_api_url.GetValue(), + Settings::values.yuzu_username.GetValue(), + Settings::values.yuzu_token.GetValue()); +#else backend = std::make_unique(); +#endif } WebService::WebResult AnnounceMultiplayerSession::Register() { @@ -142,6 +152,12 @@ bool AnnounceMultiplayerSession::IsRunning() const { void AnnounceMultiplayerSession::UpdateCredentials() { ASSERT_MSG(!IsRunning(), "Credentials can only be updated when session is not running"); + +#ifdef ENABLE_WEB_SERVICE + backend = std::make_unique(Settings::values.web_api_url.GetValue(), + Settings::values.yuzu_username.GetValue(), + Settings::values.yuzu_token.GetValue()); +#endif } } // namespace Core diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index acdf710f7d..b67df498f2 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -425,6 +425,10 @@ if (USE_DISCORD_PRESENCE) target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE) endif() +if (ENABLE_WEB_SERVICE) + target_compile_definitions(yuzu PRIVATE -DENABLE_WEB_SERVICE) +endif() + if (YUZU_USE_QT_MULTIMEDIA) target_link_libraries(yuzu PRIVATE Qt${QT_MAJOR_VERSION}::Multimedia) target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_MULTIMEDIA) diff --git a/src/yuzu/applets/qt_amiibo_settings.cpp b/src/yuzu/applets/qt_amiibo_settings.cpp index f5b423fca6..b91796ddef 100644 --- a/src/yuzu/applets/qt_amiibo_settings.cpp +++ b/src/yuzu/applets/qt_amiibo_settings.cpp @@ -13,6 +13,9 @@ #include "input_common/drivers/virtual_amiibo.h" #include "input_common/main.h" #include "ui_qt_amiibo_settings.h" +#ifdef ENABLE_WEB_SERVICE +#include "web_service/web_backend.h" +#endif #include "yuzu/applets/qt_amiibo_settings.h" #include "yuzu/main.h" @@ -88,6 +91,55 @@ void QtAmiiboSettingsDialog::LoadAmiiboInfo() { ui->amiiboInfoGroup->setVisible(false); } +void QtAmiiboSettingsDialog::LoadAmiiboApiInfo(std::string_view amiibo_id) { +#ifdef ENABLE_WEB_SERVICE + // TODO: Host this data on our website + WebService::Client client{"https://amiiboapi.com", {}, {}}; + WebService::Client image_client{"https://raw.githubusercontent.com", {}, {}}; + const auto url_path = fmt::format("/api/amiibo/?id={}", amiibo_id); + + const auto amiibo_json = client.GetJson(url_path, true).returned_data; + if (amiibo_json.empty()) { + ui->amiiboImageLabel->setVisible(false); + ui->amiiboInfoGroup->setVisible(false); + return; + } + + std::string amiibo_series{}; + std::string amiibo_name{}; + std::string amiibo_image_url{}; + std::string amiibo_type{}; + + const auto parsed_amiibo_json_json = nlohmann::json::parse(amiibo_json).at("amiibo"); + parsed_amiibo_json_json.at("amiiboSeries").get_to(amiibo_series); + parsed_amiibo_json_json.at("name").get_to(amiibo_name); + parsed_amiibo_json_json.at("image").get_to(amiibo_image_url); + parsed_amiibo_json_json.at("type").get_to(amiibo_type); + + ui->amiiboSeriesValue->setText(QString::fromStdString(amiibo_series)); + ui->amiiboNameValue->setText(QString::fromStdString(amiibo_name)); + ui->amiiboTypeValue->setText(QString::fromStdString(amiibo_type)); + + if (amiibo_image_url.size() < 34) { + ui->amiiboImageLabel->setVisible(false); + } + + const auto image_url_path = amiibo_image_url.substr(34, amiibo_image_url.size() - 34); + const auto image_data = image_client.GetImage(image_url_path, true).returned_data; + + if (image_data.empty()) { + ui->amiiboImageLabel->setVisible(false); + } + + QPixmap pixmap; + pixmap.loadFromData(reinterpret_cast(image_data.data()), + static_cast(image_data.size())); + pixmap = pixmap.scaled(250, 350, Qt::AspectRatioMode::KeepAspectRatio, + Qt::TransformationMode::SmoothTransformation); + ui->amiiboImageLabel->setPixmap(pixmap); +#endif +} + void QtAmiiboSettingsDialog::LoadAmiiboData() { Service::NFP::RegisterInfo register_info{}; Service::NFP::CommonInfo common_info{}; diff --git a/src/yuzu/applets/qt_amiibo_settings.h b/src/yuzu/applets/qt_amiibo_settings.h index 0cdb86ef35..3833cf6f2a 100644 --- a/src/yuzu/applets/qt_amiibo_settings.h +++ b/src/yuzu/applets/qt_amiibo_settings.h @@ -43,6 +43,7 @@ public: private: void LoadInfo(); void LoadAmiiboInfo(); + void LoadAmiiboApiInfo(std::string_view amiibo_id); void LoadAmiiboData(); void LoadAmiiboGameInfo(); void SetGameDataName(u32 application_area_id); diff --git a/src/yuzu/multiplayer/chat_room.cpp b/src/yuzu/multiplayer/chat_room.cpp index e0b84853cd..4463616b45 100644 --- a/src/yuzu/multiplayer/chat_room.cpp +++ b/src/yuzu/multiplayer/chat_room.cpp @@ -21,6 +21,9 @@ #include "yuzu/game_list_p.h" #include "yuzu/multiplayer/chat_room.h" #include "yuzu/multiplayer/message.h" +#ifdef ENABLE_WEB_SERVICE +#include "web_service/web_backend.h" +#endif class ChatMessage { public: @@ -384,6 +387,38 @@ void ChatRoom::SetPlayerList(const Network::RoomMember::MemberList& member_list) QStandardItem* name_item = new PlayerListItem(member.nickname, member.username, member.avatar_url, member.game_info); +#ifdef ENABLE_WEB_SERVICE + if (!icon_cache.count(member.avatar_url) && !member.avatar_url.empty()) { + // Start a request to get the member's avatar + const QUrl url(QString::fromStdString(member.avatar_url)); + QFuture future = QtConcurrent::run([url] { + WebService::Client client( + QStringLiteral("%1://%2").arg(url.scheme(), url.host()).toStdString(), "", ""); + auto result = client.GetImage(url.path().toStdString(), true); + if (result.returned_data.empty()) { + LOG_ERROR(WebService, "Failed to get avatar"); + } + return result.returned_data; + }); + auto* future_watcher = new QFutureWatcher(this); + connect(future_watcher, &QFutureWatcher::finished, this, + [this, future_watcher, avatar_url = member.avatar_url] { + const std::string result = future_watcher->result(); + if (result.empty()) + return; + QPixmap pixmap; + if (!pixmap.loadFromData(reinterpret_cast(result.data()), + static_cast(result.size()))) + return; + icon_cache[avatar_url] = + pixmap.scaled(48, 48, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + // Update all the displayed icons with the new icon_cache + UpdateIconDisplay(); + }); + future_watcher->setFuture(future); + } +#endif + player_list->invisibleRootItem()->appendRow(name_item); } UpdateIconDisplay(); diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index 6ac4693fc8..ef364ee43a 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp @@ -23,6 +23,9 @@ #include "yuzu/multiplayer/state.h" #include "yuzu/multiplayer/validation.h" #include "yuzu/uisettings.h" +#ifdef ENABLE_WEB_SERVICE +#include "web_service/verify_user_jwt.h" +#endif HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list, std::shared_ptr session, @@ -95,7 +98,12 @@ std::unique_ptr HostRoomWindow::CreateVerifyBacken bool use_validation) const { std::unique_ptr verify_backend; if (use_validation) { +#ifdef ENABLE_WEB_SERVICE + verify_backend = + std::make_unique(Settings::values.web_api_url.GetValue()); +#else verify_backend = std::make_unique(); +#endif } else { verify_backend = std::make_unique(); } @@ -193,6 +201,21 @@ void HostRoomWindow::Host() { } } std::string token; +#ifdef ENABLE_WEB_SERVICE + if (is_public) { + WebService::Client client(Settings::values.web_api_url.GetValue(), + Settings::values.yuzu_username.GetValue(), + Settings::values.yuzu_token.GetValue()); + if (auto room = room_network.GetRoom().lock()) { + token = client.GetExternalJWT(room->GetVerifyUID()).returned_data; + } + if (token.empty()) { + LOG_ERROR(WebService, "Could not get external JWT, verification may fail"); + } else { + LOG_INFO(WebService, "Successfully requested external JWT: size={}", token.size()); + } + } +#endif // TODO: Check what to do with this member->Join(ui->username->text().toStdString(), "127.0.0.1", port, 0, Network::NoPreferredIP, password, token); diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp index 68ea16d0e2..77ac842952 100644 --- a/src/yuzu/multiplayer/lobby.cpp +++ b/src/yuzu/multiplayer/lobby.cpp @@ -20,6 +20,9 @@ #include "yuzu/multiplayer/state.h" #include "yuzu/multiplayer/validation.h" #include "yuzu/uisettings.h" +#ifdef ENABLE_WEB_SERVICE +#include "web_service/web_backend.h" +#endif Lobby::Lobby(QWidget* parent, QStandardItemModel* list, std::shared_ptr session, Core::System& system_) @@ -183,6 +186,20 @@ void Lobby::OnJoinRoom(const QModelIndex& source) { // attempt to connect in a different thread QFuture f = QtConcurrent::run([nickname, ip, port, password, verify_uid, this] { std::string token; +#ifdef ENABLE_WEB_SERVICE + if (!Settings::values.yuzu_username.GetValue().empty() && + !Settings::values.yuzu_token.GetValue().empty()) { + WebService::Client client(Settings::values.web_api_url.GetValue(), + Settings::values.yuzu_username.GetValue(), + Settings::values.yuzu_token.GetValue()); + token = client.GetExternalJWT(verify_uid).returned_data; + if (token.empty()) { + LOG_ERROR(WebService, "Could not get external JWT, verification may fail"); + } else { + LOG_INFO(WebService, "Successfully requested external JWT: size={}", token.size()); + } + } +#endif if (auto room_member = room_network.GetRoomMember().lock()) { room_member->Join(nickname, ip.c_str(), port, 0, Network::NoPreferredIP, password, token); From f064967e3261c8dcb4040c5ed505965d8a68bc94 Mon Sep 17 00:00:00 2001 From: spectranator Date: Sun, 30 Jun 2024 17:14:51 +0200 Subject: [PATCH 13/13] Fixed multiplayer lobby list (thanks to anonymous contributor!) --- src/common/settings.h | 2 +- src/network/announce_multiplayer_session.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/settings.h b/src/common/settings.h index 2ea310e13d..21775c465a 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -613,7 +613,7 @@ struct Values { Category::Network}; // WebService - Setting web_api_url{linkage, "https://api.ynet-fun.xyz", "web_api_url", + Setting web_api_url{linkage, "api.ynet-fun.xyz", "web_api_url", Category::WebService}; Setting yuzu_username{linkage, std::string(), "yuzu_username", Category::WebService}; diff --git a/src/network/announce_multiplayer_session.cpp b/src/network/announce_multiplayer_session.cpp index 1f83ae0849..d6c2e6afe0 100644 --- a/src/network/announce_multiplayer_session.cpp +++ b/src/network/announce_multiplayer_session.cpp @@ -6,6 +6,7 @@ #include #include "announce_multiplayer_session.h" #include "common/announce_multiplayer_room.h" +#include "common/settings.h" #include "common/assert.h" #include "network/network.h"