
Patch Wars: Enhanced JSON Patching
Library for modders to have greater control over JSON patches
Description
<h1 id="features">Features</h1> <h2 id="prepatches">Prepatches</h2> <p>Patches found inside the <code>prepatches</code> folder of a mod's assets will run before any regular <code>patches</code> are processed, guaranteeing the ability to patch standard patches before they have run.</p> <h2 id="postpatches">Postpatches</h2> <p>Patches found inside the <code>postpatches</code> folder of a mod's assets will run after all <code>prepatches</code> and <code>patches</code> are processed.</p> <h2 id="jpath-queries">JPath Queries</h2> <p>Adds the ability to use Newtonsoft's JPath queries to define more expressive and dynamic patches. This feature is available for use in patches found in <code>patches</code>, <code>prepatches</code>, and <code>postpatches</code>.</p> <h3 id="use">Use</h3> <p>To utilize JPath queries, place your query inside the <code>path</code> field of your patch.</p> <p>If you expect and want your patch to apply to multiple elements in the target file, be sure to add <code>"patchMultiple": true</code> to your patch.</p> <p>When performing an <code>add</code> or <code>addeach</code> patch operation using JPath queries, because the element being added does not exist yet and would cause the query to fail, it must be left out of the <code>path</code> definition. Instead, add the new element name (or index) to <code>pathAppend</code>. The string found in <code>pathAppend</code> will be added to the end of the pointers found by your JPath query before patching the target file. <code>pathAppend</code> does not support JPath and must be in vanilla's standard JsonPointer notation.</p> <h3 id="examples">Examples</h3> <p>You'd like to mod the panning loot table so that temporal gears are far more common from both sand/gravel and bony soil. (Excerpt from <code>pan.json</code> as of Vintage Story v1.18.0)</p> <pre><code class="lang-json">{ <span class="hljs-attr">"code"</span>: <span class="hljs-string">"pan"</span>, <span class="hljs-attr">"attributes"</span>: { <span class="hljs-attr">"panningDrops"</span>: { <span class="hljs-attr">"@(bonysoil|bonysoil-.*)"</span>: [ // ... <span class="hljs-number">17</span> other items not shown { <span class="hljs-attr">"type"</span>: <span class="hljs-string">"item"</span>, <span class="hljs-attr">"code"</span>: <span class="hljs-string">"gear-temporal"</span>, <span class="hljs-attr">"chance"</span>: { <span class="hljs-attr">"avg"</span>: <span class="hljs-number">0.001</span>, <span class="hljs-attr">"var"</span>: <span class="hljs-number">0</span> } }, // ... ], <span class="hljs-attr">"@(sand|gravel)-.*"</span>: [ // ... <span class="hljs-number">19</span> other items not shown { <span class="hljs-attr">"type"</span>: <span class="hljs-string">"item"</span>, <span class="hljs-attr">"code"</span>: <span class="hljs-string">"gear-temporal"</span>, <span class="hljs-attr">"chance"</span>: { <span class="hljs-attr">"avg"</span>: <span class="hljs-number">0.0005</span>, <span class="hljs-attr">"var"</span>: <span class="hljs-number">0</span> } }, // ... ] } } } </code></pre> <p>If you were to write a patch file for this in the vanilla patching system (or use modmaker.exe), your patch file would look like this:</p> <pre><code class="lang-json">[ { <span class="hljs-attr">"op"</span>: <span class="hljs-string">"replace"</span>, <span class="hljs-attr">"path"</span>: <span class="hljs-string">"/attributes/panningDrops/@(bonysoil|bonysoil-.*)/17/chance/avg"</span>, <span class="hljs-attr">"value"</span>: <span class="hljs-number">20</span>, <span class="hljs-attr">"file"</span>: <span class="hljs-string">"game:blocktypes/wood/pan.json"</span>, <span class="hljs-attr">"side"</span>: <span class="hljs-string">"Server"</span> }, { <span class="hljs-attr">"op"</span>: <span class="hljs-string">"replace"</span>, <span class="hljs-attr">"path"</span>: <span class="hljs-string">"/attributes/panningDrops/@(sand|gravel)-.*/19/chance/avg"</span>, <span class="hljs-attr">"value"</span>: <span class="hljs-number">20</span>, <span class="hljs-attr">"file"</span>: <span class="hljs-string">"game:blocktypes/wood/pan.json"</span>, <span class="hljs-attr">"side"</span>: <span class="hljs-string">"Server"</span> } ] </code></pre> <p>These patches are brittle to any changes to the drop tables in vanilla as well as from other mods due to the array indexes shifting from additions and deletions. Also, you and anyone reading your patch have no idea which item in the drop table is being changed without referencing <code>pan.json</code>.</p> <p>Using a JPath query instead, your patch might look like this:</p> <pre><code class="lang-json">[ { <span class="hljs-attr">"op"</span>: <span class="hljs-string">"replace"</span>, <span class="hljs-attr">"path"</span>: <span class="hljs-string">"$.attributes.panningDrops.*..[?(@..code == 'gear-temporal')].chance.avg"</span>, <span class="hljs-attr">"value"</span>: <span class="hljs-number">20</span>, <span class="hljs-attr">"patchMultiple"</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">"file"</span>: <span class="hljs-string">"game:blocktypes/wood/pan.json"</span>, <span class="hljs-attr">"side"</span>: <span class="hljs-string">"Server"</span> } ] </code></pre> <p>Now the patch is expressive and resilient to vanilla and third party mod adjustments. The leading <code>$</code> signifies the root element. A <code>.</code> followed by a key finds the appropriately named child element. <code>.*</code> selects all of the current element's children. In this example, this is both the <code>@(bonysoil|bonysoil-.*)</code> and <code>@(sand|gravel)-.*</code> elements, but also includes any potential additions and changes to <code>panningDrops</code>. A <code>..</code> indicates any descendant element from the current point in the tree. <code>[?()]</code> is a JPa
Ratings & reviews
Sign in to leave a rating or comment.

