Jump to content

Patching: Difference between revisions

From CCDirectLink
Add documentation for the CALL step
m Change heading sizes
 
(2 intermediate revisions by the same user not shown)
Line 9: Line 9:
There is more than one way to patch the game. This page will walk you through the various ways to patch.
There is more than one way to patch the game. This page will walk you through the various ways to patch.


<hr>
== Asset Replacement ==
 
= Asset Replacement =


This is the most basic type of patching (anyone can do it).
This is the most basic type of patching (anyone can do it).
Line 17: Line 15:
This is a standard modloader feature that allows you to replace any file the game loads with your own.
This is a standard modloader feature that allows you to replace any file the game loads with your own.


== Process ==
=== Process ===


Inside your mod folder, create a folder called <code>assets</code>.
Inside your mod folder, create a folder called <code>assets</code>.
Line 49: Line 47:
* Used faceless Lea mod for some of the demonstration
* Used faceless Lea mod for some of the demonstration


= JSON Patching (Object Patching) =
== JSON Patching (Object Patching) ==


Note: This requires some know of the JSON format and some programming concepts
Note: This requires some know of the JSON format and some programming concepts
Line 61: Line 59:
You need to have file extensions visible in order to modify it.
You need to have file extensions visible in order to modify it.


== Process ==
=== Process ===


Let's say you want to patch a file <code>assets/data/test.json</code> with this as the contents:
Let's say you want to patch a file <code>assets/data/test.json</code> with this as the contents:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage" : {
     "storage" : {
Line 72: Line 70:
     }
     }
}
}
</source>
</syntaxhighlight>


Your mod is located at <code>assets/mods/my-mod/</code>
Your mod is located at <code>assets/mods/my-mod/</code>
Line 80: Line 78:
To replace "storage.level" with 200, <code>test.json.patch</code> would look like this:
To replace "storage.level" with 200, <code>test.json.patch</code> would look like this:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage" : {
     "storage" : {
Line 86: Line 84:
     }
     }
}
}
</source>
</syntaxhighlight>


To add "storage.name":
To add "storage.name":


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage" : {
     "storage" : {
Line 96: Line 94:
     }
     }
}
}
</source>
</syntaxhighlight>


Object patching is useful for adding new properties and modifying existing ones.
Object patching is useful for adding new properties and modifying existing ones.
Line 102: Line 100:
Weakness: - Inability to removal properties - Arrays are hard to patch
Weakness: - Inability to removal properties - Arrays are hard to patch


= Patch Steps =
== Patch Steps ==


Patch Steps is another way to perform json file Patching. It is more powerful than Object Patching.
Patch Steps is another way to perform json file Patching. It is more powerful than Object Patching.
Line 112: Line 110:
Location: <code>assets/data/test.json</code>
Location: <code>assets/data/test.json</code>


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage" : {
     "storage" : {
Line 118: Line 116:
     }
     }
}
}
</source>
</syntaxhighlight>


== Appliers ==
Below is a list of all the valid patch steps.
 
An Applier is a Patch Step command.
 
== Patch Step Appliers ==
 
<source lang="js"></source>


=== ENTER ===
=== ENTER ===
Line 132: Line 124:
This changes the context of a patch.
This changes the context of a patch.


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "ENTER",
     "type": "ENTER",
     "index": ["storage"]
     "index": ["storage"]
}]
}]
</source>
</syntaxhighlight>


or
or


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "ENTER",
     "type": "ENTER",
     "index": "storage"
     "index": "storage"
}]
}]
</source>
</syntaxhighlight>


would change the internal view of:
would change the internal view of:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage" : {
     "storage" : {
Line 159: Line 151:
     }
     }
}
}
</source>
</syntaxhighlight>


to
to


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "level": 200,
     "level": 200,
Line 170: Line 162:
     }]
     }]
}
}
</source>
</syntaxhighlight>


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "ENTER",
     "type": "ENTER",
     "index": ["storage", "saves", 0]
     "index": ["storage", "saves", 0]
}]
}]
</source>
</syntaxhighlight>


