Skip to content

LEGACY Tutorial Game Extension Creation with Harmony

Simon Davies edited this page May 1, 2024 · 4 revisions

Vortex extensions can import/require the “harmony-patcher” module as you do with any other JS module. The module currently exports several functions:

  • “runPatcher” which is used to start up the patcher executable and patch the targeted game assembly
  • “addLoadOrderPage” Which as the name suggests, will add a “Load Order” for the user to organize his mods
  • “raiseConsentDialog” a pre-defined, dialog which can be used to inform users that their game needs to be patched, and give them a chance to cancel the patching mechanism. (Should not be used with the “harmonypatchmod” modtype, more on that below)

The image below shows how to add the runPatcher function to your game extension. Please note we’re also defining a set of constants which we expect to use with the patcher, in this case we’re modding the “Untitled Goose Game”.

alt text

runPatcher()

The runPatcher function expects up to 8 arguments:

alt text

  • The extension’s folder (extensionPath: string)
  • Path to the game assembly’s file (dataPath: string)
  • The entry point; the patcher function call will be injected right at the start of the provided method. (Must respect the ‘Namespace.Classname::Method’ format) (entryPoint: string)
  • Boolean which tells the patcher executable whether we want to remove or inject the patch functions (remove: boolean)

All below arguments are optional and only available when using Vortex 1.2.0 and above

  • (Optional) The mods path; when omitted the mods folder will be generated alongside the game’s assembly “VortexMods” by default. Alternatively game extensions can define a custom mods path as long as it is within the game’s root folder e.g. “../UntitledGoose/Mods”. (modsPath: string)
  • (Optional) Vortex’s extension context object - used to raise error notifications within Vortex’s UI. These will be logged inside vortex.log when the API object is omitted. (context: IExtensionContext)
  • (Optional) Vortex’s In-Game Overlay component (VIGO) will deploy by default unless the game extension opts out (injectVIGO: boolean)
  • (Optional) (VIGO/Unity3D specific) - Some game assemblies we wish to patch might be located in a different directory from the UnityEngine libraries. In this case if we wish to build VIGO, the final argument allows us to tell the patcher where the UnityEngine libraries are located (This is primarily used by the harmonypatchermod mod type) (unityEngineDir: string)

alt text

In the case of “Untitled Goose Game” (UGG) we call the runPatcher function during our extension’s setup step which will attempt to patch the game assembly every time UGG game mode is activated inside Vortex; this is fine as the patcher will identify whether the game has already been patched and will not re-inject if the patch is present.

Choosing an entry-point for your game extension may be tricky and will differ between games but here are a few guidelines:

Most game developers usually follow the singleton design pattern for things like Game Managers, Audio Managers, Animation Managers or even UI Managers; the primary aim is to find a class/object which is instantiated once at the beginning of the game, and hopefully persists throughout the game’s life cycle; that being said, avoid choosing methods which are invoked more than once - the patch call should only execute once.

If the game is created using the Unity3D game engine, there’s a very good chance that the singletons are MonoBehaviour derived which means that the “Awake” and “Start” functions are perfect to inject the patch into.

addLoadOrderPage()

alt text

If mod load ordering is required, the patcher module can register and create a load order page where game extension users can organize their mods. To use this simply import the function from the harmony-patcher module and call it immediately after registering the game extension.

alt text

alt text

The function expects up to 7 arguments:

  • The extension context object which is passed to the game extension upon initialization (context: IExtensionContext)
  • The Nexus Mods game id. (gameId: string)
  • Information that the user may consider important, this will be displayed in a different panel next to the mods. (loadOrderInfo: string)
  • The path to the game’s default gameart/logo.
  • (optional) The preSort functor allows game extensions to intervene right before the load order table applies its sort functionality and displays the mods to the user. It can be used to add/modify/remove mod display entries from the table, this is helpful if for example a certain mod entry must always be locked to a certain table position due to a game specific reason.
  • (optional) The filter functor allows the game extension to filter out unwanted mod entries entirely - for example we do not want to include mod entries of a certain mod type (harmonypatchermod mod type is ignored by default)
  • (optional) The callback functor is called whenever a change has been made to the load order itself - it allows game extensions to react to the change immediately. This is useful when the game extension needs to run game specific logic such as writing the new load order to a file. Please note: Currently the load_order.txt file (used by the Vortex mod loader) will be written to automatically upon any load order change - there is no need to do this yourself.

alt text

The “Load order” tab will appear in the navigation panel alongside “Mods” as seen in the screenshot above. Clicking the tab will open the page.

raiseConsentDialog()

alt text

This function can be used to inform the user that his game assemblies require patching and ask him to give consent prior to allowing the patcher to execute. It expects two arguments:

  • The extension context object which should be passed from the game extension.
  • The Nexus Mods game id/domain name.
  • (Optional) default text for the dialog is provided by default - but if needed, the extension writer is able to provide custom text instead.

The usage example below will ensure that the consent dialog appears before we even create the modding directory. Responding negatively to the consent dialog will not allow the user to proceed, and will deactivate the game extension.

alt text

alt text

The reversal text depends on patch method.

Automated patch application and removal (Vortex 1.2.0 and above)

A new patching mechanism has been added for Vortex 1.2.0 and above which will provide a simpler patching methodology. To use this method, a “harmonyPatchDetails” object needs to be defined when registering the game extension, providing the dataPath (path to game assembly), entry point, mods path and finally specifying whether VIGO is required.

alt text

When using this method, the patch functions will be added/removed upon every deploy/purge event. Additionally, This will create a new “Vortex Harmony Mod” which will contain a patched copy of the original game assembly, alongside any other assemblies which are required by the patch inside Vortex’s staging folder. This ensures that the user has full control of the patch’s status as he is able to enable/disable this as he does with any mod.

alt text

Vortex

Games

Starfield

  • Troubleshooting
  • Developers

Baldur's Gate 3

  • Troubleshooting
  • Developers
  • Valheim
  • Bannerlord

Tools

  • BepInEx

Developers

Extensions

Outdated Documentation

Warning

The below documentation has not been checked for quality since migrating to GitHub Wiki and the information contained is potentially out of date and\or repeated.

Modding.wiki (Users)

General

User Interface

Game Guides

Troubleshooting

Modding.wiki (Developers)

General

Reference

Troubleshooting

Other links

Legacy

General

Tutorial

UI

Language

Feature

Harmony Patcher

Other

Clone this wiki locally