Skip to content

Commit

Permalink
Major docs update;
Browse files Browse the repository at this point in the history
Re-enable gh-pages deployment from main;
  • Loading branch information
agc93 committed Jul 15, 2021
1 parent c744fd5 commit 0c99584
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Expand Up @@ -39,7 +39,7 @@ jobs:
path: docs/public/
- name: Deploy to Pages
uses: peaceiris/actions-gh-pages@v3
if: github.ref == 'refs/heads/nonexistent' #temporarily disabling
if: github.ref == 'refs/heads/main' #temporarily disabling
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/public
4 changes: 2 additions & 2 deletions docs/content/en/patches/_index.md
Expand Up @@ -4,6 +4,6 @@ linkTitle: "Building a Sicario mod"
weight: 20
---

Hex patches (also referred to as file patches) are the older method of building datatable mods for Project Wingman. They involve directly editing the binary parts of game files, replacing certain bytes with new bytes (generally represented in hex form). This approach still works, and it still _supported_ by Project Sicario, but is not recommended for most scenarios as it is less robust, more likely to break in case of game updates and is just generally kinda messy.
Asset patches are the most reliable kind of patch and the one most authors should be using for most scenarios as it allows you to directly edit datatables using the same names, properties and structures the game uses, but uses a unique syntax to express this without having to learn UE4 (or development!). The first section of these docs will walk you through creating asset patches and they are what I recommend most authors to use, so you can likely skip over the section on hex patches.

With that in mind, Sicario was built with hex patching in mind so file patching is still very much supported and documentation for working with hex patches is still included.
Hex patches (also referred to as file patches) are the older method of building datatable mods for Project Wingman. They involve directly editing the binary parts of game files, replacing certain bytes with new bytes (generally represented in hex form). This approach still works, and it still _supported_ by Project Sicario, but is not recommended for most scenarios as it is less robust, more likely to break in case of game updates and is just generally kinda messy. With that in mind, Sicario was originally built with hex patching in mind so file patching is still very much supported and documentation for working with hex patches is still included.
2 changes: 1 addition & 1 deletion docs/content/en/patches/walkthrough/example.md
@@ -1,6 +1,6 @@
---
title: "Example Mod"
weight: 23
weight: 25
---

So now you've seen one basic example, but just to expand on that, here's another very simple {{< shortName >}} patch to _unlock all currently locked modifiers_:
Expand Down
45 changes: 21 additions & 24 deletions docs/content/en/patches/walkthrough/intro.md
Expand Up @@ -4,7 +4,9 @@ weight: 21
anchor: "howto-basics"
---

### The AoA unlocker mod file
Let's dive into the deep end and use a reasonably simple example of a patch file to illustrate how an asset patch file works. There's a complete example of a reasonably simple mod included below: the AoA Unlocker. This will probably seem like a lot but over the next few pages we'll walk slowly through all the individual parts so you can get an idea of how the patches work and how you can build your own.

## The AoA unlocker mod file

```json
{
Expand Down Expand Up @@ -32,9 +34,9 @@ anchor: "howto-basics"

> Note that (for now), the `FilePatches: {}` object is still ***required***, even if it's not being used.
Now let's step through each part of this file.
Now let's step through each part of this file, so you can see what each part does.

### Patch Metadata (<code>_meta</code>)
## Patch Metadata (<code>_meta</code>)

The first thing you'll usually find in a {{< shortName >}} patch file is the `_meta` field, which is an object with a few optional properties:

Expand All @@ -46,15 +48,15 @@ All three of these values will be shown to users so please don't just put "do th

There is some more metadata you can optionally provide, but that's covered later on.

### The Asset Patches (`AssetPatches`)
## The Asset Patches (`AssetPatches`)

The `AssetPatches` object is the main "substance" of a {{< shortName >}} patch. It is a dictionary grouping the files to be edited with sets of patches to be applied to that file.

> Note that to support auto-packing you need to include the game file as the full target path for the file you're editing.
In the example above, we have just one key in the object: `ProjectWingman/Content/ProjectWingman/Blueprints/Data/AircraftData/DB_Aircraft.uexp`. This just means that `DB_Aircraft.uexp` will be the only file that this patch will be applied to and it will be packed in that specific path. Each file then has an array of "patch sets".

#### Patch Sets
### Patch Sets

Patch Sets are mostly a logical organizational idea: they're a way of organizing patches together. For example, if your mod is changing multiple stats for multiple planes, you might include each plane as a separate patch set. A patch set is just an object with `name` and an array of `patches`:

Expand All @@ -65,15 +67,19 @@ Patch Sets are mostly a logical organizational idea: they're a way of organizing
}
```

On it's own a patch set doesn't do anything, that's up to the actual _patches_ in the set.
On it's own a patch set doesn't do much, that's up to the actual _patches_ in the set.

#### Patch Set Grouping

There is one important thing to note with patch sets: all the patches in a set are _matched_ together. That means if one patch requires a previous change, or matches based on a value changed by a previous patch, they need to be in separate patch sets. For example, if you change the name of something and then want a later patch to find the property based on that new name, it needs to be in its own set.