would change the internal view of:
would change the internal view of:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage" : {
     "storage" : {
Line 190: Line 182:
     }
     }
}
}
</source>
</syntaxhighlight>


to
to


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "data": "blob"
     "data": "blob"
}
}
</source>
</syntaxhighlight>


=== EXIT ===
=== EXIT ===
Line 206: Line 198:
<code>EXIT</code> undos an <code>ENTER</code>.
<code>EXIT</code> undos an <code>ENTER</code>.


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "EXIT"
     "type": "EXIT"
}]
}]
</source>
</syntaxhighlight>


is equivalent to
is equivalent to


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "EXIT",
     "type": "EXIT",
     "count": 1
     "count": 1
}]
}]
</source>
</syntaxhighlight>


For demonstration purposes, this is the contents of <code>assets/data/test.json</code>:
For demonstration purposes, this is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage": {
     "storage": {
Line 231: Line 223:
     }
     }
}
}
</source>
</syntaxhighlight>


and this is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
and this is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "ENTER",
     "type": "ENTER",
Line 243: Line 235:
     "count": 2
     "count": 2
}]
}]
</source>
</syntaxhighlight>


The first step will produce the internal result of:
The first step will produce the internal result of:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "name": 20
     "name": 20
}
}
</source>
</syntaxhighlight>


The second step will undo the first leading to the initial state.
The second step will undo the first leading to the initial state.


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage": {
     "storage": {
Line 263: Line 255:
     }
     }
}
}
</source>
</syntaxhighlight>


=== SET_KEY ===
=== SET_KEY ===
Line 269: Line 261:
This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage": {
     "storage": {
Line 277: Line 269:
     }
     }
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "SET_KEY",
     "type": "SET_KEY",
     "index": "storage"
     "index": "storage"
}]
}]
</source>
</syntaxhighlight>


This is the result:
This is the result:


<source lang="js">
<syntaxhighlight lang="js">
{}
{}
</source>
</syntaxhighlight>


This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage": {
     "storage": {
Line 304: Line 296:
     }
     }
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "SET_KEY",
     "type": "SET_KEY",
Line 314: Line 306:
     "content": 2
     "content": 2
}]
}]
</source>
</syntaxhighlight>


This is the result:
This is the result:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage": 2
     "storage": 2
}
}
</source>
</syntaxhighlight>


=== INIT_KEY ===
=== INIT_KEY ===
Line 328: Line 320:
This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage": {
     "storage": {
Line 336: Line 328:
     }
     }
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "INIT_KEY",
     "type": "INIT_KEY",
Line 348: Line 340:
     }
     }
}]
}]
</source>
</syntaxhighlight>


Nothing will change to the data because "storage" already exists.
Nothing will change to the data because "storage" already exists.
Line 354: Line 346:
Changing <code>assets/mods/my-mod/assets/data/test.json.patch</code> to:
Changing <code>assets/mods/my-mod/assets/data/test.json.patch</code> to:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "INIT_KEY",
     "type": "INIT_KEY",
Line 362: Line 354:
     }
     }
}]
}]
</source>
</syntaxhighlight>


would result in:
would result in:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "storage": {
     "storage": {
Line 377: Line 369:
     }
     }
}
}
</source>
</syntaxhighlight>


=== REMOVE_ARRAY_ELEMENT ===
=== REMOVE_ARRAY_ELEMENT ===
Line 383: Line 375:
This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": [1,2,3]
     "a": [1,2,3]
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "REMOVE_ARRAY_ELEMENT",
     "type": "REMOVE_ARRAY_ELEMENT",
     "index": 0
     "index": 0
}]
}]
</source>
</syntaxhighlight>


Applying the patch will result in this:
Applying the patch will result in this:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": [2,3]
     "a": [2,3]
}
}
</source>
</syntaxhighlight>


