Skip to content

Repository files navigation

GK-ModUpdater

Update your old Gotham Knights .pak mods to the IoStore format the final (2023) build uses.

Mods built before that update stopped working, and the game gives you nothing to debug with: no log, no error, just a mod that does nothing or a game that dies on launch. gkupdate rebuilds an old cooked .pak into the .utoc/.ucas/.pak container the current build loads, and checks the result is sound.

Converting and verifying a mod with gkupdate

This is a tool for mod authors to update their own mods. It is not a mod manager. It does not install, enable, or launch anything. If you just want to play with old .pak mods, use GK-ModLoader instead (coming soon).

What it does and does not do. GK-ModUpdater only changes a mod's packaging format, from legacy .pak to IoStore. It does not fix a mod that was already broken, and it cannot make a mod compatible with a game update that moved, renamed, or removed the assets the mod targets. If the game changed underneath the mod, converting the format will not bring the old content back. verify (with the game present) will tell you when a mod points at assets the current build no longer has, but it can only report that, not repair it.

Ships no third-party binaries. retoc and repak are other people's work under their own licences, so GK-ModUpdater finds a copy you already have or downloads one from the official release page when you ask it to.

Install (Windows)

Download the release zip, unzip it anywhere, and run gk-cli.bat (it opens a terminal with gkupdate ready). The exe is not code-signed, so on first run Windows SmartScreen may say "Windows protected your PC". Click More info then Run anyway. If you would rather not run an unsigned exe, use the from-source route at the bottom of this file instead.


Why old mods stopped working

The final build loads packages through IoStore, by PackageId, not by reading .uasset files out of a .pak. So:

  • A pak holding only loose files (.ini, .mp4) still works untouched.
  • A pak holding .uasset packages is silently ignored and must be rebuilt.

PackageId = CityHash64(lowercase("/Game/<path>") as UTF-16LE), little-endian. Mercury/Content/... maps to /Game/....

Quick start

The first run shows the terms of use and asks you to accept them once.

gkupdate tools --fetch all                 # get retoc + repak (or --set them)
gkupdate convert "C:\Mods\MyOldMod.pak" --out converted

That writes converted\MyOldMod_P.{utoc,ucas,pak}. Ship all three together, or hand them to players who use GK-ModLoader.

convert accepts a .pak, a .zip/.rar/.7z, an already-unpacked cooked tree, or a folder of any of those. Point it at a whole folder of downloads and it converts everything convertible inside.

Commands

The four commands

gkupdate convert <thing>...   an old .pak / archive / folder -> IoStore
gkupdate verify <file.utoc>   check a converted mod is structurally sound
gkupdate tools                check or install the retoc / repak helpers
gkupdate terms                show the terms of use

That's the whole tool. Exit codes: 0 fine, 1 a problem with the input, 2 a helper is missing, 3 a helper ran and failed, 4 terms not accepted.

For scripts there is --accept-terms and gkupdate terms --accept; with no console attached it prints the terms and exits 4 rather than blocking on input.


What the converter repairs

retoc to-zen --version UE4_27 gets close, but its containers are wrong for UE4.27 in three ways that crash the game. All three are fixed after conversion:

1. ExportBundlesSize = 0. The loader computes

export_data_size = ExportBundlesSize - (GraphDataOffset + GraphDataSize)

so zero underflows to ~2^64 and it dereferences a wild pointer. Set to the real ExportBundleData chunk size.

2. Self-referential PackageRedirects, one per package. Real cooked containers have none. Cleared.

3. Export bundles split one-per-load-phase instead of a single bundle holding every entry. Merged, but only for packages with no external arcs. GraphData arcs carry a ToExportBundleIndex pointing into this package's bundle list; collapsing a package that has arcs leaves them dangling and the loader walks off the end of the bundle array (a crash that reads address 0x10).

The ContainerId is re-keyed so the TOC, the header chunk's id and the ContainerId inside the header body all agree. retoc pack-raw does not do this, and a mismatch makes a container that mounts but provides nothing. The stub .pak written alongside is the 232-byte empty PakFile v9 index every working native mod ships.

Verifying your mod

convert verifies as it goes, and gkupdate verify re-checks an existing container against what the loader will check:

  • ExportBundlesSize equals the real chunk size for every package
  • bundle region size agrees with the store entry's bundle and export counts
  • every GraphData arc targets a bundle that exists
  • export data size equals the sum of the export map's serial sizes
  • directory-index package ids match CityHash64 of their /Game/ path
  • TOC id, header chunk id and header body id all agree

If GK-ModUpdater can find your game install (or you pass --game), it also checks every package your mod imports still exists in the shipped assets, which catches a mod referencing an asset a later patch deleted. It reads the base game's package list without the AES key: only the directory index and chunk payloads are encrypted, never the TOC header or the FIoChunkId table.

The provenance stamp

Every converted mod carries a small marker at the end of its .ucas, so you can tell a mod was made with GK-ModUpdater:

findstr /C:"gk-modupdater" MyMod_P.ucas

It is trailing data the game ignores, and it does not change how the mod loads. It is a marker, not a lock: it identifies provenance, but anyone can strip it, so it does not prevent misuse.

Diagnosing an unresolved import

If verify reports an unresolved import, the parent asset your mod references is gone from the current build. Legacy .uasset files keep import paths as plain strings (the zen format throws them away), so unpack the original pak and read them:

repak unpack OldMod.pak -o unpacked
# then grep the .uasset files for /Game/ references

One mod referenced a weapon material a patch had deleted; the fix was to re-parent it to the master material its sibling materials already used.


From source

python gkupdate.py tools        # see what's missing
python -m unittest discover -s tests -t .

Python 3.10+, no dependencies beyond the standard library. The tests need neither the game nor the helper tools nor a network connection.

Building the executable:

pip install pyinstaller
python build.py

Use the default onedir build. Windows Defender quarantines --onefile on sight, because the self-extracting stub trips a generic heuristic.

Layout

gkmodkit/
  cityhash.py   CityHash64 - PackageId and ContainerId derivation
  formats.py    TOC reader, zen package parser, container header read/rebuild
  convert.py    conversion pipeline, container repair, verification
  archives.py   importing and classifying downloads
  gamedir.py    read-only: locate a game install to resolve imports
  tools.py      locating or fetching retoc / repak
  errors.py     exception types - the library never calls sys.exit()
  terms.py      first-run acceptance of the terms
gkupdate.py     the CLI

gkmodkit is usable as a library. Nothing in it prints or exits; it raises from gkmodkit.errors and lets the caller decide.

Credits

Relies on retoc and repak by trumank, which you supply yourself. Neither is redistributed here.

Licence

MIT terms with an Acceptable Use Addendum. The grant does not extend to using this software with mods you do not have the right to modify and distribute, and/or to produce content that would be unacceptable in a game rated ESRB E10+ (Everyone 10+) and/or the equivalent under another ratings system. The addendum carries over into anything built on the code. That is a field-of-use restriction, so this is source-available rather than open source by the OSI definition. A licence cannot inspect a texture; it states the author's position and travels with the code. See LICENSE.

About

Converts old Gotham Knights .pak mods to the IoStore format the final (2023) build loads. For mod authors updating their own mods; not a mod manager.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages