Project icon Patchly
Patchly

The Perfect Pure Patching Plugin

60
8 days ago
Game MechanicsTechnologyLibraryOptimizationUtility

Introduction

Updated Jun 2, 2026

Patchly - The Perfect Pure Patching Plugin

Patch JSON assets instead of rewriting them

Patchly lets one pack reach into another pack's asset and change only the fields it cares about, leaving everything else untouched. You drop a .patch file next to the asset you want to change, and Patchly merges it onto the resolved original.

TL;DR

In your pack, create a file at the same path as the asset you want to change, swapping .json for .patch.

To add the mana stat to

Server/Item/Items/Armor/Iron/Armor_Iron_Head.json

make this in your pack

Server/Item/Items/Armor/Iron/Armor_Iron_Head.patch

and set it to

{
  "Armor": {
    "StatModifiers": {
      "Mana": [{ "Amount": 126, "CalculationType": "Additive" }]
    }
  }
}

That's it. You've now patched some armor!

Patch syntax

A .patch is plain JSON. Every key you write is merged onto the matching key in the resolved base asset.

FeatureExampleWhat it does
Deep merge (objects){ "A": { "B": 1 } }Only leaf B changes; sibling keys survive.
Replace array (default)"Categories": [...]Discards the parent's array, uses yours.
Append to array"Categories+": [...]Keeps the parent's entries, adds yours at the end, skipping any element already present.
Prepend to array"Categories-": [...]Keeps the parent's entries, adds yours at the front, skipping any element already present.
Append allowing duplicates"Categories++": [...]Like +, but never de-dups; appends even if an identical element already exists.
Prepend allowing duplicates"Categories--": [...]Like -, but never de-dups; prepends even if an identical element already exists.
Fill if absent"Mana?": [...]Writes the value only if the key is missing; otherwise the base wins.
Extend by index"Recipes~": [ {}, {...} ]Merges into the base element at each position; {} changes nothing.
Extend by field"Children+": [ { "$Match": "Id", "Id": "Tools", ... } ]Finds the element whose field matches and merges into it.
Delete a key"DamageResistance": nullRemoves that key from the merged asset.
Gate on packs"$Requires": "Group:Name" or "Group:Name:>=1.2.0" or [...]Patch applies only if the gate passes; otherwise skipped with a log line. The list is an AND of clauses. Prefix a pack with - to require it ABSENT. Comma-join packs in one clause for OR (any present): "A,B". So ["A", "-B", "C,D"] means A && !B && (C || D).
Win on conflicts"$Priority": 100Integer, default 0. Higher applies last and wins on conflicting fields.
Inherit another asset"$Import": "Template_Base_Item" or [ ... ]Pulls in another same-type asset as a base layer beneath your keys.

Questions and Answers

QuestionAnswer
Where do I put the .patch?Same path as what you want to patch into. .json swapped for .patch.
Which packs can be patched?Every registered pack: folder, .zip, and .jar.
Does it hot-reload?Folder packs re-merge live on .patch edit. Zip/jar packs apply once at

Next steps

  • For Pack Developers - ship .patch files in an asset-only pack and require Patchly as a dependency.
  • For Mod Developers - bundle Patchly directly into your Java plugin with Gradle Shadow.
Powered byHytaleModding