=== ADD_ARRAY_ELEMENT ===
=== ADD_ARRAY_ELEMENT ===
Line 410: Line 402:
This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": [1,2,3]
     "a": [1,2,3]
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "ENTER",
     "type": "ENTER",
Line 432: Line 424:
     "type": "EXIT"
     "type": "EXIT"
}]
}]
</source>
</syntaxhighlight>


After the first step, the internal state will be:
After the first step, the internal state will be:


<source lang="js">
<syntaxhighlight lang="js">
[1,2,3]
[1,2,3]
</source>
</syntaxhighlight>


After the second step, the number 4 will be pushed to the end of the array:
After the second step, the number 4 will be pushed to the end of the array:


<source lang="js">
<syntaxhighlight lang="js">
[1,2,3,4]
[1,2,3,4]
</source>
</syntaxhighlight>


After the third step, the number 0 will be added to the start of the array:
After the third step, the number 0 will be added to the start of the array:


<source lang="js">
<syntaxhighlight lang="js">
[0,1,2,3,4]
[0,1,2,3,4]
</source>
</syntaxhighlight>


The last step will revert the value of focus to the initial object:
The last step will revert the value of focus to the initial object:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": [0,1,2,3,4]
     "a": [0,1,2,3,4]
}
}
</source>
</syntaxhighlight>


=== IMPORT ===
=== IMPORT ===
Line 464: Line 456:
This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": {
     "a": {
Line 470: Line 462:
     }
     }
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/data/test2.json</code>:
This is the contents of <code>assets/data/test2.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "b": {
     "b": {
Line 484: Line 476:
     "d": 4
     "d": 4
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "IMPORT",
     "type": "IMPORT",
     "src": "data/test2.json"
     "src": "data/test2.json"
}]
}]
</source>
</syntaxhighlight>


This is equivalent to:
This is equivalent to:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "IMPORT",
     "type": "IMPORT",
     "src": "game:data/test2.json"
     "src": "game:data/test2.json"
}]
}]
</source>
</syntaxhighlight>


The first step would load <code>assets/data/test2.json</code> then merge it with the current value resulting in this:
The first step would load <code>assets/data/test2.json</code> then merge it with the current value resulting in this:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": {
     "a": {
Line 520: Line 512:
     "d": 4
     "d": 4
}
}
</source>
</syntaxhighlight>


If <code>assets/data/test2.json</code> had patches associated with it, it would be applied before being merged.
If <code>assets/data/test2.json</code> had patches associated with it, it would be applied before being merged.
Line 528: Line 520:
This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": {
     "a": {
Line 534: Line 526:
     }
     }
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "IMPORT",
     "type": "IMPORT",
Line 545: Line 537:
     "index": "y"
     "index": "y"
}]
}]
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/patches/data/test.json</code>:
This is the contents of <code>assets/mods/my-mod/patches/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "1": {
     "1": {
Line 557: Line 549:
     }
     }
}
}
</source>
</syntaxhighlight>


First it will load <code>assets/mods/my-mod/patches/data/test.json</code>.
First it will load <code>assets/mods/my-mod/patches/data/test.json</code>.
Line 565: Line 557:
Initial loaded file internal representation:
Initial loaded file internal representation:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "1": {
     "1": {
Line 573: Line 565:
     }
     }
}
}
</source>
</syntaxhighlight>


After entering "1":
After entering "1":


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "2": {
     "2": {
Line 583: Line 575:
     }
     }
}
}
</source>
</syntaxhighlight>


After entering "2":
After entering "2":


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "3": 4
     "3": 4
}
}
</source>
</syntaxhighlight>


After entering "3":
After entering "3":


<source lang="js">
<syntaxhighlight lang="js">
4
4
</source>
</syntaxhighlight>


Finally, it will add a key "y" with the value that resulted from the path walk (4).
Finally, it will add a key "y" with the value that resulted from the path walk (4).
Line 603: Line 595:
So the overall result will be:
So the overall result will be:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": {
     "a": {
Line 610: Line 602:
     "y": 4
     "y": 4
}
}
</source>
</syntaxhighlight>


