HoloPatcher README for mod developers - OpenKotOR/PyKotor GitHub Wiki
This page explains how to package and test a mod with HoloPatcher. If you are installing a mod as a player, see Installing Mods with HoloPatcher.
Creating a HoloPatcher mod
HoloPatcher is PyKotor's modern implementation of the TSLPatcher workflow. For mod authors, the main promise is continuity: the patch format stays compatible with established TSLPatcher packaging, while the surrounding tooling is easier to inspect, test, and extend.
Start with TSLPatcher's Official Readme if you need the original syntax reference. Use this page for the practical author workflow, current PyKotor-backed behavior, and the places where HoloPatcher documents features more clearly than the historical readme did.
Verified against source files:
Libraries/PyKotor/src/pykotor/tslpatcher/- core parser, patch model, and merge logicLibraries/PyKotor/src/pykotor/tslpatcher/mods/- per-format patch implementationsTools/HoloPatcher/src/holopatcher/- GUI flow, namespace handling, logging, and backup behavior
Implementation: Libraries/PyKotor/src/pykotor/tslpatcher/
Other mod installers and managers:
-
TSLPatcher - Original Perl TSLPatcher by stoffe (reference implementation)
-
Kotor-Patch-Manager - Alternative mod manager with different patching approach
-
KotORModSync — Multi-mod workflows, profiles, and install orchestration (complements HoloPatcher; does not replace INI patch semantics)
- Canonical (th3w1zard1/KotORModSync): https://github.com/th3w1zard1/KotORModSync/tree/c8b0d10ce3fd7525d593d34a3be8d151da7d3387
KotORModSync in practice: Use HoloPatcher (or equivalent) to apply each mod’s tslpatchdata to a game installation. Use KotORModSync when you need help tracking, ordering, or syncing many installs across folders or team members. It is not a drop-in substitute for reading [2DAList] / [TLKList] rules—those remain defined by TSLPatcher/HoloPatcher INI. Repository: th3w1zard1/KotORModSync (verify file paths on the repo default branch before adding deep #L links in the wiki).
Community context: End users and mod authors often coordinate around Deadly Stream — HoloPatcher (downloads + discussion). Large distributions such as KOTOR 1 Community Patch show what real-world HoloPatcher packaging looks like. Use those releases for workflow examples and player expectations; use this wiki and the TSLPatcher syntax pages as the source of truth for INI semantics.
Related PyKotor Tools:
Tools/HolocronToolset/- Integrated HoloPatcher GUILibraries/PyKotor/src/pykotor/tslpatcher/mods/- Individual patching modules
See also
- TSLPatcher's Official Readme - Original documentation
- Installing Mods with HoloPatcher - Player-facing install and restore flow
- TSLPatcher InstallList Syntax - file installation
- TSLPatcher TLKList Syntax - TLK patching
- TSLPatcher 2DAList Syntax - 2DA patching
- TSLPatcher GFFList Syntax - GFF patching
- TSLPatcher SSFList Syntax - SSF patching
- TSLPatcher HACKList Syntax - Advanced NCS binary patching
- Explanations on HoloPatcher Internal Logic - Internal component flow and patch-routine behavior
- Mod Creation Best Practices - General modding guidelines
Walkthrough: first HoloPatcher mod (TLK + 2DA + InstallList)
Goal: Ship a minimal TSLPatcher-compatible package that adds a dialog string, touches one 2DA row, and installs one loose file without replacing whole vanilla tables.
Prerequisites:
- TSLPatcher's Official Readme (skim)
- Syntax references open while you work:
- HoloPatcher pointed at a test game copy
Steps:
- Layout:
YourMod/tslpatchdata/changes.iniplus any side files (e.g.mymod.tlkfragment, source 2DA snippet, loose file to copy). - TLK: In
[TLKList], reference a TLK patch file and add or modify rows per TSLPatcher TLKList Syntax. Prefer merge operations over replacing entiredialog.tlkunless you intend a total replacement (replace-style examples appear under TLK replacements in HoloPatcher changes below). - 2DA: In
[2DAList], target a small change (e.g. append one row to a non-critical table in the test install) using TSLPatcher 2DAList Syntax. Use2DAMEMORY/labels so later steps can reference row indices if needed. - InstallList: Add
[InstallList]entries to copy one file (e.g. a test.nssor texture) intooverride/ormodules/per TSLPatcher InstallList Syntax. - Namespaces: If you offer variants, add
namespaces.ini; otherwise onechanges.iniis enough. - Install and inspect: Run HoloPatcher against a test install and read the log before you launch the game.
Verify in-game: Confirm the loose file appears where expected, then confirm the TLK and 2DA changes in a tool or test dialogue before shipping.
Alternatives: For learning GFF-only flows, follow Tutorial: Creating a new store in Holocron. For headless builds, use CLI quickstart.
Common failures: pointing the patcher at override/ instead of the game root, reinstalling the same option without restore backup, and shipping bad relative paths in InstallList. See Mod Creation Best Practices.
HoloPatcher changes & New Features
TLK replacements
- This is not recommended under most scenarios. You usually want to append a new entry and update your DLGs to point to it using StrRef in the ini. However for projects like the k1cp and mods that fix grammatical/spelling mistakes, this may be useful.
The basic syntax is:
[TLKList]
ReplaceFile0=tlk_modifications_file.tlk
[tlk_modifications_file.tlk]
StrRef0=2
This will replace StrRef0 in dialog.tlk with StrRef2 from tlk_modifications_file.tlk.
See our tests for more examples. Don't use the 'ignore' syntax or the 'range' syntax, these won't be documented or supported until further notice.
HACKList (Editing NCS directly)
This is a TSLPatcher feature that was not documented in the TSLPatcher readme. Public examples are rare. The main known references are Stoffe's HLFP mod and a few historical forum archives.
Due to this feature being highly undocumented and only one known usage, our implementation might not match exactly. If you happen to find an old TSLPatcher mod that produces different HACKList results than HoloPatcher, please report them here
In continuation, HoloPatcher's [HACKList] will use the following syntax:
[HACKList]
File0=script_to_modify.NCS
[script_to_modify.ncs]
20=StrRef5
40=2DAMEMORY10
60=65535
This will:
- Modify offset dec 20 (hex 0x14) of
script_to_modify.ncsand overwrite that offset with the value of StrRef5. - Modify offset dec 40 (hex 0x28) of
script_to_modify.ncsand overwrite that offset with the value of 2DAMEMORY10. - Modify offset dec 60 (hex 0x3C) of
script_to_modify.ncsand overwrite that offset with the value of dec 65535 (hex 0xFFFF) i.e. the maximum possible value. In short, HACKList writes unsigned WORD values (two bytes each) to the NCS offsets named in the INI.
For more information on HoloPatcher's implementation
pykotor.tslpatcher.reader
pykotor.tslpatcher.mods.ncs
See also
- Installing Mods with HoloPatcher -- End-user installation
- TSLPatcher's Official Readme -- TSLPatcher syntax
- TSLPatcher TLKList
- TSLPatcher SSFList -- Other patch lists
- Explanations on HoloPatcher Internal Logic -- Implementation
- Container-Formats#key -- Resource resolution
- Community sources and archives -- DeadlyStream, LucasForums for patching workflows