6. Config Patching

Updated 2 days ago

What is this?

The patching system was created in version 0.9.3. All version 0.11.X of the mod require patches to change the advanced configurations. In Version 0.12.0 a new system was implemented to allow changing the default configurations more easily. Read more about this below.

Patch files allow you to target and change as little or as many values as you desire and allows you to easily redistribute changes in your modpacks. The smaller and more specific your patches are the easier it will be to manage future updates of this mod.

Our hope is that mod and modpack authors can use this system to simply and easily create amazing custom content and configurations for Epic Loot without as much hassle.

As of 0.12.0, the current list of built-in config files are:

  • abilities.json
  • adventuredata.json
  • enchantcosts.json
  • iteminfo.json
  • itemnames.json
  • legendaries.json
  • loottables.json
  • magiceffects.json
  • materialconversions.json
  • recipes.json

Any of these files can be patched by the patching system.

Changing the baseconfig (FIRST STEP!)

Upon first launch with epic Loot installed the mod configurations will be automatically generated based on the default configurations and any existing patch files. The files will be saved under the BepInEx\config\EpicLoot\baseconfig folder. The game will use these configurations once generated, allowing easy manual editing.

However, once these files are generated they will NOT update when you edit your patches.

How does one update these files? There are two options:

  1. Delete them manually.
  2. Set the BepInEx\config\randyknapp.mods.epicloot.cfg file setting Debug - Always Refresh Core Configs to true. This will automatically delete them for you on every game restart.

If you are using patches only, and not editing these baseconfig files, we highly recommend turning this setting on to avoid confusion (re: why are my patches not applying!?).

Again please note: Every mod update that changes the default configurations will NOT take effect unless these files are refreshed! We highly encourage learning and using the patching system if you want to keep your changes long term.

Versions 12.0 - 12.2: All of your patches would apply on every startup to the baseconfig file. This was "fixed" in version 12.3 so your changes will no longer be overwritten by patches.

image

Quick Tips

This process may seem overwhelming, but can be worth the time if you plan on keeping your configs long term. Some examples can be found on github here. There are other examples in the discord, come join the conversation!

Use these as a base and continue reading the instructions below.

Translations?

The translation files are no longer patched with this system. Follow these steps to make changes:

  1. Download the base file from github here and make edits as desired.
  2. Name the file after your language such as Spanish.json. The localization files in the localization directory must use one of the game language names, Jotunn has a list here.
  3. Place this file in the BepInEx\config\EpicLoot\localizations\ directory.

Please watch the patchnotes for additions to the base translations file. Looking at the git commit history can help determine which keys you are missing upon mod updates.

Add Patch Files

All Epic Loot config patches live in "patch files", which are json files placed in a special config folder located at Valheim\BepInEx\config\EpicLoot\patches.

Screenshot 2023-01-22 061059 image

Patch Folder Structure

Within the "patches" folder, there can be any number of sub-folders and it is recommended that your patch files are put in folders with distinct and unique names related to the author or modpack that created them. For example, if Epic Loot were to release a set of optional patches that changed the loottables just for Meadows creatures, we might install those patch files in folder structure something like: <BepInEx Config Directory>\EpicLoot\patches\randyknapp\meadowsoverhaul. That way, if we release a similar set of patches for a different biome, we could install the new patches in a folder of a different name, but within the randyknapp folder.

Patch File Names

There are two ways to name your patch files:

  1. Name them the exact same name as the file that you want to patch
  2. Name them whatever you want, and specify which config file they patch within the file itself

The easiest option is #1. Creating a file called loottables.json or adventuredata.json in your patch folder will set it up so that all patches in those files will automatically be applied to their respective config files.

However, if you want to name your patch files easy to understand or memorable names for organizational purposes that is fine. Inside the file you'll be able to specify which config file the patches are targeting.

Setup Patch File

Each patch file is a json file, and therefor must be edited with a text editor. If you don't already have an IDE for modding (like Visual Studio, Rider, or VS Code), I recommend Sublime Text or Notepad++ for editing json files.

Epic Loot's json files are technically cjson, which is an extension of json that allows C++ style comments. Some text editors do not like that when doing syntax highlighting for json files and we're sorry about that.

As a json file, the main part of the file must be an object. And the main object type for our patch files is the PatchFile class (see FilePatching.cs).

Here is an example of a patch file (without any patches yet) with all the fields filled in:

{
  "TargetFile": "adventuredata.json", 
  "Author": "RandyKnapp",
  "Priority": 500,
  "RequireAll": true, 
  "Patches": []
}

TargetFile (string)

If your file is not named exactly the same as one of the base config files, this field is required. If your file is named the same as one of the base config files and you specify a different config file in this field, the patch will use the one specified in the TargetFile field, but it will spit out a warning at you.

The value of this field will be used as the default value for the TargetFile field of each patch (see next section) if it is not specified.

Author (string)

Purely for documentation purpose, this field can be any string that identifies the individual or team that published the patch.

Priority (int)