Note: "index" and "path" options are optional.
Note: "index" and "path" options are optional.
Line 620: Line 612:
This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": {
     "a": {
Line 626: Line 618:
     }
     }
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "INCLUDE",
     "type": "INCLUDE",
     "src": "mod:patches/data/test.json",
     "src": "mod:patches/data/test.json",
}]
}]
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/patches/data/test.json</code>:
This is the contents of <code>assets/mods/my-mod/patches/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "1": {
     "1": {
Line 647: Line 639:
     }
     }
}
}
</source>
</syntaxhighlight>


This is like setting the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code> to:
This is like setting the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code> to:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "1": {
     "1": {
Line 659: Line 651:
     }
     }
}
}
</source>
</syntaxhighlight>


However, <code>INCLUDE</code> is used as an organization method.
However, <code>INCLUDE</code> is used as an organization method.
Line 665: Line 657:
This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": {
     "a": {
Line 671: Line 663:
     }
     }
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "INCLUDE",
     "type": "INCLUDE",
Line 684: Line 676:
     "content": [1,2,3]
     "content": [1,2,3]
}]
}]
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/patches/data/test.json</code>:
This is the contents of <code>assets/mods/my-mod/patches/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "ENTER",
     "type": "ENTER",
     "index": ["a"]
     "index": ["a"]
}]
}]
</source>
</syntaxhighlight>


This results in:
This results in:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": {
     "a": {
Line 704: Line 696:
     "b": [1,2,3]
     "b": [1,2,3]
}
}
</source>
</syntaxhighlight>


Think of PatchStep files as its own room. What include does is generate a new room to perform some special operation. Rooms do not intefere with each other, they just modify the data.
Think of PatchStep files as its own room. What include does is generate a new room to perform some special operation. Rooms do not intefere with each other, they just modify the data.
Line 714: Line 706:
This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{}
{}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "FOR_IN",
     "type": "FOR_IN",
Line 731: Line 723:
     }]
     }]
}]
}]
</source>
</syntaxhighlight>


This results in:
This results in:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "1-id": "1",
     "1-id": "1",
Line 742: Line 734:
     "4-id": "4"
     "4-id": "4"
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{}
{}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "FOR_IN",
     "type": "FOR_IN",
Line 772: Line 764:
     }]
     }]
}]
}]
</source>
</syntaxhighlight>


This results in:
This results in:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "Bob": "1",
     "Bob": "1",
     "Joe": "2"
     "Joe": "2"
}
}
</source>
</syntaxhighlight>


=== COPY ===
=== COPY ===
Line 787: Line 779:
This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": 2,
     "a": 2,
Line 795: Line 787:
     }
     }
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "FOR_IN",
     "type": "FOR_IN",
Line 814: Line 806:
     }]
     }]
}]
}]
</source>
</syntaxhighlight>


Nothing will change. All this will do is create an internal key-value storage that looks like this:
Nothing will change. All this will do is create an internal key-value storage that looks like this:
Line 824: Line 816:
With the following data:
With the following data:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": 1,
     "a": 1,
     "b": 2
     "b": 2
}
}
</source>
</syntaxhighlight>


And the following patch step:
And the following patch step:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "type": "MERGE_CONTENT",
     "type": "MERGE_CONTENT",
Line 841: Line 833:
     }
     }
}
}
</source>
</syntaxhighlight>


<code>MERGE_CONTENT</code> would modify the data to be:
<code>MERGE_CONTENT</code> would modify the data to be:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": 3,
     "a": 3,
Line 851: Line 843:
     "c": 4
     "c": 4
}
}
</source>
</syntaxhighlight>


