Patching: Difference between revisions
Lexisother (talk | contribs) Add documentation for the CALL step |
Lexisother (talk | contribs) 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. | ||
== 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: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage" : { | "storage" : { | ||
Line 72: | Line 70: | ||
} | } | ||
} | } | ||
</ | </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: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage" : { | "storage" : { | ||
Line 86: | Line 84: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
To add "storage.name": | To add "storage.name": | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage" : { | "storage" : { | ||
Line 96: | Line 94: | ||
} | } | ||
} | } | ||
</ | </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> | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage" : { | "storage" : { | ||
Line 118: | Line 116: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
Below is a list of all the valid patch steps. | |||
=== ENTER === | === ENTER === | ||
Line 132: | Line 124: | ||
This changes the context of a patch. | This changes the context of a patch. | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "ENTER", | "type": "ENTER", | ||
"index": ["storage"] | "index": ["storage"] | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
or | or | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "ENTER", | "type": "ENTER", | ||
"index": "storage" | "index": "storage" | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
would change the internal view of: | would change the internal view of: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage" : { | "storage" : { | ||
Line 159: | Line 151: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
to | to | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"level": 200, | "level": 200, | ||
Line 170: | Line 162: | ||
}] | }] | ||
} | } | ||
</ | </syntaxhighlight> | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "ENTER", | "type": "ENTER", | ||
"index": ["storage", "saves", 0] | "index": ["storage", "saves", 0] | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
would change the internal view of: | would change the internal view of: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage" : { | "storage" : { | ||
Line 190: | Line 182: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
to | to | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"data": "blob" | "data": "blob" | ||
} | } | ||
</ | </syntaxhighlight> | ||
=== EXIT === | === EXIT === | ||
Line 206: | Line 198: | ||
<code>EXIT</code> undos an <code>ENTER</code>. | <code>EXIT</code> undos an <code>ENTER</code>. | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "EXIT" | "type": "EXIT" | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
is equivalent to | is equivalent to | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "EXIT", | "type": "EXIT", | ||
"count": 1 | "count": 1 | ||
}] | }] | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage": { | "storage": { | ||
Line 231: | Line 223: | ||
} | } | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "ENTER", | "type": "ENTER", | ||
Line 243: | Line 235: | ||
"count": 2 | "count": 2 | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
The first step will produce the internal result of: | The first step will produce the internal result of: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"name": 20 | "name": 20 | ||
} | } | ||
</ | </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. | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage": { | "storage": { | ||
Line 263: | Line 255: | ||
} | } | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage": { | "storage": { | ||
Line 277: | Line 269: | ||
} | } | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "SET_KEY", | "type": "SET_KEY", | ||
"index": "storage" | "index": "storage" | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
This is the result: | This is the result: | ||
< | <syntaxhighlight lang="js"> | ||
{} | {} | ||
</ | </syntaxhighlight> | ||
This is the contents of <code>assets/data/test.json</code>: | This is the contents of <code>assets/data/test.json</code>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage": { | "storage": { | ||
Line 304: | Line 296: | ||
} | } | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "SET_KEY", | "type": "SET_KEY", | ||
Line 314: | Line 306: | ||
"content": 2 | "content": 2 | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
This is the result: | This is the result: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage": 2 | "storage": 2 | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage": { | "storage": { | ||
Line 336: | Line 328: | ||
} | } | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "INIT_KEY", | "type": "INIT_KEY", | ||
Line 348: | Line 340: | ||
} | } | ||
}] | }] | ||
</ | </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: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "INIT_KEY", | "type": "INIT_KEY", | ||
Line 362: | Line 354: | ||
} | } | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
would result in: | would result in: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"storage": { | "storage": { | ||
Line 377: | Line 369: | ||
} | } | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": [1,2,3] | "a": [1,2,3] | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "REMOVE_ARRAY_ELEMENT", | "type": "REMOVE_ARRAY_ELEMENT", | ||
"index": 0 | "index": 0 | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
Applying the patch will result in this: | Applying the patch will result in this: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": [2,3] | "a": [2,3] | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": [1,2,3] | "a": [1,2,3] | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "ENTER", | "type": "ENTER", | ||
Line 432: | Line 424: | ||
"type": "EXIT" | "type": "EXIT" | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
After the first step, the internal state will be: | After the first step, the internal state will be: | ||
< | <syntaxhighlight lang="js"> | ||
[1,2,3] | [1,2,3] | ||
</ | </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: | ||
< | <syntaxhighlight lang="js"> | ||
[1,2,3,4] | [1,2,3,4] | ||
</ | </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: | ||
< | <syntaxhighlight lang="js"> | ||
[0,1,2,3,4] | [0,1,2,3,4] | ||
</ | </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: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": [0,1,2,3,4] | "a": [0,1,2,3,4] | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": { | "a": { | ||
Line 470: | Line 462: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
This is the contents of <code>assets/data/test2.json</code>: | This is the contents of <code>assets/data/test2.json</code>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"b": { | "b": { | ||
Line 484: | Line 476: | ||
"d": 4 | "d": 4 | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "IMPORT", | "type": "IMPORT", | ||
"src": "data/test2.json" | "src": "data/test2.json" | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
This is equivalent to: | This is equivalent to: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "IMPORT", | "type": "IMPORT", | ||
"src": "game:data/test2.json" | "src": "game:data/test2.json" | ||
}] | }] | ||
</ | </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: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": { | "a": { | ||
Line 520: | Line 512: | ||
"d": 4 | "d": 4 | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": { | "a": { | ||
Line 534: | Line 526: | ||
} | } | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "IMPORT", | "type": "IMPORT", | ||
Line 545: | Line 537: | ||
"index": "y" | "index": "y" | ||
}] | }] | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"1": { | "1": { | ||
Line 557: | Line 549: | ||
} | } | ||
} | } | ||
</ | </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: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"1": { | "1": { | ||
Line 573: | Line 565: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
After entering "1": | After entering "1": | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"2": { | "2": { | ||
Line 583: | Line 575: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
After entering "2": | After entering "2": | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"3": 4 | "3": 4 | ||
} | } | ||
</ | </syntaxhighlight> | ||
After entering "3": | After entering "3": | ||
< | <syntaxhighlight lang="js"> | ||
4 | 4 | ||
</ | </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: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": { | "a": { | ||
Line 610: | Line 602: | ||
"y": 4 | "y": 4 | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": { | "a": { | ||
Line 626: | Line 618: | ||
} | } | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "INCLUDE", | "type": "INCLUDE", | ||
"src": "mod:patches/data/test.json", | "src": "mod:patches/data/test.json", | ||
}] | }] | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"1": { | "1": { | ||
Line 647: | Line 639: | ||
} | } | ||
} | } | ||
</ | </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: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"1": { | "1": { | ||
Line 659: | Line 651: | ||
} | } | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": { | "a": { | ||
Line 671: | Line 663: | ||
} | } | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "INCLUDE", | "type": "INCLUDE", | ||
Line 684: | Line 676: | ||
"content": [1,2,3] | "content": [1,2,3] | ||
}] | }] | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "ENTER", | "type": "ENTER", | ||
"index": ["a"] | "index": ["a"] | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
This results in: | This results in: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": { | "a": { | ||
Line 704: | Line 696: | ||
"b": [1,2,3] | "b": [1,2,3] | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{} | {} | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "FOR_IN", | "type": "FOR_IN", | ||
Line 731: | Line 723: | ||
}] | }] | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
This results in: | This results in: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"1-id": "1", | "1-id": "1", | ||
Line 742: | Line 734: | ||
"4-id": "4" | "4-id": "4" | ||
} | } | ||
</ | </syntaxhighlight> | ||
This is the contents of <code>assets/data/test.json</code>: | This is the contents of <code>assets/data/test.json</code>: | ||
< | <syntaxhighlight lang="js"> | ||
{} | {} | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "FOR_IN", | "type": "FOR_IN", | ||
Line 772: | Line 764: | ||
}] | }] | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
This results in: | This results in: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"Bob": "1", | "Bob": "1", | ||
"Joe": "2" | "Joe": "2" | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": 2, | "a": 2, | ||
Line 795: | Line 787: | ||
} | } | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "FOR_IN", | "type": "FOR_IN", | ||
Line 814: | Line 806: | ||
}] | }] | ||
}] | }] | ||
</ | </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: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": 1, | "a": 1, | ||
"b": 2 | "b": 2 | ||
} | } | ||
</ | </syntaxhighlight> | ||
And the following patch step: | And the following patch step: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"type": "MERGE_CONTENT", | "type": "MERGE_CONTENT", | ||
Line 841: | Line 833: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
<code>MERGE_CONTENT</code> would modify the data to be: | <code>MERGE_CONTENT</code> would modify the data to be: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": 3, | "a": 3, | ||
Line 851: | Line 843: | ||
"c": 4 | "c": 4 | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"a": 2, | "a": 2, | ||
Line 869: | Line 861: | ||
} | } | ||
} | } | ||
</ | </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>: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "FOR_IN", | "type": "FOR_IN", | ||
Line 907: | Line 899: | ||
}] | }] | ||
}] | }] | ||
</ | </syntaxhighlight> | ||
This is the result: | This is the result: | ||
< | <syntaxhighlight lang="js"> | ||
{ | { | ||
"saved": { | "saved": { | ||
Line 921: | Line 913: | ||
} | } | ||
} | } | ||
</ | </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. | 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 | |||
}} | |||
< | <syntaxhighlight lang="js"> | ||
simplifyResources.patchSteps.callable.register("YOUR_ID", (state, args) => { | simplifyResources.patchSteps.callable.register("YOUR_ID", (state, args) => { | ||
console.log(args); | console.log(args); | ||
}); | }); | ||
</ | </syntaxhighlight> | ||
Then, in your patch file: | Then, in your patch file: | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "CALL", | "type": "CALL", | ||
Line 945: | Line 941: | ||
} | } | ||
}] | }] | ||
</ | </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 === | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "DEBUG", | "type": "DEBUG", | ||
Line 961: | Line 957: | ||
"value": false | "value": false | ||
}] | }] | ||
</ | </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. | ||
< | <syntaxhighlight lang="js"> | ||
[{ | [{ | ||
"type": "DEBUG", | "type": "DEBUG", | ||
Line 982: | Line 978: | ||
} | } | ||
}] | }] | ||
</ | </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.
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}
.