Skip to content

Dynamic Patching

EnderTurret edited this page Nov 19, 2024 · 2 revisions

Dynamic patching refers to Patched's system that allows packs to patch many files at once using the same patch. They are 'dynamic' in the sense that a pattern can refer to a large number of files with different contents. Dynamic patching allows feats such as patching every biome, which could be used for adding ores or removing undesired features. Dynamic patches were added in 5.1.0+1.20.4 and 3.3.0+1.20.1.

Dynamic patching can be enabled by adding this section to the patched block:

// pack.mcmeta
{
  "patched": {
    "format_version": 1,
    "patch_targets": [
      {
        "pack_type": "server_data", // may be either server_data or client_resources; important for mods where the same metadata represents both packs — in other words, this avoids performing expensive matching on the wrong side
        "patch": "name_of_patch", // name of the patch to apply, points to "patches/<patch>.json.patch"
        "targets": [
          {
            "namespace": [ "minecraft" ], // the namespaces to search, may be regular expressions using the construction below
            "path": [ // the paths to search, may be literal strings or regular expression patterns like below
              {
                "pattern": "worldgen/biome/.*\\.json"
              }
            ]
          }
        ]
      }
    ]
  }
}

Important

For a pack's dynamic patches to apply to a given namespace it must also have at least one file in that namespace. For example, for a dynamic patch to apply to the minecraft namespace the pack must also have a file in the minecraft namespace. It is suggested to just put an empty _dummy.json file in the root of the namespace (so it resolves as say, minecraft:_dummy). It is not important what the file is called, as long as it does not clash with any existing or future files. Thus, the unusual name suggestion.

The reason this is necessary is because Minecraft internally organizes packs by namespace, so that looking up a resource in a given namespace doesn't query packs that do not have files in that namespace. Patched relies on this information when applying patches, since packs that do not contain the namespace will not have regular patches for anything in that namespace. This assumption breaks with dynamic patching since it does not require you to have a patch in a specific namespace, leading to Patched being unable to apply the patch (since the pack is simply not in the list for that namespace).

This shortcoming may be addressed in the future since it also makes pattern-based namespaces useless.

Caution

While it may be tempting to elide the pack_type field of a dynamic patch, it is important to set it so that packs-packaged-as-mods do not break. (For example, Modrinth can automatically package a data pack as a loader-agnostic mod.) For resource packs, set it to client_resources; for data packs, use server_data.

Dynamic patching requires a different mindset to regular patching; since the contents of the files could differ significantly, one has to be more careful with how they write their patches. For example, the following patch to remove a certain undesirable feature from all biomes:

// remove_dirt_ore.json.patch
{
  "op": "remove",
  "path": "/features/6/0"
}

This patch assumes that all biomes declare 'dirt ore' as their first UNDERGROUND_ORES feature. This assumption is clearly wrong; what if the biome has them in a different order, or what if the biome has no ores (like the_void)? The patch must be rewritten to remove this assumption:

// remove_dirt_ore.json.patch
[
  {
    "op": "test",
    "path": "/features/6/0",
    "value": "minecraft:ore_dirt"
  },
  {
    "op": "remove",
    "path": "/features/6/0"
  }
]

This is much better, but what if minecraft:ore_dirt is not the first entry? What if it's the second, or third? We can fix this using a find patch:

// remove_dirt_ore.json.patch
{
  "op": "find",
  "path": "/features/6/0",
  "test": {
    "path": "",
    "value": "minecraft:ore_dirt"
  },
  "then": {
    "op": "remove",
    "path": ""
  }
}

Similar precautions need to be taken when modifying such files in bulk, although 'future-proofing' regular patches in this manner is not a bad idea.

Clone this wiki locally