##### Patch Set Grouping
This will make a bit more sense later on, but just keep it in mind if you're making changes that rely on each other.

There is one important thing to note with patch sets: all the patches in a set are matched together. That means if one patch requires a previous change, or matches based on a value changed by a previous patch, they need to be in separate patch sets. For example, if you change the name of something and then want a later patch to find the property based on that new name, it needs to be in its own set.
> The reason for this is both complex and simple: it was possible for a change from an earlier patch to then match a later patches template which was extremely confusing in practice.
#### Patches
### Patches

Now we hit the real meat of a {{< shortName >}} patch: the actual hex edit to make. Here's the example for enabling AoA for all aircraft:
Now we hit the real meat of a {{< shortName >}} patch: the actual edit to make. Here's the example for enabling AoA for all aircraft:

```json
{
Expand All @@ -84,21 +90,12 @@ Now we hit the real meat of a {{< shortName >}} patch: the actual hex edit to ma
}
```

In plain English, this object just tells {{< shortName >}} "replace the value of any `CanUseAoA` properties with `true`".

##### Template and Value

These are the actual values {{< shortName >}} will be (respectively) looking for and inserting into the binary file. When it runs, {{< appName >}} will load the file into memory, parse the file (more on that below), look for _any_ values that match the **template** value and then apply the **value**. How exactly the value is applied varies based on the patch _type_.
In plain English, this object just tells {{< shortName >}} "replace the value of any `CanUseAoA` properties with `true`", but that's probably not immediately obvious. Don't worry, it's not as complicated as it looks!

##### Types
#### Template and Value

The two main types of patches currently in use are:
These are the actual values {{< shortName >}} will be (respectively) looking for and inserting into the file. When it runs, {{< appName >}} will load the file into memory, parse the file (more on that later), look for _any_ values that match the **template** value and then apply the **value**. How exactly the value is applied varies based on the patch _type_.

|Type|Notes|
|:--:|:----|
|`propertyValue`|This is by far the most common/useful and for good reason: it's the most useful and versatile type. It sets the value of matching properties to the given value.|
|`arrayPropertyValue`|Sibling type to `propertyValue` that creates/inserts an array value to the given properties using a simple array syntax|
|`modifyPropertyValue`|Modifies a numeric value _based on it's existing value_.|
|`textProperty`|Specialized patch type for working UE4's TextProperty fields more effectively.
In short, the Template is how {{< shortName >}} knows which properties to change (and not to change) and is used to isolate out exactly what you want to change. Templates are covered in more detail in the [next](../template) section.

Most of these types use a common convention for the `value` field: `DataType:value`. This ensures that the properties are set with the correct data types the game uses. Note that other patch types might not use the same convention.
The Value of the patch, on the other hand, is how {{< shortName >}} knows _how_ you want to change it and is used to apply any number of potential changes based on the patch _type_. The patch value (and patch types) are also covered in more detail in a [later](../patches) section.
83 changes: 83 additions & 0 deletions docs/content/en/patches/walkthrough/patches.md
@@ -0,0 +1,83 @@
---
linkTitle: "Patch Types"
title: "Understanding Patches and Patch Types"
weight: 23
---

### Patches

Now we hit the real meat of a {{< shortName >}} patch: the actual edit to make. Here's the example for enabling AoA for all aircraft:

```json
{
"description": "Set CanUseAoA",
"template": "datatable:{'BaseStats*'}.{'CanUseAoA*'}",
"value": "BoolProperty:true",
"type": "propertyValue"
}
```

In plain English, this object just tells {{< shortName >}} "replace the value of any `CanUseAoA` properties with `true`".

#### Template and Value

These are the actual values {{< shortName >}} will be (respectively) looking for and inserting into the binary file. When it runs, {{< appName >}} will load the file into memory, parse the file (more on that below), look for _any_ values that match the **template** value and then apply the **value**. How exactly the value is applied varies based on the patch _type_.

Templates are covered in more detail in the [Property Templates](../template) section.

#### Types

The two main types of patches currently in use are:

|Type|Notes|
|:--:|:----|
|`propertyValue`|This is by far the most common/useful and for good reason: it's the most useful and versatile type. It sets the value of matching properties to the given value.|
|`arrayPropertyValue`|Sibling type to `propertyValue` that creates/inserts an array value to the given properties using a simple array syntax|
|`modifyPropertyValue`|Modifies a numeric value _based on it's existing value_.|
|`textProperty`|Specialized patch type for working UE4's TextProperty fields more effectively.

Most of these types use a common convention for the `value` field: `DataType:value`. This ensures that the properties are set with the correct data types the game uses. Note that other patch types might not use the same convention.

##### Special Patch Types

The 4 patch types above will handle the vast majority of Sicario patches reasonably well, but there's two patch types that deserve extra attention: `objectRef` and `duplicateEntry`

> Both of these are much more complex to get working right and I'd recommend you start with the simpler changes handled by the regular patch types.
###### `duplicateEntry` and `duplicateProperty`