For an array, it would work the same way - effectively acting as multiple <code>ADD_ARRAY_ELEMENT</code> steps being executed at the end of the array.
For an array, it would work the same way - effectively acting as multiple <code>ADD_ARRAY_ELEMENT</code> steps being executed at the end of the array.
Line 861: Line 853:
This is the contents of <code>assets/data/test.json</code>:
This is the contents of <code>assets/data/test.json</code>:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "a": 2,
     "a": 2,
Line 869: Line 861:
     }
     }
}
}
</source>
</syntaxhighlight>


This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:
This is the contents of <code>assets/mods/my-mod/assets/data/test.json.patch</code>:


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "FOR_IN",
     "type": "FOR_IN",
Line 907: Line 899:
     }]
     }]
}]
}]
</source>
</syntaxhighlight>


This is the result:
This is the result:


<source lang="js">
<syntaxhighlight lang="js">
{
{
     "saved": {
     "saved": {
Line 921: Line 913:
     }
     }
}
}
</source>
</syntaxhighlight>


=== CALL ===
=== CALL ===
Line 927: Line 919:
This step allows you to call a custom step.
This step allows you to call a custom step.


First, you define a custom step. In a CCLoader2 mod:
First, you define a custom step.
 
{{Note
  |text=The following code must be ran BEFORE prestart! That being during plugin, preload, or postload.
  |type=reminder
}}


<source lang="js">
<syntaxhighlight lang="js">
// NOTE: This MUST be done BEFORE prestart! That being: plugin, preload, postload
simplifyResources.patchSteps.callable.register("YOUR_ID", (state, args) => {
simplifyResources.patchSteps.callable.register("YOUR_ID", (state, args) => {
   console.log(args);
   console.log(args);
});
});
</source>
</syntaxhighlight>


Then, in your patch file:
Then, in your patch file:
<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "CALL",
     "type": "CALL",
Line 945: Line 941:
     }
     }
}]
}]
</source>
</syntaxhighlight>


This would log <code>{ someArg: 1 }</code> to the console whenever the step is called.
This would log <code>{ someArg: 1 }</code> to the console whenever the step is called.
Line 953: Line 949:
=== DEBUG ===
=== DEBUG ===


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "DEBUG",
     "type": "DEBUG",
Line 961: Line 957:
     "value": false
     "value": false
}]
}]
</source>
</syntaxhighlight>


This PatchStep turns Debug Mode on or off.
This PatchStep turns Debug Mode on or off.
Line 969: Line 965:
Debug mode must be on for this PatchStep to work.
Debug mode must be on for this PatchStep to work.


<source lang="js">
<syntaxhighlight lang="js">
[{
[{
     "type": "DEBUG",
     "type": "DEBUG",
Line 982: Line 978:
     }
     }
}]
}]
</source>
</syntaxhighlight>


This will first display <code>This is a comment</code> in the DevTools console. It will then display <code>{data: 3}</code>.
This will first display <code>This is a comment</code> in the DevTools console. It will then display <code>{data: 3}</code>.


[[Category:Modding guides]]
[[Category:Modding guides]]

Latest revision as of 18:18, 26 May 2023

NOTE: This article needs editing!!!

What is patching?

In the scope modding, patching is changing the original game content in any way.

How do I patch game files?

There is more than one way to patch the game. This page will walk you through the various ways to patch.

Asset Replacement

This is the most basic type of patching (anyone can do it).

This is a standard modloader feature that allows you to replace any file the game loads with your own.

Process

Inside your mod folder, create a folder called assets.

Decide what file you want to replace. For this tutorial, I will be showing you how to replace Lea's portraits.

Find the original relative path to asset of interest.

All you have to do is now mimic the folder structure.

In this example, two folders need to be created.

Inside the assets folder in your mod, create a media folder. Inside the media folder, create a face folder.

Finally, add the file you want to replace (your own lea.png).

It should end up looking something like this.

That is it!

You can find more examples in the github:CCDirectLink/CCAssetSwaps repo.

  • Used faceless Lea mod for some of the demonstration

JSON Patching (Object Patching)

Note: This requires some know of the JSON format and some programming concepts

