// Copyright 2022 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "VideoCommon/GraphicsModSystem/Config/GraphicsModGroup.h" #include #include #include #include "Common/CommonPaths.h" #include "Common/FileSearch.h" #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Core/ConfigManager.h" #include "VideoCommon/GraphicsModSystem/Config/GraphicsMod.h" #include "VideoCommon/GraphicsModSystem/Constants.h" #include "VideoCommon/HiresTextures.h" GraphicsModGroupConfig::GraphicsModGroupConfig(const std::string& game_id) : m_game_id(game_id) { } GraphicsModGroupConfig::~GraphicsModGroupConfig() = default; GraphicsModGroupConfig::GraphicsModGroupConfig(const GraphicsModGroupConfig&) = default; GraphicsModGroupConfig::GraphicsModGroupConfig(GraphicsModGroupConfig&&) = default; GraphicsModGroupConfig& GraphicsModGroupConfig::operator=(const GraphicsModGroupConfig&) = default; GraphicsModGroupConfig& GraphicsModGroupConfig::operator=(GraphicsModGroupConfig&&) = default; void GraphicsModGroupConfig::Load() { const std::string file_path = GetPath(); std::set known_paths; if (File::Exists(file_path)) { std::string json_data; if (!File::ReadFileToString(file_path, json_data)) { ERROR_LOG_FMT(VIDEO, "Failed to load graphics mod group json file '{}'", file_path); return; } picojson::value root; const auto error = picojson::parse(root, json_data); if (!error.empty()) { ERROR_LOG_FMT(VIDEO, "Failed to load graphics mod group json file '{}' due to parse error: {}", file_path, error); return; } if (!root.is()) { ERROR_LOG_FMT( VIDEO, "Failed to load graphics mod group json file '{}' due to root not being an object!", file_path); return; } const auto& mods = root.get("mods"); if (mods.is()) { for (const auto& mod_json : mods.get()) { if (mod_json.is()) { const auto& mod_json_obj = mod_json.get(); auto graphics_mod = GraphicsModConfig::Create(&mod_json_obj); if (!graphics_mod) { continue; } graphics_mod->DeserializeFromProfile(mod_json_obj); auto mod_full_path = graphics_mod->GetAbsolutePath(); known_paths.insert(std::move(mod_full_path)); m_graphics_mods.push_back(*graphics_mod); } } } } const auto try_add_mod = [&known_paths, this](const std::string& dir, GraphicsModConfig::Source source) { auto file = dir + DIR_SEP + "metadata.json"; UnifyPathSeparators(file); if (known_paths.find(file) != known_paths.end()) { return; } const auto mod = GraphicsModConfig::Create(file, source); if (mod) { m_graphics_mods.push_back(*mod); } }; const std::set graphics_mod_user_directories = GetTextureDirectoriesWithGameId(File::GetUserPath(D_GRAPHICSMOD_IDX), m_game_id); for (const auto& graphics_mod_directory : graphics_mod_user_directories) { try_add_mod(graphics_mod_directory, GraphicsModConfig::Source::User); } const std::set graphics_mod_system_directories = GetTextureDirectoriesWithGameId( File::GetSysDirectory() + DOLPHIN_SYSTEM_GRAPHICS_MOD_DIR, m_game_id); for (const auto& graphics_mod_directory : graphics_mod_system_directories) { try_add_mod(graphics_mod_directory, GraphicsModConfig::Source::System); } std::sort(m_graphics_mods.begin(), m_graphics_mods.end()); for (auto& mod : m_graphics_mods) { m_path_to_graphics_mod[mod.GetAbsolutePath()] = &mod; } m_change_count++; } void GraphicsModGroupConfig::Save() const { const std::string file_path = GetPath(); std::ofstream json_stream; File::OpenFStream(json_stream, file_path, std::ios_base::out); if (!json_stream.is_open()) { ERROR_LOG_FMT(VIDEO, "Failed to open graphics mod group json file '{}' for writing", file_path); return; } picojson::object serialized_root; picojson::array serialized_mods; for (const auto& mod : m_graphics_mods) { picojson::object serialized_mod; mod.SerializeToProfile(&serialized_mod); serialized_mods.push_back(picojson::value{serialized_mod}); } serialized_root["mods"] = picojson::value{serialized_mods}; const auto output = picojson::value{serialized_root}.serialize(true); json_stream << output; } void GraphicsModGroupConfig::SetChangeCount(u32 change_count) { m_change_count = change_count; } u32 GraphicsModGroupConfig::GetChangeCount() const { return m_change_count; } const std::vector& GraphicsModGroupConfig::GetMods() const { return m_graphics_mods; } std::vector& GraphicsModGroupConfig::GetMods() { return m_graphics_mods; } GraphicsModConfig* GraphicsModGroupConfig::GetMod(const std::string& absolute_path) const { if (const auto iter = m_path_to_graphics_mod.find(absolute_path); iter != m_path_to_graphics_mod.end()) { return iter->second; } return nullptr; } const std::string& GraphicsModGroupConfig::GetGameID() const { return m_game_id; } std::string GraphicsModGroupConfig::GetPath() const { const std::string game_mod_root = File::GetUserPath(D_CONFIG_IDX) + GRAPHICSMOD_CONFIG_DIR; return fmt::format("{}/{}.json", game_mod_root, m_game_id); }