Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patches: Virtual move/remove/create game files patches #13483

Merged
merged 1 commit into from
Mar 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 53 additions & 4 deletions Utilities/bin_patch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "version.h"
#include "Emu/Memory/vm.h"
#include "Emu/System.h"
#include "Emu/VFS.h"

#include "util/types.hpp"
#include "util/endian.hpp"
Expand Down Expand Up @@ -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::lef64: return "lef64";
case patch_type::utf8: return "utf8";
case patch_type::move_file: return "move_file";
case patch_type::hide_file: return "hide_file";
}

return unknown;
Expand Down Expand Up @@ -682,16 +685,17 @@ bool patch_engine::add_patch_data(YAML::Node node, patch_info& info, u32 modifie
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);
return false;
}

struct patch_data p_data{};
p_data.type = type;
p_data.offset = addr_node.as<u32>(0) + modifier;
p_data.original_value = value_node.Scalar();
p_data.type = type;
p_data.offset = addr_node.as<u32>(0) + modifier;
p_data.original_offset = addr_node.Scalar();
p_data.original_value = value_node.Scalar();

const bool is_config_value = info.default_config_values.contains(p_data.original_value);
const patch_config_value config_value = is_config_value ? ::at32(info.default_config_values, p_data.original_value) : patch_config_value{};
Expand Down Expand Up @@ -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());
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
Expand Down
8 changes: 8 additions & 0 deletions Utilities/bin_patch.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,15 @@ enum class patch_type
bef32,
bef64,
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
{
double_range,
Expand All @@ -69,6 +76,7 @@ class patch_engine
{
patch_type type = patch_type::load;
u32 offset = 0;
std::string original_offset{}; // Used for specifying paths
std::string original_value{}; // Used for import consistency (avoid rounding etc.)
union
{
Expand Down