As the majority of the game assets are json files, this is really useful to know about.

What this allows you to do is modify any json file without doing a file replacement.

The same ideas apply as assets override, except the file will have .patch added to the full file name.

You need to have file extensions visible in order to modify it.

Process

Let's say you want to patch a file assets/data/test.json with this as the contents:

{
    "storage" : {
        "level": 100,
        "xp": 500
    }
}

Your mod is located at assets/mods/my-mod/

You would create a file with the filepath assets/mods/my-mod/assets/data/test.json.patch

To replace "storage.level" with 200, test.json.patch would look like this:

{
    "storage" : {
        "level": 200
    }
}

To add "storage.name":

{
    "storage" : {
        "name": "Shizuka"
    }
}

Object patching is useful for adding new properties and modifying existing ones.

Weakness: - Inability to removal properties - Arrays are hard to patch

Patch Steps

Patch Steps is another way to perform json file Patching. It is more powerful than Object Patching.

The only difference between Object Patching and Patch Steps is the format of the .patch file.

We will be using the same sample json file used to demonstrate how Object Patching works.

Location: assets/data/test.json

{
    "storage" : {
        "level": 200
    }
}

Below is a list of all the valid patch steps.

ENTER

This changes the context of a patch.

[{
    "type": "ENTER",
    "index": ["storage"]
}]

or

[{
    "type": "ENTER",
    "index": "storage"
}]

would change the internal view of:

{
    "storage" : {
        "level": 200,
        "saves": [{
            "data": "blob"
        }]
    }
}

to

{
    "level": 200,
    "saves": [{
        "data": "blob"
    }]
}
[{
    "type": "ENTER",
    "index": ["storage", "saves", 0]
}]

would change the internal view of:

{
    "storage" : {
        "level": 200,
        "saves": [{
            "data": "blob"
        }]
    }
}

to

{
    "data": "blob"
}

EXIT

For every ENTER, there should be at least one EXIT.

EXIT undos an ENTER.

[{
    "type": "EXIT"
}]

is equivalent to

[{
    "type": "EXIT",
    "count": 1
}]

For demonstration purposes, this is the contents of assets/data/test.json:

{
    "storage": {
        "user": {
            "name": 20
        }
    }
}

and this is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "ENTER",
    "index": ["storage", "user"]
}, {
    "type": "EXIT",
    "count": 2
}]

The first step will produce the internal result of:

{
    "name": 20
}

The second step will undo the first leading to the initial state.

{
    "storage": {
        "user": {
            "name": 20
        }
    }
}

SET_KEY

This is the contents of assets/data/test.json:

{
    "storage": {
        "user": {
            "name": 20
        }
    }
}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "SET_KEY",
    "index": "storage"
}]

This is the result:

{}

This is the contents of assets/data/test.json:

{
    "storage": {
        "user": {
            "name": 20
        }
    }
}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "SET_KEY",
    "index": "storage",
    "content": 2
}]

This is the result:

{
    "storage": 2
}

INIT_KEY

This is the contents of assets/data/test.json:

{
    "storage": {
        "user": {
            "name": 20
        }
    }
}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "INIT_KEY",
    "index": "storage",
    "content": {
        "a": 2
    }
}]

Nothing will change to the data because "storage" already exists.

Changing assets/mods/my-mod/assets/data/test.json.patch to:

[{
    "type": "INIT_KEY",
    "index": "storage2",
    "content": {
        "a": 2
    }
}]

would result in:

{
    "storage": {
        "user": {
            "name": 20
        }
    },
    "storage2": {
        "a": 2
    }
}

REMOVE_ARRAY_ELEMENT

This is the contents of assets/data/test.json:

{
    "a": [1,2,3]
}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "REMOVE_ARRAY_ELEMENT",
    "index": 0
}]

Applying the patch will result in this:

{
    "a": [2,3]
}

ADD_ARRAY_ELEMENT

This is the contents of assets/data/test.json:

{
    "a": [1,2,3]
}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "ENTER",
    "index": "a"
},{
    "type": "ADD_ARRAY_ELEMENT",
    "content": 4
}, {
    "type": "ADD_ARRAY_ELEMENT",
    "index": 0,
    "content": 0
}, {
    "type": "EXIT"
}]

After the first step, the internal state will be:

[1,2,3]

After the second step, the number 4 will be pushed to the end of the array:

[1,2,3,4]

After the third step, the number 0 will be added to the start of the array:

[0,1,2,3,4]

The last step will revert the value of focus to the initial object:

{
    "a": [0,1,2,3,4]
}

IMPORT

This is the contents of assets/data/test.json:

{
    "a": {
        "b": 2
    }
}

This is the contents of assets/data/test2.json:

{
    "b": {
        "a": 2
    },
    "c": {
        "a": 3
    },
    "d": 4
}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "IMPORT",
    "src": "data/test2.json"
}]

This is equivalent to:

[{
    "type": "IMPORT",
    "src": "game:data/test2.json"
}]

The first step would load assets/data/test2.json then merge it with the current value resulting in this:

{
    "a": {
        "b": 2
    },
    "b": {
        "a": 2
    },
    ,
    "c": {
        "a": 3
    },
    "d": 4
}

If assets/data/test2.json had patches associated with it, it would be applied before being merged.

Another feature is loading json files inside the mod directory and merging. No patches to the loaded file will be done if mod: is specified.

This is the contents of assets/data/test.json:

{
    "a": {
        "b": 2
    }
}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "IMPORT",
    "src": "mod:patches/data/test.json",
    "path": ["1", "2", "3"],
    "index": "y"
}]

This is the contents of assets/mods/my-mod/patches/data/test.json:

{
    "1": {
        "2": {
            "3": 4
        }
    }
}

First it will load assets/mods/my-mod/patches/data/test.json.

Then it will walk the path specified.

Initial loaded file internal representation:

{
    "1": {
        "2": {
            "3": 4
        }
    }
}

After entering "1":

{
    "2": {
        "3": 4
    }
}

After entering "2":

{
    "3": 4
}

After entering "3":

4

Finally, it will add a key "y" with the value that resulted from the path walk (4).

So the overall result will be:

{
    "a": {
        "b": 2
    },
    "y": 4
}

Note: "index" and "path" options are optional.

INCLUDE

The purpose of INCLUDE is to allow external Object Patching or PatchSteps to be performed.

This is the contents of assets/data/test.json:

{
    "a": {
        "b": 2
    }
}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "INCLUDE",
    "src": "mod:patches/data/test.json",
}]

This is the contents of assets/mods/my-mod/patches/data/test.json:

{
    "1": {
        "2": {
            "3": 4
        }
    }
}

This is like setting the contents of assets/mods/my-mod/assets/data/test.json.patch to:

{
    "1": {
        "2": {
            "3": 4
        }
    }
}

However, INCLUDE is used as an organization method.

This is the contents of assets/data/test.json:

{
    "a": {
        "b": 2
    }
}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "INCLUDE",
    "src": "mod:patches/data/test.json",
}, {
    "type": "SET_KEY",
    "index": "b",
    "content": [1,2,3]
}]

This is the contents of assets/mods/my-mod/patches/data/test.json:

[{
    "type": "ENTER",
    "index": ["a"]
}]

This results in:

{
    "a": {
        "b": 2
    },
    "b": [1,2,3]
}

Think of PatchStep files as its own room. What include does is generate a new room to perform some special operation. Rooms do not intefere with each other, they just modify the data.

FOR_IN

This PatchStep is useful for combining repeated set of PatchSteps with only slightly variations in input.

This is the contents of assets/data/test.json:

{}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "FOR_IN",
    "keyword": "__INDEX__",
    "values": [1,2,3,4],
    "body": [{
        "type": "SET_KEY",
        "index": "__INDEX__-id",
        "content": "__INDEX__"
    }]
}]