This Priority field indicates the order in which patches will be executed. It must be a positive integer between 0 and 1000 (inclusive). 1000 is the highest priority and will be applied first, 0 is the lowest and will be applied last.

The value of this field is used as the default value for the Priority field of each patch if it is not specified. The default value for this field if unspecified is 500.

RequireAll (bool)

The RequireAll field is a boolean (true/false) field indicating if all the patches in this file are "required". A "required" patch means that if the patch's Path (see the Setup Patches section) does not select any json tokens from the base config file, an error will be thrown. Sometimes it is valuable if you are optionally patching someone else's patches that may or may not be loaded by the player to have it simply ignore failed patches if the item they are trying to patch doesn't exist.

If set to true, all patches will have their Required field overwritten to true. If set to false, each patch can set its own Required field (which defaults to false if not provided). The default value of RequireAll if unspecified is false.

Patches (array of Patch objects)

This array holds all the patches that you want to apply. It will be a comma separated list of objects, each containing the patch data.

"Patches": [
  {
    // patch data...
  },
  {
    // patch data...
  }
]

Setup Patches

Now that you've set up the file properties, you can go about creating any number of patches. Each patch has several fields which will be explained in detail below. Most fields are optional and will be set to the default values if you omit them in your patch file.

{
  "Priority": 500,
  "TargetFile": "adventuredata.json",
  "Required": true,
  "Path": "$.SecretStash.OtherItems[?(@.CoinsCost < 300)]",
  "Action": "Add",
  "PropertyName": "ForestTokenCost",
  "Value": 10
},

Priority (int)

Like the Priority of the file object, each individual patch can set its own priority that will override the default priority set in the file. This field indicates the order in which patches will be executed. It must be a positive integer between 0 and 1000 (inclusive). 1000 is the highest priority and will be applied first, 0 is the lowest and will be applied last.

If unspecified, the default value for this field is whatever is set in the Priority field of the file object.

TargetFile (string)

It is perfectly okay to have a single file with patches being applied to many different base config files. If a TargetFile field is not specified in the file object itself, then each patch must specify which config file they wish to patch.

An error will be thrown and the patch will be skipped if both the file and the patch are missing the TargetFile field, or if the file specified is not one of the files listed at the beginning of this article.

Required (bool)

The Required field is a boolean (true/false) field indicating if this patch is "required". A "required" patch means that if the patch's Path (see below) does not select any json tokens from the base config file, an error will be thrown. Sometimes it is valuable if you are optionally patching someone else's patches that may or may not be loaded by the player to have it simply ignore failed patches if the item they are trying to patch doesn't exist.

If set to true, this patch will be required. If omitted or set to false, this patch will use the value of the RequireAll field of the file object.

Path (JsonPath string)

This complex string tells the patching system exactly which part or parts of the target file you want to change. It uses the JsonPath syntax by Stefan Goessner, which can be found in brief here: JsonPath Specification

EpicLoot is now using the Newtonsoft Json Parser for .NET. You can find examples of how JsonPath is used to select json tokens here: Json.NET Docs - Querying JSON with JsonPath

This patch can resolve to zero, one, or many tokens in the file. If the patch is Required (see below), and the path resolves to zero selected tokens, then an error will be displayed in the BepInEx console.

Once the path resolves to some number of tokens, the patch Action (see below) will be taken against each of those tokens.

In the example above:

"Path": "$.SecretStash.OtherItems[?(@.CoinsCost < 300)]",

the path will select the "SecretStash" object at the root of the adventuredata.json file, then select its child object called "OtherItems", which is an array, and then it will select every object in that array that has a property "CoinsCost" of less than 300. Remember, this can result in selecting multiple tokens.

Action (string, one of an enumeration)

The Action field can be set to one of the following values, and each one does something different when the patch is applied to the selected token.

Action         What it does
-----------------------------------------------------------------------------------------------------------------
None           Do nothing.

Add            Add the provided value to the selected object with the provided property name, if the property 
               already exists, it's value is overwritten.
                 Must be specified: Value, PropertyName

Overwrite      Replace the selected token's value with the provided value.
                 Must be specified: Value

Remove         Remove the selected token from the array or object.

Append         Append the provided value to the end of the selected array.
                 Must be specified: Value

AppendAll      Append the provided array value to the end of the selected array.
                 Must be specified: Value (must be an array)

InsertBefore   Insert the provided value into the array containing the selected token, before the token.
                 Must be specified: Value

InsertAfter    Insert the provided value into the array containing the selected token, after the token.
                 Must be specified: Value

RemoveAll      Remove all elements of an array or all properties of an object.

PropertyName (string)

This optional field specifies the name of the property when patching using the Add action from above. It is only needed when the patch is using the Add action.

Value (any valid json)

The Value field of the patch can contain any valid json value you want. The entirety of this value will be added, used to overwrite, inserted, or appended to the token(s) selected by this patch's Path. When using AppendAll, Value must be an Array ("Value" : []).

Happy patching!

If you have any questions, please join the RandyKnapp Modding Discord and ask: RandyKnapp's Mod Community