2020-12-25 02:18:36 +00:00
|
|
|
#pragma once
|
2017-03-28 23:54:05 +00:00
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <string>
|
|
|
|
#include <unordered_map>
|
2023-06-25 12:53:42 +00:00
|
|
|
#include <functional>
|
2017-03-28 23:54:05 +00:00
|
|
|
|
2020-12-13 13:34:45 +00:00
|
|
|
#include "util/types.hpp"
|
2020-06-02 08:39:24 +00:00
|
|
|
#include "util/yaml.hpp"
|
|
|
|
|
2020-06-27 08:32:00 +00:00
|
|
|
namespace patch_key
|
|
|
|
{
|
|
|
|
static const std::string all = "All";
|
2020-06-29 22:16:24 +00:00
|
|
|
static const std::string anchors = "Anchors";
|
|
|
|
static const std::string author = "Author";
|
|
|
|
static const std::string games = "Games";
|
|
|
|
static const std::string group = "Group";
|
|
|
|
static const std::string notes = "Notes";
|
|
|
|
static const std::string patch = "Patch";
|
|
|
|
static const std::string patch_version = "Patch Version";
|
|
|
|
static const std::string version = "Version";
|
2023-02-18 15:40:12 +00:00
|
|
|
static const std::string enabled = "Enabled";
|
2023-02-19 11:59:46 +00:00
|
|
|
static const std::string config_values = "Configurable Values";
|
2023-02-18 22:57:23 +00:00
|
|
|
static const std::string value = "Value";
|
|
|
|
static const std::string type = "Type";
|
|
|
|
static const std::string min = "Min";
|
|
|
|
static const std::string max = "Max";
|
|
|
|
static const std::string allowed_values = "Allowed Values";
|
2020-06-27 08:32:00 +00:00
|
|
|
}
|
|
|
|
|
2021-04-12 12:14:08 +00:00
|
|
|
inline static const std::string patch_engine_version = "1.2";
|
2020-06-30 19:35:15 +00:00
|
|
|
|
2017-03-28 23:54:05 +00:00
|
|
|
enum class patch_type
|
|
|
|
{
|
2020-06-13 00:16:28 +00:00
|
|
|
invalid,
|
2017-09-17 14:33:59 +00:00
|
|
|
load,
|
2021-08-23 13:21:49 +00:00
|
|
|
alloc, // Allocate memory at address (zeroized executable memory)
|
2021-09-01 10:38:17 +00:00
|
|
|
code_alloc,// Allocate memory somewhere, saves branch to memory at specfied address (filled with PPU NOP and branch for returning)
|
|
|
|
jump, // Install special 32-bit jump instruction (PPU only atm)
|
2021-09-02 15:14:26 +00:00
|
|
|
jump_link, // jump + set link (PPU only atm)
|
2021-09-06 07:33:44 +00:00
|
|
|
jump_func, // jump to exported function (PPU only, forever)
|
2017-03-28 23:54:05 +00:00
|
|
|
byte,
|
|
|
|
le16,
|
|
|
|
le32,
|
|
|
|
le64,
|
2017-07-17 13:34:04 +00:00
|
|
|
lef32,
|
|
|
|
lef64,
|
2017-03-28 23:54:05 +00:00
|
|
|
be16,
|
|
|
|
be32,
|
2021-02-12 12:02:31 +00:00
|
|
|
bd32, // be32 with data hint (non-code)
|
2017-03-28 23:54:05 +00:00
|
|
|
be64,
|
2021-02-12 12:02:31 +00:00
|
|
|
bd64, // be64 with data hint (non-code)
|
2017-07-17 13:34:04 +00:00
|
|
|
bef32,
|
|
|
|
bef64,
|
2023-09-25 15:32:50 +00:00
|
|
|
bp_exec, // Execution Breakpoint
|
2021-02-12 12:02:31 +00:00
|
|
|
utf8, // Text of string (not null-terminated automatically)
|
2023-07-12 17:43:33 +00:00
|
|
|
c_utf8, // Text of string (null-terminated automatically)
|
2023-03-03 13:43:46 +00:00
|
|
|
move_file, // Move file
|
|
|
|
hide_file, // Hide file
|
2017-03-28 23:54:05 +00:00
|
|
|
};
|
|
|
|
|
2023-03-03 13:43:46 +00:00
|
|
|
static constexpr bool patch_type_uses_hex_offset(patch_type type)
|
|
|
|
{
|
2023-07-12 17:43:33 +00:00
|
|
|
return type >= patch_type::alloc && type <= patch_type::c_utf8;
|
2023-03-03 13:43:46 +00:00
|
|
|
}
|
|
|
|
|
2023-02-19 11:59:46 +00:00
|
|
|
enum class patch_configurable_type
|
2023-02-18 22:57:23 +00:00
|
|
|
{
|
|
|
|
double_range,
|
|
|
|
double_enum,
|
|
|
|
long_range,
|
|
|
|
long_enum
|
|
|
|
};
|
|
|
|
|
2017-03-28 23:54:05 +00:00
|
|
|
class patch_engine
|
|
|
|
{
|
2020-06-02 08:39:24 +00:00
|
|
|
public:
|
|
|
|
struct patch_data
|
2017-03-28 23:54:05 +00:00
|
|
|
{
|
2020-06-02 08:39:24 +00:00
|
|
|
patch_type type = patch_type::load;
|
|
|
|
u32 offset = 0;
|
2023-03-03 13:43:46 +00:00
|
|
|
std::string original_offset{}; // Used for specifying paths
|
2021-03-30 15:31:46 +00:00
|
|
|
std::string original_value{}; // Used for import consistency (avoid rounding etc.)
|
2020-06-12 19:09:08 +00:00
|
|
|
union
|
|
|
|
{
|
|
|
|
u64 long_value;
|
|
|
|
f64 double_value;
|
2021-03-30 15:31:46 +00:00
|
|
|
} value{0};
|
2021-09-01 10:38:17 +00:00
|
|
|
mutable u32 alloc_addr = 0; // Used to save optional allocation address (if occured)
|
2017-03-28 23:54:05 +00:00
|
|
|
};
|
2020-12-13 13:34:45 +00:00
|
|
|
|
2023-02-19 09:58:16 +00:00
|
|
|
struct patch_allowed_value
|
|
|
|
{
|
|
|
|
std::string label;
|
|
|
|
f64 value{};
|
|
|
|
|
|
|
|
bool operator==(const patch_allowed_value& other) const
|
|
|
|
{
|
|
|
|
return value == other.value && label == other.label;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-02-19 11:59:46 +00:00
|
|
|
struct patch_config_value
|
2023-02-18 22:57:23 +00:00
|
|
|
{
|
|
|
|
f64 value{};
|
|
|
|
f64 min{};
|
|
|
|
f64 max{};
|
2023-02-19 11:59:46 +00:00
|
|
|
patch_configurable_type type{};
|
2023-02-19 09:58:16 +00:00
|
|
|
std::vector<patch_allowed_value> allowed_values;
|
2023-02-18 22:57:23 +00:00
|
|
|
|
2023-02-19 11:59:46 +00:00
|
|
|
bool operator==(const patch_config_value& other) const
|
2023-02-18 22:57:23 +00:00
|
|
|
{
|
|
|
|
return value == other.value && min == other.min && max == other.max && type == other.type && allowed_values == other.allowed_values;
|
|
|
|
}
|
2023-02-19 19:34:21 +00:00
|
|
|
|
2024-08-14 16:20:08 +00:00
|
|
|
void set_and_check_value(f64 new_value, std::string_view name);
|
2023-02-18 22:57:23 +00:00
|
|
|
};
|
|
|
|
|
2023-02-18 15:40:12 +00:00
|
|
|
struct patch_config_values
|
|
|
|
{
|
|
|
|
bool enabled{};
|
2023-02-19 11:59:46 +00:00
|
|
|
std::map<std::string, patch_config_value> config_values;
|
2023-02-18 15:40:12 +00:00
|
|
|
};
|
2023-02-18 22:57:23 +00:00
|
|
|
|
2023-02-18 15:40:12 +00:00
|
|
|
using patch_app_versions = std::unordered_map<std::string /*app_version*/, patch_config_values>;
|
2020-06-26 00:58:06 +00:00
|
|
|
using patch_serials = std::unordered_map<std::string /*serial*/, patch_app_versions>;
|
|
|
|
using patch_titles = std::unordered_map<std::string /*serial*/, patch_serials>;
|
2017-03-28 23:54:05 +00:00
|
|
|
|
2020-06-02 08:39:24 +00:00
|
|
|
struct patch_info
|
|
|
|
{
|
|
|
|
// Patch information
|
2021-03-30 15:31:46 +00:00
|
|
|
std::vector<patch_data> data_list{};
|
|
|
|
patch_titles titles{};
|
|
|
|
std::string description{};
|
|
|
|
std::string patch_version{};
|
|
|
|
std::string patch_group{};
|
|
|
|
std::string author{};
|
|
|
|
std::string notes{};
|
|
|
|
std::string source_path{};
|
2023-02-19 11:59:46 +00:00
|
|
|
std::map<std::string, patch_config_value> default_config_values;
|
2017-03-28 23:54:05 +00:00
|
|
|
|
2020-06-19 11:46:56 +00:00
|
|
|
// Redundant information for accessibility (see patch_container)
|
2021-03-30 15:31:46 +00:00
|
|
|
std::string hash{};
|
|
|
|
std::string version{};
|
2023-02-19 11:59:46 +00:00
|
|
|
std::map<std::string, patch_config_value> actual_config_values;
|
2020-06-02 08:39:24 +00:00
|
|
|
};
|
|
|
|
|
2020-06-19 11:46:56 +00:00
|
|
|
struct patch_container
|
2020-06-02 08:39:24 +00:00
|
|
|
{
|
2021-03-30 15:31:46 +00:00
|
|
|
std::unordered_map<std::string /*description*/, patch_info> patch_info_map{};
|
|
|
|
std::string hash{};
|
|
|
|
std::string version{};
|
2020-06-02 08:39:24 +00:00
|
|
|
};
|
|
|
|
|
2021-08-23 13:21:49 +00:00
|
|
|
enum mem_protection : u8
|
|
|
|
{
|
|
|
|
wx = 0, // Read + Write + Execute (default)
|
|
|
|
ro = 1, // Read
|
|
|
|
rx = 2, // Read + Execute
|
|
|
|
rw = 3, // Read + Write
|
|
|
|
mask = 3,
|
|
|
|
};
|
|
|
|
|
2020-06-19 11:46:56 +00:00
|
|
|
using patch_map = std::unordered_map<std::string /*hash*/, patch_container>;
|
2020-06-02 08:39:24 +00:00
|
|
|
|
|
|
|
patch_engine();
|
|
|
|
|
2021-03-02 16:22:39 +00:00
|
|
|
patch_engine(const patch_engine&) = delete;
|
|
|
|
|
|
|
|
patch_engine& operator=(const patch_engine&) = delete;
|
|
|
|
|
2020-06-02 08:39:24 +00:00
|
|
|
// Returns the directory in which patch_config.yml is located
|
|
|
|
static std::string get_patch_config_path();
|
|
|
|
|
2020-06-30 19:35:15 +00:00
|
|
|
// Returns the directory in which patches are located
|
|
|
|
static std::string get_patches_path();
|
|
|
|
|
2020-06-19 17:47:51 +00:00
|
|
|
// Returns the filepath for the imported_patch.yml
|
|
|
|
static std::string get_imported_patch_path();
|
|
|
|
|
2020-06-02 08:39:24 +00:00
|
|
|
// Load from file and append to specified patches map
|
2020-09-06 09:47:45 +00:00
|
|
|
static bool load(patch_map& patches, const std::string& path, std::string content = "", bool importing = false, std::stringstream* log_messages = nullptr);
|
2020-06-02 08:39:24 +00:00
|
|
|
|
|
|
|
// Read and add a patch node to the patch info
|
2024-08-14 16:20:08 +00:00
|
|
|
static bool read_patch_node(patch_info& info, YAML::Node node, const YAML::Node& root, std::string_view path, std::stringstream* log_messages = nullptr);
|
2020-06-02 08:39:24 +00:00
|
|
|
|
2021-09-02 18:48:56 +00:00
|
|
|
// Get the patch type from a string
|
2024-08-14 16:20:08 +00:00
|
|
|
static patch_type get_patch_type(std::string_view text);
|
2021-09-02 18:48:56 +00:00
|
|
|
|
2020-06-02 08:39:24 +00:00
|
|
|
// Get the patch type of a patch node
|
|
|
|
static patch_type get_patch_type(YAML::Node node);
|
|
|
|
|
|
|
|
// Add the data of a patch node
|
2024-08-14 16:20:08 +00:00
|
|
|
static bool add_patch_data(YAML::Node node, patch_info& info, u32 modifier, const YAML::Node& root, std::string_view path, std::stringstream* log_messages = nullptr);
|
2020-06-02 08:39:24 +00:00
|
|
|
|
|
|
|
// Save to patch_config.yml
|
2021-01-08 17:36:12 +00:00
|
|
|
static void save_config(const patch_map& patches_map);
|
2020-06-02 08:39:24 +00:00
|
|
|
|
2020-06-12 19:09:08 +00:00
|
|
|
// Save a patch file
|
2020-06-19 13:38:51 +00:00
|
|
|
static bool save_patches(const patch_map& patches, const std::string& path, std::stringstream* log_messages = nullptr);
|
2020-06-12 19:09:08 +00:00
|
|
|
|
|
|
|
// Create or append patches to a file
|
2020-12-18 07:39:54 +00:00
|
|
|
static bool import_patches(const patch_map& patches, const std::string& path, usz& count, usz& total, std::stringstream* log_messages = nullptr);
|
2020-06-12 19:09:08 +00:00
|
|
|
|
2020-06-19 17:47:51 +00:00
|
|
|
// Remove a patch from a file
|
|
|
|
static bool remove_patch(const patch_info& info);
|
|
|
|
|
2020-06-02 08:39:24 +00:00
|
|
|
// Load patch_config.yml
|
2021-01-08 17:36:12 +00:00
|
|
|
static patch_map load_config();
|
2020-06-02 08:39:24 +00:00
|
|
|
|
|
|
|
// Load from file and append to member patches map
|
|
|
|
void append_global_patches();
|
|
|
|
|
|
|
|
// Load from title relevant files and append to member patches map
|
2024-08-14 16:20:08 +00:00
|
|
|
void append_title_patches(std::string_view title_id);
|
2017-03-28 23:54:05 +00:00
|
|
|
|
2017-07-17 13:34:04 +00:00
|
|
|
// Apply patch (returns the number of entries applied)
|
2023-07-12 17:43:33 +00:00
|
|
|
std::basic_string<u32> apply(const std::string& name, std::function<u8*(u32, u32)> mem_translate, u32 filesz = -1, u32 min_addr = 0);
|
2020-06-02 08:39:24 +00:00
|
|
|
|
2021-09-01 10:38:17 +00:00
|
|
|
// Deallocate memory used by patches
|
|
|
|
void unload(const std::string& name);
|
|
|
|
|
2020-06-02 08:39:24 +00:00
|
|
|
private:
|
|
|
|
// Database
|
2021-03-30 15:31:46 +00:00
|
|
|
patch_map m_map{};
|
2020-06-28 11:26:10 +00:00
|
|
|
|
|
|
|
// Only one patch per patch group can be applied
|
2021-03-30 15:31:46 +00:00
|
|
|
std::set<std::string> m_applied_groups{};
|
2017-03-28 23:54:05 +00:00
|
|
|
};
|