Due to data-driven structure with exposed config files, Phantom Brigade has always been fairly easy to modify. By modifying any file in the Configs folder, you can create a wide range of mods (altering scenarios, rebalancing equipment, adding new units or localization, etc.). However, this approach to modding has some issues and limitations:
simulation.yaml, no other mod could modify anything reliant on that file
This new modding system is an attempt to solve all these issues. It closely follows modding systems in popular moddable Unity games. To start, you need to do the following:
mods.yamlfile and place it into
C:\Users\[USER]\AppData\Local\PhantomBrigade\Settingsfolder. See examples of file content above.
listis empty or matches existing folders in required format (more on that below)
metadata.yamlfile that provides some essential information about content of the mod to the game, allowing for loading it and for drawing of mod management UI
a.b.c, for example
0.16.0etc. - do not include any suffixes like
-b3103Eyou see in build info watermark)
enabledproperty set to
true, new main menu option will appear in the game - Mods menu
metadata.yamlin a given folder
mods.yaml- the UI is just an interface modifying that property in the config.
mods.yamlfrom disk and update the UI accordingly.
Warning! The game already applies mods on startup (based on config state at that point). The option to “Apply Mods” available in the menu above is not the recommended way to applying changes in mod configuration and could cause unforeseen issues. If you change something in the mod menu, e.g. disable, enable or reorder mods, we recommend to hit “Save Config” and restart the game to see the effects. Furthermore, there is no support for loading library mods (code injection mods) more than once per session, as it is impossible to undo unpredictable changes they might make to the runtime - any such mod will be skipped if the game already loaded a code mod during the current session. However, this option can be useful for quickly checking changes while developing config mods and in other such cases.
Mod directories listed in
list property in
mods.yaml (included and activated via mod menu or manual editing of this config) will be analyzed by the game on startup. Based on information provided in
metadata.yaml , the game will check the mod for compatibility with current version and will traverse contents of its folder, attempting to load it. See subsequent sections for details on supported mod content types.
Mods can include several so-called content types. These are represented by subfolders in the mod folder and their presence is declared in
metadata.yaml. The set of supported content types will be expanded over time to include more (like localizations), but for now, the four following types are supported.
This is the simplest possible type of mod content, quite similar to editing Configs folder directly.
This content type allows for much more fine grained modifications resistant to multiple mods modifying the same file, file changing shape when game is updated etc.
Mods/[ModName]/ConfigEditsand put your .yaml matching path/name of existing
simulation.yamlcontains hundreds of parameters, and many different mods will definitely want to modify it, whether it's to change allowed squad size of physics settings or loot generation multipliers.
simulation.yamlfile modifying a line called
squadSizeand another can have
simulation.yamldescribing changes to couple other fields - and every change will be seamlessly merged. It's as if every single collection entry or field in our configs is a separate .yaml or a separate folder, allowing for very targeted changes.
The format of these edit configs is relatively simple.
removedto true to remove targeted config from the game (for instance, if your mod replaces parts of the arsenal and needs to remove built-in weapons from the game)
editsfield to perform fine grained changes in targeted config
-, just like any serialized
List<T>in other configs.
- 'hidden: true'. This enables you to use reserved characters anywhere within the line.
:- left side is a path, and right side is a value
squadSizeto a value of
3you can just type:
- ‘squadSize: 3’.
.- for instance, here is a modification to a field nested 1 level deep:
- 'customPlayerSlot.spawnTagsUsed: true'.
- ‘states.no_hostiles.visible: false’(
no_hostilesis a dictionary key here);
0is a list index here!)
editsfield is not a dictionary. For instance, it's totally fine to modify tags field once (e.g. removing something) and then modify it again (e.g. to add something)
float.TryParse. An example would be
(3.1, 4, 7.2)etc.
!d(for “default”). Use it like so:
- 'customExitBehaviour: !d'
- ‘field: 7’- overwrite field named
fieldwith value of 7
List<T>, the following operations are supported:
- ‘list.4: 7’- overwrite index 4 in list named
listwith value of 7
- ‘list.0: 7 !+’- insert value of 7 to the very beginning of the list
- 'list.8: 7 !+'- insert value of 7 to index 8 (if list has more entries) or just to the very end of the list (if list has fewer entries than 8)
- 'list.3: !-- remove entry at index 3
HashSet<string>, the following operations are supported:
- 'tags: context_facility !+'- attempt to insert the string
context_facilityto the hash set
- 'tags: context_fort !-'- attempt to remove the string
context_fortfrom the hash set
Dictionary<T>, the following operations are supported:
- ‘dictionary.existing_key: true’- overwrite value at key
existing_keyin dictionary named
dictionarywith value of
- ‘dictionary.new_key: true !+’- attempt to insert value of
truewith new key
new_keyinto the dictionary
- 'dictionary.existing_key: !-- attempt to remove the entry with key
This is a very powerful type of mod content enabled by C#/Unity's reliance on editable interpreted language (IL): ability to load libraries that can patch game logic and execute new code.
ModLink- if found, it's instantiated, filled with data, and has a special entry method invoked
ModLinkprovides an entry point to modders: you can declare an override to
OnLoadmethod in it, executing arbitrary code; you get access to full mod metadata (so you know where you are, what mod you're in, what other mods are loaded) and access to the Harmony patcher object, allowing you to modify code in PB.
General setup of a new library goes as follows:
0Harmony.dlldownloaded from 2.1 release on Harmony website (future releases of Phantom Brigade might include it directly in the Managed folder above)
UnityEngine.dllfrom your install folder, e.g.
Entitas.dllfrom your install folder
idfield in your
public class ModTestLink : ModLink
OnLoadwith this signature:
public override void OnLoad (Harmony harmonyInstance)
metadatafield that can tell you what folder you're working with, what mod is this library loaded in, etc; access
ModManager.loadedModsto interact with other mods, access any game classes, perform custom patching procedures using
Harmonyobject passed into the method etc.
[HarmonyPatch (typeof (PhantomBrigade.GameController), MethodType.Normal), HarmonyPatch ("Initialize")]
OnLoadoverride and comment out
base.OnLoad (harmonyInstance)call in it.
This content type allows you to overwrite existing textures or extend the set of available textures:
This type of content payload enables you to add text to the localization database. It is rare (and will be even rare in the future) that data files under
Configs/DataDecomposed contain any player facing text, since storing text that way prevents the possibility of localization and easy text modification. Most of the text in the game will eventually be stored in localization database, under
Configs/Text, split into versions for different languages. This poses a problem to mods, however - if you add a new item, and the text for it is not stored in the main data config, how do you add player facing text for it?
For an example, if you're adding a new thruster subsystem, you definitely want it to have a name and a description. But name and description do not come from subsystem config, since the game supports their localization - the game takes the subsystem name like
internal_aux_thruster_mod, decides on localization keys based on it, like
internal_aux_thruster_mod__text and tries to fetch text using these keys from the appropriate text sector of the loaded language (e.g.
Configs/Text/English/Sectors/equipment_subsystems.yaml. Without ability to mod these text sectors, your new item can't have a user-facing name/description.
How this type of content can be used is highlighted on the screenshot above, but just in case, here is a step by step overview:
ConfigOverrides\DataDecomposed\Equipment\Subsystemscalled internal_aux_thruster_mod.yaml. Such a file doesn't exist in the base game - it's a new item, not a modified one. The game can't show any text for it.
Configs\Text\English\Sectorsin the game install folder for name of an existing subsystem, like internal_aux_thruster_hotrod, to see which sector file such text is stored in and how the text keys are structured.
Internally, localization edits are applied every time the game loads language database and a registered per language key, which means that:
MyMod\LocalizationEdits\English\equipment_subsystems.yamlfile to add text to players using English but you can also add a second file at
MyMod\LocalizationEdits\Japanese\equipment_subsystems.yamlto add support for Japanese localization. Or someone can make a new mod extending your mod, containing localization for a first mod for a specific language.
Here is an example: this item doesn't exist in base game and was added by a mod, and the game properly displays custom name and description depicted in file screenshots in previous image:
This content type allows you to add entire new localizations to the game. General principle is as follows:
Configs/Textinto MyMod/Localizations, rename it to the language you are localizing the game into, e.g.
Some additional notes:
data.toggle-localization-debug, which will render all localized text in a different color and randomize its content
Keep an eye out on game log - it will contain plenty of information from mod manager in case anything goes wrong, or confirmation of successful loading if everything goes well. Look for messages towards very beginning of the log, prefixed with “Mod Manager”. To look at the log, press Shift+F11 or open the log file in application data folder.
It might also be useful to enable
developerMode property in
debug.yaml in AppData\Local\PhantomBrigade\Settings to get access to additional options, debug information and console commands while developing a mod.
Note that no bug reports or crashes from a game in developer mode or with active mods will be processed by BYG.