mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
patcher: patch groups (#812)
## Link to GitHub Issue or related Pull Request, if one exists Fixes #245 ## Description of change Introduce patch groups. JSON schema now allows for a `"type": "group"`: ```json { "type": "group", "gameCode": "LDJ", "id": "timer-freeze", "name": "Timer Freeze Patches", "description": "Freezes various timers in the game." }, { "name": "Standard/Menu Timer Freeze", "description": "Freezes all non-premium area timers.", "caution": "", "gameCode": "LDJ", "type": "memory", "group": "timer-freeze", "patches": [ { "offset": 9962743, "dllName": "bm2dx.dll", "dataDisabled": "0F84", "dataEnabled": "90E9" } ] }, { "name": "Premium Free Timer Freeze", "description": "Freezes all premium area timers.", "caution": "", "gameCode": "LDJ", "type": "memory", "group": "timer-freeze", "patches": [ { "offset": 9111965, "dllName": "bm2dx.dll", "dataDisabled": "7E", "dataEnabled": "EB" } ] }, ``` In the UI, these will show up as tree nodes. The parent is not actually treated as a patch; e.g., its state is not saved to the patch manager config file; only the child patches states are managed, the parent's state only bubble up only in the UI. In downlevel versions of spice, group parents will show up as a patch of invalid type. Child patches will still show up as individual patches. ## Testing *how was the code tested?*
This commit is contained in:
@@ -199,8 +199,13 @@ namespace patcher {
|
||||
log_warning("patchmanager", "embedded patches json file parse error: {}", static_cast<uint32_t>(error));
|
||||
}
|
||||
|
||||
const auto group_definitions = parse_patch_group_definitions(doc);
|
||||
|
||||
// iterate patches
|
||||
for (auto &patch : doc.GetArray()) {
|
||||
if (is_patch_group_definition(patch)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// verfiy patch data
|
||||
auto name_it = patch.FindMember("name");
|
||||
@@ -214,6 +219,9 @@ namespace patcher {
|
||||
name_it->value.GetString());
|
||||
continue;
|
||||
}
|
||||
const std::string game_code(
|
||||
game_code_it->value.GetString(),
|
||||
game_code_it->value.GetStringLength());
|
||||
auto description_it = patch.FindMember("description");
|
||||
if (description_it == patch.MemberEnd() || !description_it->value.IsString()) {
|
||||
log_warning("patchmanager", "failed to parse description for {}",
|
||||
@@ -235,7 +243,7 @@ namespace patcher {
|
||||
// build patch data
|
||||
PatchData patch_data {
|
||||
.enabled = false,
|
||||
.game_code = game_code_it->value.GetString(),
|
||||
.game_code = game_code,
|
||||
.datecode_min = 0,
|
||||
.datecode_max = 0,
|
||||
.name = name_it->value.GetString(),
|
||||
@@ -247,6 +255,11 @@ namespace patcher {
|
||||
.patches_memory = std::vector<MemoryPatch>(),
|
||||
.patches_union = std::vector<UnionPatch>(),
|
||||
.patch_number = NumberPatch(),
|
||||
.group_id = resolve_patch_group_id(
|
||||
patch,
|
||||
group_definitions,
|
||||
game_code,
|
||||
name_it->value.GetString()),
|
||||
.last_status = PatchStatus::Disabled,
|
||||
.hash = "",
|
||||
.unverified = false,
|
||||
@@ -533,6 +546,7 @@ namespace patcher {
|
||||
}
|
||||
|
||||
// auto apply
|
||||
register_patch_group(patch_data, group_definitions);
|
||||
if (apply_patches && setting_auto_apply && patch_data.enabled) {
|
||||
print_auto_apply_status(patch_data);
|
||||
apply_patch(patch_data, true);
|
||||
@@ -663,6 +677,7 @@ namespace patcher {
|
||||
|
||||
// clear old patches
|
||||
patches.clear();
|
||||
patch_groups.clear();
|
||||
// drop the cached sorted view so the table rebuilds it (in default order)
|
||||
// on the next frame
|
||||
patches_sorted.clear();
|
||||
@@ -719,6 +734,7 @@ namespace patcher {
|
||||
bool imported = false;
|
||||
// clear old patches
|
||||
patches.clear();
|
||||
patch_groups.clear();
|
||||
patches_sorted.clear();
|
||||
url_fetch_errors.clear();
|
||||
|
||||
@@ -755,8 +771,13 @@ namespace patcher {
|
||||
rapidjson::GetParseError_En(error));
|
||||
}
|
||||
|
||||
const auto group_definitions = parse_patch_group_definitions(doc);
|
||||
|
||||
// iterate patches
|
||||
for (auto &patch : doc.GetArray()) {
|
||||
if (is_patch_group_definition(patch)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// verfiy patch data
|
||||
auto name_it = patch.FindMember("name");
|
||||
@@ -778,6 +799,9 @@ namespace patcher {
|
||||
name_it->value.GetString());
|
||||
continue;
|
||||
}
|
||||
const std::string game_code(
|
||||
game_code_it->value.GetString(),
|
||||
game_code_it->value.GetStringLength());
|
||||
auto description_it = patch.FindMember("description");
|
||||
if (description_it == patch.MemberEnd() || !description_it->value.IsString()) {
|
||||
log_warning("patchmanager", "failed to parse description for {}",
|
||||
@@ -809,7 +833,7 @@ namespace patcher {
|
||||
// build patch data
|
||||
PatchData patch_data {
|
||||
.enabled = false,
|
||||
.game_code = game_code_it->value.GetString(),
|
||||
.game_code = game_code,
|
||||
.datecode_min = 0,
|
||||
.datecode_max = 0,
|
||||
.name = name_it->value.GetString(),
|
||||
@@ -821,6 +845,11 @@ namespace patcher {
|
||||
.patches_memory = std::vector<MemoryPatch>(),
|
||||
.patches_union = std::vector<UnionPatch>(),
|
||||
.patch_number = NumberPatch(),
|
||||
.group_id = resolve_patch_group_id(
|
||||
patch,
|
||||
group_definitions,
|
||||
game_code,
|
||||
name_it->value.GetString()),
|
||||
.last_status = PatchStatus::Disabled,
|
||||
.hash = "",
|
||||
.unverified = false,
|
||||
@@ -1264,6 +1293,7 @@ namespace patcher {
|
||||
}
|
||||
|
||||
// auto apply
|
||||
register_patch_group(patch_data, group_definitions);
|
||||
if (apply_patches && setting_auto_apply && patch_data.enabled) {
|
||||
print_auto_apply_status(patch_data);
|
||||
apply_patch(patch_data, true);
|
||||
|
||||
Reference in New Issue
Block a user