Patches: Virtual move/remove game files patches

This commit is contained in:
Eladash 2023-03-03 15:43:46 +02:00 committed by Megamouse
parent 1d7a00666e
commit 382a7c94a2
2 changed files with 61 additions and 4 deletions

View File

@ -4,6 +4,7 @@
#include "version.h" #include "version.h"
#include "Emu/Memory/vm.h" #include "Emu/Memory/vm.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/VFS.h"
#include "util/types.hpp" #include "util/types.hpp"
#include "util/endian.hpp" #include "util/endian.hpp"
@ -76,6 +77,8 @@ void fmt_class_string<patch_type>::format(std::string& out, u64 arg)
case patch_type::lef32: return "lef32"; case patch_type::lef32: return "lef32";
case patch_type::lef64: return "lef64"; case patch_type::lef64: return "lef64";
case patch_type::utf8: return "utf8"; case patch_type::utf8: return "utf8";
case patch_type::move_file: return "move_file";
case patch_type::hide_file: return "hide_file";
} }
return unknown; return unknown;
@ -682,7 +685,7 @@ bool patch_engine::add_patch_data(YAML::Node node, patch_info& info, u32 modifie
return false; return false;
} }
if (!addr_node.Scalar().starts_with("0x")) if (patch_type_uses_hex_offset(type) && !addr_node.Scalar().starts_with("0x"))
{ {
append_log_message(log_messages, fmt::format("Skipping patch node %s. Address element has wrong format %s. (key: %s, location: %s)", info.description, addr_node.Scalar(), info.hash, get_yaml_node_location(node)), &patch_log.error); append_log_message(log_messages, fmt::format("Skipping patch node %s. Address element has wrong format %s. (key: %s, location: %s)", info.description, addr_node.Scalar(), info.hash, get_yaml_node_location(node)), &patch_log.error);
return false; return false;
@ -691,6 +694,7 @@ bool patch_engine::add_patch_data(YAML::Node node, patch_info& info, u32 modifie
struct patch_data p_data{}; struct patch_data p_data{};
p_data.type = type; p_data.type = type;
p_data.offset = addr_node.as<u32>(0) + modifier; p_data.offset = addr_node.as<u32>(0) + modifier;
p_data.original_offset = addr_node.Scalar();
p_data.original_value = value_node.Scalar(); p_data.original_value = value_node.Scalar();
const bool is_config_value = info.default_config_values.contains(p_data.original_value); const bool is_config_value = info.default_config_values.contains(p_data.original_value);
@ -1191,6 +1195,51 @@ static usz apply_modification(std::basic_string<u32>& applied, patch_engine::pat
std::memcpy(ptr, p.original_value.data(), p.original_value.size()); std::memcpy(ptr, p.original_value.data(), p.original_value.size());
break; break;
} }
case patch_type::move_file:
case patch_type::hide_file:
{
const bool is_hide = p.type == patch_type::hide_file;
std::string original_vfs_path = p.original_offset;
std::string dest_vfs_path = p.original_value;
if (original_vfs_path.empty())
{
patch_log.error("Failed to patch file: original path is empty", original_vfs_path);
continue;
}
if (!is_hide && dest_vfs_path.empty())
{
patch_log.error("Failed to patch file: destination path is empty", dest_vfs_path);
continue;
}
if (!original_vfs_path.starts_with("/dev_"))
{
original_vfs_path.insert(0, "/dev_");
}
if (!is_hide && !dest_vfs_path.starts_with("/dev_"))
{
dest_vfs_path.insert(0, "/dev_");
}
const std::string dest_path = is_hide ? fs::get_config_dir() + "delete_this_dir.../delete_this..." : vfs::get(dest_vfs_path);
if (dest_path.empty())
{
patch_log.error("Failed to patch file path at '%s': destination is not mounted", original_vfs_path, dest_vfs_path);
continue;
}
if (!vfs::mount(original_vfs_path, dest_path))
{
patch_log.error("Failed to patch file path at '%s': vfs::mount(dest='%s') failed", original_vfs_path, dest_vfs_path);
continue;
}
break;
}
} }
// Possibly an executable instruction // Possibly an executable instruction

View File

@ -52,8 +52,15 @@ enum class patch_type
bef32, bef32,
bef64, bef64,
utf8, // Text of string (not null-terminated automatically) utf8, // Text of string (not null-terminated automatically)
move_file, // Move file
hide_file, // Hide file
}; };
static constexpr bool patch_type_uses_hex_offset(patch_type type)
{
return type >= patch_type::alloc && type <= patch_type::utf8;
}
enum class patch_configurable_type enum class patch_configurable_type
{ {
double_range, double_range,
@ -69,6 +76,7 @@ public:
{ {
patch_type type = patch_type::load; patch_type type = patch_type::load;
u32 offset = 0; u32 offset = 0;
std::string original_offset{}; // Used for specifying paths
std::string original_value{}; // Used for import consistency (avoid rounding etc.) std::string original_value{}; // Used for import consistency (avoid rounding etc.)
union union
{ {