This results in:

{
    "1-id": "1",
    "2-id": "2",
    "3-id": "3",
    "4-id": "4"
}

This is the contents of assets/data/test.json:

{}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "FOR_IN",
    "keyword": {
        "name": "__NAME__",
        "id": "__ID__"
    },
    "values": [{
        "name": "Bob",
        "id": 1
    },{
        "name": "Joe",
        "id": 2
    }],
    "body": [{
        "type": "SET_KEY",
        "index": "__NAME__",
        "content": "__ID__"
    }]
}]

This results in:

{
    "Bob": "1",
    "Joe": "2"
}

COPY

This is the contents of assets/data/test.json:

{
    "a": 2,
    "b": [3],
    "c": {
        "d": 4
    }
}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "FOR_IN",
    "keyword": "__VAR__",
    "values": ["a", "b", "c"],
    "body": [{
        "type": "ENTER",
        "index": "__VAR__"
    },{
        "type": "COPY",
        "alias": "alias-__VAR__",
    }, {
        "type": "EXIT"
    }]
}]

Nothing will change. All this will do is create an internal key-value storage that looks like this:

{ "alias-a": 2, "alias-b": [3], "alias-c": { "d": 4 } }

MERGE_CONTENT

With the following data:

{
    "a": 1,
    "b": 2
}

And the following patch step:

{
    "type": "MERGE_CONTENT",
    "content": {
        "a": 3,
        "c": 4
    }
}

MERGE_CONTENT would modify the data to be:

{
    "a": 3,
    "b": 2,
    "c": 4
}

For an array, it would work the same way - effectively acting as multiple ADD_ARRAY_ELEMENT steps being executed at the end of the array.

PASTE

This command relies on COPY.

This is the contents of assets/data/test.json:

{
    "a": 2,
    "b": [3],
    "c": {
        "d": 4
    }
}

This is the contents of assets/mods/my-mod/assets/data/test.json.patch:

[{
    "type": "FOR_IN",
    "keyword": "__VAR__",
    "values": ["a", "b", "c"],
    "body": [{
        "type": "ENTER",
        "index": "__VAR__"
    },{
        "type": "COPY",
        "alias": "alias-__VAR__"
    },{
        "type": "EXIT"
    },{
        "type": "SET_KEY",
        "index": "__VAR__"
    }]
}, {
    "type": "SET_KEY",
    "index": "saved",
    "content": {}
}, {
    "type": "ENTER",
    "index": "saved"
}, {
    "type": "FOR_IN",
    "keyword": "__VAR__",
    "values": ["a", "b", "c"],
    "body": [{
        "type": "PASTE",
        "alias": "alias-__VAR__",
        "index": "__VAR__"
    }]
}]

This is the result:

{
    "saved": {
        "a": 2,
        "b": [3],
        "c": {
            "d": 4
        }
    }
}

CALL

This step allows you to call a custom step.

First, you define a custom step.

The following code must be ran BEFORE prestart! That being during plugin, preload, or postload.
simplifyResources.patchSteps.callable.register("YOUR_ID", (state, args) => {
  console.log(args);
});

Then, in your patch file:

[{
    "type": "CALL",
    "id": "YOUR_ID",
    "args": {
        "someArg": 1
    }
}]

This would log { someArg: 1 } to the console whenever the step is called.

If you think patch steps are lacking in some way, CALL allows you to define your own steps that process your args in some way without having to contribute back to the library.

DEBUG

[{
    "type": "DEBUG",
    "value": true
}, {
    "type": "DEBUG",
    "value": false
}]

This PatchStep turns Debug Mode on or off.

COMMENT

Debug mode must be on for this PatchStep to work.

[{
    "type": "DEBUG",
    "value": true
},{
    "type": "COMMENT",
    "value": "This is a comment"
}, {
    "type": "COMMENT",
    "value": {
        "data": 3
    }
}]

This will first display This is a comment in the DevTools console. It will then display {data: 3}.