diff --git a/CMakeLists.txt b/CMakeLists.txt index e9f7458..9135c62 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> 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 ebf425b..7ad99e4 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& 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 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/Common/ExceptionHandler/ExceptionHandler_win32.cpp b/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp index 25dca26..9f38cdd 100644 --- a/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp +++ b/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp @@ -61,7 +61,7 @@ bool CreateMiniDump(CrashDump dump, EXCEPTION_POINTERS* pep) if (dump == CrashDump::Disabled) return true; - fs::path p = ActiveSettings::GetPath("crashdump"); + fs::path p = ActiveSettings::GetDataPath("crashdump"); std::error_code ec; fs::create_directories(p, ec); @@ -356,11 +356,11 @@ void createCrashlog(EXCEPTION_POINTERS* e, PCONTEXT context) const auto temp_time = std::chrono::system_clock::to_time_t(now); const auto& time = *std::gmtime(&temp_time); - fs::path p = ActiveSettings::GetPath("crashdump"); + fs::path p = ActiveSettings::GetDataPath("crashdump"); p /= fmt::format("log_{:04d}{:02d}{:02d}_{:02d}{:02d}{:02d}.txt", 1900 + time.tm_year, time.tm_mon + 1, time.tm_mday, time.tm_year, time.tm_hour, time.tm_min, time.tm_sec); std::error_code ec; - fs::copy_file(ActiveSettings::GetPath("log.txt"), p, ec); + fs::copy_file(ActiveSettings::GetDataPath("log.txt"), p, ec); } exit(0); 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 95ceae1..c47ebeb 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(fmt::runtime(format), std::forward(args)...); } + template + [[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(fmt::runtime(format), std::forward(args)...); + } + + template + [[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(fmt::runtime(format), std::forward(args)...); + } + + template + [[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(fmt::runtime(format), std::forward(args)...); + } + + template + [[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(fmt::runtime(format), std::forward(args)...); + } + + template + [[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(fmt::runtime(format), std::forward(args)...); + } + + template + [[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(fmt::runtime(format), std::forward(args)...); + } + + template + [[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(fmt::runtime(format), std::forward(args)...); + } + + template + [[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(fmt::runtime(format), std::forward(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 e78b30b..b1a72b0 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 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); } @@ -399,4 +403,3 @@ void CemuApp::ActivateApp(wxActivateEvent& event) 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 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 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 8f26f81..2fb052e 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 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) {