diff options
author | Anuskuss | 2022-09-05 17:55:18 +0200 |
---|---|---|
committer | Anuskuss | 2022-09-05 17:55:18 +0200 |
commit | 881ca6dc5fcbc748d0af0be0f8ebf980febdf9a7 (patch) | |
tree | 6f0885718c086b21600e897c303d933d2266906a | |
parent | 17de74562df12eab0ec37bee222c03d9d3e7c681 (diff) | |
download | aur-881ca6dc5fcbc748d0af0be0f8ebf980febdf9a7.tar.gz |
Turned inline patches into external files
-rw-r--r-- | .SRCINFO | 4 | ||||
-rw-r--r-- | PKGBUILD | 805 | ||||
-rw-r--r-- | clang.patch | 14 | ||||
-rw-r--r-- | xdg.patch | 833 |
4 files changed, 860 insertions, 796 deletions
@@ -31,6 +31,8 @@ pkgbase = cemu source = git+https://github.com/Exzap/ZArchive#commit=48914a07df3c213333c580bb5e5bb3393442ca5b source = git+https://github.com/arsenm/sanitizers-cmake#commit=aab6948fa863bc1cbe5d0850bc46b9ef02ed4c1a source = git+https://github.com/google/googletest#commit=800f5422ac9d9e0ad59cd860a2ef3a679588acb4 + source = clang.patch + source = xdg.patch sha256sums = SKIP sha256sums = 5cae7072042b3043e12d53d50ef404bbb76949dad1de368d7f993a15c8c05ecc sha256sums = 9f14c788aee15b777051e48f868c5d4d959bd679fc5050e3d2a29de80d8fd32e @@ -40,5 +42,7 @@ pkgbase = cemu sha256sums = SKIP sha256sums = SKIP sha256sums = SKIP + sha256sums = 893832f2e7dd7784e9df423020ff2acc63ffe8d9b75b7d92f371f7dd57313131 + sha256sums = c8b6cefa33256c84435313c02f03dfe55b651db573642c12b3db01e1a51a64da pkgname = cemu @@ -39,6 +39,9 @@ source=( # cubeb submodules git+https://github.com/arsenm/sanitizers-cmake#commit=aab6948fa863bc1cbe5d0850bc46b9ef02ed4c1a git+https://github.com/google/googletest#commit=800f5422ac9d9e0ad59cd860a2ef3a679588acb4 + # patches + clang.patch + xdg.patch ) sha256sums=( SKIP @@ -50,6 +53,8 @@ sha256sums=( SKIP SKIP SKIP + 893832f2e7dd7784e9df423020ff2acc63ffe8d9b75b7d92f371f7dd57313131 + c8b6cefa33256c84435313c02f03dfe55b651db573642c12b3db01e1a51a64da ) pkgver() { @@ -91,20 +96,7 @@ prepare() { which clang++ &> /dev/null && [[ -z $CXX ]] && export CXX=$(which clang++) # clang workaround - [[ $CXX == *clang* ]] && git apply << 'EOF' ---- a/src/Cemu/Logging/CemuLogging.h -+++ b/src/Cemu/Logging/CemuLogging.h -@@ -58,9 +58,6 @@ bool cemuLog_log(LogType type, TFmt format, TArgs&&... args) - if (!cemuLog_isLoggingEnabled(type)) - return false; - -- const auto format_view = fmt::to_string_view(format); -- const auto text = fmt::vformat(format_view, fmt::make_args_checked<TArgs...>(format_view, args...)); -- cemuLog_log(type, std::basic_string_view(text.data(), text.size())); - return true; - } - -EOF + [[ $CXX == *clang* ]] && git apply "$srcdir/clang.patch" # glm fix sed -i 's/glm::glm/glm/' src/Common/CMakeLists.txt src/input/CMakeLists.txt @@ -112,23 +104,11 @@ EOF # glslang fix sed -i 's/GLSLANG_VERSION_LESS/GLSLANG_VERSION_GREATER/' src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp - # xdg base dir support - _xdg_patch + # xdg base dir support (https://github.com/cemu-project/Cemu/pull/130) + git apply "$srcdir/xdg.patch" # gameProfiles improvement - git apply << 'EOF' ---- a/src/Cafe/GameProfile/GameProfile.cpp -+++ b/src/Cafe/GameProfile/GameProfile.cpp -@@ -185,7 +185,7 @@ bool GameProfile::Load(uint64_t title_id) - std::optional<std::vector<uint8>> profileContents = FileStream::LoadIntoMemory(gameProfilePath); - if (!profileContents) - { -- gameProfilePath = ActiveSettings::GetSystemDataPath("gameProfiles/default/{:016x}.ini", title_id); -+ gameProfilePath = ActiveSettings::GetSystemDataPath("gameProfiles/{:016x}.ini", title_id); - profileContents = FileStream::LoadIntoMemory(gameProfilePath); - if (!profileContents) - return false; -EOF + sed -i 's|gameProfiles/default|gameProfiles|' src/Cafe/GameProfile/GameProfile.cpp } build() { @@ -161,770 +141,3 @@ package() { sed -i "s|^Icon=info.cemu.Cemu$|Icon=cemu|;s|^Exec=cemu$|Exec=env GDK_BACKEND=x11 /usr/bin/cemu|" dist/linux/info.cemu.Cemu.desktop install -Dm644 dist/linux/info.cemu.Cemu.desktop "$pkgdir/usr/share/applications/cemu.desktop" } - -_xdg_patch() { - # https://github.com/cemu-project/Cemu/pull/130 - git apply << 'EOF' ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -50,6 +50,13 @@ option(ENABLE_OPENGL "Enables the OpenGL backend" ON) - option(ENABLE_VULKAN "Enables the Vulkan backend" ON) - option(ENABLE_DISCORD_RPC "Enables the Discord Rich Presence feature" ON) - -+if (UNIX) -+ option(ENABLE_XDG_DIRS "Enable storage according to XDG specification" ON) -+endif() -+if (SYSTEM_DATA_PATH) -+ add_compile_definitions(SYSTEM_DATA_PATH=\"${SYSTEM_DATA_PATH}\") -+endif() -+ - # input backends - if (WIN32) - option(ENABLE_XINPUT "Enables the usage of XInput" ON) -@@ -125,6 +132,10 @@ if (ENABLE_CUBEB) - add_compile_definitions("HAS_CUBEB=1") - endif() - -+if (ENABLE_XDG_DIRS) -+ add_compile_definitions(XDG) -+endif() -+ - add_subdirectory("dependencies/ih264d" EXCLUDE_FROM_ALL) - - find_package(ZArchive) ---- a/src/Cafe/Account/Account.cpp -+++ b/src/Cafe/Account/Account.cpp -@@ -424,7 +424,7 @@ OnlineValidator Account::ValidateOnlineFiles() const - { - OnlineValidator result{}; - -- const auto otp = ActiveSettings::GetPath("otp.bin"); -+ const auto otp = ActiveSettings::GetDataPath("otp.bin"); - if (!fs::exists(otp)) - result.otp = OnlineValidator::FileState::Missing; - else if (fs::file_size(otp) != 1024) -@@ -432,7 +432,7 @@ OnlineValidator Account::ValidateOnlineFiles() const - else - result.otp = OnlineValidator::FileState::Ok; - -- const auto seeprom = ActiveSettings::GetPath("seeprom.bin"); -+ const auto seeprom = ActiveSettings::GetDataPath("seeprom.bin"); - if (!fs::exists(seeprom)) - result.seeprom = OnlineValidator::FileState::Missing; - else if (fs::file_size(seeprom) != 512) ---- a/src/Cafe/CafeSystem.cpp -+++ b/src/Cafe/CafeSystem.cpp -@@ -289,7 +289,7 @@ uint32 loadSharedData() - for (sint32 i = 0; i < sizeof(shareddataDef) / sizeof(shareddataDef[0]); i++) - { - bool existsInMLC = fs::exists(ActiveSettings::GetMlcPath(shareddataDef[i].mlcPath)); -- bool existsInResources = fs::exists(ActiveSettings::GetPath(shareddataDef[i].resourcePath)); -+ bool existsInResources = fs::exists(ActiveSettings::GetSystemDataPath(shareddataDef[i].resourcePath)); - - if (!existsInMLC && !existsInResources) - { -@@ -314,7 +314,7 @@ uint32 loadSharedData() - // alternatively fall back to our shared fonts - if (!fontFile) - { -- path = ActiveSettings::GetPath(shareddataDef[i].resourcePath); -+ path = ActiveSettings::GetSystemDataPath(shareddataDef[i].resourcePath); - fontFile = FileStream::openFile2(path); - } - if (!fontFile) -@@ -340,7 +340,7 @@ uint32 loadSharedData() - return memory_getVirtualOffsetFromPointer(dataWritePtr); - } - // alternative method: load RAM dump -- const auto path = ActiveSettings::GetPath("shareddata.bin"); -+ const auto path = ActiveSettings::GetSystemDataPath("shareddata.bin"); - FileStream* ramDumpFile = FileStream::openFile2(path); - if (ramDumpFile) - { ---- a/src/Cafe/Filesystem/FST/KeyCache.cpp -+++ b/src/Cafe/Filesystem/FST/KeyCache.cpp -@@ -59,7 +59,7 @@ void KeyCache_Prepare() - sKeyCachePrepared = true; - g_keyCache.clear(); - // load keys -- auto keysPath = ActiveSettings::GetPath("keys.txt"); -+ auto keysPath = ActiveSettings::GetConfigPath("keys.txt"); - FileStream* fs_keys = FileStream::openFile2(keysPath); - if( !fs_keys ) - { ---- a/src/Cafe/GameProfile/GameProfile.cpp -+++ b/src/Cafe/GameProfile/GameProfile.cpp -@@ -180,12 +180,12 @@ void gameProfile_load() - - bool GameProfile::Load(uint64_t title_id) - { -- auto gameProfilePath = ActiveSettings::GetPath("gameProfiles/{:016x}.ini", title_id); -+ auto gameProfilePath = ActiveSettings::GetConfigPath("gameProfiles/{:016x}.ini", title_id); - - std::optional<std::vector<uint8>> profileContents = FileStream::LoadIntoMemory(gameProfilePath); - if (!profileContents) - { -- gameProfilePath = ActiveSettings::GetPath("gameProfiles/default/{:016x}.ini", title_id); -+ gameProfilePath = ActiveSettings::GetSystemDataPath("gameProfiles/default/{:016x}.ini", title_id); - profileContents = FileStream::LoadIntoMemory(gameProfilePath); - if (!profileContents) - return false; -@@ -276,7 +276,7 @@ bool GameProfile::Load(uint64_t title_id) - - void GameProfile::Save(uint64_t title_id) - { -- auto gameProfilePath = ActiveSettings::GetPath("gameProfiles/{:016x}.ini", title_id); -+ auto gameProfilePath = ActiveSettings::GetConfigPath("gameProfiles/{:016x}.ini", title_id); - FileStream* fs = FileStream::createFile2(gameProfilePath); - if (!fs) - { ---- a/src/Cafe/GraphicPack/GraphicPack2.cpp -+++ b/src/Cafe/GraphicPack/GraphicPack2.cpp -@@ -63,7 +63,7 @@ void GraphicPack2::LoadGraphicPack(fs::path graphicPackPath) - void GraphicPack2::LoadAll() - { - std::error_code ec; -- fs::path basePath = ActiveSettings::GetPath("graphicPacks"); -+ fs::path basePath = ActiveSettings::GetDataPath("graphicPacks"); - for (fs::recursive_directory_iterator it(basePath, ec); it != end(it); ++it) - { - if (!it->is_directory(ec)) ---- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp -+++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp -@@ -197,17 +197,17 @@ void LatteShaderCache_load() - LatteShaderCache_initCompileQueue(); - // create directories - std::error_code ec; -- fs::create_directories(ActiveSettings::GetPath("shaderCache/transferable"), ec); -- fs::create_directories(ActiveSettings::GetPath("shaderCache/precompiled"), ec); -+ fs::create_directories(ActiveSettings::GetCachePath("shaderCache/transferable"), ec); -+ fs::create_directories(ActiveSettings::GetCachePath("shaderCache/precompiled"), ec); - // initialize renderer specific caches - if (g_renderer->GetType() == RendererAPI::Vulkan) - RendererShaderVk::ShaderCacheLoading_begin(cacheTitleId); - else if (g_renderer->GetType() == RendererAPI::OpenGL) - RendererShaderGL::ShaderCacheLoading_begin(cacheTitleId); - // get cache file name -- const auto pathGeneric = ActiveSettings::GetPath("shaderCache/transferable/{:016x}_shaders.bin", cacheTitleId); -- const auto pathGenericPre1_25_0 = ActiveSettings::GetPath("shaderCache/transferable/{:016x}.bin", cacheTitleId); // before 1.25.0 -- const auto pathGenericPre1_16_0 = ActiveSettings::GetPath("shaderCache/transferable/{:08x}.bin", CafeSystem::GetRPXHashBase()); // before 1.16.0 -+ const auto pathGeneric = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}_shaders.bin", cacheTitleId); -+ const auto pathGenericPre1_25_0 = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}.bin", cacheTitleId); // before 1.25.0 -+ const auto pathGenericPre1_16_0 = ActiveSettings::GetCachePath("shaderCache/transferable/{:08x}.bin", CafeSystem::GetRPXHashBase()); // before 1.16.0 - - LatteShaderCache_handleDeprecatedCacheFiles(pathGeneric, pathGenericPre1_25_0, pathGenericPre1_16_0); - // calculate extraVersion for transferable and precompiled shader cache ---- a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp -+++ b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp -@@ -279,7 +279,7 @@ void RendererShaderGL::ShaderCacheLoading_begin(uint64 cacheTitleId) - { - const uint32 cacheMagic = GeneratePrecompiledCacheId(); - const std::string cacheFilename = fmt::format("{:016x}_gl.bin", cacheTitleId); -- const std::wstring cachePath = ActiveSettings::GetPath("shaderCache/precompiled/{}", cacheFilename).generic_wstring(); -+ const std::wstring cachePath = ActiveSettings::GetCachePath("shaderCache/precompiled/{}", cacheFilename).generic_wstring(); - g_programBinaryCache = FileCache::Open(cachePath, true, cacheMagic); - if (g_programBinaryCache == nullptr) - cemuLog_log(LogType::Force, "Unable to open OpenGL precompiled cache {}", cacheFilename); ---- a/src/Cafe/HW/Latte/Renderer/Renderer.cpp -+++ b/src/Cafe/HW/Latte/Renderer/Renderer.cpp -@@ -133,7 +133,7 @@ void Renderer::SaveScreenshot(const std::vector<uint8>& rgb_data, int width, int - // save to png file - if (save_screenshot) - { -- fs::path screendir = ActiveSettings::GetPath("screenshots"); -+ fs::path screendir = ActiveSettings::GetDataPath("screenshots"); - if (!fs::exists(screendir)) - fs::create_directory(screendir); - ---- a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp -+++ b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp -@@ -456,7 +456,7 @@ void RendererShaderVk::ShaderCacheLoading_begin(uint64 cacheTitleId) - } - uint32 spirvCacheMagic = GeneratePrecompiledCacheId(); - const std::string cacheFilename = fmt::format("{:016x}_spirv.bin", cacheTitleId); -- const std::wstring cachePath = ActiveSettings::GetPath("shaderCache/precompiled/{}", cacheFilename).generic_wstring(); -+ const std::wstring cachePath = ActiveSettings::GetCachePath("shaderCache/precompiled/{}", cacheFilename).generic_wstring(); - s_spirvCache = FileCache::Open(cachePath, true, spirvCacheMagic); - if (s_spirvCache == nullptr) - cemuLog_log(LogType::Force, "Unable to open SPIR-V cache {}", cacheFilename); ---- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp -+++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp -@@ -32,8 +32,8 @@ VulkanPipelineStableCache& VulkanPipelineStableCache::GetInstance() - uint32 VulkanPipelineStableCache::BeginLoading(uint64 cacheTitleId) - { - std::error_code ec; -- fs::create_directories(ActiveSettings::GetPath("shaderCache/transferable"), ec); -- const auto pathCacheFile = ActiveSettings::GetPath("shaderCache/transferable/{:016x}_vkpipeline.bin", cacheTitleId); -+ fs::create_directories(ActiveSettings::GetCachePath("shaderCache/transferable"), ec); -+ const auto pathCacheFile = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}_vkpipeline.bin", cacheTitleId); - - // init cache loader state - g_vkCacheState.pipelineLoadIndex = 0; ---- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp -+++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp -@@ -2303,7 +2303,7 @@ void VulkanRenderer::WaitCommandBufferFinished(uint64 commandBufferId) - - void VulkanRenderer::PipelineCacheSaveThread(size_t cache_size) - { -- const auto dir = ActiveSettings::GetPath("shaderCache/driver/vk"); -+ const auto dir = ActiveSettings::GetCachePath("shaderCache/driver/vk"); - if (!fs::exists(dir)) - { - try -@@ -2380,7 +2380,7 @@ void VulkanRenderer::PipelineCacheSaveThread(size_t cache_size) - void VulkanRenderer::CreatePipelineCache() - { - std::vector<uint8_t> cacheData; -- const auto dir = ActiveSettings::GetPath("shaderCache/driver/vk"); -+ const auto dir = ActiveSettings::GetCachePath("shaderCache/driver/vk"); - if (fs::exists(dir)) - { - const auto filename = dir / fmt::format("{:016x}.bin", CafeSystem::GetForegroundTitleId()); ---- a/src/Cafe/HW/MMU/MMU.cpp -+++ b/src/Cafe/HW/MMU/MMU.cpp -@@ -409,7 +409,7 @@ void memory_writeDumpFile(uint32 startAddr, uint32 size, const fs::path& path) - void memory_createDump() - { - const uint32 pageSize = MemMapper::GetPageSize(); -- fs::path path = ActiveSettings::GetPath("dump/ramDump{:}", (uint32)time(nullptr)); -+ fs::path path = ActiveSettings::GetDataPath("dump/ramDump{:}", (uint32)time(nullptr)); - fs::create_directories(path); - - for (auto& itr : g_mmuRanges) ---- a/src/Cafe/IOSU/legacy/iosu_crypto.cpp -+++ b/src/Cafe/IOSU/legacy/iosu_crypto.cpp -@@ -563,7 +563,7 @@ void iosuCrypto_loadSSLCertificates() - void iosuCrypto_init() - { - // load OTP dump -- if (std::ifstream otp_file(ActiveSettings::GetPath("otp.bin"), std::ifstream::in | std::ios::binary); otp_file.is_open()) -+ if (std::ifstream otp_file(ActiveSettings::GetDataPath("otp.bin"), std::ifstream::in | std::ios::binary); otp_file.is_open()) - { - otp_file.seekg(0, std::ifstream::end); - const auto length = otp_file.tellg(); -@@ -586,7 +586,7 @@ void iosuCrypto_init() - hasOtpMem = false; - } - -- if (std::ifstream seeprom_file(ActiveSettings::GetPath("seeprom.bin"), std::ifstream::in | std::ios::binary); seeprom_file.is_open()) -+ if (std::ifstream seeprom_file(ActiveSettings::GetDataPath("seeprom.bin"), std::ifstream::in | std::ios::binary); seeprom_file.is_open()) - { - seeprom_file.seekg(0, std::ifstream::end); - const auto length = seeprom_file.tellg(); -@@ -630,13 +630,13 @@ sint32 iosuCrypt_checkRequirementsForOnlineMode(std::wstring& additionalErrorInf - { - std::error_code ec; - // check if otp.bin is present -- const auto otp_file = ActiveSettings::GetPath("otp.bin"); -+ const auto otp_file = ActiveSettings::GetDataPath("otp.bin"); - if(!fs::exists(otp_file, ec)) - return IOS_CRYPTO_ONLINE_REQ_OTP_MISSING; - if(fs::file_size(otp_file, ec) != 1024) - return IOS_CRYPTO_ONLINE_REQ_OTP_CORRUPTED; - // check if seeprom.bin is present -- const auto seeprom_file = ActiveSettings::GetPath("seeprom.bin"); -+ const auto seeprom_file = ActiveSettings::GetDataPath("seeprom.bin"); - if (!fs::exists(seeprom_file, ec)) - return IOS_CRYPTO_ONLINE_REQ_SEEPROM_MISSING; - if (fs::file_size(seeprom_file, ec) != 512) ---- a/src/Cafe/OS/RPL/rpl.cpp -+++ b/src/Cafe/OS/RPL/rpl.cpp -@@ -2122,7 +2122,7 @@ void RPLLoader_LoadDependency(rplDependency_t* dependency) - // attempt to load rpl from Cemu's /cafeLibs/ directory - if (ActiveSettings::LoadSharedLibrariesEnabled()) - { -- const auto filePath = ActiveSettings::GetPath("cafeLibs/{}", dependency->filepath); -+ const auto filePath = ActiveSettings::GetDataPath("cafeLibs/{}", dependency->filepath); - auto fileData = FileStream::LoadIntoMemory(filePath); - if (fileData) - { ---- a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp -+++ b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp -@@ -107,7 +107,7 @@ namespace coreinit - return; - - std::error_code ec; -- const auto path = ActiveSettings::GetPath("sdcard/"); -+ const auto path = ActiveSettings::GetDataPath("sdcard/"); - fs::create_directories(path, ec); - FSCDeviceHostFS_Mount("/vol/external01", path.generic_wstring().c_str() , FSC_PRIORITY_BASE); - -@@ -140,7 +140,7 @@ namespace coreinit - return FS_RESULT::ERR_PLACEHOLDER; - - std::error_code ec; -- const auto path = ActiveSettings::GetPath("sdcard/"); -+ const auto path = ActiveSettings::GetDataPath("sdcard/"); - fs::create_directories(path, ec); - if (!FSCDeviceHostFS_Mount(mountPathOut, path.generic_wstring().c_str(), FSC_PRIORITY_BASE)) - return FS_RESULT::ERR_PLACEHOLDER; ---- a/src/Cemu/Logging/CemuLogging.cpp -+++ b/src/Cemu/Logging/CemuLogging.cpp -@@ -98,7 +98,7 @@ void cemuLog_createLogFile(bool triggeredByCrash) - if (LogContext.file_stream.is_open()) - return; - -- const auto path = ActiveSettings::GetPath("log.txt"); -+ const auto path = ActiveSettings::GetDataPath("log.txt"); - LogContext.file_stream.open(path, std::ios::out); - if (LogContext.file_stream.fail()) - { ---- a/src/config/ActiveSettings.cpp -+++ b/src/config/ActiveSettings.cpp -@@ -18,7 +18,7 @@ void ActiveSettings::LoadOnce() - s_path = s_full_path.parent_path(); - s_filename = s_full_path.filename(); - -- g_config.SetFilename(GetPath("settings.xml").generic_wstring()); -+ g_config.SetFilename(GetConfigPath("settings.xml").generic_wstring()); - g_config.Load(); - - std::wstring additionalErrorInfo; -@@ -220,8 +220,59 @@ fs::path ActiveSettings::GetMlcPath() - return GetDefaultMLCPath(); - } - --fs::path ActiveSettings::GetDefaultMLCPath() -+#ifdef XDG -+std::string ActiveSettings::GetXDGPath(const char* envVar, const std::string& defaultValue) -+{ -+ auto raw_value = std::getenv(envVar); -+ return !raw_value || std::strlen(raw_value) == 0 ? defaultValue : std::string(raw_value); -+} -+#endif -+ -+fs::path ActiveSettings::GetConfigPath() -+{ -+#ifdef XDG -+ auto config_home = GetXDGPath("XDG_CONFIG_HOME", fmt::format("{}/.config", std::getenv("HOME"))); -+ auto dir = fs::path(fmt::format("{}/cemu", config_home)); -+ if (!fs::exists(dir)) -+ fs::create_directories(dir); -+ return dir; -+#endif -+ return s_full_path; -+} -+ -+fs::path ActiveSettings::GetCachePath() -+{ -+#ifdef XDG -+ auto config_home = GetXDGPath("XDG_CACHE_HOME", fmt::format("{}/.cache", std::getenv("HOME"))); -+ auto dir = fs::path(fmt::format("{}/cemu", config_home)); -+ if (!fs::exists(dir)) -+ fs::create_directories(dir); -+ return dir; -+#endif -+ return s_full_path; -+} -+ -+fs::path ActiveSettings::GetDataPath() -+{ -+#ifdef XDG -+ auto config_home = GetXDGPath("XDG_DATA_HOME", fmt::format("{}/.local/share", std::getenv("HOME"))); -+ auto dir = fs::path(fmt::format("{}/cemu", config_home)); -+ if (!fs::exists(dir)) -+ fs::create_directories(dir); -+ return dir; -+#endif -+ return s_full_path; -+} -+ -+fs::path ActiveSettings::GetSystemDataPath() - { -- return GetPath("mlc01"); -+#ifdef SYSTEM_DATA_PATH -+ return fs::path(SYSTEM_DATA_PATH); -+#endif -+ return s_full_path; - } - -+fs::path ActiveSettings::GetDefaultMLCPath() -+{ -+ return GetDataPath("mlc01"); -+} ---- a/src/config/ActiveSettings.h -+++ b/src/config/ActiveSettings.h -@@ -13,6 +13,11 @@ public: - [[nodiscard]] static fs::path GetFilename() { return s_filename; } - - [[nodiscard]] static fs::path GetMlcPath(); -+ [[nodiscard]] static fs::path GetCachePath(); -+ [[nodiscard]] static fs::path GetConfigPath(); -+ [[nodiscard]] static fs::path GetDataPath(); -+ [[nodiscard]] static fs::path GetSystemDataPath(); -+ [[nodiscard]] static std::string GetXDGPath(const char* envVar, const std::string& defaultValue); - - [[nodiscard]] static fs::path GetPath(std::string_view p) - { -@@ -57,6 +62,62 @@ public: - return GetMlcPath() / fmt::format(format, std::forward<TArgs>(args)...); - } - -+ template <typename ...TArgs> -+ [[nodiscard]] static fs::path GetCachePath(std::string_view format, TArgs&&... args) -+ { -+ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); -+ return GetCachePath() / fmt::format(format, std::forward<TArgs>(args)...); -+ } -+ -+ template <typename ...TArgs> -+ [[nodiscard]] static fs::path GetCachePath(std::wstring_view format, TArgs&&... args) -+ { -+ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); -+ return GetCachePath() / fmt::format(format, std::forward<TArgs>(args)...); -+ } -+ -+ template <typename ...TArgs> -+ [[nodiscard]] static fs::path GetConfigPath(std::string_view format, TArgs&&... args) -+ { -+ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); -+ return GetConfigPath() / fmt::format(format, std::forward<TArgs>(args)...); -+ } -+ -+ template <typename ...TArgs> -+ [[nodiscard]] static fs::path GetConfigPath(std::wstring_view format, TArgs&&... args) -+ { -+ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); -+ return GetConfigPath() / fmt::format(format, std::forward<TArgs>(args)...); -+ } -+ -+ template <typename ...TArgs> -+ [[nodiscard]] static fs::path GetDataPath(std::string_view format, TArgs&&... args) -+ { -+ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); -+ return GetDataPath() / fmt::format(format, std::forward<TArgs>(args)...); -+ } -+ -+ template <typename ...TArgs> -+ [[nodiscard]] static fs::path GetDataPath(std::wstring_view format, TArgs&&... args) -+ { -+ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); -+ return GetDataPath() / fmt::format(format, std::forward<TArgs>(args)...); -+ } -+ -+ template<typename ...TArgs> -+ [[nodiscard]] static fs::path GetSystemDataPath(std::string_view format, TArgs&&... args) -+ { -+ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); -+ return GetSystemDataPath() / fmt::format(format, std::forward<TArgs>(args)...); -+ } -+ -+ template<typename ...TArgs> -+ [[nodiscard]] static fs::path GetSystemDataPath(std::wstring_view format, TArgs&&... args) -+ { -+ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); -+ return GetSystemDataPath() / fmt::format(format, std::forward<TArgs>(args)...); -+ } -+ - // get mlc path to default cemu root dir/mlc01 - [[nodiscard]] static fs::path GetDefaultMLCPath(); - -@@ -126,4 +187,3 @@ private: - - inline static bool s_has_required_online_files = false; - }; -- ---- a/src/gui/CemuApp.cpp -+++ b/src/gui/CemuApp.cpp -@@ -115,7 +115,7 @@ bool CemuApp::OnInit() - - Bind(wxEVT_ACTIVATE_APP, &CemuApp::ActivateApp, this); - -- if (!TestWriteAccess(ActiveSettings::GetPath())) -+ if (!TestWriteAccess(ActiveSettings::GetConfigPath())) - wxMessageBox(_("Cemu can't write to its directory.\nPlease move it to a different location or run Cemu as administrator!"), _("Warning"), wxOK | wxCENTRE | wxICON_EXCLAMATION, nullptr); - - auto& config = GetConfig(); -@@ -183,7 +183,7 @@ int CemuApp::FilterEvent(wxEvent& event) - - std::vector<const wxLanguageInfo*> CemuApp::GetAvailableLanguages() - { -- const auto path = ActiveSettings::GetPath("resources"); -+ const auto path = ActiveSettings::GetSystemDataPath("resources"); - if (!exists(path)) - return {}; - -@@ -308,11 +308,15 @@ void CemuApp::CreateDefaultFiles(bool first_start) - // cemu directories - try - { -- const auto controllerProfileFolder = GetCemuPath(L"controllerProfiles").ToStdWstring(); -+ const auto controllerProfileFolder = ActiveSettings::GetConfigPath(L"controllerProfiles").generic_wstring(); - if (!fs::exists(controllerProfileFolder)) - fs::create_directories(controllerProfileFolder); - -- const auto memorySearcherFolder = GetCemuPath(L"memorySearcher").ToStdWstring(); -+ const auto gameProfileFolder = ActiveSettings::GetConfigPath(L"gameProfiles").generic_wstring(); -+ if (!fs::exists(gameProfileFolder)) -+ fs::create_directories(gameProfileFolder); -+ -+ const auto memorySearcherFolder = ActiveSettings::GetConfigPath(L"memorySearcher").generic_wstring(); - if (!fs::exists(memorySearcherFolder)) - fs::create_directories(memorySearcherFolder); - } -@@ -398,5 +402,3 @@ void CemuApp::ActivateApp(wxActivateEvent& event) - g_window_info.app_active = event.GetActive(); - event.Skip(); - } -- -- ---- a/src/gui/ChecksumTool.cpp -+++ b/src/gui/ChecksumTool.cpp -@@ -133,7 +133,7 @@ ChecksumTool::ChecksumTool(wxWindow* parent, wxTitleManagerList::TitleEntry& ent - const auto title_id_str = fmt::format("{:016x}", m_json_entry.title_id); - const auto default_file = fmt::format("{}_v{}.json", title_id_str, m_info.GetAppTitleVersion()); - -- const auto checksum_path = ActiveSettings::GetPath("resources/checksums/{}", default_file); -+ const auto checksum_path = ActiveSettings::GetDataPath("resources/checksums/{}", default_file); - if (exists(checksum_path)) - m_verify_online->Enable(); - } -@@ -185,7 +185,7 @@ void ChecksumTool::LoadOnlineData() const - - std::string latest_commit; - -- const auto checksum_path = ActiveSettings::GetPath("resources/checksums"); -+ const auto checksum_path = ActiveSettings::GetDataPath("resources/checksums"); - if (exists(checksum_path)) - { - std::string current_commit; -@@ -593,7 +593,7 @@ void ChecksumTool::OnVerifyOnline(wxCommandEvent& event) - const auto title_id_str = fmt::format("{:016x}", m_json_entry.title_id); - const auto default_file = fmt::format("{}_v{}.json", title_id_str, m_info.GetAppTitleVersion()); - -- const auto checksum_path = ActiveSettings::GetPath("resources/checksums/{}", default_file); -+ const auto checksum_path = ActiveSettings::GetDataPath("resources/checksums/{}", default_file); - if(!exists(checksum_path)) - return; - ---- a/src/gui/DownloadGraphicPacksWindow.cpp -+++ b/src/gui/DownloadGraphicPacksWindow.cpp -@@ -65,7 +65,7 @@ bool DownloadGraphicPacksWindow::curlDownloadFile(const char *url, curlDownloadF - bool checkGraphicPackDownloadedVersion(const char* nameVersion, bool& hasVersionFile) - { - hasVersionFile = false; -- const auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks/version.txt"); -+ const auto path = ActiveSettings::GetDataPath("graphicPacks/downloadedGraphicPacks/version.txt"); - std::unique_ptr<FileStream> file(FileStream::openFile2(path)); - - std::string versionInFile; -@@ -78,7 +78,7 @@ bool checkGraphicPackDownloadedVersion(const char* nameVersion, bool& hasVersion - - void createGraphicPackDownloadedVersionFile(const char* nameVersion) - { -- const auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks/version.txt"); -+ const auto path = ActiveSettings::GetDataPath("graphicPacks/downloadedGraphicPacks/version.txt"); - std::unique_ptr<FileStream> file(FileStream::createFile2(path)); - if (file) - file->writeString(nameVersion); -@@ -90,7 +90,7 @@ void createGraphicPackDownloadedVersionFile(const char* nameVersion) - - void deleteDownloadedGraphicPacks() - { -- const auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks"); -+ const auto path = ActiveSettings::GetDataPath("graphicPacks/downloadedGraphicPacks"); - std::error_code er; - if (!fs::exists(path, er)) - return; -@@ -238,7 +238,7 @@ void DownloadGraphicPacksWindow::UpdateThread() - return; - } - -- auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks"); -+ auto path = ActiveSettings::GetDataPath("graphicPacks/downloadedGraphicPacks"); - std::error_code er; - //fs::remove_all(path, er); -> Don't delete the whole folder and recreate it immediately afterwards because sometimes it just fails - deleteDownloadedGraphicPacks(); -@@ -258,7 +258,7 @@ void DownloadGraphicPacksWindow::UpdateThread() - std::strstr(sb.name, "..\\") != nullptr) - continue; // bad path - -- path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks/{}", sb.name); -+ path = ActiveSettings::GetDataPath("graphicPacks/downloadedGraphicPacks/{}", sb.name); - - size_t sbNameLen = strlen(sb.name); - if(sbNameLen == 0) ---- a/src/gui/MainWindow.cpp -+++ b/src/gui/MainWindow.cpp -@@ -997,7 +997,7 @@ void MainWindow::OnDebugSetting(wxCommandEvent& event) - { - try - { -- const auto path = CemuApp::GetCemuPath(L"dump\\curl").ToStdWstring(); -+ const auto path = ActiveSettings::GetDataPath(L"dump/curl").generic_wstring(); - fs::create_directories(path); - } - catch (const std::exception& ex) -@@ -1054,8 +1054,8 @@ void MainWindow::OnDebugDumpUsedTextures(wxCommandEvent& event) - try - { - // create directory -- const auto path = CemuApp::GetCemuPath(L"dump\\textures"); -- fs::create_directories(path.ToStdWstring()); -+ const auto path = ActiveSettings::GetDataPath(L"dump/textures"); -+ fs::create_directories(path.generic_wstring()); - } - catch (const std::exception& ex) - { -@@ -1075,8 +1075,8 @@ void MainWindow::OnDebugDumpUsedShaders(wxCommandEvent& event) - try - { - // create directory -- const auto path = CemuApp::GetCemuPath(L"dump\\shaders"); -- fs::create_directories(path.ToStdWstring()); -+ const auto path = ActiveSettings::GetDataPath(L"dump/shaders"); -+ fs::create_directories(path.generic_wstring()); - } - catch (const std::exception & ex) - { ---- a/src/gui/MemorySearcherTool.cpp -+++ b/src/gui/MemorySearcherTool.cpp -@@ -270,7 +270,7 @@ void MemorySearcherTool::OnFilter(wxCommandEvent& event) - - void MemorySearcherTool::Load() - { -- const auto memorySearcherPath = ActiveSettings::GetPath("memorySearcher/{:016x}.ini", CafeSystem::GetForegroundTitleId()); -+ const auto memorySearcherPath = ActiveSettings::GetConfigPath("memorySearcher/{:016x}.ini", CafeSystem::GetForegroundTitleId()); - auto memSearcherIniContents = FileStream::LoadIntoMemory(memorySearcherPath); - if (!memSearcherIniContents) - return; -@@ -322,7 +322,7 @@ void MemorySearcherTool::Load() - - void MemorySearcherTool::Save() - { -- const auto memorySearcherPath = ActiveSettings::GetPath("memorySearcher/{:016x}.ini", CafeSystem::GetForegroundTitleId()); -+ const auto memorySearcherPath = ActiveSettings::GetConfigPath("memorySearcher/{:016x}.ini", CafeSystem::GetForegroundTitleId()); - FileStream* fs = FileStream::createFile2(memorySearcherPath); - if (fs) - { ---- a/src/gui/debugger/DebuggerWindow2.cpp -+++ b/src/gui/debugger/DebuggerWindow2.cpp -@@ -272,7 +272,7 @@ DebuggerWindow2::DebuggerWindow2(wxFrame& parent, const wxRect& display_size) - { - this->wxWindowBase::SetBackgroundColour(*wxWHITE); - -- const auto file = ActiveSettings::GetPath("debugger/config.xml"); -+ const auto file = ActiveSettings::GetConfigPath("debugger/config.xml"); - m_config.SetFilename(file.generic_wstring()); - m_config.Load(); - -@@ -472,7 +472,7 @@ bool DebuggerWindow2::Show(bool show) - std::wstring DebuggerWindow2::GetModuleStoragePath(std::string module_name, uint32_t crc_hash) const - { - if (module_name.empty() || crc_hash == 0) return std::wstring(); -- return ActiveSettings::GetPath("debugger/{}_{:#10x}.xml", module_name, crc_hash).generic_wstring(); -+ return ActiveSettings::GetConfigPath("debugger/{}_{:#10x}.xml", module_name, crc_hash).generic_wstring(); - } - - void DebuggerWindow2::OnBreakpointHit(wxCommandEvent& event) ---- a/src/gui/input/InputSettings2.cpp -+++ b/src/gui/input/InputSettings2.cpp -@@ -669,10 +669,10 @@ void InputSettings2::on_profile_delete(wxCommandEvent& event) - } - try - { -- const fs::path old_path = ActiveSettings::GetPath(fmt::format("controllerProfiles/{}.txt", selection)); -+ const fs::path old_path = ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/{}.txt", selection)); - fs::remove(old_path); - -- const fs::path path = ActiveSettings::GetPath(fmt::format("controllerProfiles/{}.xml", selection)); -+ const fs::path path = ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/{}.xml", selection)); - fs::remove(path); - - profile_names->ChangeValue(kDefaultProfileName); ---- a/src/input/InputManager.cpp -+++ b/src/input/InputManager.cpp -@@ -76,9 +76,9 @@ bool InputManager::load(size_t player_index, std::string_view filename) - { - fs::path file_path; - if (filename.empty()) -- file_path = ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}", player_index)); -+ file_path = ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/controller{}", player_index)); - else -- file_path = ActiveSettings::GetPath(fmt::format("controllerProfiles/{}", filename)); -+ file_path = ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/{}", filename)); - - auto old_file = file_path; - old_file.replace_extension(".txt"); // test .txt extension -@@ -448,7 +448,7 @@ bool InputManager::save(size_t player_index, std::string_view filename) - if (!emulated_controller) - return false; - -- fs::path file_path = ActiveSettings::GetPath("controllerProfiles"); -+ fs::path file_path = ActiveSettings::GetConfigPath("controllerProfiles"); - fs::create_directories(file_path); - - const auto is_default_file = filename.empty(); -@@ -664,8 +664,8 @@ EmulatedControllerPtr InputManager::delete_controller(size_t player_index, bool - if(delete_profile) - { - std::error_code ec{}; -- fs::remove(ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}.xml", player_index)), ec); -- fs::remove(ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}.txt", player_index)), ec); -+ fs::remove(ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/controller{}.xml", player_index)), ec); -+ fs::remove(ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/controller{}.txt", player_index)), ec); - } - - return result; -@@ -680,8 +680,8 @@ EmulatedControllerPtr InputManager::delete_controller(size_t player_index, bool - controller = {}; - - std::error_code ec{}; -- fs::remove(ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}.xml", player_index)), ec); -- fs::remove(ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}.txt", player_index)), ec); -+ fs::remove(ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/controller{}.xml", player_index)), ec); -+ fs::remove(ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/controller{}.txt", player_index)), ec); - - return result; - } -@@ -782,7 +782,7 @@ void InputManager::apply_game_profile() - - std::vector<std::string> InputManager::get_profiles() - { -- const auto path = ActiveSettings::GetPath("controllerProfiles"); -+ const auto path = ActiveSettings::GetConfigPath("controllerProfiles"); - if (!exists(path)) - return {}; - ---- a/src/main.cpp -+++ b/src/main.cpp -@@ -160,7 +160,7 @@ void _putenvSafe(const char* c) - void reconfigureGLDrivers() - { - // reconfigure GL drivers to store -- const fs::path nvCacheDir = ActiveSettings::GetPath("shaderCache/driver/nvidia/"); -+ const fs::path nvCacheDir = ActiveSettings::GetCachePath("shaderCache/driver/nvidia/"); - - std::error_code err; - fs::create_directories(nvCacheDir, err); -@@ -242,7 +242,7 @@ void unitTests() - - int mainEmulatorHLE() - { -- if (!TestWriteAccess(ActiveSettings::GetPath())) -+ if (!TestWriteAccess(ActiveSettings::GetConfigPath())) - wxMessageBox("Cemu doesn't have write access to it's own directory.\nPlease move it to a different location or run Cemu as administrator!", "Warning", wxOK|wxICON_ERROR); // todo - different error messages per OS - LatteOverlay_init(); - // run a couple of tests if in non-release mode -@@ -264,7 +264,7 @@ int mainEmulatorHLE() - // init Cafe system (todo - the stuff above should be part of this too) - CafeSystem::Initialize(); - // init title list -- CafeTitleList::Initialize(ActiveSettings::GetPath("title_list_cache.xml")); -+ CafeTitleList::Initialize(ActiveSettings::GetCachePath("title_list_cache.xml")); - for (auto& it : GetConfig().game_paths) - CafeTitleList::AddScanPath(it); - fs::path mlcPath = ActiveSettings::GetMlcPath(); ---- a/src/util/libusbWrapper/libusbWrapper.cpp -+++ b/src/util/libusbWrapper/libusbWrapper.cpp -@@ -18,7 +18,7 @@ void libusbWrapper::init() - m_module = LoadLibraryW(L"libusb-1.0.dll"); - if (!m_module) - { -- const auto path = ActiveSettings::GetPath("resources/libusb-1.0.dll"); -+ const auto path = ActiveSettings::GetSystemDataPath("resources/libusb-1.0.dll"); - m_module = LoadLibraryW(path.generic_wstring().c_str()); - if (!m_module) - { -EOF -} diff --git a/clang.patch b/clang.patch new file mode 100644 index 000000000000..23e768434fed --- /dev/null +++ b/clang.patch @@ -0,0 +1,14 @@ +diff --git a/src/Cemu/Logging/CemuLogging.h b/src/Cemu/Logging/CemuLogging.h +index 4238b63..a9b1daa 100644 +--- a/src/Cemu/Logging/CemuLogging.h ++++ b/src/Cemu/Logging/CemuLogging.h +@@ -58,9 +58,6 @@ bool cemuLog_log(LogType type, TFmt format, TArgs&&... args) + if (!cemuLog_isLoggingEnabled(type)) + return false; + +- const auto format_view = fmt::to_string_view(format); +- const auto text = fmt::vformat(format_view, fmt::make_args_checked<TArgs...>(format_view, args...)); +- cemuLog_log(type, std::basic_string_view(text.data(), text.size())); + return true; + } + diff --git a/xdg.patch b/xdg.patch new file mode 100644 index 000000000000..e2937554ea53 --- /dev/null +++ b/xdg.patch @@ -0,0 +1,833 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index b001421..4868374 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -58,6 +58,13 @@ option(ENABLE_OPENGL "Enables the OpenGL backend" ON) + option(ENABLE_VULKAN "Enables the Vulkan backend" ON) + option(ENABLE_DISCORD_RPC "Enables the Discord Rich Presence feature" ON) + ++if (UNIX) ++ option(ENABLE_XDG_DIRS "Enable storage according to XDG specification" ON) ++endif() ++if (SYSTEM_DATA_PATH) ++ add_compile_definitions(SYSTEM_DATA_PATH=\"${SYSTEM_DATA_PATH}\") ++endif() ++ + # input backends + if (WIN32) + option(ENABLE_XINPUT "Enables the usage of XInput" ON) +@@ -133,6 +140,10 @@ if (ENABLE_CUBEB) + add_compile_definitions("HAS_CUBEB=1") + endif() + ++if (ENABLE_XDG_DIRS) ++ add_compile_definitions(XDG) ++endif() ++ + add_subdirectory("dependencies/ih264d" EXCLUDE_FROM_ALL) + + find_package(ZArchive) +diff --git a/src/Cafe/Account/Account.cpp b/src/Cafe/Account/Account.cpp +index f370c81..55fc824 100644 +--- a/src/Cafe/Account/Account.cpp ++++ b/src/Cafe/Account/Account.cpp +@@ -424,7 +424,7 @@ OnlineValidator Account::ValidateOnlineFiles() const + { + OnlineValidator result{}; + +- const auto otp = ActiveSettings::GetPath("otp.bin"); ++ const auto otp = ActiveSettings::GetDataPath("otp.bin"); + if (!fs::exists(otp)) + result.otp = OnlineValidator::FileState::Missing; + else if (fs::file_size(otp) != 1024) +@@ -432,7 +432,7 @@ OnlineValidator Account::ValidateOnlineFiles() const + else + result.otp = OnlineValidator::FileState::Ok; + +- const auto seeprom = ActiveSettings::GetPath("seeprom.bin"); ++ const auto seeprom = ActiveSettings::GetDataPath("seeprom.bin"); + if (!fs::exists(seeprom)) + result.seeprom = OnlineValidator::FileState::Missing; + else if (fs::file_size(seeprom) != 512) +diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp +index bfa5d82..50f46d1 100644 +--- a/src/Cafe/CafeSystem.cpp ++++ b/src/Cafe/CafeSystem.cpp +@@ -289,7 +289,7 @@ uint32 loadSharedData() + for (sint32 i = 0; i < sizeof(shareddataDef) / sizeof(shareddataDef[0]); i++) + { + bool existsInMLC = fs::exists(ActiveSettings::GetMlcPath(shareddataDef[i].mlcPath)); +- bool existsInResources = fs::exists(ActiveSettings::GetPath(shareddataDef[i].resourcePath)); ++ bool existsInResources = fs::exists(ActiveSettings::GetSystemDataPath(shareddataDef[i].resourcePath)); + + if (!existsInMLC && !existsInResources) + { +@@ -314,7 +314,7 @@ uint32 loadSharedData() + // alternatively fall back to our shared fonts + if (!fontFile) + { +- path = ActiveSettings::GetPath(shareddataDef[i].resourcePath); ++ path = ActiveSettings::GetSystemDataPath(shareddataDef[i].resourcePath); + fontFile = FileStream::openFile2(path); + } + if (!fontFile) +@@ -340,7 +340,7 @@ uint32 loadSharedData() + return memory_getVirtualOffsetFromPointer(dataWritePtr); + } + // alternative method: load RAM dump +- const auto path = ActiveSettings::GetPath("shareddata.bin"); ++ const auto path = ActiveSettings::GetSystemDataPath("shareddata.bin"); + FileStream* ramDumpFile = FileStream::openFile2(path); + if (ramDumpFile) + { +diff --git a/src/Cafe/Filesystem/FST/KeyCache.cpp b/src/Cafe/Filesystem/FST/KeyCache.cpp +index 7fedc3d..124611f 100644 +--- a/src/Cafe/Filesystem/FST/KeyCache.cpp ++++ b/src/Cafe/Filesystem/FST/KeyCache.cpp +@@ -59,7 +59,7 @@ void KeyCache_Prepare() + sKeyCachePrepared = true; + g_keyCache.clear(); + // load keys +- auto keysPath = ActiveSettings::GetPath("keys.txt"); ++ auto keysPath = ActiveSettings::GetConfigPath("keys.txt"); + FileStream* fs_keys = FileStream::openFile2(keysPath); + if( !fs_keys ) + { +diff --git a/src/Cafe/GameProfile/GameProfile.cpp b/src/Cafe/GameProfile/GameProfile.cpp +index d3e930e..85de1f4 100644 +--- a/src/Cafe/GameProfile/GameProfile.cpp ++++ b/src/Cafe/GameProfile/GameProfile.cpp +@@ -180,12 +180,12 @@ void gameProfile_load() + + bool GameProfile::Load(uint64_t title_id) + { +- auto gameProfilePath = ActiveSettings::GetPath("gameProfiles/{:016x}.ini", title_id); ++ auto gameProfilePath = ActiveSettings::GetConfigPath("gameProfiles/{:016x}.ini", title_id); + + std::optional<std::vector<uint8>> profileContents = FileStream::LoadIntoMemory(gameProfilePath); + if (!profileContents) + { +- gameProfilePath = ActiveSettings::GetPath("gameProfiles/default/{:016x}.ini", title_id); ++ gameProfilePath = ActiveSettings::GetSystemDataPath("gameProfiles/default/{:016x}.ini", title_id); + profileContents = FileStream::LoadIntoMemory(gameProfilePath); + if (!profileContents) + return false; +@@ -276,7 +276,7 @@ bool GameProfile::Load(uint64_t title_id) + + void GameProfile::Save(uint64_t title_id) + { +- auto gameProfilePath = ActiveSettings::GetPath("gameProfiles/{:016x}.ini", title_id); ++ auto gameProfilePath = ActiveSettings::GetConfigPath("gameProfiles/{:016x}.ini", title_id); + FileStream* fs = FileStream::createFile2(gameProfilePath); + if (!fs) + { +diff --git a/src/Cafe/GraphicPack/GraphicPack2.cpp b/src/Cafe/GraphicPack/GraphicPack2.cpp +index 41e33a1..38e52bb 100644 +--- a/src/Cafe/GraphicPack/GraphicPack2.cpp ++++ b/src/Cafe/GraphicPack/GraphicPack2.cpp +@@ -63,7 +63,7 @@ void GraphicPack2::LoadGraphicPack(fs::path graphicPackPath) + void GraphicPack2::LoadAll() + { + std::error_code ec; +- fs::path basePath = ActiveSettings::GetPath("graphicPacks"); ++ fs::path basePath = ActiveSettings::GetDataPath("graphicPacks"); + for (fs::recursive_directory_iterator it(basePath, ec); it != end(it); ++it) + { + if (!it->is_directory(ec)) +diff --git a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +index bcdaffa..aa8c296 100644 +--- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp ++++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +@@ -197,17 +197,17 @@ void LatteShaderCache_load() + LatteShaderCache_initCompileQueue(); + // create directories + std::error_code ec; +- fs::create_directories(ActiveSettings::GetPath("shaderCache/transferable"), ec); +- fs::create_directories(ActiveSettings::GetPath("shaderCache/precompiled"), ec); ++ fs::create_directories(ActiveSettings::GetCachePath("shaderCache/transferable"), ec); ++ fs::create_directories(ActiveSettings::GetCachePath("shaderCache/precompiled"), ec); + // initialize renderer specific caches + if (g_renderer->GetType() == RendererAPI::Vulkan) + RendererShaderVk::ShaderCacheLoading_begin(cacheTitleId); + else if (g_renderer->GetType() == RendererAPI::OpenGL) + RendererShaderGL::ShaderCacheLoading_begin(cacheTitleId); + // get cache file name +- const auto pathGeneric = ActiveSettings::GetPath("shaderCache/transferable/{:016x}_shaders.bin", cacheTitleId); +- const auto pathGenericPre1_25_0 = ActiveSettings::GetPath("shaderCache/transferable/{:016x}.bin", cacheTitleId); // before 1.25.0 +- const auto pathGenericPre1_16_0 = ActiveSettings::GetPath("shaderCache/transferable/{:08x}.bin", CafeSystem::GetRPXHashBase()); // before 1.16.0 ++ const auto pathGeneric = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}_shaders.bin", cacheTitleId); ++ const auto pathGenericPre1_25_0 = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}.bin", cacheTitleId); // before 1.25.0 ++ const auto pathGenericPre1_16_0 = ActiveSettings::GetCachePath("shaderCache/transferable/{:08x}.bin", CafeSystem::GetRPXHashBase()); // before 1.16.0 + + LatteShaderCache_handleDeprecatedCacheFiles(pathGeneric, pathGenericPre1_25_0, pathGenericPre1_16_0); + // calculate extraVersion for transferable and precompiled shader cache +diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp +index e9e86f5..dc088ae 100644 +--- a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp ++++ b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp +@@ -279,7 +279,7 @@ void RendererShaderGL::ShaderCacheLoading_begin(uint64 cacheTitleId) + { + const uint32 cacheMagic = GeneratePrecompiledCacheId(); + const std::string cacheFilename = fmt::format("{:016x}_gl.bin", cacheTitleId); +- const std::wstring cachePath = ActiveSettings::GetPath("shaderCache/precompiled/{}", cacheFilename).generic_wstring(); ++ const std::wstring cachePath = ActiveSettings::GetCachePath("shaderCache/precompiled/{}", cacheFilename).generic_wstring(); + g_programBinaryCache = FileCache::Open(cachePath, true, cacheMagic); + if (g_programBinaryCache == nullptr) + cemuLog_log(LogType::Force, "Unable to open OpenGL precompiled cache {}", cacheFilename); +diff --git a/src/Cafe/HW/Latte/Renderer/Renderer.cpp b/src/Cafe/HW/Latte/Renderer/Renderer.cpp +index c7f7b81..366ce54 100644 +--- a/src/Cafe/HW/Latte/Renderer/Renderer.cpp ++++ b/src/Cafe/HW/Latte/Renderer/Renderer.cpp +@@ -133,7 +133,7 @@ void Renderer::SaveScreenshot(const std::vector<uint8>& rgb_data, int width, int + // save to png file + if (save_screenshot) + { +- fs::path screendir = ActiveSettings::GetPath("screenshots"); ++ fs::path screendir = ActiveSettings::GetDataPath("screenshots"); + if (!fs::exists(screendir)) + fs::create_directory(screendir); + +diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp +index 7af5204..703c92d 100644 +--- a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp ++++ b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp +@@ -456,7 +456,7 @@ void RendererShaderVk::ShaderCacheLoading_begin(uint64 cacheTitleId) + } + uint32 spirvCacheMagic = GeneratePrecompiledCacheId(); + const std::string cacheFilename = fmt::format("{:016x}_spirv.bin", cacheTitleId); +- const std::wstring cachePath = ActiveSettings::GetPath("shaderCache/precompiled/{}", cacheFilename).generic_wstring(); ++ const std::wstring cachePath = ActiveSettings::GetCachePath("shaderCache/precompiled/{}", cacheFilename).generic_wstring(); + s_spirvCache = FileCache::Open(cachePath, true, spirvCacheMagic); + if (s_spirvCache == nullptr) + cemuLog_log(LogType::Force, "Unable to open SPIR-V cache {}", cacheFilename); +diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp +index 50d5a25..b86b0a5 100644 +--- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp ++++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp +@@ -32,8 +32,8 @@ VulkanPipelineStableCache& VulkanPipelineStableCache::GetInstance() + uint32 VulkanPipelineStableCache::BeginLoading(uint64 cacheTitleId) + { + std::error_code ec; +- fs::create_directories(ActiveSettings::GetPath("shaderCache/transferable"), ec); +- const auto pathCacheFile = ActiveSettings::GetPath("shaderCache/transferable/{:016x}_vkpipeline.bin", cacheTitleId); ++ fs::create_directories(ActiveSettings::GetCachePath("shaderCache/transferable"), ec); ++ const auto pathCacheFile = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}_vkpipeline.bin", cacheTitleId); + + // init cache loader state + g_vkCacheState.pipelineLoadIndex = 0; +diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +index 7c81a3c..8cf1f12 100644 +--- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp ++++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +@@ -2305,7 +2305,7 @@ void VulkanRenderer::WaitCommandBufferFinished(uint64 commandBufferId) + + void VulkanRenderer::PipelineCacheSaveThread(size_t cache_size) + { +- const auto dir = ActiveSettings::GetPath("shaderCache/driver/vk"); ++ const auto dir = ActiveSettings::GetCachePath("shaderCache/driver/vk"); + if (!fs::exists(dir)) + { + try +@@ -2382,7 +2382,7 @@ void VulkanRenderer::PipelineCacheSaveThread(size_t cache_size) + void VulkanRenderer::CreatePipelineCache() + { + std::vector<uint8_t> cacheData; +- const auto dir = ActiveSettings::GetPath("shaderCache/driver/vk"); ++ const auto dir = ActiveSettings::GetCachePath("shaderCache/driver/vk"); + if (fs::exists(dir)) + { + const auto filename = dir / fmt::format("{:016x}.bin", CafeSystem::GetForegroundTitleId()); +diff --git a/src/Cafe/HW/MMU/MMU.cpp b/src/Cafe/HW/MMU/MMU.cpp +index 87bf572..10d69ef 100644 +--- a/src/Cafe/HW/MMU/MMU.cpp ++++ b/src/Cafe/HW/MMU/MMU.cpp +@@ -409,7 +409,7 @@ void memory_writeDumpFile(uint32 startAddr, uint32 size, const fs::path& path) + void memory_createDump() + { + const uint32 pageSize = MemMapper::GetPageSize(); +- fs::path path = ActiveSettings::GetPath("dump/ramDump{:}", (uint32)time(nullptr)); ++ fs::path path = ActiveSettings::GetDataPath("dump/ramDump{:}", (uint32)time(nullptr)); + fs::create_directories(path); + + for (auto& itr : g_mmuRanges) +diff --git a/src/Cafe/IOSU/legacy/iosu_crypto.cpp b/src/Cafe/IOSU/legacy/iosu_crypto.cpp +index 0433995..ef30a2b 100644 +--- a/src/Cafe/IOSU/legacy/iosu_crypto.cpp ++++ b/src/Cafe/IOSU/legacy/iosu_crypto.cpp +@@ -563,7 +563,7 @@ void iosuCrypto_loadSSLCertificates() + void iosuCrypto_init() + { + // load OTP dump +- if (std::ifstream otp_file(ActiveSettings::GetPath("otp.bin"), std::ifstream::in | std::ios::binary); otp_file.is_open()) ++ if (std::ifstream otp_file(ActiveSettings::GetDataPath("otp.bin"), std::ifstream::in | std::ios::binary); otp_file.is_open()) + { + otp_file.seekg(0, std::ifstream::end); + const auto length = otp_file.tellg(); +@@ -586,7 +586,7 @@ void iosuCrypto_init() + hasOtpMem = false; + } + +- if (std::ifstream seeprom_file(ActiveSettings::GetPath("seeprom.bin"), std::ifstream::in | std::ios::binary); seeprom_file.is_open()) ++ if (std::ifstream seeprom_file(ActiveSettings::GetDataPath("seeprom.bin"), std::ifstream::in | std::ios::binary); seeprom_file.is_open()) + { + seeprom_file.seekg(0, std::ifstream::end); + const auto length = seeprom_file.tellg(); +@@ -630,13 +630,13 @@ sint32 iosuCrypt_checkRequirementsForOnlineMode(std::wstring& additionalErrorInf + { + std::error_code ec; + // check if otp.bin is present +- const auto otp_file = ActiveSettings::GetPath("otp.bin"); ++ const auto otp_file = ActiveSettings::GetDataPath("otp.bin"); + if(!fs::exists(otp_file, ec)) + return IOS_CRYPTO_ONLINE_REQ_OTP_MISSING; + if(fs::file_size(otp_file, ec) != 1024) + return IOS_CRYPTO_ONLINE_REQ_OTP_CORRUPTED; + // check if seeprom.bin is present +- const auto seeprom_file = ActiveSettings::GetPath("seeprom.bin"); ++ const auto seeprom_file = ActiveSettings::GetDataPath("seeprom.bin"); + if (!fs::exists(seeprom_file, ec)) + return IOS_CRYPTO_ONLINE_REQ_SEEPROM_MISSING; + if (fs::file_size(seeprom_file, ec) != 512) +diff --git a/src/Cafe/OS/RPL/rpl.cpp b/src/Cafe/OS/RPL/rpl.cpp +index 90f9225..40c8e42 100644 +--- a/src/Cafe/OS/RPL/rpl.cpp ++++ b/src/Cafe/OS/RPL/rpl.cpp +@@ -2122,7 +2122,7 @@ void RPLLoader_LoadDependency(rplDependency_t* dependency) + // attempt to load rpl from Cemu's /cafeLibs/ directory + if (ActiveSettings::LoadSharedLibrariesEnabled()) + { +- const auto filePath = ActiveSettings::GetPath("cafeLibs/{}", dependency->filepath); ++ const auto filePath = ActiveSettings::GetDataPath("cafeLibs/{}", dependency->filepath); + auto fileData = FileStream::LoadIntoMemory(filePath); + if (fileData) + { +diff --git a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp +index 3d13fdb..fb72ca8 100644 +--- a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp ++++ b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp +@@ -107,7 +107,7 @@ namespace coreinit + return; + + std::error_code ec; +- const auto path = ActiveSettings::GetPath("sdcard/"); ++ const auto path = ActiveSettings::GetDataPath("sdcard/"); + fs::create_directories(path, ec); + FSCDeviceHostFS_Mount("/vol/external01", path.generic_wstring().c_str() , FSC_PRIORITY_BASE); + +@@ -140,7 +140,7 @@ namespace coreinit + return FS_RESULT::ERR_PLACEHOLDER; + + std::error_code ec; +- const auto path = ActiveSettings::GetPath("sdcard/"); ++ const auto path = ActiveSettings::GetDataPath("sdcard/"); + fs::create_directories(path, ec); + if (!FSCDeviceHostFS_Mount(mountPathOut, path.generic_wstring().c_str(), FSC_PRIORITY_BASE)) + return FS_RESULT::ERR_PLACEHOLDER; +diff --git a/src/Cemu/Logging/CemuLogging.cpp b/src/Cemu/Logging/CemuLogging.cpp +index f58e798..6d403de 100644 +--- a/src/Cemu/Logging/CemuLogging.cpp ++++ b/src/Cemu/Logging/CemuLogging.cpp +@@ -98,7 +98,7 @@ void cemuLog_createLogFile(bool triggeredByCrash) + if (LogContext.file_stream.is_open()) + return; + +- const auto path = ActiveSettings::GetPath("log.txt"); ++ const auto path = ActiveSettings::GetDataPath("log.txt"); + LogContext.file_stream.open(path, std::ios::out); + if (LogContext.file_stream.fail()) + { +diff --git a/src/Cemu/Logging/CemuLogging.h b/src/Cemu/Logging/CemuLogging.h +index 4238b63..a9b1daa 100644 +--- a/src/Cemu/Logging/CemuLogging.h ++++ b/src/Cemu/Logging/CemuLogging.h +@@ -58,9 +58,6 @@ bool cemuLog_log(LogType type, TFmt format, TArgs&&... args) + if (!cemuLog_isLoggingEnabled(type)) + return false; + +- const auto format_view = fmt::to_string_view(format); +- const auto text = fmt::vformat(format_view, fmt::make_args_checked<TArgs...>(format_view, args...)); +- cemuLog_log(type, std::basic_string_view(text.data(), text.size())); + return true; + } + +diff --git a/src/config/ActiveSettings.cpp b/src/config/ActiveSettings.cpp +index c7ff4fe..23bc364 100644 +--- a/src/config/ActiveSettings.cpp ++++ b/src/config/ActiveSettings.cpp +@@ -18,7 +18,7 @@ void ActiveSettings::LoadOnce() + s_path = s_full_path.parent_path(); + s_filename = s_full_path.filename(); + +- g_config.SetFilename(GetPath("settings.xml").generic_wstring()); ++ g_config.SetFilename(GetConfigPath("settings.xml").generic_wstring()); + g_config.Load(); + + std::wstring additionalErrorInfo; +@@ -220,8 +220,59 @@ fs::path ActiveSettings::GetMlcPath() + return GetDefaultMLCPath(); + } + +-fs::path ActiveSettings::GetDefaultMLCPath() ++#ifdef XDG ++std::string ActiveSettings::GetXDGPath(const char* envVar, const std::string& defaultValue) ++{ ++ auto raw_value = std::getenv(envVar); ++ return !raw_value || std::strlen(raw_value) == 0 ? defaultValue : std::string(raw_value); ++} ++#endif ++ ++fs::path ActiveSettings::GetConfigPath() ++{ ++#ifdef XDG ++ auto config_home = GetXDGPath("XDG_CONFIG_HOME", fmt::format("{}/.config", std::getenv("HOME"))); ++ auto dir = fs::path(fmt::format("{}/cemu", config_home)); ++ if (!fs::exists(dir)) ++ fs::create_directories(dir); ++ return dir; ++#endif ++ return s_full_path; ++} ++ ++fs::path ActiveSettings::GetCachePath() ++{ ++#ifdef XDG ++ auto config_home = GetXDGPath("XDG_CACHE_HOME", fmt::format("{}/.cache", std::getenv("HOME"))); ++ auto dir = fs::path(fmt::format("{}/cemu", config_home)); ++ if (!fs::exists(dir)) ++ fs::create_directories(dir); ++ return dir; ++#endif ++ return s_full_path; ++} ++ ++fs::path ActiveSettings::GetDataPath() ++{ ++#ifdef XDG ++ auto config_home = GetXDGPath("XDG_DATA_HOME", fmt::format("{}/.local/share", std::getenv("HOME"))); ++ auto dir = fs::path(fmt::format("{}/cemu", config_home)); ++ if (!fs::exists(dir)) ++ fs::create_directories(dir); ++ return dir; ++#endif ++ return s_full_path; ++} ++ ++fs::path ActiveSettings::GetSystemDataPath() + { +- return GetPath("mlc01"); ++#ifdef SYSTEM_DATA_PATH ++ return fs::path(SYSTEM_DATA_PATH); ++#endif ++ return s_full_path; + } + ++fs::path ActiveSettings::GetDefaultMLCPath() ++{ ++ return GetDataPath("mlc01"); ++} +diff --git a/src/config/ActiveSettings.h b/src/config/ActiveSettings.h +index 44b5f50..e5a35d4 100644 +--- a/src/config/ActiveSettings.h ++++ b/src/config/ActiveSettings.h +@@ -13,6 +13,11 @@ public: + [[nodiscard]] static fs::path GetFilename() { return s_filename; } + + [[nodiscard]] static fs::path GetMlcPath(); ++ [[nodiscard]] static fs::path GetCachePath(); ++ [[nodiscard]] static fs::path GetConfigPath(); ++ [[nodiscard]] static fs::path GetDataPath(); ++ [[nodiscard]] static fs::path GetSystemDataPath(); ++ [[nodiscard]] static std::string GetXDGPath(const char* envVar, const std::string& defaultValue); + + [[nodiscard]] static fs::path GetPath(std::string_view p) + { +@@ -57,6 +62,62 @@ public: + return GetMlcPath() / fmt::format(format, std::forward<TArgs>(args)...); + } + ++ template <typename ...TArgs> ++ [[nodiscard]] static fs::path GetCachePath(std::string_view format, TArgs&&... args) ++ { ++ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); ++ return GetCachePath() / fmt::format(format, std::forward<TArgs>(args)...); ++ } ++ ++ template <typename ...TArgs> ++ [[nodiscard]] static fs::path GetCachePath(std::wstring_view format, TArgs&&... args) ++ { ++ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); ++ return GetCachePath() / fmt::format(format, std::forward<TArgs>(args)...); ++ } ++ ++ template <typename ...TArgs> ++ [[nodiscard]] static fs::path GetConfigPath(std::string_view format, TArgs&&... args) ++ { ++ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); ++ return GetConfigPath() / fmt::format(format, std::forward<TArgs>(args)...); ++ } ++ ++ template <typename ...TArgs> ++ [[nodiscard]] static fs::path GetConfigPath(std::wstring_view format, TArgs&&... args) ++ { ++ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); ++ return GetConfigPath() / fmt::format(format, std::forward<TArgs>(args)...); ++ } ++ ++ template <typename ...TArgs> ++ [[nodiscard]] static fs::path GetDataPath(std::string_view format, TArgs&&... args) ++ { ++ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); ++ return GetDataPath() / fmt::format(format, std::forward<TArgs>(args)...); ++ } ++ ++ template <typename ...TArgs> ++ [[nodiscard]] static fs::path GetDataPath(std::wstring_view format, TArgs&&... args) ++ { ++ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); ++ return GetDataPath() / fmt::format(format, std::forward<TArgs>(args)...); ++ } ++ ++ template<typename ...TArgs> ++ [[nodiscard]] static fs::path GetSystemDataPath(std::string_view format, TArgs&&... args) ++ { ++ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); ++ return GetSystemDataPath() / fmt::format(format, std::forward<TArgs>(args)...); ++ } ++ ++ template<typename ...TArgs> ++ [[nodiscard]] static fs::path GetSystemDataPath(std::wstring_view format, TArgs&&... args) ++ { ++ cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); ++ return GetSystemDataPath() / fmt::format(format, std::forward<TArgs>(args)...); ++ } ++ + // get mlc path to default cemu root dir/mlc01 + [[nodiscard]] static fs::path GetDefaultMLCPath(); + +@@ -126,4 +187,3 @@ private: + + inline static bool s_has_required_online_files = false; + }; +- +diff --git a/src/gui/CemuApp.cpp b/src/gui/CemuApp.cpp +index 17e31f7..1d145d3 100644 +--- a/src/gui/CemuApp.cpp ++++ b/src/gui/CemuApp.cpp +@@ -115,7 +115,7 @@ bool CemuApp::OnInit() + + Bind(wxEVT_ACTIVATE_APP, &CemuApp::ActivateApp, this); + +- if (!TestWriteAccess(ActiveSettings::GetPath())) ++ if (!TestWriteAccess(ActiveSettings::GetConfigPath())) + wxMessageBox(_("Cemu can't write to its directory.\nPlease move it to a different location or run Cemu as administrator!"), _("Warning"), wxOK | wxCENTRE | wxICON_EXCLAMATION, nullptr); + + auto& config = GetConfig(); +@@ -183,7 +183,7 @@ int CemuApp::FilterEvent(wxEvent& event) + + std::vector<const wxLanguageInfo*> CemuApp::GetAvailableLanguages() + { +- const auto path = ActiveSettings::GetPath("resources"); ++ const auto path = ActiveSettings::GetSystemDataPath("resources"); + if (!exists(path)) + return {}; + +@@ -308,11 +308,15 @@ void CemuApp::CreateDefaultFiles(bool first_start) + // cemu directories + try + { +- const auto controllerProfileFolder = GetCemuPath(L"controllerProfiles").ToStdWstring(); ++ const auto controllerProfileFolder = ActiveSettings::GetConfigPath(L"controllerProfiles").generic_wstring(); + if (!fs::exists(controllerProfileFolder)) + fs::create_directories(controllerProfileFolder); + +- const auto memorySearcherFolder = GetCemuPath(L"memorySearcher").ToStdWstring(); ++ const auto gameProfileFolder = ActiveSettings::GetConfigPath(L"gameProfiles").generic_wstring(); ++ if (!fs::exists(gameProfileFolder)) ++ fs::create_directories(gameProfileFolder); ++ ++ const auto memorySearcherFolder = ActiveSettings::GetConfigPath(L"memorySearcher").generic_wstring(); + if (!fs::exists(memorySearcherFolder)) + fs::create_directories(memorySearcherFolder); + } +@@ -398,5 +402,3 @@ void CemuApp::ActivateApp(wxActivateEvent& event) + g_window_info.app_active = event.GetActive(); + event.Skip(); + } +- +- +diff --git a/src/gui/ChecksumTool.cpp b/src/gui/ChecksumTool.cpp +index 74422c9..9787ffd 100644 +--- a/src/gui/ChecksumTool.cpp ++++ b/src/gui/ChecksumTool.cpp +@@ -133,7 +133,7 @@ ChecksumTool::ChecksumTool(wxWindow* parent, wxTitleManagerList::TitleEntry& ent + const auto title_id_str = fmt::format("{:016x}", m_json_entry.title_id); + const auto default_file = fmt::format("{}_v{}.json", title_id_str, m_info.GetAppTitleVersion()); + +- const auto checksum_path = ActiveSettings::GetPath("resources/checksums/{}", default_file); ++ const auto checksum_path = ActiveSettings::GetDataPath("resources/checksums/{}", default_file); + if (exists(checksum_path)) + m_verify_online->Enable(); + } +@@ -185,7 +185,7 @@ void ChecksumTool::LoadOnlineData() const + + std::string latest_commit; + +- const auto checksum_path = ActiveSettings::GetPath("resources/checksums"); ++ const auto checksum_path = ActiveSettings::GetDataPath("resources/checksums"); + if (exists(checksum_path)) + { + std::string current_commit; +@@ -593,7 +593,7 @@ void ChecksumTool::OnVerifyOnline(wxCommandEvent& event) + const auto title_id_str = fmt::format("{:016x}", m_json_entry.title_id); + const auto default_file = fmt::format("{}_v{}.json", title_id_str, m_info.GetAppTitleVersion()); + +- const auto checksum_path = ActiveSettings::GetPath("resources/checksums/{}", default_file); ++ const auto checksum_path = ActiveSettings::GetDataPath("resources/checksums/{}", default_file); + if(!exists(checksum_path)) + return; + +diff --git a/src/gui/DownloadGraphicPacksWindow.cpp b/src/gui/DownloadGraphicPacksWindow.cpp +index 28e5bf6..6811b99 100644 +--- a/src/gui/DownloadGraphicPacksWindow.cpp ++++ b/src/gui/DownloadGraphicPacksWindow.cpp +@@ -65,7 +65,7 @@ bool DownloadGraphicPacksWindow::curlDownloadFile(const char *url, curlDownloadF + bool checkGraphicPackDownloadedVersion(const char* nameVersion, bool& hasVersionFile) + { + hasVersionFile = false; +- const auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks/version.txt"); ++ const auto path = ActiveSettings::GetDataPath("graphicPacks/downloadedGraphicPacks/version.txt"); + std::unique_ptr<FileStream> file(FileStream::openFile2(path)); + + std::string versionInFile; +@@ -78,7 +78,7 @@ bool checkGraphicPackDownloadedVersion(const char* nameVersion, bool& hasVersion + + void createGraphicPackDownloadedVersionFile(const char* nameVersion) + { +- const auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks/version.txt"); ++ const auto path = ActiveSettings::GetDataPath("graphicPacks/downloadedGraphicPacks/version.txt"); + std::unique_ptr<FileStream> file(FileStream::createFile2(path)); + if (file) + file->writeString(nameVersion); +@@ -90,7 +90,7 @@ void createGraphicPackDownloadedVersionFile(const char* nameVersion) + + void deleteDownloadedGraphicPacks() + { +- const auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks"); ++ const auto path = ActiveSettings::GetDataPath("graphicPacks/downloadedGraphicPacks"); + std::error_code er; + if (!fs::exists(path, er)) + return; +@@ -238,7 +238,7 @@ void DownloadGraphicPacksWindow::UpdateThread() + return; + } + +- auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks"); ++ auto path = ActiveSettings::GetDataPath("graphicPacks/downloadedGraphicPacks"); + std::error_code er; + //fs::remove_all(path, er); -> Don't delete the whole folder and recreate it immediately afterwards because sometimes it just fails + deleteDownloadedGraphicPacks(); +@@ -258,7 +258,7 @@ void DownloadGraphicPacksWindow::UpdateThread() + std::strstr(sb.name, "..\\") != nullptr) + continue; // bad path + +- path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks/{}", sb.name); ++ path = ActiveSettings::GetDataPath("graphicPacks/downloadedGraphicPacks/{}", sb.name); + + size_t sbNameLen = strlen(sb.name); + if(sbNameLen == 0) +diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp +index b23a5ca..032d0af 100644 +--- a/src/gui/MainWindow.cpp ++++ b/src/gui/MainWindow.cpp +@@ -997,7 +997,7 @@ void MainWindow::OnDebugSetting(wxCommandEvent& event) + { + try + { +- const auto path = CemuApp::GetCemuPath(L"dump\\curl").ToStdWstring(); ++ const auto path = ActiveSettings::GetDataPath(L"dump/curl").generic_wstring(); + fs::create_directories(path); + } + catch (const std::exception& ex) +@@ -1054,8 +1054,8 @@ void MainWindow::OnDebugDumpUsedTextures(wxCommandEvent& event) + try + { + // create directory +- const auto path = CemuApp::GetCemuPath(L"dump\\textures"); +- fs::create_directories(path.ToStdWstring()); ++ const auto path = ActiveSettings::GetDataPath(L"dump/textures"); ++ fs::create_directories(path.generic_wstring()); + } + catch (const std::exception& ex) + { +@@ -1075,8 +1075,8 @@ void MainWindow::OnDebugDumpUsedShaders(wxCommandEvent& event) + try + { + // create directory +- const auto path = CemuApp::GetCemuPath(L"dump\\shaders"); +- fs::create_directories(path.ToStdWstring()); ++ const auto path = ActiveSettings::GetDataPath(L"dump/shaders"); ++ fs::create_directories(path.generic_wstring()); + } + catch (const std::exception & ex) + { +diff --git a/src/gui/MemorySearcherTool.cpp b/src/gui/MemorySearcherTool.cpp +index c7c6c73..3ecfff5 100644 +--- a/src/gui/MemorySearcherTool.cpp ++++ b/src/gui/MemorySearcherTool.cpp +@@ -270,7 +270,7 @@ void MemorySearcherTool::OnFilter(wxCommandEvent& event) + + void MemorySearcherTool::Load() + { +- const auto memorySearcherPath = ActiveSettings::GetPath("memorySearcher/{:016x}.ini", CafeSystem::GetForegroundTitleId()); ++ const auto memorySearcherPath = ActiveSettings::GetConfigPath("memorySearcher/{:016x}.ini", CafeSystem::GetForegroundTitleId()); + auto memSearcherIniContents = FileStream::LoadIntoMemory(memorySearcherPath); + if (!memSearcherIniContents) + return; +@@ -322,7 +322,7 @@ void MemorySearcherTool::Load() + + void MemorySearcherTool::Save() + { +- const auto memorySearcherPath = ActiveSettings::GetPath("memorySearcher/{:016x}.ini", CafeSystem::GetForegroundTitleId()); ++ const auto memorySearcherPath = ActiveSettings::GetConfigPath("memorySearcher/{:016x}.ini", CafeSystem::GetForegroundTitleId()); + FileStream* fs = FileStream::createFile2(memorySearcherPath); + if (fs) + { +diff --git a/src/gui/debugger/DebuggerWindow2.cpp b/src/gui/debugger/DebuggerWindow2.cpp +index cca9bfb..e31031d 100644 +--- a/src/gui/debugger/DebuggerWindow2.cpp ++++ b/src/gui/debugger/DebuggerWindow2.cpp +@@ -272,7 +272,7 @@ DebuggerWindow2::DebuggerWindow2(wxFrame& parent, const wxRect& display_size) + { + this->wxWindowBase::SetBackgroundColour(*wxWHITE); + +- const auto file = ActiveSettings::GetPath("debugger/config.xml"); ++ const auto file = ActiveSettings::GetConfigPath("debugger/config.xml"); + m_config.SetFilename(file.generic_wstring()); + m_config.Load(); + +@@ -472,7 +472,7 @@ bool DebuggerWindow2::Show(bool show) + std::wstring DebuggerWindow2::GetModuleStoragePath(std::string module_name, uint32_t crc_hash) const + { + if (module_name.empty() || crc_hash == 0) return std::wstring(); +- return ActiveSettings::GetPath("debugger/{}_{:#10x}.xml", module_name, crc_hash).generic_wstring(); ++ return ActiveSettings::GetConfigPath("debugger/{}_{:#10x}.xml", module_name, crc_hash).generic_wstring(); + } + + void DebuggerWindow2::OnBreakpointHit(wxCommandEvent& event) +diff --git a/src/gui/input/InputSettings2.cpp b/src/gui/input/InputSettings2.cpp +index 5793cbd..e48d2a2 100644 +--- a/src/gui/input/InputSettings2.cpp ++++ b/src/gui/input/InputSettings2.cpp +@@ -669,10 +669,10 @@ void InputSettings2::on_profile_delete(wxCommandEvent& event) + } + try + { +- const fs::path old_path = ActiveSettings::GetPath(fmt::format("controllerProfiles/{}.txt", selection)); ++ const fs::path old_path = ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/{}.txt", selection)); + fs::remove(old_path); + +- const fs::path path = ActiveSettings::GetPath(fmt::format("controllerProfiles/{}.xml", selection)); ++ const fs::path path = ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/{}.xml", selection)); + fs::remove(path); + + profile_names->ChangeValue(kDefaultProfileName); +diff --git a/src/input/InputManager.cpp b/src/input/InputManager.cpp +index 4ae43ce..852c918 100644 +--- a/src/input/InputManager.cpp ++++ b/src/input/InputManager.cpp +@@ -76,9 +76,9 @@ bool InputManager::load(size_t player_index, std::string_view filename) + { + fs::path file_path; + if (filename.empty()) +- file_path = ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}", player_index)); ++ file_path = ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/controller{}", player_index)); + else +- file_path = ActiveSettings::GetPath(fmt::format("controllerProfiles/{}", filename)); ++ file_path = ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/{}", filename)); + + auto old_file = file_path; + old_file.replace_extension(".txt"); // test .txt extension +@@ -448,7 +448,7 @@ bool InputManager::save(size_t player_index, std::string_view filename) + if (!emulated_controller) + return false; + +- fs::path file_path = ActiveSettings::GetPath("controllerProfiles"); ++ fs::path file_path = ActiveSettings::GetConfigPath("controllerProfiles"); + fs::create_directories(file_path); + + const auto is_default_file = filename.empty(); +@@ -664,8 +664,8 @@ EmulatedControllerPtr InputManager::delete_controller(size_t player_index, bool + if(delete_profile) + { + std::error_code ec{}; +- fs::remove(ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}.xml", player_index)), ec); +- fs::remove(ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}.txt", player_index)), ec); ++ fs::remove(ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/controller{}.xml", player_index)), ec); ++ fs::remove(ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/controller{}.txt", player_index)), ec); + } + + return result; +@@ -680,8 +680,8 @@ EmulatedControllerPtr InputManager::delete_controller(size_t player_index, bool + controller = {}; + + std::error_code ec{}; +- fs::remove(ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}.xml", player_index)), ec); +- fs::remove(ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}.txt", player_index)), ec); ++ fs::remove(ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/controller{}.xml", player_index)), ec); ++ fs::remove(ActiveSettings::GetConfigPath(fmt::format("controllerProfiles/controller{}.txt", player_index)), ec); + + return result; + } +@@ -782,7 +782,7 @@ void InputManager::apply_game_profile() + + std::vector<std::string> InputManager::get_profiles() + { +- const auto path = ActiveSettings::GetPath("controllerProfiles"); ++ const auto path = ActiveSettings::GetConfigPath("controllerProfiles"); + if (!exists(path)) + return {}; + +diff --git a/src/main.cpp b/src/main.cpp +index f94b276..fb8baec 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -160,7 +160,7 @@ void _putenvSafe(const char* c) + void reconfigureGLDrivers() + { + // reconfigure GL drivers to store +- const fs::path nvCacheDir = ActiveSettings::GetPath("shaderCache/driver/nvidia/"); ++ const fs::path nvCacheDir = ActiveSettings::GetCachePath("shaderCache/driver/nvidia/"); + + std::error_code err; + fs::create_directories(nvCacheDir, err); +@@ -242,7 +242,7 @@ void unitTests() + + int mainEmulatorHLE() + { +- if (!TestWriteAccess(ActiveSettings::GetPath())) ++ if (!TestWriteAccess(ActiveSettings::GetConfigPath())) + wxMessageBox("Cemu doesn't have write access to it's own directory.\nPlease move it to a different location or run Cemu as administrator!", "Warning", wxOK|wxICON_ERROR); // todo - different error messages per OS + LatteOverlay_init(); + // run a couple of tests if in non-release mode +@@ -264,7 +264,7 @@ int mainEmulatorHLE() + // init Cafe system (todo - the stuff above should be part of this too) + CafeSystem::Initialize(); + // init title list +- CafeTitleList::Initialize(ActiveSettings::GetPath("title_list_cache.xml")); ++ CafeTitleList::Initialize(ActiveSettings::GetCachePath("title_list_cache.xml")); + for (auto& it : GetConfig().game_paths) + CafeTitleList::AddScanPath(it); + fs::path mlcPath = ActiveSettings::GetMlcPath(); +diff --git a/src/util/libusbWrapper/libusbWrapper.cpp b/src/util/libusbWrapper/libusbWrapper.cpp +index e1d7298..6e498c8 100644 +--- a/src/util/libusbWrapper/libusbWrapper.cpp ++++ b/src/util/libusbWrapper/libusbWrapper.cpp +@@ -18,7 +18,7 @@ void libusbWrapper::init() + m_module = LoadLibraryW(L"libusb-1.0.dll"); + if (!m_module) + { +- const auto path = ActiveSettings::GetPath("resources/libusb-1.0.dll"); ++ const auto path = ActiveSettings::GetSystemDataPath("resources/libusb-1.0.dll"); + m_module = LoadLibraryW(path.generic_wstring().c_str()); + if (!m_module) + { |