Starbound

Starbound

Not enough ratings
Modding: JSON Patching Guide
By Ceterai
A compilation of resources and rules on how to use json-patching for modding.
WEBSITE[ceterai.github.io] | SUPPORT ME[buymeacoffee.com]
3
   
Award
Favorite
Favorited
Unfavorite
What is json-patching
While creating a mod for Starbound you might run into a situation, where you need to edit .json and .config files, that are originally present in Starbound's assets (or assets of another mod).
In this case in most situations it's best to not edit them directly, and instead create a .patch file that adds/edits/removes data from these files.

This is called JSON-Patching. You can read more about it here[jsonpatch.com].
How to write json-patches
First, you need to create a .patch file.
The name of this file should be a copy of the name of a file you want to patch.
Example: if you want to patch a file called stone.json, you need to name your patching file stone.json.patch.

Now, you need to write its contents. There are 2 ways to do this:

  1. Writing it yourself

    The syntax for .patch files can be found on this website[jsonpatch.com].
    Keep in mind that Starbound has an extended syntax it supports, for that checkout the "Useful Materials" section.

    Note: please do not forget, that every patch file should contain a list of objects (patches themselves), even if there's only one patch.

    Example:
    [ { "op" : "add", "path" : "/items/-", "value" : "myvalue1" }, { "op" : "add", "path" : "/items/-", "value" : "myvalue2" } ]

  2. Using online services

    There is this helpful service[json-patch-builder-online.github.io] that lets you provide the initial contents of a file you need to patch, and the expected results.

To check, that your .patch file works correctly, you can use this service[json-schema-validator.herokuapp.com] or this one[jsonpatch.me].
Keep in mind that Starbound might still process your patches slightly differently than here.

We're almost done.
Some rules
There's a couple of rules on how the game applies these patches:
  • Your patch file should be located on the same relative path as the file you are patching.
    Example:
    Let's say your mod is called my_cool_mod and you are trying to patch a file called distributions.config, located in Starbound assets at packed/biomes/distributions.config.
    In this case you need to put your patch file on this path: .../my_cool_mod/biomes/distributions.config.patch
  • It is possible to use .patch files to edit files from other mods. To do that, all you need to know is the relative path of the file you want to patch.
    Example:
    Let's say your mod is called my_cool_mod and you are trying to patch a file called superfile.json from mod other_mod at .../other_mod/items/superfile.json.
    In this case you need to put your patch file on this path: .../my_cool_mod/items/superfile.json.patch

That's it! You're good to go!
Batching Patches
While usually one ".patch" file contains a list of patches to be performed, you could optionally batch those patches to divide them into separate groups - this way instead of containing a plain list of patches, your file will contain a list of lists of patches, or a list of patch batches, like so:
[ [ { "op" : "add", "path" : "/planetTypeNames/ct_alterash_planet", "value" : "Alterash" }, { "op" : "add", "path" : "/planetTypeColors/ct_alterash_planet", "value" : [32, 240, 128] } ], [ { "op" : "add", "path" : "/displayStatusEffects/ct_analyzed", "value" : true }, { "op" : "add", "path" : "/displayStatusEffects/ct_autoanalyzer" , "value" : true } ] ]
Why do this? Discover in the next section!
Conditional Patches
What if you needed to apply a patch to a file, only if it contained a specific field?
For example, if you're not sure, if the file can be overwritten by a different mode that removes that value.

In that case, you could use a "test" patch operation, that checks if the existing parameter exists, or if it contains a specific value.

Specifying value will check if the key is equal to that specific value, omitting it will simply check for existence of that key under the specified path.
Adding ""inverse" : true" will invert the test, like adding "not" to a programming condition.

Examples
Taken from a post made by a game dev, link in the end of the guide:
// handles wrong values { "op" : "test", "path" : "/foo", "value" : "not bar", "inverse" : true } // handles missing values { "op" : "test", "path" : "/baz/2", "value" : 9, "inverse" : true } // handles wrong types { "op" : "test", "path" : "/test/xyzzy/somekey", "value" : null, "inverse" : true } // check path for existence { "op" : "test", "path" : "/test/xyzzy/0" } // check path for non-existence { "op" : "test", "path" : "/baz/4", "inverse" : true }

Note: if a test fails, all of the patches in the current batch (or file, if you're not using batches) won't apply.

Conditional Patch Batches
What if you need to apply different patches to a file under different conditions? If a key is equal to true, then add this, if it's false, then remove this.
Or, what if you have patches, that should be applied no matter what, and also have patches that should only be applied under a specific condition?

This is where you want to use batches.
A failing test will only discard all patches in a batch, so the other batches will be independant from it.
[ [ // if the planet name is not "Alterash", then make it "Alterash". { "op" : "test", "path" : "/planets/ct_alterash", "value" : "Alterash", "inverse" : true }, { "op" : "add", "path" : "/planets/ct_alterash", "value" : "Alterash" } ], [ // no condition - always apply these patches. { "op" : "add", "path" : "/planetColors/ct_alterash", "value" : [32, 240, 128] }, { "op" : "add", "path" : "/planetColors/ct_alterash_prime", "value" : [32, 128, 240] } ], [ // if a key "displayStatusEffects" exists in the root of the file, apply patches to it. { "op" : "test", "path" : "/displayStatusEffects" }, { "op" : "add", "path" : "/displayStatusEffects/ct_analyzed", "value" : true }, { "op" : "add", "path" : "/displayStatusEffects/ct_autoanalyzer" , "value" : true } ] ]
Useful Materials
These are some useful links that cover a lot of use cases and might answer some of your questions.

A very extensive, but quite old guide that also covers this topic:
Basic Patching Now With Path Guide [v1.9][community.playstarbound.com] - by The | Suit

Extended functionality for the "test" operation supported by Starbound:
You can invert tests and you can check just for existence of a key[community.playstarbound.com]

Starbound supports Patch Batches - when a patch file contains multiple lists of patches. Useful with "test" operations for conditional patching:
Patch Batches[community.playstarbound.com]
Conclusion
I've made this guide mainly for referencing it in other guides.
This guide assumes you know how to unpack game files.
Please let me know if I forgot or mixed up anything.
Thank you for reading!
2 Comments
FUS 5 Aug, 2024 @ 10:04am 
Invaluable guide :2018bestaward:
Ceterai  [author] 22 Jun, 2023 @ 6:07pm 
Added links to another patch-checking service, as well as the "Useful Materials" section.