From 6be4b03050c5bc3d0a6f453e7ac2b381ab1dec15 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 9 Oct 2025 15:19:32 -0400 Subject: [PATCH] [desktop] feat: import/export data Currently not the ideal solution. Can't be cancelled due to JlCompress currently lacking a method of cancellation, but for now this is a good prototype. Signed-off-by: crueter --- .../colorful/icons/48x48/download.png | Bin 0 -> 1689 bytes dist/qt_themes/colorful/icons/48x48/trash.png | Bin 744 -> 0 bytes .../qt_themes/colorful/icons/48x48/upload.png | Bin 0 -> 1689 bytes .../colorful/icons/48x48/user-trash.png | Bin 0 -> 1445 bytes dist/qt_themes/colorful/style.qrc | 4 +- .../colorful_midnight_blue/style.qrc | 4 +- dist/qt_themes/default/default.qrc | 4 +- .../default/icons/48x48/download.png | Bin 0 -> 853 bytes dist/qt_themes/default/icons/48x48/upload.png | Bin 0 -> 820 bytes .../icons/48x48/{trash.png => user-trash.png} | Bin dist/qt_themes/default_dark/style.qrc | 4 +- .../qdarkstyle/icons/48x48/download.png | Bin 0 -> 883 bytes .../qdarkstyle/icons/48x48/upload.png | Bin 0 -> 853 bytes .../icons/48x48/{trash.png => user-trash.png} | Bin dist/qt_themes/qdarkstyle/style.qrc | 4 +- .../qdarkstyle_midnight_blue/style.qrc | 3 + quazip.patch | 56 +++++ src/frontend_common/data_manager.cpp | 4 +- src/qt_common/CMakeLists.txt | 21 +- src/qt_common/qt_content_util.cpp | 204 +++++++++++++++--- src/qt_common/qt_content_util.h | 2 + src/qt_common/qt_frontend_util.cpp | 11 + src/qt_common/qt_frontend_util.h | 29 +-- src/qt_common/qt_game_util.cpp | 8 +- src/qt_common/qt_path_util.cpp | 7 +- src/yuzu/CMakeLists.txt | 21 +- src/yuzu/compatdb.cpp | 2 +- src/yuzu/configuration/configure_web.cpp | 2 +- src/yuzu/data_dialog.cpp | 28 ++- src/yuzu/data_dialog.h | 3 + src/yuzu/data_widget.ui | 122 ++++++++--- src/yuzu/main.cpp | 8 + src/yuzu/multiplayer/chat_room.cpp | 2 +- src/yuzu/multiplayer/client_room.cpp | 2 +- src/yuzu/multiplayer/direct_connect.cpp | 2 +- src/yuzu/multiplayer/host_room.cpp | 2 +- src/yuzu/multiplayer/lobby.cpp | 2 +- 37 files changed, 433 insertions(+), 128 deletions(-) create mode 100644 dist/qt_themes/colorful/icons/48x48/download.png delete mode 100644 dist/qt_themes/colorful/icons/48x48/trash.png create mode 100644 dist/qt_themes/colorful/icons/48x48/upload.png create mode 100644 dist/qt_themes/colorful/icons/48x48/user-trash.png create mode 100644 dist/qt_themes/default/icons/48x48/download.png create mode 100644 dist/qt_themes/default/icons/48x48/upload.png rename dist/qt_themes/default/icons/48x48/{trash.png => user-trash.png} (100%) create mode 100644 dist/qt_themes/qdarkstyle/icons/48x48/download.png create mode 100644 dist/qt_themes/qdarkstyle/icons/48x48/upload.png rename dist/qt_themes/qdarkstyle/icons/48x48/{trash.png => user-trash.png} (100%) create mode 100644 quazip.patch diff --git a/dist/qt_themes/colorful/icons/48x48/download.png b/dist/qt_themes/colorful/icons/48x48/download.png new file mode 100644 index 0000000000000000000000000000000000000000..a24a434ce7b48f93e99a67acbd11f915858df440 GIT binary patch literal 1689 zcmV;K24?w*P)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy32;bRa{vGxhX4Q_hXIe}@nrx200(qQO+^Rk3JDS`B%k)#X8-^N z?@2^KRA}DqnQM$xWxIbJ+OB5A6q&rkJ#eS!pdH1!=t`l~UPM(_#x4VavLgSuVTFvS-e}A9&J? zT9%!i5vcByoXq9Sd*1i|T>sBAMxBz3Bmwvl@H5~Vnj^=7p90U6@};bvg@ONbiJS0@ zvp_#^vd(oKzzSgg!TmUa{%T5%mJ7KFb7}`z{e6m09yQg%Pc8@z3&;bI!j#tu7=PM@K@l|z?;D6 zEcPA+`hXO88yK=#=%H=^#e6YKMv|9+!$2!A?)^Z$(&t@R8!!p<7xTr8kDGkJW=SP! zMdX2Cve7^|+g0eQUXH^(G4Mnb;t+=r(o(Keofbe+Nld84WY+=T09p;(XR^0sI$6vY zFDZ!b;qFM8+CvBh3pNOxF6BzPa2Cp#XPK==+z)&gxKHSZnPr_>$a34pw?&ug@Y}|> zMMUI66z(*$PDC5}-w|FL#1U{UunPDLu*^TVBhvU>e6T!P9lk>WM)&I89IcP0eQbRn5=+!RzZ7J)evy*Lppp5kT+Q;@B`o$;I$d0 z(GWrkypv_wE5Jfv47i>1!>d-HYMHfT?CBouKBAy>>!PhqvBc8@Pg@$LQA+wLp?iRP zeebJWS!aEcabW;mi@O9&l!wblfSqP`%I|*xSPZNKa)>M_L{_!8y#_QajnD z)u_5VuEqyeW>lB8G$HQ$`&kiAa0cOZBN_RyFv$m7lnQe95C#} zbOYauvZrJ?iGiG9D`nc?o89QHcGR$!&1{E7_8KtJwP^aPU9OY^u)t(%+~4m4ZU7cI zzv{)i`WIcSt^t&A4)@GW~YHSfStfIUSu-hYIlVP zP4-nF_t?N=|D_&}AA39m3%Nj89|%7|bRw2}EFBQ~rO@+0pULVP)6Z(S+C9|0(9Etg zvkgxC)_9s71YQMRKuu0PuUE-N4~3`7LJ}rqeT( zq>{{Y&h%x(eZUuiMZhWGZ@{yb*~^A0v+NFx2RsFL0B3;xi03?AzEvueCND`#SwlUh zGG&L!m^5rkXw-vpDe!qjCevCWd5T=+RvH5K8n#QOKOv3>!mPPf!}Ix`k)C-%D}dXD zHUf7zi#_Akz%6qX=l{%m)v#WF?cbc=+z>Hr7=VK?nN|Q_lJrerJ+RzKAWq0m0DDdL z0`Q7Oc6{^V%?*>mrT_rwsr1A`IiWQ|_j)$E#c%(^us;C15PwFD6qgj!X6)NE05z3% z32>{)HhOlVrU>>G^Tl_Y+SDf_$!Z6Z0w)X`YIMAjRFZaJEpU^6bqLsB%9Tzx*zg3Q zCCWs&Y4f|#> zSIj&Eoocd&rk literal 0 HcmV?d00001 diff --git a/dist/qt_themes/colorful/icons/48x48/trash.png b/dist/qt_themes/colorful/icons/48x48/trash.png deleted file mode 100644 index e60dce2e32474e1d2c1329c1b23e88ab72a230b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 744 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/48x48/bad_folder.png icons/48x48/chip.png icons/48x48/folder.png - icons/48x48/trash.png + icons/48x48/user-trash.png + icons/48x48/download.png + icons/48x48/upload.png icons/48x48/list-add.png icons/48x48/no_avatar.png icons/48x48/sd_card.png diff --git a/dist/qt_themes/colorful_midnight_blue/style.qrc b/dist/qt_themes/colorful_midnight_blue/style.qrc index 2aee8ea1e1..18f8a6b823 100644 --- a/dist/qt_themes/colorful_midnight_blue/style.qrc +++ b/dist/qt_themes/colorful_midnight_blue/style.qrc @@ -11,7 +11,9 @@ SPDX-License-Identifier: GPL-2.0-or-later ../colorful/icons/48x48/bad_folder.png ../colorful/icons/48x48/chip.png ../colorful/icons/48x48/folder.png - ../colorful/icons/48x48/trash.png + ../colorful/icons/48x48/user-trash.png + ../colorful/icons/48x48/download.png + ../colorful/icons/48x48/upload.png ../colorful/icons/48x48/list-add.png ../colorful/icons/48x48/sd_card.png ../colorful/icons/256x256/plus_folder.png diff --git a/dist/qt_themes/default/default.qrc b/dist/qt_themes/default/default.qrc index 45a91ef2dc..e59f0ade9c 100644 --- a/dist/qt_themes/default/default.qrc +++ b/dist/qt_themes/default/default.qrc @@ -14,7 +14,9 @@ SPDX-License-Identifier: GPL-2.0-or-later icons/48x48/bad_folder.png icons/48x48/chip.png icons/48x48/folder.png - icons/48x48/trash.png + icons/48x48/user-trash.png + icons/48x48/download.png + icons/48x48/upload.png icons/48x48/list-add.png icons/48x48/sd_card.png icons/48x48/star.png diff --git a/dist/qt_themes/default/icons/48x48/download.png b/dist/qt_themes/default/icons/48x48/download.png new file mode 100644 index 0000000000000000000000000000000000000000..c0e32136550092bd142a01cdfd0460259f6251be GIT binary patch literal 853 zcmV-b1FHOqP)TDZgO+IcbK=`fpAZ9lAD?5ob&z7^E@-p zJa;5XqG`t_e1@Bt!>8D|9JL}V*qBAcQ@DoBJ*R%c3rUjv-DJIyCX;3Mn*YPYb9lAs zV#^_5W6rr}nl82+0#?+90@}8rfVOQYplurpXxoMY+P0y9w(Zdp5D~9L#P<<#J0gCG zh<77mb=Be#u_hwk%W^G5#B4;oTq;S4*ThNOLDJ)w@pMf#kK*m3xylI0dwCwm<%oFcen}!?QhMd{1TPh* zDn5iJq}@AccqF)unVj=8S)05Z|6pffu9Dj&ZxjHi;|n-YimAe$&u-~nPt)+Xu&*>v z#f__R{MaD;&)8gvrAkmHVjaF~0R9TrSLUc1n2C5C=WD=!i8Zwt>I7#Z0w*fKe}IwN z_3I|+5;BFm1;Fp(NMm(-ASQ4Q*Rj~A_!5rhh&UwwHoJg>Iq^rc8ohCg8PhpE%Z%=^ ze7Z#Ue~48BAofVN)q7*+FgYM*RhF}8{b`J5u_BvHWykPEJTU-h6F$zM|G-BE{6Byv zaj8Q6FFFF=su0}qs~D>>Z^rOLjrwoGw>1(Z(y_Uv0{m9os9F1Kn6H^6kuC%FmwR+0cC;BGyWKp|3U715J799+=140#{}w?KiwHo#Z=kOn=6C_(uCzy{dmTB7Leo ztTs(L$u4OBYL@lSyVpXaIQ0NP74?%kYoVUmz7uDqp9S<=jke{B8Pgd&-_6|kw-PID fkJjeygJ}N&qHq1?)^XoA00000NkvXXu0mjfK+lgO literal 0 HcmV?d00001 diff --git a/dist/qt_themes/default/icons/48x48/upload.png b/dist/qt_themes/default/icons/48x48/upload.png new file mode 100644 index 0000000000000000000000000000000000000000..46120cbdaf83bc3b47ca1ac5e479915d90157e9b GIT binary patch literal 820 zcmV-41Izr0P)Mc{ zK~!jg?b*AF6;~Vw@Xy&|7f~z(5kwmc!N!>QLM0#;Hj-!+$sZu3Q7c8npq7?te8nPY zLL|YIVwHyoM#0`lvVthSja#g%7(Ete2G*OovorVJ-MK6G3tt%Kob&sAzvs;3Jj59F znpleO@dyub7E7ij*EEPZ-biRL55sE-8PCt+-TD=MpwcQ;c>P z!LF*J>KKS6Wuw>_W4tnDkQlFH1OBR!yDjP%IE~i@_pf4ojPX|0KrzNqe2PB{ieKT| zsw6Qrtx7J2qCNuA)E;z{1ZZ$2qDBNc&H%eosxY2 zD+?ifT_Mjzrs+%wVa?beVf6{Ly8QacM`QuJ}#5 z-z57D#<~m=@h`U35dT@$rd_IROw(z6JXv$dCq%OqAJ&3qHsT%Qr}=v-{i+NA0000../colorful/icons/48x48/bad_folder.png ../colorful/icons/48x48/chip.png ../colorful/icons/48x48/folder.png - ../colorful/icons/48x48/trash.png + ../colorful/icons/48x48/user-trash.png + ../colorful/icons/48x48/download.png + ../colorful/icons/48x48/upload.png ../qdarkstyle/icons/48x48/no_avatar.png ../colorful/icons/48x48/list-add.png ../colorful/icons/48x48/sd_card.png diff --git a/dist/qt_themes/qdarkstyle/icons/48x48/download.png b/dist/qt_themes/qdarkstyle/icons/48x48/download.png new file mode 100644 index 0000000000000000000000000000000000000000..d4d26fe2eaa949c2ba10ef2befe7e814f6815e7e GIT binary patch literal 883 zcmV-(1C0EMP)JPrH=yja!$E3g;%r^sOCBAtc2%UbaOF9C;& z4pxr@+G56@FFIH~64+3h2{f8!0*$7bK%;3U&}f3tw(+2TE^99SIz5-m{Xx|)x77_iHJE5)qP2IrMUtpfX5^H zUjrtA&J?~n2)^wD5o0aD@uZH@BoO!T+yRUOZzS;3156N~@Je!3$$vuo!^<1Tf;tj2 zJ`&D}V@d5!sw-_7T&|%%j&73;zsTDgX)yJ7!iC$?T>Nzf$`hyyxJRM-yg=PW--(>Xw@;J z@?pFBSxn$+E~(pUh&W(SRZp)~eph5&uKf8#x?k@Z0Q+5m~FftWM{QJ&HP) z(~0Um^@z#EA5~{#{Qa(;4t<`9(fEJ@#8+5RKUZI|w(vdbwRQabt9Dh{_12nPQVV}c zMsT*70A_#^&`NOhcp-u9AHc4vzGr~BsL79I*BHz0uw|hY=mLIO)%SL-$t87;Aj8eX zUEl)2p>YrJ3DFwoO6nN!*2ZZol+iLU&}bDo7$^fnz*mh{l7S&$xJ*!O_=x}4mG~6+ z7}h>gb^|8~)?i;L002ov JPDHLkV1mEpn_&O| literal 0 HcmV?d00001 diff --git a/dist/qt_themes/qdarkstyle/icons/48x48/upload.png b/dist/qt_themes/qdarkstyle/icons/48x48/upload.png new file mode 100644 index 0000000000000000000000000000000000000000..ce255fb467cc47f0c025f21ca8007712562790d1 GIT binary patch literal 853 zcmV-b1FHOqP)K5rU(mld&Ac5=#)L ziMR|RwnQ8)iIG@hU*<5z#PT^*RnV$ys;XyHoAj5wOTGW{`=$C-b-jm5KaBC}3H6Qo zT0N$Y>yKXjA%1o!x{`NlOT8OdsdmMPkLXrc)vJLm>h}ck5#Q8J^<eDw^_v6>JIfQKgW&OdD`u_-IGnan76Z2lej?X_&%hI4H?RnJm!VF?+c0-;SgQ-T z7WTNCx=Jl?!75{O!UEmg*ZuOm2kMH3fud;`D4K?WqG=c?nudX*X&5M)0cT()aD-r+ zqnqF>ENSeFsrfXaU)hwWf5AKP&pjros0Tzwc5`#>EQ6Mrm6 z-&S?7;nreFJ)fh9>ieir#TaLBKJZ$7r5-o_e4t7FkhAyM$iSMM1tPY_2unM**VubC z>eU*Hbg6UAF22Ry_lSC<9ksK@BB~$NrKT6ZEX=9KbAvO4rRt6Zji2ZP@ex1Nlj>xv z3!kE%3S+DBU7b{sx1w5bN%QZoC(uE#U-Swn0b>X@vzk-nz68crTpIy&#sv?`uQ8Ek z(us{@3@{0}|J${N)q+cECxOFy;svme;7(2jwh^zfv!q@D=KniweM);7Xf0Yr4YZbl zGr+l`mE_3tb@M~`KAFI3D(4TV8}n07S9*p8E}O_{Jm(RmSfhs fV8DIQ{CE5W#2scUP!j%w00000NkvXXu0mjf5jlvy literal 0 HcmV?d00001 diff --git a/dist/qt_themes/qdarkstyle/icons/48x48/trash.png b/dist/qt_themes/qdarkstyle/icons/48x48/user-trash.png similarity index 100% rename from dist/qt_themes/qdarkstyle/icons/48x48/trash.png rename to dist/qt_themes/qdarkstyle/icons/48x48/user-trash.png diff --git a/dist/qt_themes/qdarkstyle/style.qrc b/dist/qt_themes/qdarkstyle/style.qrc index 2b5ca31e72..3902996058 100644 --- a/dist/qt_themes/qdarkstyle/style.qrc +++ b/dist/qt_themes/qdarkstyle/style.qrc @@ -9,7 +9,9 @@ icons/48x48/bad_folder.png icons/48x48/chip.png icons/48x48/folder.png - icons/48x48/trash.png + icons/48x48/user-trash.png + icons/48x48/download.png + icons/48x48/upload.png icons/48x48/no_avatar.png icons/48x48/list-add.png icons/48x48/sd_card.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc b/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc index dc3d7fecbd..75212008a3 100644 --- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc +++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc @@ -6,6 +6,9 @@ ../qdarkstyle/icons/48x48/bad_folder.png ../qdarkstyle/icons/48x48/chip.png ../qdarkstyle/icons/48x48/folder.png + ../qdarkstyle/icons/48x48/user-trash.png + ../qdarkstyle/icons/48x48/download.png + ../qdarkstyle/icons/48x48/upload.png ../qdarkstyle/icons/48x48/no_avatar.png ../qdarkstyle/icons/48x48/list-add.png ../qdarkstyle/icons/48x48/sd_card.png diff --git a/quazip.patch b/quazip.patch new file mode 100644 index 0000000000..4954fbde75 --- /dev/null +++ b/quazip.patch @@ -0,0 +1,56 @@ +diff --git a/quazip/JlCompress.cpp b/quazip/JlCompress.cpp +index 5394b2c..c189e8b 100644 +--- a/quazip/JlCompress.cpp ++++ b/quazip/JlCompress.cpp +@@ -26,6 +26,8 @@ see quazip/(un)zip.h files for details. Basically it's the zlib license. + #include "JlCompress.h" + #include + ++bool JlCompress::m_cancelled = false; ++ + bool JlCompress::copyData(QIODevice &inFile, QIODevice &outFile) + { + while (!inFile.atEnd()) { +@@ -474,6 +476,11 @@ QStringList JlCompress::getFileList(QIODevice *ioDevice) + return getFileList(zip); + } + ++void JlCompress::cancel() ++{ ++ m_cancelled = true; ++} ++ + QString JlCompress::extractFile(QIODevice *ioDevice, QString fileName, QString fileDest) + { + QuaZip zip(ioDevice); +@@ -484,4 +491,4 @@ QStringList JlCompress::extractFiles(QIODevice *ioDevice, QStringList files, QSt + { + QuaZip zip(ioDevice); + return extractFiles(zip, files, dir); +-} ++} +diff --git a/quazip/JlCompress.h b/quazip/JlCompress.h +index 1b009f2..28b4aba 100644 +--- a/quazip/JlCompress.h ++++ b/quazip/JlCompress.h +@@ -77,7 +77,7 @@ public: + }; + + public: +- explicit Options(const CompressionStrategy& strategy) ++ explicit Options(const CompressionStrategy& strategy) + : m_compressionStrategy(strategy) {} + + explicit Options(const QDateTime& dateTime = QDateTime(), const CompressionStrategy& strategy = Default) +@@ -323,6 +323,11 @@ public: + are present separately. + */ + static QStringList getFileList(QIODevice *ioDevice); ++ ++ static void cancel(); ++ ++private: ++ static bool m_cancelled; + }; + + #endif /* JLCOMPRESSFOLDER_H_ */ diff --git a/src/frontend_common/data_manager.cpp b/src/frontend_common/data_manager.cpp index 4a63ed9e28..e83e3ada40 100644 --- a/src/frontend_common/data_manager.cpp +++ b/src/frontend_common/data_manager.cpp @@ -21,7 +21,9 @@ const std::string GetDataDir(DataDir dir) case DataDir::UserNand: return (nand_dir / "user" / "Contents" / "registered").string(); case DataDir::SysNand: - return (nand_dir / "system").string(); + // NB: do NOT delete save + // that contains profile data and other stuff + return (nand_dir / "system" / "Contents" / "registered").string(); case DataDir::Mods: return Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir); case DataDir::Shaders: diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index fe728e0377..1f633fd894 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -35,9 +35,28 @@ if (ENABLE_QT) target_link_libraries(qt_common PRIVATE Qt6::Widgets) endif() +target_compile_definitions(qt_common PUBLIC + # Use QStringBuilder for string concatenation to reduce + # the overall number of temporary strings created. + QT_USE_QSTRINGBUILDER + + # Disable implicit conversions from/to C strings + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII + + # Disable implicit type narrowing in signal/slot connect() calls. + QT_NO_NARROWING_CONVERSIONS_IN_CONNECT + + # Disable unsafe overloads of QProcess' start() function. + QT_NO_PROCESS_COMBINED_ARGUMENT_START + + # Disable implicit QString->QUrl conversions to enforce use of proper resolving functions. + QT_NO_URL_CAST_FROM_STRING +) + add_subdirectory(externals) -target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) +target_link_libraries(qt_common PRIVATE core Qt6::Core Qt6::Concurrent SimpleIni::SimpleIni QuaZip::QuaZip) target_link_libraries(qt_common PUBLIC frozen::frozen) if (NOT APPLE AND ENABLE_OPENGL) diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 9cbd1caf02..98ae9620c7 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -1,17 +1,21 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -#include "qt_common/qt_game_util.h" +#include "frontend_common/data_manager.h" #include "qt_content_util.h" #include "common/fs/fs.h" #include "core/hle/service/acc/profile_manager.h" #include "frontend_common/content_manager.h" #include "frontend_common/firmware_manager.h" #include "qt_common/qt_common.h" +#include "qt_common/qt_game_util.h" #include "qt_common/qt_progress_dialog.h" #include "qt_frontend_util.h" +#include +#include #include +#include namespace QtCommon::Content { @@ -21,10 +25,10 @@ bool CheckGameFirmware(u64 program_id, QObject* parent) && !FirmwareManager::CheckFirmwarePresence(*system)) { auto result = QtCommon::Frontend::ShowMessage( QMessageBox::Warning, - "Game Requires Firmware", - "The game you are trying to launch requires firmware to boot or to get past the " - "opening menu. Please " - "dump and install firmware, or press \"OK\" to launch anyways.", + tr("Game Requires Firmware"), + tr("The game you are trying to launch requires firmware to boot or to get past the " + "opening menu. Please " + "dump and install firmware, or press \"OK\" to launch anyways."), QMessageBox::Ok | QMessageBox::Cancel, parent); @@ -60,8 +64,8 @@ void InstallFirmware(const QString& location, bool recursive) const auto ShowMessage = [&]() { QtCommon::Frontend::ShowMessage(icon, - failedTitle, - GetFirmwareInstallResultString(result)); + tr(failedTitle), + tr(GetFirmwareInstallResultString(result))); }; LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); @@ -125,8 +129,8 @@ void InstallFirmware(const QString& location, bool recursive) i++; auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), FileSys::OpenMode::Read); - auto firmware_dst_vfile = firmware_vdir - ->CreateFileRelative(firmware_src_path.filename().string()); + auto firmware_dst_vfile = firmware_vdir->CreateFileRelative( + firmware_src_path.filename().string()); if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { LOG_ERROR(Frontend, @@ -168,9 +172,9 @@ void InstallFirmware(const QString& location, bool recursive) const auto failed_names = QString::fromStdString( fmt::format("{}", fmt::join(results, "\n"))); progress.close(); - QtCommon::Frontend::Critical(tr("Firmware integrity verification failed!"), - tr("Verification failed for the following files:\n\n%1") - .arg(failed_names)); + QtCommon::Frontend::Critical( + tr("Firmware integrity verification failed!"), + tr("Verification failed for the following files:\n\n%1").arg(failed_names)); return; } @@ -181,10 +185,10 @@ void InstallFirmware(const QString& location, bool recursive) const std::string display_version(firmware_data.display_version.data()); result = FirmwareInstallResult::Success; - QtCommon::Frontend::Information(rootObject, - tr(successTitle), - tr(GetFirmwareInstallResultString(result)) - .arg(QString::fromStdString(display_version))); + QtCommon::Frontend::Information( + rootObject, + tr(successTitle), + tr(GetFirmwareInstallResultString(result)).arg(QString::fromStdString(display_version))); } QString UnzipFirmwareToTmp(const QString& location) @@ -193,7 +197,7 @@ QString UnzipFirmwareToTmp(const QString& location) fs::path tmp{fs::temp_directory_path()}; if (!fs::create_directories(tmp / "eden" / "firmware")) { - return ""; + return QString(); } tmp /= "eden"; @@ -205,7 +209,7 @@ QString UnzipFirmwareToTmp(const QString& location) QStringList result = JlCompress::extractDir(&zip, qCacheDir); if (result.isEmpty()) { - return ""; + return QString(); } return qCacheDir; @@ -264,9 +268,8 @@ void InstallKeys() return; } - FirmwareManager::KeyInstallResult result = FirmwareManager::InstallKeys(key_source_location - .toStdString(), - "keys"); + FirmwareManager::KeyInstallResult result + = FirmwareManager::InstallKeys(key_source_location.toStdString(), "keys"); system->GetFileSystemController().CreateFactories(*QtCommon::vfs); @@ -282,9 +285,14 @@ void InstallKeys() } } -void VerifyInstalledContents() { +void VerifyInstalledContents() +{ // Initialize a progress dialog. - QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, QtCommon::rootObject); + QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."), + tr("Cancel"), + 0, + 100, + QtCommon::rootObject); progress.setWindowModality(Qt::WindowModal); progress.setMinimumDuration(100); progress.setAutoClose(false); @@ -296,16 +304,17 @@ void VerifyInstalledContents() { return progress.wasCanceled(); }; - const std::vector result = - ContentManager::VerifyInstalledContents(*QtCommon::system, *QtCommon::provider, QtProgressCallback); + const std::vector result + = ContentManager::VerifyInstalledContents(*QtCommon::system, + *QtCommon::provider, + QtProgressCallback); progress.close(); if (result.empty()) { QtCommon::Frontend::Information(tr("Integrity verification succeeded!"), tr("The operation completed successfully.")); } else { - const auto failed_names = - QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); + const auto failed_names = QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); QtCommon::Frontend::Critical( tr("Integrity verification failed!"), tr("Verification failed for the following files:\n\n%1").arg(failed_names)); @@ -332,7 +341,7 @@ void FixProfiles() qorphaned.reserve(8 * 33); for (const std::string& s : orphaned) { - qorphaned += "\n" + QString::fromStdString(s); + qorphaned = qorphaned % QStringLiteral("\n") % QString::fromStdString(s); } QtCommon::Frontend::Critical( @@ -348,18 +357,19 @@ void FixProfiles() QtCommon::Game::OpenSaveFolder(); } -void ClearDataDir(FrontendCommon::DataManager::DataDir dir) { - auto result = QtCommon::Frontend::Warning("Really clear data?", - "Important data may be lost!", +void ClearDataDir(FrontendCommon::DataManager::DataDir dir) +{ + auto result = QtCommon::Frontend::Warning(tr("Really clear data?"), + tr("Important data may be lost!"), QMessageBox::Yes | QMessageBox::No); if (result != QMessageBox::Yes) return; result = QtCommon::Frontend::Warning( - "Are you REALLY sure?", - "Once deleted, your data will NOT come back!\n" - "Only do this if you're 100% sure you want to delete this data.", + tr("Are you REALLY sure?"), + tr("Once deleted, your data will NOT come back!\n" + "Only do this if you're 100% sure you want to delete this data."), QMessageBox::Yes | QMessageBox::No); if (result != QMessageBox::Yes) @@ -373,4 +383,130 @@ void ClearDataDir(FrontendCommon::DataManager::DataDir dir) { dialog.close(); } +void ExportDataDir(FrontendCommon::DataManager::DataDir data_dir, std::function callback) +{ + const std::string dir = FrontendCommon::DataManager::GetDataDir(data_dir); + + const QString zip_dump_location + = QtCommon::Frontend::GetSaveFileName(tr("Select Export Location"), + QStringLiteral("export.zip"), + tr("Zipped Archives (*.zip)")); + + if (zip_dump_location.isEmpty()) + return; + + QMetaObject::Connection* connection = new QMetaObject::Connection; + *connection = QObject::connect(qApp, &QGuiApplication::aboutToQuit, rootObject, [=]() mutable { + QtCommon::Frontend::Warning(tr("Still Exporting"), + tr("Eden is still exporting some data, and will continue " + "running in the background until it's done.")); + }); + + QtCommon::Frontend::QtProgressDialog* progress = new QtCommon::Frontend::QtProgressDialog( + tr("Compressing, this may take a while..."), tr("Background"), 0, 0, rootObject); + + progress->setWindowModality(Qt::WindowModal); + progress->show(); + QGuiApplication::processEvents(); + + QFuture future = QtConcurrent::run([&]() { + return JlCompress::compressDir(zip_dump_location, + QString::fromStdString(dir), + true, + QDir::Hidden | QDir::Files | QDir::Dirs); + }); + + QFutureWatcher* watcher = new QFutureWatcher(rootObject); + + QObject::connect(watcher, &QFutureWatcher::finished, rootObject, [=]() { + progress->close(); + progress->deleteLater(); + QObject::disconnect(*connection); + delete connection; + + if (watcher->result()) { + QtCommon::Frontend::Information(tr("Exported Successfully"), + tr("Data was exported successfully.")); + } else { + QtCommon::Frontend::Critical( + tr("Export Failed"), + tr("Ensure you have write permissions on the targeted directory and try again.")); + } + + watcher->deleteLater(); + callback(); + }); + + watcher->setFuture(future); +} + +void ImportDataDir(FrontendCommon::DataManager::DataDir data_dir, std::function callback) +{ + const std::string dir = FrontendCommon::DataManager::GetDataDir(data_dir); + + using namespace QtCommon::Frontend; + + const QString zip_dump_location = GetOpenFileName(tr("Select Import Location"), + {}, + tr("Zipped Archives (*.zip)")); + + if (zip_dump_location.isEmpty()) + return; + + StandardButton button = Warning( + tr("Import Warning"), + tr("All previous data in this directory will be deleted. Are you sure you wish to " + "proceed?"), + StandardButton::Yes | StandardButton::No); + + if (button != QMessageBox::Yes) + return; + + FrontendCommon::DataManager::ClearDir(data_dir); + + QMetaObject::Connection* connection = new QMetaObject::Connection; + *connection = QObject::connect(qApp, &QGuiApplication::aboutToQuit, rootObject, [=]() mutable { + Warning(tr("Still Importing"), + tr("Eden is still importing some data, and will continue " + "running in the background until it's done.")); + }); + + QtProgressDialog* progress = new QtProgressDialog(tr("Decompressing, this may take a while..."), + tr("Background"), + 0, + 0, + rootObject); + + progress->setWindowModality(Qt::WindowModal); + progress->show(); + QGuiApplication::processEvents(); + + QFuture future = QtConcurrent::run([=]() { + return !JlCompress::extractDir(zip_dump_location, + QString::fromStdString(dir)).empty(); + }); + + QFutureWatcher* watcher = new QFutureWatcher(rootObject); + + QObject::connect(watcher, &QFutureWatcher::finished, rootObject, [=]() { + progress->close(); + progress->deleteLater(); + QObject::disconnect(*connection); + delete connection; + + if (watcher->result()) { + Information(tr("Imported Successfully"), tr("Data was imported successfully.")); + } else { + Critical( + tr("Import Failed"), + tr("Ensure you have read permissions on the targeted directory and try again.")); + } + + watcher->deleteLater(); + callback(); + }); + + watcher->setFuture(future); +} + } // namespace QtCommon::Content diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index b2443829ab..fb6d1b85fa 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -48,6 +48,8 @@ void VerifyGameContents(const std::string &game_path); void VerifyInstalledContents(); void ClearDataDir(FrontendCommon::DataManager::DataDir dir); +void ExportDataDir(FrontendCommon::DataManager::DataDir dir, std::function callback = {}); +void ImportDataDir(FrontendCommon::DataManager::DataDir dir, std::function callback = {}); // Profiles // void FixProfiles(); diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index d519669ad5..3fe0ba0a80 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -32,4 +32,15 @@ const QString GetOpenFileName(const QString &title, #endif } +const QString GetSaveFileName(const QString &title, + const QString &dir, + const QString &filter, + QString *selectedFilter, + Options options) +{ +#ifdef YUZU_QT_WIDGETS + return QFileDialog::getSaveFileName((QWidget *) rootObject, title, dir, filter, selectedFilter, options); +#endif +} + } // namespace QtCommon::Frontend diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index f86b9e1357..59e8f15a4e 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -97,10 +97,10 @@ Q_ENUM_NS(Icon) // TODO(crueter) widgets-less impl, choices et al. StandardButton ShowMessage(Icon icon, - const QString &title, - const QString &text, - StandardButtons buttons = StandardButton::NoButton, - QObject *parent = nullptr); + const QString &title, + const QString &text, + StandardButtons buttons = StandardButton::NoButton, + QObject *parent = nullptr); #define UTIL_OVERRIDES(level) \ inline StandardButton level(QObject *parent, \ @@ -110,21 +110,6 @@ StandardButton ShowMessage(Icon icon, { \ return ShowMessage(Icon::level, title, text, buttons, parent); \ } \ - inline StandardButton level(QObject *parent, \ - const char *title, \ - const char *text, \ - StandardButtons buttons \ - = StandardButton::Ok) \ - { \ - return ShowMessage(Icon::level, tr(title), tr(text), buttons, parent); \ - } \ - inline StandardButton level(const char *title, \ - const char *text, \ - StandardButtons buttons \ - = StandardButton::Ok) \ - { \ - return ShowMessage(Icon::level, tr(title), tr(text), buttons, rootObject); \ - } \ inline StandardButton level(const QString title, \ const QString &text, \ StandardButtons buttons \ @@ -144,5 +129,11 @@ const QString GetOpenFileName(const QString &title, QString *selectedFilter = nullptr, Options options = Options()); +const QString GetSaveFileName(const QString &title, + const QString &dir, + const QString &filter, + QString *selectedFilter = nullptr, + Options options = Options()); + } // namespace QtCommon::Frontend #endif // QT_FRONTEND_UTIL_H diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index ac922ea967..0eddd10fe1 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -220,8 +220,8 @@ void RemoveBaseContent(u64 program_id, InstalledEntryType type) program_id); if (res) { QtCommon::Frontend::Information(rootObject, - "Successfully Removed", - "Successfully removed the installed base game."); + tr("Successfully Removed"), + tr("Successfully removed the installed base game.")); } else { QtCommon::Frontend::Warning( rootObject, @@ -235,8 +235,8 @@ void RemoveUpdateContent(u64 program_id, InstalledEntryType type) const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id); if (res) { QtCommon::Frontend::Information(rootObject, - "Successfully Removed", - "Successfully removed the installed update."); + tr("Successfully Removed"), + tr("Successfully removed the installed update.")); } else { QtCommon::Frontend::Warning(rootObject, GetGameListErrorRemoving(type), diff --git a/src/qt_common/qt_path_util.cpp b/src/qt_common/qt_path_util.cpp index 761e6e8405..632424e0ca 100644 --- a/src/qt_common/qt_path_util.cpp +++ b/src/qt_common/qt_path_util.cpp @@ -17,7 +17,12 @@ bool OpenShaderCache(u64 program_id, QObject *parent) const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; if (!Common::FS::CreateDirs(shader_cache_folder_path)) { - QtCommon::Frontend::ShowMessage(QMessageBox::Warning, "Error Opening Shader Cache", "Failed to create or open shader cache for this title, ensure your app data directory has write permissions.", QMessageBox::Ok, parent); + QtCommon::Frontend::ShowMessage(QMessageBox::Warning, + tr("Error Opening Shader Cache"), + tr("Failed to create or open shader cache for this title, " + "ensure your app data directory has write permissions."), + QMessageBox::Ok, + parent); } const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index f4669d0914..010a3db174 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -393,7 +393,7 @@ endif() target_link_libraries(yuzu PRIVATE nlohmann_json::nlohmann_json) target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core qt_common) -target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets) +target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets Qt6::Concurrent) target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) if (NOT WIN32) @@ -408,25 +408,6 @@ if (UNIX AND NOT APPLE) endif() endif() -target_compile_definitions(yuzu PRIVATE - # Use QStringBuilder for string concatenation to reduce - # the overall number of temporary strings created. - QT_USE_QSTRINGBUILDER - - # Disable implicit conversions from/to C strings - QT_NO_CAST_FROM_ASCII - QT_NO_CAST_TO_ASCII - - # Disable implicit type narrowing in signal/slot connect() calls. - QT_NO_NARROWING_CONVERSIONS_IN_CONNECT - - # Disable unsafe overloads of QProcess' start() function. - QT_NO_PROCESS_COMBINED_ARGUMENT_START - - # Disable implicit QString->QUrl conversions to enforce use of proper resolving functions. - QT_NO_URL_CAST_FROM_STRING -) - if (YUZU_ENABLE_COMPATIBILITY_REPORTING) target_compile_definitions(yuzu PRIVATE YUZU_ENABLE_COMPATIBILITY_REPORTING) endif() diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp index 0e58f17405..85cac51eea 100644 --- a/src/yuzu/compatdb.cpp +++ b/src/yuzu/compatdb.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "common/logging/log.h" #include "ui_compatdb.h" #include "yuzu/compatdb.h" diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp index 15a0029901..7a693be10c 100644 --- a/src/yuzu/configuration/configure_web.cpp +++ b/src/yuzu/configuration/configure_web.cpp @@ -14,7 +14,7 @@ #include #endif -#include +#include #include "common/settings.h" #include "ui_configure_web.h" #include "qt_common/uisettings.h" diff --git a/src/yuzu/data_dialog.cpp b/src/yuzu/data_dialog.cpp index 87d81e4f43..d7c937e7ed 100644 --- a/src/yuzu/data_dialog.cpp +++ b/src/yuzu/data_dialog.cpp @@ -4,12 +4,16 @@ #include "data_dialog.h" #include "frontend_common/data_manager.h" #include "qt_common/qt_content_util.h" +#include "qt_common/qt_frontend_util.h" +#include "qt_common/qt_progress_dialog.h" #include "qt_common/qt_string_lookup.h" #include "ui_data_dialog.h" #include +#include #include -#include +#include +#include DataDialog::DataDialog(QWidget *parent) : QDialog(parent) @@ -49,25 +53,41 @@ DataWidget::DataWidget(FrontendCommon::DataManager::DataDir data_dir, ui->tooltip->setText(QtCommon::StringLookup::Lookup(tooltip)); - ui->clear->setIcon(QIcon::fromTheme(QStringLiteral("trash"))); + ui->clear->setIcon(QIcon::fromTheme(QStringLiteral("user-trash"))); ui->open->setIcon(QIcon::fromTheme(QStringLiteral("folder"))); + ui->upload->setIcon(QIcon::fromTheme(QStringLiteral("upload"))); + ui->download->setIcon(QIcon::fromTheme(QStringLiteral("download"))); connect(ui->clear, &QPushButton::clicked, this, &DataWidget::clear); connect(ui->open, &QPushButton::clicked, this, &DataWidget::open); + connect(ui->upload, &QPushButton::clicked, this, &DataWidget::upload); + connect(ui->download, &QPushButton::clicked, this, &DataWidget::download); scan(); } -void DataWidget::clear() { +void DataWidget::clear() +{ QtCommon::Content::ClearDataDir(m_dir); scan(); } -void DataWidget::open() { +void DataWidget::open() +{ QDesktopServices::openUrl(QUrl::fromLocalFile( QString::fromStdString(FrontendCommon::DataManager::GetDataDir(m_dir)))); } +void DataWidget::upload() +{ + QtCommon::Content::ExportDataDir(m_dir); +} + +void DataWidget::download() +{ + QtCommon::Content::ImportDataDir(m_dir, std::bind(&DataWidget::scan, this)); +} + void DataWidget::scan() { ui->size->setText(tr("Calculating...")); diff --git a/src/yuzu/data_dialog.h b/src/yuzu/data_dialog.h index 9f367d6049..8a64659965 100644 --- a/src/yuzu/data_dialog.h +++ b/src/yuzu/data_dialog.h @@ -37,6 +37,9 @@ public: public slots: void clear(); void open(); + void upload(); + void download(); + void scan(); private: diff --git a/src/yuzu/data_widget.ui b/src/yuzu/data_widget.ui index ed67078fa1..99010d8856 100644 --- a/src/yuzu/data_widget.ui +++ b/src/yuzu/data_widget.ui @@ -13,8 +13,8 @@ Form - - + + @@ -50,14 +50,8 @@ - - - - QLayout::SizeConstraint::SetFixedSize - - - 25 - + + @@ -69,7 +63,7 @@ 52 - 42 + 47 @@ -77,14 +71,10 @@ QPushButton { - border-style: solid; - border-width:1px; - border-radius:25px; - border-color: transparent; - max-width:50px; - max-height:40px; - min-width:50px; - min-height:40px; +max-width: 50px; +max-height: 45px; +min-width: 50px; +min-height: 45px; } @@ -92,8 +82,8 @@ - 24 - 24 + 28 + 28 @@ -109,7 +99,7 @@ 52 - 42 + 47 @@ -117,14 +107,10 @@ QPushButton { - border-style: solid; - border-width:1px; - border-radius:25px; - border-color: transparent; - max-width:50px; - max-height:40px; - min-width:50px; - min-height:40px; +max-width: 50px; +max-height: 45px; +min-width: 50px; +min-height: 45px; } @@ -132,8 +118,80 @@ - 24 - 24 + 28 + 28 + + + + + + + + + 1 + 1 + + + + + 52 + 47 + + + + Export all data in this directory. This may take a while! + + + QPushButton { +max-width: 50px; +max-height: 45px; +min-width: 50px; +min-height: 45px; +} + + + + + + + 28 + 28 + + + + + + + + + 1 + 1 + + + + + 52 + 47 + + + + Import data for this directory. This may take a while, and will delete ALL EXISTING DATA! + + + QPushButton { +max-width: 50px; +max-height: 45px; +min-width: 50px; +min-height: 45px; +} + + + + + + + 28 + 28 diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index b6dded447c..21c92c495f 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3939,6 +3939,10 @@ void GMainWindow::OnEdenDependencies() { void GMainWindow::OnDataDialog() { DataDialog dataDialog(this); dataDialog.exec(); + + // refresh stuff in case it was cleared + OnGameListRefresh(); + } void GMainWindow::OnToggleFilterBar() { @@ -4481,11 +4485,15 @@ void GMainWindow::SetFirmwareVersion() { if (result.IsError() || !CheckFirmwarePresence()) { LOG_INFO(Frontend, "Installed firmware: No firmware available"); + ui->menu_Applets->setEnabled(false); + ui->menu_Create_Shortcuts->setEnabled(false); firmware_label->setVisible(false); return; } firmware_label->setVisible(true); + ui->menu_Applets->setEnabled(true); + ui->menu_Create_Shortcuts->setEnabled(true); const std::string display_version(firmware_data.display_version.data()); const std::string display_title(firmware_data.display_title.data()); diff --git a/src/yuzu/multiplayer/chat_room.cpp b/src/yuzu/multiplayer/chat_room.cpp index 4c2c41ea2a..53beda0f8e 100644 --- a/src/yuzu/multiplayer/chat_room.cpp +++ b/src/yuzu/multiplayer/chat_room.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include "common/logging/log.h" #include "network/announce_multiplayer_session.h" #include "ui_chat_room.h" diff --git a/src/yuzu/multiplayer/client_room.cpp b/src/yuzu/multiplayer/client_room.cpp index 93d6662c1e..4e995c044f 100644 --- a/src/yuzu/multiplayer/client_room.cpp +++ b/src/yuzu/multiplayer/client_room.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include "common/logging/log.h" #include "network/announce_multiplayer_session.h" #include "ui_client_room.h" diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp index deac3b9e59..6291979fe6 100644 --- a/src/yuzu/multiplayer/direct_connect.cpp +++ b/src/yuzu/multiplayer/direct_connect.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include "common/settings.h" #include "core/core.h" #include "core/internal_network/network_interface.h" diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index 4dd3958550..cc163a5420 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "common/logging/log.h" #include "common/settings.h" #include "core/core.h" diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp index 84723041df..e8daa0c6eb 100644 --- a/src/yuzu/multiplayer/lobby.cpp +++ b/src/yuzu/multiplayer/lobby.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include "common/logging/log.h" #include "common/settings.h" #include "core/core.h"