This one is pretty powerful as its the most reliable way to _add_ new properties to an existing object, by duplicating an existing property of an object. Adding a new property just requires matching the parent property, then specifying the source property's name and and the duplicate property's (unique) name.

Here's a patch that adds a new weapon based on the STDM:

```json
{
"description": "Clone MSSL",
"template": "datatable:[*]",
"value": "'MSSL'>'MSTM'",
"type": "duplicateEntry"
}
```

The template just matches the top-level datatable (i.e. all entries in the table) and the value follows the simple pattern of `'SourceName':'TargetName'` so you can specify the row to be duplicated (i.e. the `MSSL` row) and what the new row should be named (`MSTM`). This will take a copy of the `MSSL` property data and add it as a new property to the end of the datatable.

> `duplicateProperty` follows the same logic but for duplicating properties on an object rather than the whole object. It's a bit more niche.
Note that as covered in the "Patch Set Grouping" section above, patch sets are _matched_ together, so if you add a new property then want to match that property in later patches, make sure they're in a separate patch _set_.

###### `objectRef`

The `objectRef` patch type is used to change what object a property refers to. Internally, UE4 refers to objects using links that seem kind of convoluted on the surface: the property just has a number referring to an entry in the linked class list, which refers to another entry in the linked class list which then refers to an entry in the header list. That's a mess, so the `objectRef` patch type will handle updating each of those parts in order.

For example, here's a patch that changes what texture the first skin slot on the F-16C uses:

```json
{
"description": "Change the default skin 1",
"template": "datatable:['F-16C'].[0].{'SkinLibraryLegacy*'}.[[0]]",
"value": "'F16Custom_01':'/Game/Assets/Objects/Aircraft/F16C/Textures/Skin/F16Custom_01'",
"type": "objectRef"
}
```

You'll note that the template syntax is the same as always: just use the template that matches the linked property you want to change. The value syntax though is a little different, and can best be summed up as `'ObjectName':'ObjectPath'`. Simply specify what object that property should link to and the patch type will handle updating the linked classes and header list.
8 changes: 5 additions & 3 deletions docs/content/en/patches/walkthrough/template.md
Expand Up @@ -24,7 +24,7 @@ This is the most daunting part to understand, but really isn't as bad as it look
datatable:{'BaseStats*'}.{'CanUseAoA*'}
```

First off, the easy part: the type. The `datatable:` tells Sicario to load the file as a UE4 DataTable and returns every row. Next up is a set of filters separated by `.`s. In our case, both filters are doing the same thing: returning only the struct properties with a name that starts with the string `BaseStats`. Next, the result of that filter (i.e. a bunch of properties named `BaseStats`) are passed into the second filter. That filter just returns any struct properties with a name that starts with `CanUseAoA`. All the properties that match that last filter are passed directly to the patch type to have the value modified.
First off, the easy part: the type. The `datatable:` tells Sicario to load the file as a UE4 DataTable and returns every row. Next up is a set of filters separated by `.`s. In our case, both filters are doing the same thing: returning only the struct properties with a name that starts with a certain string, first off `BaseStats`. Next, the result of that filter (i.e. a bunch of properties named `BaseStats`) are passed into the second filter. That filter just returns any struct properties with a name that starts with `CanUseAoA`. All the properties that match that last filter are passed directly to the patch type to have the value modified.

#### Example in Action

Expand Down Expand Up @@ -93,7 +93,7 @@ Now if we step through this one again, you'll see a few new filters, but the sam

> The `[]` vs `[[]]` distinction can be tricky. The easiest summary is that `[[]]` matches the _contents_ of an `ArrayProperty`, but `[]` just matches the first property it sees and returns the whole property
Now that's a lot of filters, the result of which is that of the entire lengthy and complex `DB_Aircraft` datatable, that result returns exactly **one** thing: the _unmodded_ second weapon hardpoint for the FC-15.
Now that's a lot of filters, the result of which is that out of the entire lengthy and complex `DB_Aircraft` datatable, that result returns exactly **one** thing: the _unmodded_ second weapon hardpoint for the FC-15.

While they can be tricky to make, a well-written template will ensure that you only change the values you want and can even ensure that you don't overwrite modded values, allowing users to merge your patch with others better.

Expand All @@ -112,4 +112,6 @@ Here's a very brief summary of the available filters for use in templates:
|`<string>`|`<IntProperty>`, `<StructProperty>`|Matches only the incoming properties of the specific given type|
|`<string=int>`|`<IntProperty=2>`, `<FloatProperty=1.5>`|Matches only incoming properties of the specific type *and* specific value|
|`<string='string'>`|`<StrProperty='saa,mlaa'>`|Same as above, but for non-numeric types|
|`<string::string>`|`<S_CannonType::NewEnumerator2>`|Matches only enum properties, with the right enum type and the right enum value|
|`<string::string>`|`<S_CannonType::NewEnumerator2>`|Matches only enum properties, with the right enum type and the right enum value|

There's also one special filter: `[*]`. That filter will just match everything and return all the properties it receives. This can be useful if you're trying to match a whole datatable for example.

0 comments on commit 0c99584

Please sign in to comment.