This is an official reference page. If you encounter inaccuracies or would like to expand the page, please message the developers in the #phantom-modding channel on BYG Discord.
This page details the design of the modding system in Phantom Brigade and is intended for mod developers. If you're looking for mod installation instructions or general guidelines, please refer to the top level Modding page.
Due to data-driven structure with exposed config files, Phantom Brigade could always be modified directly. It's possible to alter scenarios, rebalance equipment, adding new units or localization, etc. by changing files in the installation folder. However, this approach to modding has some issues and limitations:
The modding system is an attempt to solve all these issues. It closely follows the design of the mod systems in other popular moddable Unity games. To start modding, open the AppData/Local/PhantomBrigade/Mods
folder. Versions of the game prior to 1.1 required additional manual setup (manually creating the Mods
folder and Settings/mods.yaml
), but this is no longer necessary.
If you can't find the folder, Windows Explorer settings might be set to hide it on your PC. Please refer to the following web page for details. View hidden files and folders in Windows - Microsoft Support
Alternatively, you can press the "Local mods" button in the Mods tab of the main menu to open the folder.
Each mod gets a separate subfolder, e.g. Mods/MyMod1
, Mods/MyMod2
and so on:
In each mod folder, there should be a metadata.yaml
file that provides some essential information about content of the mod to the game, allowing for loading it and for drawing of mod management UI
The main menu allows you to see all the mods detected in the mod folder:
The game applies mods on startup. If you install, disable or re-enable a mod, you will need to restart the game to see the effects.
Mods can include different 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 has expanded over time to include configs, localizations, images and more.
includesConfigOverrides
ConfigOverrides/
This is the simplest possible type of mod content, quite similar to editing Configs folder directly.
includesConfigEdits
ConfigEdits/
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]/ConfigEdits
and put your .yaml matching path/name of existingsimulation.yaml
contains 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.yaml
file modifying a line called squadSize
and another can have simulation.yaml
describing 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.
removed
to 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)edits
field 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
squadSize
to a value of 3
you 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_hostiles
is a dictionary key here); unitChecks.0.value: 1
(0
is a list index here!)edits
field is not a dictionary. For instance, it's totally fine to modify a tags
collection once (e.g. removing something) and then modify it again (e.g. to add something)string
, bool
, int
, float
, Vector2
, Vector3
, Vector4
true
int.TryParse
and float.TryParse
. An example would be 6
, 8.62
etc.(3.1, 4, 7.2)
etc.!d
(for “default”). Use it like so: - 'customExitBehaviour: !d'
- ‘field: 7’
- overwrite field named field
with value of 7List<T>
, the following operations are supported:- ‘list.4: 7’
- overwrite index 4 in list named list
with 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 3HashSet<string>
, the following operations are supported:- 'tags: context_facility !+'
- attempt to insert the string context_facility
to the hash set tags
- 'tags: context_fort !-'
- attempt to remove the string context_fort
from the hash setDictionary<T>
, the following operations are supported:- ‘dictionary.existing_key: true’
- overwrite value at key existing_key
in dictionary named dictionary
with value of true
- ‘dictionary.new_key: true !+’
- attempt to insert value of true
with new key new_key
into the dictionary- 'dictionary.existing_key: !-
- attempt to remove the entry with key existing_key
!+
- add new entry!-
- remove entry!d
- set to default value (for reference types - a new instance, not null)!n
- set to nullColor
fields is not supportedincludesLibraries
Libraries/
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.
Mods/[ModName]/Libraries/MyLibrary.dll
ModLink
- if found, it's instantiated, filled with data, and has a special entry method invokedModLink
provides an entry point to modders: you can declare an override to OnLoad
method 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.dll
downloaded from 2.1 release on Harmony website (future releases of Phantom Brigade might include it directly in the Managed folder above)Assembly-CSharp.dll
, Assembly-CSharp-firstpass.dll
System.dll
and UnityEngine.dll
from your install folder, e.g. PB/PhantomBrigade_Data/Managed/
Entitas.dll
from your install folderModLink.cs
fileid
field in your metadata.yaml
, e.g. ModTest
ModLink
, e.g. public class ModTestLink : ModLink
OnLoad
with this signature: public override void OnLoad (Harmony harmonyInstance)
metadata
field that can tell you what folder you're working with, what mod is this library loaded in, etc; access ModManager.loadedMods
to interact with other mods, access any game classes, perform custom patching procedures using Harmony
object passed into the method etc.Patches
[HarmonyPatch (typeof (PhantomBrigade.GameController), MethodType.Normal), HarmonyPatch ("Initialize")]
OnLoad
override and comment out base.OnLoad (harmonyInstance)
call in it.includesTextures
Textures/
This content type allows you to overwrite existing textures or extend the set of available textures:
image
field in steps
of DataContainerOverworldEvent
(in Configs/DataDecomposed/Overworld/Events)image
field of DataContainerOverworldEntityBlueprint
in (Configs/DataDecomposed/Overworld/Entities)includesLocalizationEdits
LocalizationEdits/
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 Confgs/Data
and 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__name
and 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\Subsystems
called 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\Sectors
in 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.yaml
file to add text to players using English but you can also add a second file at MyMod\LocalizationEdits\Japanese\equipment_subsystems.yaml
to 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:
includesLocalizations
Localizations/
This content type allows you to add entire new localizations to the game. General principle is as follows:
Configs/Text
into MyMod/Localizations, rename it to the language you are localizing the game into, e.g. MyMod/Localizaions/French
Some additional notes:
data.toggle-localization-debug
, which will render all localized text in a different color and randomize its contentKeep 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 Ctrl+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.