summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt21
-rw-r--r--README.md4
-rw-r--r--src/common/alignment.h4
-rw-r--r--src/core/file_sys/bis_factory.cpp23
-rw-r--r--src/core/file_sys/sdmc_factory.cpp4
-rw-r--r--src/core/file_sys/vfs_real.cpp27
-rw-r--r--src/core/hle/service/am/am.cpp14
-rw-r--r--src/core/settings.h29
-rw-r--r--src/input_common/CMakeLists.txt3
-rw-r--r--src/input_common/gcadapter/gc_adapter.cpp11
-rw-r--r--src/input_common/gcadapter/gc_adapter.h15
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp42
-rw-r--r--src/input_common/gcadapter/gc_poller.h2
-rw-r--r--src/input_common/main.cpp1
-rw-r--r--src/input_common/udp/client.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp12
-rw-r--r--src/yuzu/CMakeLists.txt6
-rw-r--r--src/yuzu/configuration/config.cpp29
-rw-r--r--src/yuzu/configuration/configure_filesystem.cpp27
-rw-r--r--src/yuzu/configuration/configure_filesystem.ui121
-rw-r--r--src/yuzu/configuration/configure_general.cpp2
-rw-r--r--src/yuzu/game_list.cpp4
-rw-r--r--src/yuzu/install_dialog.cpp72
-rw-r--r--src/yuzu/install_dialog.h36
-rw-r--r--src/yuzu/main.cpp358
-rw-r--r--src/yuzu/main.h15
-rw-r--r--src/yuzu/main.ui2
-rw-r--r--src/yuzu_cmd/config.cpp9
28 files changed, 468 insertions, 427 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1c0e49c03..ce46a2c2b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -118,8 +118,17 @@ message(STATUS "Target architecture: ${ARCHITECTURE}")
118# Configure C++ standard 118# Configure C++ standard
119# =========================== 119# ===========================
120 120
121set(CMAKE_CXX_STANDARD 17) 121# boost asio's concept usage doesn't play nicely with some compilers yet.
122set(CMAKE_CXX_STANDARD_REQUIRED ON) 122add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS)
123if (MSVC)
124 add_compile_options(/std:c++latest)
125
126 # cubeb and boost still make use of deprecated result_of.
127 add_definitions(-D_HAS_DEPRECATED_RESULT_OF)
128else()
129 set(CMAKE_CXX_STANDARD 20)
130 set(CMAKE_CXX_STANDARD_REQUIRED ON)
131endif()
123 132
124# Output binaries to bin/ 133# Output binaries to bin/
125set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) 134set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
@@ -330,14 +339,16 @@ elseif(SDL2_FOUND)
330endif() 339endif()
331 340
332# Ensure libusb is properly configured (based on dolphin libusb include) 341# Ensure libusb is properly configured (based on dolphin libusb include)
333include(FindPkgConfig) 342if(NOT APPLE)
334find_package(LibUSB) 343 include(FindPkgConfig)
344 find_package(LibUSB)
345endif()
335if (NOT LIBUSB_FOUND) 346if (NOT LIBUSB_FOUND)
336 add_subdirectory(externals/libusb) 347 add_subdirectory(externals/libusb)
348 set(LIBUSB_INCLUDE_DIR "")
337 set(LIBUSB_LIBRARIES usb) 349 set(LIBUSB_LIBRARIES usb)
338endif() 350endif()
339 351
340
341# Prefer the -pthread flag on Linux. 352# Prefer the -pthread flag on Linux.
342set(THREADS_PREFER_PTHREAD_FLAG ON) 353set(THREADS_PREFER_PTHREAD_FLAG ON)
343find_package(Threads REQUIRED) 354find_package(Threads REQUIRED)
diff --git a/README.md b/README.md
index 1e9f67e08..e4ecb531d 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@ yuzu emulator
2============= 2=============
3[![Travis CI Build Status](https://travis-ci.com/yuzu-emu/yuzu.svg?branch=master)](https://travis-ci.com/yuzu-emu/yuzu) 3[![Travis CI Build Status](https://travis-ci.com/yuzu-emu/yuzu.svg?branch=master)](https://travis-ci.com/yuzu-emu/yuzu)
4[![Azure Mainline CI Build Status](https://dev.azure.com/yuzu-emu/yuzu/_apis/build/status/yuzu%20mainline?branchName=master)](https://dev.azure.com/yuzu-emu/yuzu/) 4[![Azure Mainline CI Build Status](https://dev.azure.com/yuzu-emu/yuzu/_apis/build/status/yuzu%20mainline?branchName=master)](https://dev.azure.com/yuzu-emu/yuzu/)
5[![Discord](https://img.shields.io/discord/398318088170242053?color=%237289DA&label=yuzu&logo=discord&logoColor=white)](https://discord.gg/XQV6dn9) 5[![Discord](https://img.shields.io/discord/398318088170242053?color=%237289DA&label=yuzu&logo=discord&logoColor=white)](https://discord.com/invite/u77vRWY)
6 6
7yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/). 7yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/).
8 8
@@ -16,7 +16,7 @@ yuzu is licensed under the GPLv2 (or any later version). Refer to the license.tx
16 16
17Check out our [website](https://yuzu-emu.org/)! 17Check out our [website](https://yuzu-emu.org/)!
18 18
19For development discussion, please join us on [Discord](https://discord.gg/XQV6dn9). 19For development discussion, please join us on [Discord](https://discord.com/invite/u77vRWY).
20 20
21### Development 21### Development
22 22
diff --git a/src/common/alignment.h b/src/common/alignment.h
index f8c49e079..b37044bb6 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -11,7 +11,9 @@ namespace Common {
11template <typename T> 11template <typename T>
12constexpr T AlignUp(T value, std::size_t size) { 12constexpr T AlignUp(T value, std::size_t size) {
13 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 13 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
14 return static_cast<T>(value + (size - value % size) % size); 14 auto mod{static_cast<T>(value % size)};
15 value -= mod;
16 return static_cast<T>(mod == T{0} ? value : value + size);
15} 17}
16 18
17template <typename T> 19template <typename T>
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index 8935a62c3..285277ef8 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -12,6 +12,10 @@
12 12
13namespace FileSys { 13namespace FileSys {
14 14
15constexpr u64 NAND_USER_SIZE = 0x680000000; // 26624 MiB
16constexpr u64 NAND_SYSTEM_SIZE = 0xA0000000; // 2560 MiB
17constexpr u64 NAND_TOTAL_SIZE = 0x747C00000; // 29820 MiB
18
15BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_) 19BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_)
16 : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)), 20 : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)),
17 dump_root(std::move(dump_root_)), 21 dump_root(std::move(dump_root_)),
@@ -110,30 +114,29 @@ VirtualDir BISFactory::GetImageDirectory() const {
110 114
111u64 BISFactory::GetSystemNANDFreeSpace() const { 115u64 BISFactory::GetSystemNANDFreeSpace() const {
112 const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system"); 116 const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system");
113 if (sys_dir == nullptr) 117 if (sys_dir == nullptr) {
114 return 0; 118 return GetSystemNANDTotalSpace();
119 }
115 120
116 return GetSystemNANDTotalSpace() - sys_dir->GetSize(); 121 return GetSystemNANDTotalSpace() - sys_dir->GetSize();
117} 122}
118 123
119u64 BISFactory::GetSystemNANDTotalSpace() const { 124u64 BISFactory::GetSystemNANDTotalSpace() const {
120 return static_cast<u64>(Settings::values.nand_system_size); 125 return NAND_SYSTEM_SIZE;
121} 126}
122 127
123u64 BISFactory::GetUserNANDFreeSpace() const { 128u64 BISFactory::GetUserNANDFreeSpace() const {
124 const auto usr_dir = GetOrCreateDirectoryRelative(nand_root, "/user"); 129 // For some reason games such as BioShock 1 checks whether this is exactly 0x680000000 bytes.
125 if (usr_dir == nullptr) 130 // Set the free space to be 1 MiB less than the total as a workaround to this issue.
126 return 0; 131 return GetUserNANDTotalSpace() - 0x100000;
127
128 return GetUserNANDTotalSpace() - usr_dir->GetSize();
129} 132}
130 133
131u64 BISFactory::GetUserNANDTotalSpace() const { 134u64 BISFactory::GetUserNANDTotalSpace() const {
132 return static_cast<u64>(Settings::values.nand_user_size); 135 return NAND_USER_SIZE;
133} 136}
134 137
135u64 BISFactory::GetFullNANDTotalSpace() const { 138u64 BISFactory::GetFullNANDTotalSpace() const {
136 return static_cast<u64>(Settings::values.nand_total_size); 139 return NAND_TOTAL_SIZE;
137} 140}
138 141
139VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const { 142VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const {
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
index 5113a1ca6..6f732e4d8 100644
--- a/src/core/file_sys/sdmc_factory.cpp
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -10,6 +10,8 @@
10 10
11namespace FileSys { 11namespace FileSys {
12 12
13constexpr u64 SDMC_TOTAL_SIZE = 0x10000000000; // 1 TiB
14
13SDMCFactory::SDMCFactory(VirtualDir dir_) 15SDMCFactory::SDMCFactory(VirtualDir dir_)
14 : dir(std::move(dir_)), contents(std::make_unique<RegisteredCache>( 16 : dir(std::move(dir_)), contents(std::make_unique<RegisteredCache>(
15 GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"), 17 GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"),
@@ -46,7 +48,7 @@ u64 SDMCFactory::GetSDMCFreeSpace() const {
46} 48}
47 49
48u64 SDMCFactory::GetSDMCTotalSpace() const { 50u64 SDMCFactory::GetSDMCTotalSpace() const {
49 return static_cast<u64>(Settings::values.sdmc_size); 51 return SDMC_TOTAL_SIZE;
50} 52}
51 53
52} // namespace FileSys 54} // namespace FileSys
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index e21300a7c..96ce5957c 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -112,19 +112,26 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
112 const auto new_path = 112 const auto new_path =
113 FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); 113 FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
114 114
115 if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
116 FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
117 return nullptr;
118
119 if (cache.find(old_path) != cache.end()) { 115 if (cache.find(old_path) != cache.end()) {
120 auto cached = cache[old_path]; 116 auto file = cache[old_path].lock();
121 if (!cached.expired()) { 117
122 auto file = cached.lock(); 118 if (!cache[old_path].expired()) {
123 file->Open(new_path, "r+b"); 119 file->Close();
124 cache.erase(old_path); 120 }
125 cache[new_path] = file; 121
122 if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
123 FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) {
124 return nullptr;
126 } 125 }
126
127 cache.erase(old_path);
128 file->Open(new_path, "r+b");
129 cache[new_path] = file;
130 } else {
131 UNREACHABLE();
132 return nullptr;
127 } 133 }
134
128 return OpenFile(new_path, Mode::ReadWrite); 135 return OpenFile(new_path, Mode::ReadWrite);
129} 136}
130 137
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 256449aa7..4e7a0bec9 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1407,7 +1407,19 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
1407 u32 supported_languages = 0; 1407 u32 supported_languages = 0;
1408 FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; 1408 FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()};
1409 1409
1410 const auto res = pm.GetControlMetadata(); 1410 const auto res = [this] {
1411 const auto title_id = system.CurrentProcess()->GetTitleID();
1412
1413 FileSys::PatchManager pm{title_id};
1414 auto res = pm.GetControlMetadata();
1415 if (res.first != nullptr) {
1416 return res;
1417 }
1418
1419 FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)};
1420 return pm_update.GetControlMetadata();
1421 }();
1422
1411 if (res.first != nullptr) { 1423 if (res.first != nullptr) {
1412 supported_languages = res.first->GetSupportedLanguages(); 1424 supported_languages = res.first->GetSupportedLanguages();
1413 } 1425 }
diff --git a/src/core/settings.h b/src/core/settings.h
index b3451a704..3eb336f75 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -346,31 +346,6 @@ struct TouchscreenInput {
346 u32 rotation_angle; 346 u32 rotation_angle;
347}; 347};
348 348
349enum class NANDTotalSize : u64 {
350 S29_1GB = 0x747C00000ULL,
351};
352
353enum class NANDUserSize : u64 {
354 S26GB = 0x680000000ULL,
355};
356
357enum class NANDSystemSize : u64 {
358 S2_5GB = 0xA0000000,
359};
360
361enum class SDMCSize : u64 {
362 S1GB = 0x40000000,
363 S2GB = 0x80000000,
364 S4GB = 0x100000000ULL,
365 S8GB = 0x200000000ULL,
366 S16GB = 0x400000000ULL,
367 S32GB = 0x800000000ULL,
368 S64GB = 0x1000000000ULL,
369 S128GB = 0x2000000000ULL,
370 S256GB = 0x4000000000ULL,
371 S1TB = 0x10000000000ULL,
372};
373
374enum class RendererBackend { 349enum class RendererBackend {
375 OpenGL = 0, 350 OpenGL = 0,
376 Vulkan = 1, 351 Vulkan = 1,
@@ -508,10 +483,6 @@ struct Values {
508 bool gamecard_inserted; 483 bool gamecard_inserted;
509 bool gamecard_current_game; 484 bool gamecard_current_game;
510 std::string gamecard_path; 485 std::string gamecard_path;
511 NANDTotalSize nand_total_size;
512 NANDSystemSize nand_system_size;
513 NANDUserSize nand_user_size;
514 SDMCSize sdmc_size;
515 486
516 // Debugging 487 // Debugging
517 bool record_frame_times; 488 bool record_frame_times;
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 3bd76dd23..317c25bad 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -30,7 +30,8 @@ if(SDL2_FOUND)
30 target_compile_definitions(input_common PRIVATE HAVE_SDL2) 30 target_compile_definitions(input_common PRIVATE HAVE_SDL2)
31endif() 31endif()
32 32
33target_link_libraries(input_common PUBLIC ${LIBUSB_LIBRARIES}) 33target_include_directories(input_common SYSTEM PRIVATE ${LIBUSB_INCLUDE_DIR})
34target_link_libraries(input_common PRIVATE ${LIBUSB_LIBRARIES})
34 35
35create_target_directory_groups(input_common) 36create_target_directory_groups(input_common)
36target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost) 37target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost)
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp
index 6d9f4d9eb..38210ffcb 100644
--- a/src/input_common/gcadapter/gc_adapter.cpp
+++ b/src/input_common/gcadapter/gc_adapter.cpp
@@ -4,6 +4,7 @@
4 4
5#include <chrono> 5#include <chrono>
6#include <thread> 6#include <thread>
7#include <libusb.h>
7#include "common/logging/log.h" 8#include "common/logging/log.h"
8#include "input_common/gcadapter/gc_adapter.h" 9#include "input_common/gcadapter/gc_adapter.h"
9 10
@@ -33,7 +34,7 @@ Adapter::Adapter() {
33 } 34 }
34} 35}
35 36
36GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_payload) { 37GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) {
37 GCPadStatus pad = {}; 38 GCPadStatus pad = {};
38 bool get_origin = false; 39 bool get_origin = false;
39 40
@@ -198,7 +199,7 @@ void Adapter::StartScanThread() {
198 } 199 }
199 200
200 detect_thread_running = true; 201 detect_thread_running = true;
201 detect_thread = std::thread([=] { ScanThreadFunc(); }); 202 detect_thread = std::thread(&Adapter::ScanThreadFunc, this);
202} 203}
203 204
204void Adapter::StopScanThread() { 205void Adapter::StopScanThread() {
@@ -227,7 +228,7 @@ void Adapter::Setup() {
227 } 228 }
228 229
229 if (devices != nullptr) { 230 if (devices != nullptr) {
230 for (std::size_t index = 0; index < device_count; ++index) { 231 for (std::size_t index = 0; index < static_cast<std::size_t>(device_count); ++index) {
231 if (CheckDeviceAccess(devices[index])) { 232 if (CheckDeviceAccess(devices[index])) {
232 // GC Adapter found and accessible, registering it 233 // GC Adapter found and accessible, registering it
233 GetGCEndpoint(devices[index]); 234 GetGCEndpoint(devices[index]);
@@ -357,11 +358,11 @@ void Adapter::Reset() {
357 } 358 }
358} 359}
359 360
360bool Adapter::DeviceConnected(int port) { 361bool Adapter::DeviceConnected(std::size_t port) {
361 return adapter_controllers_status[port] != ControllerTypes::None; 362 return adapter_controllers_status[port] != ControllerTypes::None;
362} 363}
363 364
364void Adapter::ResetDeviceType(int port) { 365void Adapter::ResetDeviceType(std::size_t port) {
365 adapter_controllers_status[port] = ControllerTypes::None; 366 adapter_controllers_status[port] = ControllerTypes::None;
366} 367}
367 368
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h
index b1c2a1958..e2cdd6255 100644
--- a/src/input_common/gcadapter/gc_adapter.h
+++ b/src/input_common/gcadapter/gc_adapter.h
@@ -8,10 +8,13 @@
8#include <mutex> 8#include <mutex>
9#include <thread> 9#include <thread>
10#include <unordered_map> 10#include <unordered_map>
11#include <libusb.h>
12#include "common/common_types.h" 11#include "common/common_types.h"
13#include "common/threadsafe_queue.h" 12#include "common/threadsafe_queue.h"
14 13
14struct libusb_context;
15struct libusb_device;
16struct libusb_device_handle;
17
15namespace GCAdapter { 18namespace GCAdapter {
16 19
17enum { 20enum {
@@ -97,6 +100,9 @@ public:
97 void BeginConfiguration(); 100 void BeginConfiguration();
98 void EndConfiguration(); 101 void EndConfiguration();
99 102
103 /// Returns true if there is a device connected to port
104 bool DeviceConnected(std::size_t port);
105
100 std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); 106 std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue();
101 const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; 107 const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const;
102 108
@@ -104,7 +110,7 @@ public:
104 const std::array<GCState, 4>& GetPadState() const; 110 const std::array<GCState, 4>& GetPadState() const;
105 111
106private: 112private:
107 GCPadStatus GetPadStatus(int port, const std::array<u8, 37>& adapter_payload); 113 GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload);
108 114
109 void PadToState(const GCPadStatus& pad, GCState& state); 115 void PadToState(const GCPadStatus& pad, GCState& state);
110 116
@@ -116,11 +122,8 @@ private:
116 /// Stop scanning for the adapter 122 /// Stop scanning for the adapter
117 void StopScanThread(); 123 void StopScanThread();
118 124
119 /// Returns true if there is a device connected to port
120 bool DeviceConnected(int port);
121
122 /// Resets status of device connected to port 125 /// Resets status of device connected to port
123 void ResetDeviceType(int port); 126 void ResetDeviceType(std::size_t port);
124 127
125 /// Returns true if we successfully gain access to GC Adapter 128 /// Returns true if we successfully gain access to GC Adapter
126 bool CheckDeviceAccess(libusb_device* device); 129 bool CheckDeviceAccess(libusb_device* device);
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index 385ce8430..b20419ec3 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -6,6 +6,7 @@
6#include <list> 6#include <list>
7#include <mutex> 7#include <mutex>
8#include <utility> 8#include <utility>
9#include "common/assert.h"
9#include "common/threadsafe_queue.h" 10#include "common/threadsafe_queue.h"
10#include "input_common/gcadapter/gc_adapter.h" 11#include "input_common/gcadapter/gc_adapter.h"
11#include "input_common/gcadapter/gc_poller.h" 12#include "input_common/gcadapter/gc_poller.h"
@@ -20,7 +21,10 @@ public:
20 ~GCButton() override; 21 ~GCButton() override;
21 22
22 bool GetStatus() const override { 23 bool GetStatus() const override {
23 return gcadapter->GetPadState()[port].buttons.at(button); 24 if (gcadapter->DeviceConnected(port)) {
25 return gcadapter->GetPadState()[port].buttons.at(button);
26 }
27 return false;
24 } 28 }
25 29
26private: 30private:
@@ -43,13 +47,17 @@ public:
43 } 47 }
44 48
45 bool GetStatus() const override { 49 bool GetStatus() const override {
46 const float axis_value = (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 128.0f; 50 if (gcadapter->DeviceConnected(port)) {
47 if (trigger_if_greater) { 51 const float axis_value =
48 // TODO: Might be worthwile to set a slider for the trigger threshold. It is currently 52 (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 128.0f;
49 // always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick 53 if (trigger_if_greater) {
50 return axis_value > threshold; 54 // TODO: Might be worthwile to set a slider for the trigger threshold. It is
55 // currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick
56 return axis_value > threshold;
57 }
58 return axis_value < -threshold;
51 } 59 }
52 return axis_value < -threshold; 60 return false;
53 } 61 }
54 62
55private: 63private:
@@ -94,9 +102,12 @@ std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::Param
94 return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater, 102 return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater,
95 adapter.get()); 103 adapter.get());
96 } 104 }
105
106 UNREACHABLE();
107 return nullptr;
97} 108}
98 109
99Common::ParamPackage GCButtonFactory::GetNextInput() { 110Common::ParamPackage GCButtonFactory::GetNextInput() const {
100 Common::ParamPackage params; 111 Common::ParamPackage params;
101 GCAdapter::GCPadStatus pad; 112 GCAdapter::GCPadStatus pad;
102 auto& queue = adapter->GetPadQueue(); 113 auto& queue = adapter->GetPadQueue();
@@ -147,11 +158,14 @@ public:
147 : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter) {} 158 : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter) {}
148 159
149 float GetAxis(int axis) const { 160 float GetAxis(int axis) const {
150 std::lock_guard lock{mutex}; 161 if (gcadapter->DeviceConnected(port)) {
151 // division is not by a perfect 128 to account for some variance in center location 162 std::lock_guard lock{mutex};
152 // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range 163 // division is not by a perfect 128 to account for some variance in center location
153 // [20-230] 164 // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range
154 return (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 95.0f; 165 // [20-230]
166 return (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 95.0f;
167 }
168 return 0.0f;
155 } 169 }
156 170
157 std::pair<float, float> GetAnalog(int axis_x, int axis_y) const { 171 std::pair<float, float> GetAnalog(int axis_x, int axis_y) const {
@@ -249,7 +263,7 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() {
249 const u8 axis = static_cast<u8>(pad.axis); 263 const u8 axis = static_cast<u8>(pad.axis);
250 if (analog_x_axis == -1) { 264 if (analog_x_axis == -1) {
251 analog_x_axis = axis; 265 analog_x_axis = axis;
252 controller_number = port; 266 controller_number = static_cast<int>(port);
253 } else if (analog_y_axis == -1 && analog_x_axis != axis && controller_number == port) { 267 } else if (analog_y_axis == -1 && analog_x_axis != axis && controller_number == port) {
254 analog_y_axis = axis; 268 analog_y_axis = axis;
255 } 269 }
diff --git a/src/input_common/gcadapter/gc_poller.h b/src/input_common/gcadapter/gc_poller.h
index e96af7d51..0527f328f 100644
--- a/src/input_common/gcadapter/gc_poller.h
+++ b/src/input_common/gcadapter/gc_poller.h
@@ -25,7 +25,7 @@ public:
25 */ 25 */
26 std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override; 26 std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override;
27 27
28 Common::ParamPackage GetNextInput(); 28 Common::ParamPackage GetNextInput() const;
29 29
30 /// For device input configuration/polling 30 /// For device input configuration/polling
31 void BeginConfiguration(); 31 void BeginConfiguration();
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index fd0af1019..b9d5d0ec3 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -4,7 +4,6 @@
4 4
5#include <memory> 5#include <memory>
6#include <thread> 6#include <thread>
7#include <libusb.h>
8#include "common/param_package.h" 7#include "common/param_package.h"
9#include "input_common/analog_from_button.h" 8#include "input_common/analog_from_button.h"
10#include "input_common/gcadapter/gc_adapter.h" 9#include "input_common/gcadapter/gc_adapter.h"
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index da5227058..e63c73c4f 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -234,7 +234,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
234 std::function<void(Status)> status_callback, 234 std::function<void(Status)> status_callback,
235 std::function<void(u16, u16, u16, u16)> data_callback) { 235 std::function<void(u16, u16, u16, u16)> data_callback) {
236 236
237 std::thread([=] { 237 std::thread([=, this] {
238 constexpr u16 CALIBRATION_THRESHOLD = 100; 238 constexpr u16 CALIBRATION_THRESHOLD = 100;
239 239
240 u16 min_x{UINT16_MAX}; 240 u16 min_x{UINT16_MAX};
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 380ed532b..7625871c2 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -332,23 +332,23 @@ private:
332 332
333 if constexpr (has_extended_dynamic_state) { 333 if constexpr (has_extended_dynamic_state) {
334 // With extended dynamic states we can specify the length and stride of a vertex buffer 334 // With extended dynamic states we can specify the length and stride of a vertex buffer
335 // std::array<VkDeviceSize, N> sizes; 335 std::array<VkDeviceSize, N> sizes;
336 std::array<u16, N> strides; 336 std::array<u16, N> strides;
337 // std::copy(vertex.sizes.begin(), vertex.sizes.begin() + N, sizes.begin()); 337 std::copy(vertex.sizes.begin(), vertex.sizes.begin() + N, sizes.begin());
338 std::copy(vertex.strides.begin(), vertex.strides.begin() + N, strides.begin()); 338 std::copy(vertex.strides.begin(), vertex.strides.begin() + N, strides.begin());
339 339
340 if constexpr (is_indexed) { 340 if constexpr (is_indexed) {
341 scheduler.Record( 341 scheduler.Record(
342 [buffers, offsets, strides, index = index](vk::CommandBuffer cmdbuf) { 342 [buffers, offsets, sizes, strides, index = index](vk::CommandBuffer cmdbuf) {
343 cmdbuf.BindIndexBuffer(index.buffer, index.offset, index.type); 343 cmdbuf.BindIndexBuffer(index.buffer, index.offset, index.type);
344 cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(), 344 cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(),
345 offsets.data(), nullptr, 345 offsets.data(), sizes.data(),
346 ExpandStrides(strides).data()); 346 ExpandStrides(strides).data());
347 }); 347 });
348 } else { 348 } else {
349 scheduler.Record([buffers, offsets, strides](vk::CommandBuffer cmdbuf) { 349 scheduler.Record([buffers, offsets, sizes, strides](vk::CommandBuffer cmdbuf) {
350 cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(), 350 cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(),
351 offsets.data(), nullptr, 351 offsets.data(), sizes.data(),
352 ExpandStrides(strides).data()); 352 ExpandStrides(strides).data());
353 }); 353 });
354 } 354 }
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 5f175b989..a862b2610 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -104,11 +104,13 @@ add_executable(yuzu
104 game_list_p.h 104 game_list_p.h
105 game_list_worker.cpp 105 game_list_worker.cpp
106 game_list_worker.h 106 game_list_worker.h
107 hotkeys.cpp
108 hotkeys.h
109 install_dialog.cpp
110 install_dialog.h
107 loading_screen.cpp 111 loading_screen.cpp
108 loading_screen.h 112 loading_screen.h
109 loading_screen.ui 113 loading_screen.ui
110 hotkeys.cpp
111 hotkeys.h
112 main.cpp 114 main.cpp
113 main.h 115 main.h
114 main.ui 116 main.ui
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 430e78e5f..9e9b38214 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -505,22 +505,6 @@ void Config::ReadDataStorageValues() {
505 ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool(); 505 ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool();
506 Settings::values.gamecard_path = 506 Settings::values.gamecard_path =
507 ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString(); 507 ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString();
508 Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(
509 ReadSetting(QStringLiteral("nand_total_size"),
510 QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB)))
511 .toULongLong());
512 Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(
513 ReadSetting(QStringLiteral("nand_user_size"),
514 QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB)))
515 .toULongLong());
516 Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
517 ReadSetting(QStringLiteral("nand_system_size"),
518 QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB)))
519 .toULongLong());
520 Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(
521 ReadSetting(QStringLiteral("sdmc_size"),
522 QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB)))
523 .toULongLong());
524 508
525 qt_config->endGroup(); 509 qt_config->endGroup();
526} 510}
@@ -1034,18 +1018,7 @@ void Config::SaveDataStorageValues() {
1034 false); 1018 false);
1035 WriteSetting(QStringLiteral("gamecard_path"), 1019 WriteSetting(QStringLiteral("gamecard_path"),
1036 QString::fromStdString(Settings::values.gamecard_path), QStringLiteral("")); 1020 QString::fromStdString(Settings::values.gamecard_path), QStringLiteral(""));
1037 WriteSetting(QStringLiteral("nand_total_size"), 1021
1038 QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_total_size)),
1039 QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB)));
1040 WriteSetting(QStringLiteral("nand_user_size"),
1041 QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_user_size)),
1042 QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB)));
1043 WriteSetting(QStringLiteral("nand_system_size"),
1044 QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_system_size)),
1045 QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB)));
1046 WriteSetting(QStringLiteral("sdmc_size"),
1047 QVariant::fromValue<u64>(static_cast<u64>(Settings::values.sdmc_size)),
1048 QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB)));
1049 qt_config->endGroup(); 1022 qt_config->endGroup();
1050} 1023}
1051 1024
diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp
index 835ee821c..a089f5733 100644
--- a/src/yuzu/configuration/configure_filesystem.cpp
+++ b/src/yuzu/configuration/configure_filesystem.cpp
@@ -11,19 +11,6 @@
11#include "yuzu/configuration/configure_filesystem.h" 11#include "yuzu/configuration/configure_filesystem.h"
12#include "yuzu/uisettings.h" 12#include "yuzu/uisettings.h"
13 13
14namespace {
15
16template <typename T>
17void SetComboBoxFromData(QComboBox* combo_box, T data) {
18 const auto index = combo_box->findData(QVariant::fromValue(static_cast<u64>(data)));
19 if (index >= combo_box->count() || index < 0)
20 return;
21
22 combo_box->setCurrentIndex(index);
23}
24
25} // Anonymous namespace
26
27ConfigureFilesystem::ConfigureFilesystem(QWidget* parent) 14ConfigureFilesystem::ConfigureFilesystem(QWidget* parent)
28 : QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) { 15 : QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) {
29 ui->setupUi(this); 16 ui->setupUi(this);
@@ -73,11 +60,6 @@ void ConfigureFilesystem::setConfiguration() {
73 60
74 ui->cache_game_list->setChecked(UISettings::values.cache_game_list); 61 ui->cache_game_list->setChecked(UISettings::values.cache_game_list);
75 62
76 SetComboBoxFromData(ui->nand_size, Settings::values.nand_total_size);
77 SetComboBoxFromData(ui->usrnand_size, Settings::values.nand_user_size);
78 SetComboBoxFromData(ui->sysnand_size, Settings::values.nand_system_size);
79 SetComboBoxFromData(ui->sdmc_size, Settings::values.sdmc_size);
80
81 UpdateEnabledControls(); 63 UpdateEnabledControls();
82} 64}
83 65
@@ -98,15 +80,6 @@ void ConfigureFilesystem::applyConfiguration() {
98 Settings::values.dump_nso = ui->dump_nso->isChecked(); 80 Settings::values.dump_nso = ui->dump_nso->isChecked();
99 81
100 UISettings::values.cache_game_list = ui->cache_game_list->isChecked(); 82 UISettings::values.cache_game_list = ui->cache_game_list->isChecked();
101
102 Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(
103 ui->nand_size->itemData(ui->nand_size->currentIndex()).toULongLong());
104 Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
105 ui->nand_size->itemData(ui->sysnand_size->currentIndex()).toULongLong());
106 Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(
107 ui->nand_size->itemData(ui->usrnand_size->currentIndex()).toULongLong());
108 Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(
109 ui->nand_size->itemData(ui->sdmc_size->currentIndex()).toULongLong());
110} 83}
111 84
112void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) { 85void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) {
diff --git a/src/yuzu/configuration/configure_filesystem.ui b/src/yuzu/configuration/configure_filesystem.ui
index 58cd07f52..84bea0600 100644
--- a/src/yuzu/configuration/configure_filesystem.ui
+++ b/src/yuzu/configuration/configure_filesystem.ui
@@ -116,127 +116,6 @@
116 </widget> 116 </widget>
117 </item> 117 </item>
118 <item> 118 <item>
119 <widget class="QGroupBox" name="groupBox_3">
120 <property name="title">
121 <string>Storage Sizes</string>
122 </property>
123 <layout class="QGridLayout" name="gridLayout_3">
124 <item row="3" column="0">
125 <widget class="QLabel" name="label_5">
126 <property name="text">
127 <string>SD Card</string>
128 </property>
129 </widget>
130 </item>
131 <item row="1" column="0">
132 <widget class="QLabel" name="label_4">
133 <property name="text">
134 <string>System NAND</string>
135 </property>
136 </widget>
137 </item>
138 <item row="1" column="1">
139 <widget class="QComboBox" name="sysnand_size">
140 <item>
141 <property name="text">
142 <string>2.5 GB</string>
143 </property>
144 </item>
145 </widget>
146 </item>
147 <item row="3" column="1">
148 <widget class="QComboBox" name="sdmc_size">
149 <property name="currentText">
150 <string>32 GB</string>
151 </property>
152 <item>
153 <property name="text">
154 <string>1 GB</string>
155 </property>
156 </item>
157 <item>
158 <property name="text">
159 <string>2 GB</string>
160 </property>
161 </item>
162 <item>
163 <property name="text">
164 <string>4 GB</string>
165 </property>
166 </item>
167 <item>
168 <property name="text">
169 <string>8 GB</string>
170 </property>
171 </item>
172 <item>
173 <property name="text">
174 <string>16 GB</string>
175 </property>
176 </item>
177 <item>
178 <property name="text">
179 <string>32 GB</string>
180 </property>
181 </item>
182 <item>
183 <property name="text">
184 <string>64 GB</string>
185 </property>
186 </item>
187 <item>
188 <property name="text">
189 <string>128 GB</string>
190 </property>
191 </item>
192 <item>
193 <property name="text">
194 <string>256 GB</string>
195 </property>
196 </item>
197 <item>
198 <property name="text">
199 <string>1 TB</string>
200 </property>
201 </item>
202 </widget>
203 </item>
204 <item row="2" column="1">
205 <widget class="QComboBox" name="usrnand_size">
206 <item>
207 <property name="text">
208 <string>26 GB</string>
209 </property>
210 </item>
211 </widget>
212 </item>
213 <item row="2" column="0">
214 <widget class="QLabel" name="label_6">
215 <property name="text">
216 <string>User NAND</string>
217 </property>
218 </widget>
219 </item>
220 <item row="0" column="0">
221 <widget class="QLabel" name="label_7">
222 <property name="text">
223 <string>NAND</string>
224 </property>
225 </widget>
226 </item>
227 <item row="0" column="1">
228 <widget class="QComboBox" name="nand_size">
229 <item>
230 <property name="text">
231 <string>29.1 GB</string>
232 </property>
233 </item>
234 </widget>
235 </item>
236 </layout>
237 </widget>
238 </item>
239 <item>
240 <widget class="QGroupBox" name="groupBox_4"> 119 <widget class="QGroupBox" name="groupBox_4">
241 <property name="title"> 120 <property name="title">
242 <string>Patch Manager</string> 121 <string>Patch Manager</string>
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 1fb62d1cf..20316c9cc 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -65,6 +65,8 @@ void ConfigureGeneral::ApplyConfiguration() {
65 Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() == 65 Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() ==
66 Qt::Checked); 66 Qt::Checked);
67 Settings::values.frame_limit.SetValue(ui->frame_limit->value()); 67 Settings::values.frame_limit.SetValue(ui->frame_limit->value());
68 }
69 if (Settings::values.use_multi_core.UsingGlobal()) {
68 Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked()); 70 Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked());
69 } 71 }
70 } else { 72 } else {
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index bfb600df0..ab7fc7a24 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -531,8 +531,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
531 UISettings::GameDir& game_dir = 531 UISettings::GameDir& game_dir =
532 *selected.data(GameListDir::GameDirRole).value<UISettings::GameDir*>(); 532 *selected.data(GameListDir::GameDirRole).value<UISettings::GameDir*>();
533 533
534 QAction* move_up = context_menu.addAction(tr(u8"\U000025b2 Move Up")); 534 QAction* move_up = context_menu.addAction(tr("\u25B2 Move Up"));
535 QAction* move_down = context_menu.addAction(tr(u8"\U000025bc Move Down ")); 535 QAction* move_down = context_menu.addAction(tr("\u25bc Move Down"));
536 QAction* open_directory_location = context_menu.addAction(tr("Open Directory Location")); 536 QAction* open_directory_location = context_menu.addAction(tr("Open Directory Location"));
537 537
538 const int row = selected.row(); 538 const int row = selected.row();
diff --git a/src/yuzu/install_dialog.cpp b/src/yuzu/install_dialog.cpp
new file mode 100644
index 000000000..06b0b1874
--- /dev/null
+++ b/src/yuzu/install_dialog.cpp
@@ -0,0 +1,72 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QCheckBox>
6#include <QDialogButtonBox>
7#include <QFileInfo>
8#include <QHBoxLayout>
9#include <QLabel>
10#include <QListWidget>
11#include <QVBoxLayout>
12#include "yuzu/install_dialog.h"
13#include "yuzu/uisettings.h"
14
15InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialog(parent) {
16 file_list = new QListWidget(this);
17
18 for (const QString& file : files) {
19 QListWidgetItem* item = new QListWidgetItem(QFileInfo(file).fileName(), file_list);
20 item->setData(Qt::UserRole, file);
21 item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
22 item->setCheckState(Qt::Checked);
23 }
24
25 file_list->setMinimumWidth((file_list->sizeHintForColumn(0) * 11) / 10);
26
27 vbox_layout = new QVBoxLayout;
28
29 hbox_layout = new QHBoxLayout;
30
31 description = new QLabel(tr("Please confirm these are the files you wish to install."));
32
33 update_description =
34 new QLabel(tr("Installing an Update or DLC will overwrite the previously installed one."));
35
36 buttons = new QDialogButtonBox;
37 buttons->addButton(QDialogButtonBox::Cancel);
38 buttons->addButton(tr("Install"), QDialogButtonBox::AcceptRole);
39
40 connect(buttons, &QDialogButtonBox::accepted, this, &InstallDialog::accept);
41 connect(buttons, &QDialogButtonBox::rejected, this, &InstallDialog::reject);
42
43 hbox_layout->addWidget(buttons);
44
45 vbox_layout->addWidget(description);
46 vbox_layout->addWidget(update_description);
47 vbox_layout->addWidget(file_list);
48 vbox_layout->addLayout(hbox_layout);
49
50 setLayout(vbox_layout);
51 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
52 setWindowTitle(tr("Install Files to NAND"));
53}
54
55InstallDialog::~InstallDialog() = default;
56
57QStringList InstallDialog::GetFiles() const {
58 QStringList files;
59
60 for (int i = 0; i < file_list->count(); ++i) {
61 const QListWidgetItem* item = file_list->item(i);
62 if (item->checkState() == Qt::Checked) {
63 files.append(item->data(Qt::UserRole).toString());
64 }
65 }
66
67 return files;
68}
69
70int InstallDialog::GetMinimumWidth() const {
71 return file_list->width();
72}
diff --git a/src/yuzu/install_dialog.h b/src/yuzu/install_dialog.h
new file mode 100644
index 000000000..e4aba1b06
--- /dev/null
+++ b/src/yuzu/install_dialog.h
@@ -0,0 +1,36 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QDialog>
8
9class QCheckBox;
10class QDialogButtonBox;
11class QHBoxLayout;
12class QLabel;
13class QListWidget;
14class QVBoxLayout;
15
16class InstallDialog : public QDialog {
17 Q_OBJECT
18
19public:
20 explicit InstallDialog(QWidget* parent, const QStringList& files);
21 ~InstallDialog() override;
22
23 QStringList GetFiles() const;
24 bool ShouldOverwriteFiles() const;
25 int GetMinimumWidth() const;
26
27private:
28 QListWidget* file_list;
29
30 QVBoxLayout* vbox_layout;
31 QHBoxLayout* hbox_layout;
32
33 QLabel* description;
34 QLabel* update_description;
35 QDialogButtonBox* buttons;
36};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 4d501a8f9..432379705 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -107,6 +107,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
107#include "yuzu/game_list.h" 107#include "yuzu/game_list.h"
108#include "yuzu/game_list_p.h" 108#include "yuzu/game_list_p.h"
109#include "yuzu/hotkeys.h" 109#include "yuzu/hotkeys.h"
110#include "yuzu/install_dialog.h"
110#include "yuzu/loading_screen.h" 111#include "yuzu/loading_screen.h"
111#include "yuzu/main.h" 112#include "yuzu/main.h"
112#include "yuzu/uisettings.h" 113#include "yuzu/uisettings.h"
@@ -847,6 +848,9 @@ void GMainWindow::ConnectWidgetEvents() {
847 connect(game_list, &GameList::OpenPerGameGeneralRequested, this, 848 connect(game_list, &GameList::OpenPerGameGeneralRequested, this,
848 &GMainWindow::OnGameListOpenPerGameProperties); 849 &GMainWindow::OnGameListOpenPerGameProperties);
849 850
851 connect(this, &GMainWindow::UpdateInstallProgress, this,
852 &GMainWindow::IncrementInstallProgress);
853
850 connect(this, &GMainWindow::EmulationStarting, render_window, 854 connect(this, &GMainWindow::EmulationStarting, render_window,
851 &GRenderWindow::OnEmulationStarting); 855 &GRenderWindow::OnEmulationStarting);
852 connect(this, &GMainWindow::EmulationStopping, render_window, 856 connect(this, &GMainWindow::EmulationStopping, render_window,
@@ -1593,187 +1597,255 @@ void GMainWindow::OnMenuLoadFolder() {
1593 } 1597 }
1594} 1598}
1595 1599
1600void GMainWindow::IncrementInstallProgress() {
1601 install_progress->setValue(install_progress->value() + 1);
1602}
1603
1596void GMainWindow::OnMenuInstallToNAND() { 1604void GMainWindow::OnMenuInstallToNAND() {
1597 const QString file_filter = 1605 const QString file_filter =
1598 tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive " 1606 tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive "
1599 "(*.nca);;Nintendo Submissions Package (*.nsp);;NX Cartridge " 1607 "(*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge "
1600 "Image (*.xci)"); 1608 "Image (*.xci)");
1601 QString filename = QFileDialog::getOpenFileName(this, tr("Install File"),
1602 UISettings::values.roms_path, file_filter);
1603 1609
1604 if (filename.isEmpty()) { 1610 QStringList filenames = QFileDialog::getOpenFileNames(
1611 this, tr("Install Files"), UISettings::values.roms_path, file_filter);
1612
1613 if (filenames.isEmpty()) {
1605 return; 1614 return;
1606 } 1615 }
1607 1616
1617 InstallDialog installDialog(this, filenames);
1618 if (installDialog.exec() == QDialog::Rejected) {
1619 return;
1620 }
1621
1622 const QStringList files = installDialog.GetFiles();
1623
1624 if (files.isEmpty()) {
1625 return;
1626 }
1627
1628 int remaining = filenames.size();
1629
1630 // This would only overflow above 2^43 bytes (8.796 TB)
1631 int total_size = 0;
1632 for (const QString& file : files) {
1633 total_size += static_cast<int>(QFile(file).size() / 0x1000);
1634 }
1635 if (total_size < 0) {
1636 LOG_CRITICAL(Frontend, "Attempting to install too many files, aborting.");
1637 return;
1638 }
1639
1640 QStringList new_files{}; // Newly installed files that do not yet exist in the NAND
1641 QStringList overwritten_files{}; // Files that overwrote those existing in the NAND
1642 QStringList failed_files{}; // Files that failed to install due to errors
1643
1644 ui.action_Install_File_NAND->setEnabled(false);
1645
1646 install_progress = new QProgressDialog(QStringLiteral(""), tr("Cancel"), 0, total_size, this);
1647 install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint &
1648 ~Qt::WindowMaximizeButtonHint);
1649 install_progress->setAttribute(Qt::WA_DeleteOnClose, true);
1650 install_progress->setFixedWidth(installDialog.GetMinimumWidth() + 40);
1651 install_progress->show();
1652
1653 for (const QString& file : files) {
1654 install_progress->setWindowTitle(tr("%n file(s) remaining", "", remaining));
1655 install_progress->setLabelText(
1656 tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName()));
1657
1658 QFuture<InstallResult> future;
1659 InstallResult result;
1660
1661 if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) ||
1662 file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
1663
1664 future = QtConcurrent::run([this, &file] { return InstallNSPXCI(file); });
1665
1666 while (!future.isFinished()) {
1667 QCoreApplication::processEvents();
1668 }
1669
1670 result = future.result();
1671
1672 } else {
1673 result = InstallNCA(file);
1674 }
1675
1676 std::this_thread::sleep_for(std::chrono::milliseconds(10));
1677
1678 switch (result) {
1679 case InstallResult::Success:
1680 new_files.append(QFileInfo(file).fileName());
1681 break;
1682 case InstallResult::Overwrite:
1683 overwritten_files.append(QFileInfo(file).fileName());
1684 break;
1685 case InstallResult::Failure:
1686 failed_files.append(QFileInfo(file).fileName());
1687 break;
1688 }
1689
1690 --remaining;
1691 }
1692
1693 install_progress->close();
1694
1695 const QString install_results =
1696 (new_files.isEmpty() ? QStringLiteral("")
1697 : tr("%n file(s) were newly installed\n", "", new_files.size())) +
1698 (overwritten_files.isEmpty()
1699 ? QStringLiteral("")
1700 : tr("%n file(s) were overwritten\n", "", overwritten_files.size())) +
1701 (failed_files.isEmpty() ? QStringLiteral("")
1702 : tr("%n file(s) failed to install\n", "", failed_files.size()));
1703
1704 QMessageBox::information(this, tr("Install Results"), install_results);
1705 game_list->PopulateAsync(UISettings::values.game_dirs);
1706 FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
1707 "game_list");
1708 ui.action_Install_File_NAND->setEnabled(true);
1709}
1710
1711InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
1608 const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, 1712 const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
1609 const FileSys::VirtualFile& dest, std::size_t block_size) { 1713 const FileSys::VirtualFile& dest, std::size_t block_size) {
1610 if (src == nullptr || dest == nullptr) 1714 if (src == nullptr || dest == nullptr) {
1611 return false; 1715 return false;
1612 if (!dest->Resize(src->GetSize())) 1716 }
1717 if (!dest->Resize(src->GetSize())) {
1613 return false; 1718 return false;
1719 }
1614 1720
1615 std::array<u8, 0x1000> buffer{}; 1721 std::array<u8, 0x1000> buffer{};
1616 const int progress_maximum = static_cast<int>(src->GetSize() / buffer.size());
1617
1618 QProgressDialog progress(
1619 tr("Installing file \"%1\"...").arg(QString::fromStdString(src->GetName())),
1620 tr("Cancel"), 0, progress_maximum, this);
1621 progress.setWindowModality(Qt::WindowModal);
1622 1722
1623 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { 1723 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
1624 if (progress.wasCanceled()) { 1724 if (install_progress->wasCanceled()) {
1625 dest->Resize(0); 1725 dest->Resize(0);
1626 return false; 1726 return false;
1627 } 1727 }
1628 1728
1629 const int progress_value = static_cast<int>(i / buffer.size()); 1729 emit UpdateInstallProgress();
1630 progress.setValue(progress_value);
1631 1730
1632 const auto read = src->Read(buffer.data(), buffer.size(), i); 1731 const auto read = src->Read(buffer.data(), buffer.size(), i);
1633 dest->Write(buffer.data(), read, i); 1732 dest->Write(buffer.data(), read, i);
1634 } 1733 }
1635
1636 return true; 1734 return true;
1637 }; 1735 };
1638 1736
1639 const auto success = [this]() { 1737 std::shared_ptr<FileSys::NSP> nsp;
1640 QMessageBox::information(this, tr("Successfully Installed"), 1738 if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
1641 tr("The file was successfully installed.")); 1739 nsp = std::make_shared<FileSys::NSP>(
1642 game_list->PopulateAsync(UISettings::values.game_dirs); 1740 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1643 FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + 1741 if (nsp->IsExtractedType()) {
1644 DIR_SEP + "game_list"); 1742 return InstallResult::Failure;
1645 };
1646
1647 const auto failed = [this]() {
1648 QMessageBox::warning(
1649 this, tr("Failed to Install"),
1650 tr("There was an error while attempting to install the provided file. It "
1651 "could have an incorrect format or be missing metadata. Please "
1652 "double-check your file and try again."));
1653 };
1654
1655 const auto overwrite = [this]() {
1656 return QMessageBox::question(this, tr("Failed to Install"),
1657 tr("The file you are attempting to install already exists "
1658 "in the cache. Would you like to overwrite it?")) ==
1659 QMessageBox::Yes;
1660 };
1661
1662 if (filename.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) ||
1663 filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
1664 std::shared_ptr<FileSys::NSP> nsp;
1665 if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
1666 nsp = std::make_shared<FileSys::NSP>(
1667 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1668 if (nsp->IsExtractedType())
1669 failed();
1670 } else {
1671 const auto xci = std::make_shared<FileSys::XCI>(
1672 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1673 nsp = xci->GetSecurePartitionNSP();
1674 }
1675
1676 if (nsp->GetStatus() != Loader::ResultStatus::Success) {
1677 failed();
1678 return;
1679 }
1680 const auto res = Core::System::GetInstance()
1681 .GetFileSystemController()
1682 .GetUserNANDContents()
1683 ->InstallEntry(*nsp, false, qt_raw_copy);
1684 if (res == FileSys::InstallResult::Success) {
1685 success();
1686 } else {
1687 if (res == FileSys::InstallResult::ErrorAlreadyExists) {
1688 if (overwrite()) {
1689 const auto res2 = Core::System::GetInstance()
1690 .GetFileSystemController()
1691 .GetUserNANDContents()
1692 ->InstallEntry(*nsp, true, qt_raw_copy);
1693 if (res2 == FileSys::InstallResult::Success) {
1694 success();
1695 } else {
1696 failed();
1697 }
1698 }
1699 } else {
1700 failed();
1701 }
1702 } 1743 }
1703 } else { 1744 } else {
1704 const auto nca = std::make_shared<FileSys::NCA>( 1745 const auto xci = std::make_shared<FileSys::XCI>(
1705 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); 1746 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1706 const auto id = nca->GetStatus(); 1747 nsp = xci->GetSecurePartitionNSP();
1748 }
1707 1749
1708 // Game updates necessary are missing base RomFS 1750 if (nsp->GetStatus() != Loader::ResultStatus::Success) {
1709 if (id != Loader::ResultStatus::Success && 1751 return InstallResult::Failure;
1710 id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { 1752 }
1711 failed(); 1753 const auto res =
1712 return; 1754 Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry(
1713 } 1755 *nsp, true, qt_raw_copy);
1756 if (res == FileSys::InstallResult::Success) {
1757 return InstallResult::Success;
1758 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
1759 return InstallResult::Overwrite;
1760 } else {
1761 return InstallResult::Failure;
1762 }
1763}
1714 1764
1715 const QStringList tt_options{tr("System Application"), 1765InstallResult GMainWindow::InstallNCA(const QString& filename) {
1716 tr("System Archive"), 1766 const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
1717 tr("System Application Update"), 1767 const FileSys::VirtualFile& dest, std::size_t block_size) {
1718 tr("Firmware Package (Type A)"), 1768 if (src == nullptr || dest == nullptr) {
1719 tr("Firmware Package (Type B)"), 1769 return false;
1720 tr("Game"),
1721 tr("Game Update"),
1722 tr("Game DLC"),
1723 tr("Delta Title")};
1724 bool ok;
1725 const auto item = QInputDialog::getItem(
1726 this, tr("Select NCA Install Type..."),
1727 tr("Please select the type of title you would like to install this NCA as:\n(In "
1728 "most instances, the default 'Game' is fine.)"),
1729 tt_options, 5, false, &ok);
1730
1731 auto index = tt_options.indexOf(item);
1732 if (!ok || index == -1) {
1733 QMessageBox::warning(this, tr("Failed to Install"),
1734 tr("The title type you selected for the NCA is invalid."));
1735 return;
1736 } 1770 }
1737 1771 if (!dest->Resize(src->GetSize())) {
1738 // If index is equal to or past Game, add the jump in TitleType. 1772 return false;
1739 if (index >= 5) {
1740 index += static_cast<size_t>(FileSys::TitleType::Application) -
1741 static_cast<size_t>(FileSys::TitleType::FirmwarePackageB);
1742 } 1773 }
1743 1774
1744 FileSys::InstallResult res; 1775 std::array<u8, 0x1000> buffer{};
1745 if (index >= static_cast<s32>(FileSys::TitleType::Application)) {
1746 res = Core::System::GetInstance()
1747 .GetFileSystemController()
1748 .GetUserNANDContents()
1749 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false,
1750 qt_raw_copy);
1751 } else {
1752 res = Core::System::GetInstance()
1753 .GetFileSystemController()
1754 .GetSystemNANDContents()
1755 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false,
1756 qt_raw_copy);
1757 }
1758 1776
1759 if (res == FileSys::InstallResult::Success) { 1777 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
1760 success(); 1778 if (install_progress->wasCanceled()) {
1761 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { 1779 dest->Resize(0);
1762 if (overwrite()) { 1780 return false;
1763 const auto res2 = Core::System::GetInstance()
1764 .GetFileSystemController()
1765 .GetUserNANDContents()
1766 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index),
1767 true, qt_raw_copy);
1768 if (res2 == FileSys::InstallResult::Success) {
1769 success();
1770 } else {
1771 failed();
1772 }
1773 } 1781 }
1774 } else { 1782
1775 failed(); 1783 emit UpdateInstallProgress();
1784
1785 const auto read = src->Read(buffer.data(), buffer.size(), i);
1786 dest->Write(buffer.data(), read, i);
1776 } 1787 }
1788 return true;
1789 };
1790
1791 const auto nca =
1792 std::make_shared<FileSys::NCA>(vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1793 const auto id = nca->GetStatus();
1794
1795 // Game updates necessary are missing base RomFS
1796 if (id != Loader::ResultStatus::Success &&
1797 id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
1798 return InstallResult::Failure;
1799 }
1800
1801 const QStringList tt_options{tr("System Application"),
1802 tr("System Archive"),
1803 tr("System Application Update"),
1804 tr("Firmware Package (Type A)"),
1805 tr("Firmware Package (Type B)"),
1806 tr("Game"),
1807 tr("Game Update"),
1808 tr("Game DLC"),
1809 tr("Delta Title")};
1810 bool ok;
1811 const auto item = QInputDialog::getItem(
1812 this, tr("Select NCA Install Type..."),
1813 tr("Please select the type of title you would like to install this NCA as:\n(In "
1814 "most instances, the default 'Game' is fine.)"),
1815 tt_options, 5, false, &ok);
1816
1817 auto index = tt_options.indexOf(item);
1818 if (!ok || index == -1) {
1819 QMessageBox::warning(this, tr("Failed to Install"),
1820 tr("The title type you selected for the NCA is invalid."));
1821 return InstallResult::Failure;
1822 }
1823
1824 // If index is equal to or past Game, add the jump in TitleType.
1825 if (index >= 5) {
1826 index += static_cast<size_t>(FileSys::TitleType::Application) -
1827 static_cast<size_t>(FileSys::TitleType::FirmwarePackageB);
1828 }
1829
1830 FileSys::InstallResult res;
1831 if (index >= static_cast<s32>(FileSys::TitleType::Application)) {
1832 res = Core::System::GetInstance()
1833 .GetFileSystemController()
1834 .GetUserNANDContents()
1835 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
1836 } else {
1837 res = Core::System::GetInstance()
1838 .GetFileSystemController()
1839 .GetSystemNANDContents()
1840 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
1841 }
1842
1843 if (res == FileSys::InstallResult::Success) {
1844 return InstallResult::Success;
1845 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
1846 return InstallResult::Overwrite;
1847 } else {
1848 return InstallResult::Failure;
1777 } 1849 }
1778} 1850}
1779 1851
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 8e3d39c38..adff65fb5 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -28,6 +28,7 @@ class MicroProfileDialog;
28class ProfilerWidget; 28class ProfilerWidget;
29class QLabel; 29class QLabel;
30class QPushButton; 30class QPushButton;
31class QProgressDialog;
31class WaitTreeWidget; 32class WaitTreeWidget;
32enum class GameListOpenTarget; 33enum class GameListOpenTarget;
33class GameListPlaceholder; 34class GameListPlaceholder;
@@ -47,6 +48,12 @@ enum class EmulatedDirectoryTarget {
47 SDMC, 48 SDMC,
48}; 49};
49 50
51enum class InstallResult {
52 Success,
53 Overwrite,
54 Failure,
55};
56
50enum class ReinitializeKeyBehavior { 57enum class ReinitializeKeyBehavior {
51 NoWarning, 58 NoWarning,
52 Warning, 59 Warning,
@@ -102,6 +109,8 @@ signals:
102 // Signal that tells widgets to update icons to use the current theme 109 // Signal that tells widgets to update icons to use the current theme
103 void UpdateThemedIcons(); 110 void UpdateThemedIcons();
104 111
112 void UpdateInstallProgress();
113
105 void ErrorDisplayFinished(); 114 void ErrorDisplayFinished();
106 115
107 void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid); 116 void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
@@ -198,6 +207,7 @@ private slots:
198 void OnGameListOpenPerGameProperties(const std::string& file); 207 void OnGameListOpenPerGameProperties(const std::string& file);
199 void OnMenuLoadFile(); 208 void OnMenuLoadFile();
200 void OnMenuLoadFolder(); 209 void OnMenuLoadFolder();
210 void IncrementInstallProgress();
201 void OnMenuInstallToNAND(); 211 void OnMenuInstallToNAND();
202 void OnMenuRecentFile(); 212 void OnMenuRecentFile();
203 void OnConfigure(); 213 void OnConfigure();
@@ -218,6 +228,8 @@ private slots:
218 228
219private: 229private:
220 std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); 230 std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
231 InstallResult InstallNSPXCI(const QString& filename);
232 InstallResult InstallNCA(const QString& filename);
221 void UpdateWindowTitle(const std::string& title_name = {}, 233 void UpdateWindowTitle(const std::string& title_name = {},
222 const std::string& title_version = {}); 234 const std::string& title_version = {});
223 void UpdateStatusBar(); 235 void UpdateStatusBar();
@@ -272,6 +284,9 @@ private:
272 284
273 HotkeyRegistry hotkey_registry; 285 HotkeyRegistry hotkey_registry;
274 286
287 // Install progress dialog
288 QProgressDialog* install_progress;
289
275protected: 290protected:
276 void dropEvent(QDropEvent* event) override; 291 void dropEvent(QDropEvent* event) override;
277 void dragEnterEvent(QDragEnterEvent* event) override; 292 void dragEnterEvent(QDragEnterEvent* event) override;
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index bee6e107e..c3a1d715e 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -130,7 +130,7 @@
130 <bool>true</bool> 130 <bool>true</bool>
131 </property> 131 </property>
132 <property name="text"> 132 <property name="text">
133 <string>Install File to NAND...</string> 133 <string>Install Files to NAND...</string>
134 </property> 134 </property>
135 </action> 135 </action>
136 <action name="action_Load_File"> 136 <action name="action_Load_File">
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 441d8e8f7..7773228c8 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -335,15 +335,6 @@ void Config::ReadValues() {
335 Settings::values.gamecard_current_game = 335 Settings::values.gamecard_current_game =
336 sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false); 336 sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false);
337 Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", ""); 337 Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", "");
338 Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(sdl2_config->GetInteger(
339 "Data Storage", "nand_total_size", static_cast<long>(Settings::NANDTotalSize::S29_1GB)));
340 Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(sdl2_config->GetInteger(
341 "Data Storage", "nand_user_size", static_cast<long>(Settings::NANDUserSize::S26GB)));
342 Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
343 sdl2_config->GetInteger("Data Storage", "nand_system_size",
344 static_cast<long>(Settings::NANDSystemSize::S2_5GB)));
345 Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(sdl2_config->GetInteger(
346 "Data Storage", "sdmc_size", static_cast<long>(Settings::SDMCSize::S16GB)));
347 338
348 // System 339 // System
349 Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false); 340 Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);