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:
bicarus
2026-07-19 02:10:13 -07:00
committed by GitHub
parent a8cc85531c
commit be4bb00390
7 changed files with 741 additions and 50 deletions
+9 -1
View File
@@ -2,7 +2,6 @@
#include <filesystem>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <string>
@@ -74,6 +73,13 @@ namespace patcher {
bool fatal_error = false;
};
struct PatchGroup {
std::string name;
std::string description;
std::string caution;
std::string name_in_lower_case;
};
struct PatchData {
bool enabled;
std::string game_code;
@@ -86,6 +92,7 @@ namespace patcher {
std::vector<MemoryPatch> patches_memory;
std::vector<UnionPatch> patches_union;
NumberPatch patch_number;
std::string group_id;
PatchStatus last_status;
std::string hash;
bool unverified = false;
@@ -129,6 +136,7 @@ namespace patcher {
PatchStatus is_patch_active(PatchData& patch);
bool apply_patch(PatchData& patch, bool active);
const PatchGroup* find_patch_group(const PatchData& patch);
std::string displayPath(const std::filesystem::path& path);
}