This tool is used to create a single .pak file from a collection of mods for an Unreal Engine game. The initial focus will be on supporting STALKER 2 pak mods (notably cfg mods and .ini mods), but more games and file formats may be supported in the future.
Due to the way unreal games load mods, it's impossible to only take some parts of one mod and combine them with parts of another mod unless you manually unpack the .pak files and repack them. This tool automates this process by automatically unpacking the .pak files, resolving any conflicts between the mods, and repacking them into a single .pak file.
- Single binary with no dependencies
- Automatically resolves conflicts between STALKER 2
.cfgfiles on a per-value basis - Automatically resolves conflicts between
.jsonfiles on a per-value basis - Automatically resolves conflicts between Unreal Engine
.inifiles on a per-value basis - Attempts to automatically resolve conflicts for all other file types
- Download the latest release from the latest GitHub release: https://github.com/joe-p/unreal-pak-mod-manager/releases
- Place the
unreal-pak-mod-manager.exein any folder you'd like. This is where all the mods and final modpack will be saved. For example:C:\MyModpack - Double click the
unreal-pak-mod-manager.exeto run it (or run it from the terminal) and you should see
Created default config file: \\?\C:\MyModpack\config.toml
Created mods directory, put pak files here and run this program again to create a modpack: \\?\C:\MyModpack\mods
Press Enter to exit..
- Place all of your
.pakfiles you wish to add to your modpack in themodsfolder next to theunreal-pak-mod-manager.exe - Run
unreal-pak-mod-manager.exeagain and you should see:
Processing the mods in the following order:
0: mods\ZZFrancisLouisSOVer2_P.pak
1: mods\zzz_Grok_Bloodsucker-60percent_HP_P.pak
2: mods\zzz_Grok_Boar-40percent_HP_P.pak
3: mods\zzz_Grok_Burer-40percent_HP_P.pak
4: mods\zzz_Grok_Cat-40percent_HP_P.pak
5: mods\zzz_Grok_Chimera-60percent_HP_P.pak
6: mods\zzz_Grok_Controller-40percent_HP_P.pak
7: mods\zzz_Grok_Deer-20percent_HP_P.pak
8: mods\zzz_Grok_Flesh-40percent_HP_P.pak
9: mods\zzz_Grok_Poltergeist-60percent_HP_P.pak
10: mods\zzz_Grok_PseudoDog-60percent_HP_P.pak
11: mods\zzz_Grok_Pseudogiant-40percent_HP_P.pak
12: mods\~S2optimizedTweaksBASE_v1.91_P.pak
ZZFrancisLouisSOVer2_P.pak: Extracting Engine/Config/Windows/WindowsEngine.ini
ZZFrancisLouisSOVer2_P.pak: Extracting MADE_BY_FRANCISLOUIS.txt
zzz_Grok_Bloodsucker-60percent_HP_P.pak: Extracting Stalker2/Content/GameLite/GameData/ObjPrototypes/Bloodsucker.cfg
zzz_Grok_Boar-40percent_HP_P.pak: Extracting Stalker2/Content/GameLite/GameData/ObjPrototypes/Boar.cfg
zzz_Grok_Burer-40percent_HP_P.pak: Extracting Stalker2/Content/GameLite/GameData/ObjPrototypes/Burer.cfg
zzz_Grok_Cat-40percent_HP_P.pak: Extracting Stalker2/Content/GameLite/GameData/ObjPrototypes/Cat.cfg
zzz_Grok_Chimera-60percent_HP_P.pak: Extracting Stalker2/Content/GameLite/GameData/ObjPrototypes/Chimera.cfg
zzz_Grok_Controller-40percent_HP_P.pak: Extracting Stalker2/Content/GameLite/GameData/ObjPrototypes/Controller.cfg
zzz_Grok_Deer-20percent_HP_P.pak: Extracting Stalker2/Content/GameLite/GameData/ObjPrototypes/Deer.cfg
zzz_Grok_Flesh-40percent_HP_P.pak: Extracting Stalker2/Content/GameLite/GameData/ObjPrototypes/Flesh.cfg
zzz_Grok_Poltergeist-60percent_HP_P.pak: Extracting Stalker2/Content/GameLite/GameData/ObjPrototypes/Poltergeist.cfg
zzz_Grok_PseudoDog-60percent_HP_P.pak: Extracting Stalker2/Content/GameLite/GameData/ObjPrototypes/PseudoDog.cfg
zzz_Grok_Pseudogiant-40percent_HP_P.pak: Extracting Stalker2/Content/GameLite/GameData/ObjPrototypes/Pseudogiant.cfg
~S2optimizedTweaksBASE_v1.91_P.pak: Extracting Engine/Config/Windows/WindowsEngine.ini
~S2optimizedTweaksBASE_v1.91_P.pak: Extracting Stalker2/A message.jpg
ZZFrancisLouisSOVer2_P_pak: Merging with priority 0
ZZFrancisLouisSOVer2_P_pak: Merging files
ZZFrancisLouisSOVer2_P_pak: All files merged without conflicts
zzz_Grok_Bloodsucker-60percent_HP_P_pak: Merging with priority 1
zzz_Grok_Bloodsucker-60percent_HP_P_pak: Merging files
zzz_Grok_Bloodsucker-60percent_HP_P_pak: All files merged without conflicts
zzz_Grok_Boar-40percent_HP_P_pak: Merging with priority 2
zzz_Grok_Boar-40percent_HP_P_pak: Merging files
zzz_Grok_Boar-40percent_HP_P_pak: All files merged without conflicts
zzz_Grok_Burer-40percent_HP_P_pak: Merging with priority 3
zzz_Grok_Burer-40percent_HP_P_pak: Merging files
zzz_Grok_Burer-40percent_HP_P_pak: All files merged without conflicts
zzz_Grok_Cat-40percent_HP_P_pak: Merging with priority 4
zzz_Grok_Cat-40percent_HP_P_pak: Merging files
zzz_Grok_Cat-40percent_HP_P_pak: All files merged without conflicts
zzz_Grok_Chimera-60percent_HP_P_pak: Merging with priority 5
zzz_Grok_Chimera-60percent_HP_P_pak: Merging files
zzz_Grok_Chimera-60percent_HP_P_pak: All files merged without conflicts
zzz_Grok_Controller-40percent_HP_P_pak: Merging with priority 6
zzz_Grok_Controller-40percent_HP_P_pak: Merging files
zzz_Grok_Controller-40percent_HP_P_pak: All files merged without conflicts
zzz_Grok_Deer-20percent_HP_P_pak: Merging with priority 7
zzz_Grok_Deer-20percent_HP_P_pak: Merging files
zzz_Grok_Deer-20percent_HP_P_pak: All files merged without conflicts
zzz_Grok_Flesh-40percent_HP_P_pak: Merging with priority 8
zzz_Grok_Flesh-40percent_HP_P_pak: Merging files
zzz_Grok_Flesh-40percent_HP_P_pak: All files merged without conflicts
zzz_Grok_Poltergeist-60percent_HP_P_pak: Merging with priority 9
zzz_Grok_Poltergeist-60percent_HP_P_pak: Merging files
zzz_Grok_Poltergeist-60percent_HP_P_pak: All files merged without conflicts
zzz_Grok_PseudoDog-60percent_HP_P_pak: Merging with priority 10
zzz_Grok_PseudoDog-60percent_HP_P_pak: Merging files
zzz_Grok_PseudoDog-60percent_HP_P_pak: All files merged without conflicts
zzz_Grok_Pseudogiant-40percent_HP_P_pak: Merging with priority 11
zzz_Grok_Pseudogiant-40percent_HP_P_pak: Merging files
zzz_Grok_Pseudogiant-40percent_HP_P_pak: All files merged without conflicts
_S2optimizedTweaksBASE_v1_91_P_pak: Merging with priority 12
_S2optimizedTweaksBASE_v1_91_P_pak: Merging files
_S2optimizedTweaksBASE_v1_91_P_pak: All files merged without conflicts
upmm_modpack.pak: Packing Engine/Config/Windows/WindowsEngine.ini
upmm_modpack.pak: Packing MADE_BY_FRANCISLOUIS.txt
upmm_modpack.pak: Packing Stalker2/A message.jpg
upmm_modpack.pak: Packing Stalker2/Content/GameLite/GameData/ObjPrototypes/Bloodsucker.cfg
upmm_modpack.pak: Packing Stalker2/Content/GameLite/GameData/ObjPrototypes/Boar.cfg
upmm_modpack.pak: Packing Stalker2/Content/GameLite/GameData/ObjPrototypes/Burer.cfg
upmm_modpack.pak: Packing Stalker2/Content/GameLite/GameData/ObjPrototypes/Cat.cfg
upmm_modpack.pak: Packing Stalker2/Content/GameLite/GameData/ObjPrototypes/Chimera.cfg
upmm_modpack.pak: Packing Stalker2/Content/GameLite/GameData/ObjPrototypes/Controller.cfg
upmm_modpack.pak: Packing Stalker2/Content/GameLite/GameData/ObjPrototypes/Deer.cfg
upmm_modpack.pak: Packing Stalker2/Content/GameLite/GameData/ObjPrototypes/Flesh.cfg
upmm_modpack.pak: Packing Stalker2/Content/GameLite/GameData/ObjPrototypes/Poltergeist.cfg
upmm_modpack.pak: Packing Stalker2/Content/GameLite/GameData/ObjPrototypes/PseudoDog.cfg
upmm_modpack.pak: Packing Stalker2/Content/GameLite/GameData/ObjPrototypes/Pseudogiant.cfg
upmm_modpack.pak created successfully!
Press Enter to exit...
- Move
upmm_modpack.pakto the~modsfolder. The default location for Steam installs isC:\Program Files (x86)\Steam\steamapps\common\S.T.A.L.K.E.R. 2 Heart of Chornobyl\Stalker2\Content\Paks\~mods
Note: You can also use the copy_to_dir in the config.toml to automate the last step of copying it into ~mods
To control the order of mods, the directories used by the program, and the name of the final modpack you can modify the config.toml. See example/config.toml for an example configuration file that explains all the options (note the mods here are nonsensical and are only for example purposes).
The main benefit this tool has over other tools is that it resolves conflicts between mods on a per-value basis rather than regular (or manual) merge conflict resolution. This makes the merge process more robust and able to handle more complex changes. This also means that non-functional changes, such as changing comments or moving lines, will not affect the outcome of the merge. It also does not have any external dependencies since it is written in Rust and able to use the repak library directly.
I personally don't have much GUI experience and do not want to sink time into creating one where there is still a lot of work to be done on the core functionality. Because this mod tool is a single binary that is driven by a single TOML file anyone is more than welcome to create their own GUI for it using their language of choice or contribute a GUI to this project. The GUI would simply need to read/write the config file and then spawn the tool as a subprocess. Once I am happy with the core functionality, I will begin to create a GUI for it if one has not already been created.
Some cfg files that are shipped with the game are seemingly malformed. The most common thing is a missing stuct.end like in Stalker2/Content/GameLite/GameData/Scripts/OnGameLaunch/OnGameLaunchScripts_EQ155.cfg:
[0] : struct.begin
SID = OnGameLaunchScripts_EQ155
ScriptsArray : struct.begin
[*] = XSetGlobalBool DBG_IsDebug 1
[*] = XStartQuestNodeBySID EQ155_P_Technical_DebugStart
struct.end
It's entirely possible that this is the intended syntax of CFG files, but since it's so rare I am assuming it is not intentional thus the parser will throw an error when encoutering these files. Since I doubt these are commonly modded files, that seems to be acceptable for now. I have ran this tool against every single file in pakchunk0 to ensure every file can be parsed properly. Below are the ones that will cause the tool to throw an error:
./Stalker2/Content/GameLite/GameData/ArtifactPrototypes/QuestArtifactPrototypes.cfg
./Stalker2/Content/GameLite/GameData/ItemGeneratorPrototypes/GDItemGeneratorPrototype/VortexDudeItemGenerator.cfg
./Stalker2/Content/GameLite/GameData/Scripts/OnGameLaunch/OnGameLaunchScripts_E01_MQ01_NoIntro.cfg
./Stalker2/Content/GameLite/GameData/Scripts/OnGameLaunch/OnGameLaunchScripts_E16_Bossfight_Scar.cfg
./Stalker2/Content/GameLite/GameData/Scripts/OnGameLaunch/OnGameLaunchScripts_EQ152_Spark.cfg
./Stalker2/Content/GameLite/GameData/Scripts/OnGameLaunch/OnGameLaunchScripts_EQ152_Ward.cfg
./Stalker2/Content/GameLite/GameData/Scripts/OnGameLaunch/OnGameLaunchScripts_EQ154.cfg
./Stalker2/Content/GameLite/GameData/Scripts/OnGameLaunch/OnGameLaunchScripts_EQ155.cfg
If you are using a mod that contains one of these files or encounter similar syntax in the wild please let me know!
By default, Windows defender will warn you any time you use an unsigned exe for the first time. This DOES NOT mean it is a virus, it's just Windows making sure you know what you are running and should go away after the first time you run it. I could fix this by signing the exe, but I need to pay for a proper signing key. If this tool sees adoption, I will look into signing it to avoid this. If you are still skeptical, you can clone this repo yourself and build via cargo build --release --target x86_64-pc-windows-gnu
By default, the tool will create a staging directory that contains all of the files before they are packed. You can look at these files to see the final result that is in the modpack. This staging directory is a git repository, so you can also use git to view a history of how the files changed over time as mods were merged in. I eventually plan to add an easier way to review changes for those that aren't familiar with git.