mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-06-11 16:49:28 +02:00
VideoCommon: add logic to read a GraphicsMod from configuration
This commit is contained in:
291
Source/Core/VideoCommon/GraphicsModSystem/Config/GraphicsMod.cpp
Normal file
291
Source/Core/VideoCommon/GraphicsModSystem/Config/GraphicsMod.cpp
Normal file
@ -0,0 +1,291 @@
|
||||
// Copyright 2022 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "VideoCommon/GraphicsModSystem/Config/GraphicsMod.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "VideoCommon/GraphicsModSystem/Constants.h"
|
||||
|
||||
std::optional<GraphicsModConfig> GraphicsModConfig::Create(const std::string& file_path,
|
||||
Source source)
|
||||
{
|
||||
std::string json_data;
|
||||
if (!File::ReadFileToString(file_path, json_data))
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO, "Failed to load graphics mod json file '{}'", file_path);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
picojson::value root;
|
||||
const auto error = picojson::parse(root, json_data);
|
||||
|
||||
if (!error.empty())
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO, "Failed to load graphics mod json file '{}' due to parse error: {}",
|
||||
file_path, error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
GraphicsModConfig result;
|
||||
if (!result.DeserializeFromConfig(root))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
result.m_source = source;
|
||||
if (source == Source::User)
|
||||
{
|
||||
const std::string base_path = File::GetUserPath(D_GRAPHICSMOD_IDX);
|
||||
if (base_path.size() > file_path.size())
|
||||
{
|
||||
ERROR_LOG_FMT(
|
||||
VIDEO,
|
||||
"Failed to load graphics mod json file '{}' due to it not matching the base path: {}",
|
||||
file_path, base_path);
|
||||
return std::nullopt;
|
||||
}
|
||||
result.m_relative_path = file_path.substr(base_path.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string base_path = File::GetSysDirectory() + DOLPHIN_SYSTEM_GRAPHICS_MOD_DIR;
|
||||
if (base_path.size() > file_path.size())
|
||||
{
|
||||
ERROR_LOG_FMT(
|
||||
VIDEO,
|
||||
"Failed to load graphics mod json file '{}' due to it not matching the base path: {}",
|
||||
file_path, base_path);
|
||||
return std::nullopt;
|
||||
}
|
||||
result.m_relative_path = file_path.substr(base_path.size());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<GraphicsModConfig> GraphicsModConfig::Create(const picojson::object* obj)
|
||||
{
|
||||
if (!obj)
|
||||
return std::nullopt;
|
||||
|
||||
const auto source_it = obj->find("source");
|
||||
if (source_it == obj->end())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
const std::string source_str = source_it->second.to_str();
|
||||
|
||||
const auto path_it = obj->find("path");
|
||||
if (path_it == obj->end())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
const std::string relative_path = path_it->second.to_str();
|
||||
|
||||
if (source_str == "system")
|
||||
{
|
||||
return Create(fmt::format("{}{}{}", File::GetSysDirectory(), DOLPHIN_SYSTEM_GRAPHICS_MOD_DIR,
|
||||
relative_path),
|
||||
Source::System);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Create(File::GetUserPath(D_GRAPHICSMOD_IDX) + relative_path, Source::User);
|
||||
}
|
||||
}
|
||||
|
||||
std::string GraphicsModConfig::GetAbsolutePath() const
|
||||
{
|
||||
if (m_source == Source::System)
|
||||
{
|
||||
return WithUnifiedPathSeparators(fmt::format("{}{}{}", File::GetSysDirectory(),
|
||||
DOLPHIN_SYSTEM_GRAPHICS_MOD_DIR, m_relative_path));
|
||||
}
|
||||
else
|
||||
{
|
||||
return WithUnifiedPathSeparators(File::GetUserPath(D_GRAPHICSMOD_IDX) + m_relative_path);
|
||||
}
|
||||
}
|
||||
|
||||
bool GraphicsModConfig::DeserializeFromConfig(const picojson::value& value)
|
||||
{
|
||||
const auto& meta = value.get("meta");
|
||||
if (meta.is<picojson::object>())
|
||||
{
|
||||
const auto& title = meta.get("title");
|
||||
if (title.is<std::string>())
|
||||
{
|
||||
m_title = title.to_str();
|
||||
}
|
||||
|
||||
const auto& author = meta.get("author");
|
||||
if (author.is<std::string>())
|
||||
{
|
||||
m_author = author.to_str();
|
||||
}
|
||||
|
||||
const auto& description = meta.get("description");
|
||||
if (description.is<std::string>())
|
||||
{
|
||||
m_description = description.to_str();
|
||||
}
|
||||
}
|
||||
|
||||
const auto& groups = value.get("groups");
|
||||
if (groups.is<picojson::array>())
|
||||
{
|
||||
for (const auto& group_val : groups.get<picojson::array>())
|
||||
{
|
||||
if (!group_val.is<picojson::object>())
|
||||
{
|
||||
ERROR_LOG_FMT(
|
||||
VIDEO, "Failed to load mod configuration file, specified group is not a json object");
|
||||
return false;
|
||||
}
|
||||
GraphicsTargetGroupConfig group;
|
||||
if (!group.DeserializeFromConfig(group_val.get<picojson::object>()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_groups.push_back(group);
|
||||
}
|
||||
}
|
||||
|
||||
const auto& features = value.get("features");
|
||||
if (features.is<picojson::array>())
|
||||
{
|
||||
for (const auto& feature_val : features.get<picojson::array>())
|
||||
{
|
||||
if (!feature_val.is<picojson::object>())
|
||||
{
|
||||
ERROR_LOG_FMT(
|
||||
VIDEO, "Failed to load mod configuration file, specified feature is not a json object");
|
||||
return false;
|
||||
}
|
||||
GraphicsModFeatureConfig feature;
|
||||
if (!feature.DeserializeFromConfig(feature_val.get<picojson::object>()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_features.push_back(feature);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GraphicsModConfig::SerializeToProfile(picojson::object* obj) const
|
||||
{
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
auto& json_obj = *obj;
|
||||
switch (m_source)
|
||||
{
|
||||
case Source::User:
|
||||
{
|
||||
json_obj["source"] = picojson::value{"user"};
|
||||
}
|
||||
break;
|
||||
case Source::System:
|
||||
{
|
||||
json_obj["source"] = picojson::value{"system"};
|
||||
}
|
||||
break;
|
||||
};
|
||||
|
||||
json_obj["path"] = picojson::value{m_relative_path};
|
||||
|
||||
picojson::array serialized_groups;
|
||||
for (const auto& group : m_groups)
|
||||
{
|
||||
picojson::object serialized_group;
|
||||
group.SerializeToProfile(&serialized_group);
|
||||
serialized_groups.push_back(picojson::value{serialized_group});
|
||||
}
|
||||
json_obj["groups"] = picojson::value{serialized_groups};
|
||||
|
||||
picojson::array serialized_features;
|
||||
for (const auto& feature : m_features)
|
||||
{
|
||||
picojson::object serialized_feature;
|
||||
feature.SerializeToProfile(&serialized_feature);
|
||||
serialized_features.push_back(picojson::value{serialized_feature});
|
||||
}
|
||||
json_obj["features"] = picojson::value{serialized_features};
|
||||
|
||||
json_obj["enabled"] = picojson::value{m_enabled};
|
||||
|
||||
json_obj["weight"] = picojson::value{static_cast<double>(m_weight)};
|
||||
}
|
||||
|
||||
void GraphicsModConfig::DeserializeFromProfile(const picojson::object& obj)
|
||||
{
|
||||
if (const auto it = obj.find("groups"); it != obj.end())
|
||||
{
|
||||
if (it->second.is<picojson::array>())
|
||||
{
|
||||
auto serialized_groups = it->second.get<picojson::array>();
|
||||
if (serialized_groups.size() != m_groups.size())
|
||||
return;
|
||||
|
||||
for (std::size_t i = 0; i < serialized_groups.size(); i++)
|
||||
{
|
||||
const auto& serialized_group_val = serialized_groups[i];
|
||||
if (serialized_group_val.is<picojson::object>())
|
||||
{
|
||||
const auto& serialized_group = serialized_group_val.get<picojson::object>();
|
||||
m_groups[i].DeserializeFromProfile(serialized_group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto it = obj.find("features"); it != obj.end())
|
||||
{
|
||||
if (it->second.is<picojson::array>())
|
||||
{
|
||||
auto serialized_features = it->second.get<picojson::array>();
|
||||
if (serialized_features.size() != m_features.size())
|
||||
return;
|
||||
|
||||
for (std::size_t i = 0; i < serialized_features.size(); i++)
|
||||
{
|
||||
const auto& serialized_feature_val = serialized_features[i];
|
||||
if (serialized_feature_val.is<picojson::object>())
|
||||
{
|
||||
const auto& serialized_feature = serialized_feature_val.get<picojson::object>();
|
||||
m_features[i].DeserializeFromProfile(serialized_feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto it = obj.find("enabled"); it != obj.end())
|
||||
{
|
||||
if (it->second.is<bool>())
|
||||
{
|
||||
m_enabled = it->second.get<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto it = obj.find("weight"); it != obj.end())
|
||||
{
|
||||
if (it->second.is<double>())
|
||||
{
|
||||
m_weight = static_cast<u16>(it->second.get<double>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GraphicsModConfig::operator<(const GraphicsModConfig& other) const
|
||||
{
|
||||
return m_weight < other.m_weight;
|
||||
}
|
Reference in New Issue
Block a user