Problem
Currently, STS2 mod developers need the Godot editor (or MegaDot fork) installed just to export a .pck file containing localization JSON and card art. For simple content mods that only add cards, relics, or potions, this is a heavy requirement — the actual mod code is a single .dll, but the assets need a full Godot project and export pipeline.
This creates friction for new mod developers and makes CI/CD difficult (Godot headless export requires specific binaries).
Would this fit BaseLib's vision?
I ran into this while building a simple content mod (sts2-secret-script) and ended up reverse-engineering the PCK and ctex formats to avoid needing the Godot editor. I have a working proof of concept and would be happy to contribute a proper C# implementation if this fits the direction you see for BaseLib/the mod template.
If you'd prefer this lives as a separate package or in the mod template rather than BaseLib itself, I'm open to that too — just wanted to check before building it out.
Proposed Solution
A standalone PCK packer that runs as part of the dotnet build pipeline, potentially distributed as a NuGet package (e.g. Alchyr.Sts2.PckPacker alongside the existing Alchyr.Sts2.BaseLib and Alchyr.Sts2.ModAnalyzers).
It would:
- Pack localization JSON files — passed through as-is into the PCK
- Convert PNG images to Godot
.ctex format — lossless WebP with the GST2 header
- Generate
.import remap files — so Godot's resource loader finds the textures
- Produce a valid Godot 4.5 format-v3 PCK — ready to deploy to the mods directory
Usage
Integrated as an MSBuild target, something like:
<PackageReference Include="Alchyr.Sts2.PckPacker" Version="*" />
With a build target that runs after compile:
<Target Name="PackPck" AfterTargets="Build">
<!-- automatically packs ModName/ directory into ModName.pck -->
</Target>
Technical Findings
PCK Format (Godot 4.5, format version 3)
The PCK is a simple binary archive. Header (104 bytes):
| Offset |
Size |
Field |
Value |
| 0x00 |
4 |
Magic |
GDPC |
| 0x04 |
4 |
Format version |
3 |
| 0x08 |
4 |
Engine major |
4 |
| 0x0C |
4 |
Engine minor |
5 |
| 0x10 |
4 |
Engine patch |
1 |
| 0x14 |
4 |
Pack flags |
0x02 (PACK_REL_FILEBASE) |
| 0x18 |
8 |
Files base offset |
(header size) |
| 0x20 |
8 |
Directory offset |
(after all file data) |
| 0x28 |
64 |
Reserved |
zeros |
File data follows immediately after the header, aligned to 32-byte boundaries. The directory index (at the end) contains per-file entries:
| Size |
Field |
| 4 |
Path length (padded to 4-byte boundary) |
| var |
UTF-8 path (e.g. res://ModName/localization/eng/cards.json) |
| 8 |
File offset (relative to files base) |
| 8 |
File size |
| 16 |
MD5 hash |
| 4 |
Flags (0 = none) |
ctex Format (CompressedTexture2D)
Godot cannot load raw PNGs from a PCK — they must be imported to .ctex format. The ctex file is a 56-byte header followed by a WebP payload:
| Offset |
Size |
Field |
Value |
| 0x00 |
4 |
Magic |
GST2 |
| 0x04 |
4 |
Version |
1 |
| 0x08 |
4 |
Width |
image width |
| 0x0C |
4 |
Height |
image height |
| 0x10 |
4 |
Flags |
0x0D000000 (lossless, no mipmaps) |
| 0x14 |
4 |
Limiter |
-1 (0xFFFFFFFF) |
| 0x18 |
12 |
Padding |
zeros |
| 0x24 |
4 |
Data format |
2 |
| 0x28 |
4 |
Packed dimensions |
(height << 16) | width |
| 0x2C |
4 |
Padding |
0 |
| 0x30 |
4 |
Image format |
5 (WebP) |
| 0x34 |
4 |
WebP data size |
size of following RIFF/WebP blob |
| 0x38 |
var |
WebP data |
lossless WebP image (RGBA) |
This was reverse-engineered from BaseLib.pck and the game's own imported textures. The compress/mode=0 + lossy_quality=1.0 settings used by the game correspond to lossless WebP encoding.
Import Remap Files
For Godot to find textures via their original res://ModName/images/... paths, the PCK must also contain .import remap files:
[remap]
importer="texture"
type="CompressedTexture2D"
path="res://.godot/imported/filename.png-imported.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://ModName/images/card_portraits/filename.png"
dest_files=["res://.godot/imported/filename.png-imported.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=1.0
mipmaps/generate=false
What Goes in a Typical Content Mod PCK
| Type |
Format in PCK |
Conversion needed |
| Localization JSON |
.json |
None (passthrough) |
| Card/relic/power art |
.ctex |
PNG → lossless WebP → GST2 header |
| Import remaps |
.import |
Auto-generated per PNG |
Scenes (.tscn) |
.tscn or .scn |
None (passthrough) |
Resources (.tres) |
.tres |
None (passthrough) |
Proof of Concept
We have a working Python implementation (~130 lines) that successfully:
- Converts PNGs to ctex (lossless WebP with GST2 header)
- Generates import remap files
- Packs everything into a valid format-v3 PCK
- Produces PCKs that load correctly in STS2
See: pack_pck.py in BSchneppe/sts2-secret-script — a working STS2 mod that uses this packer to build its PCK in CI without the Godot editor.
Implementation Options
-
C# MSBuild task in a NuGet package — Best integration. Runs automatically on build. Could use ImageSharp + a WebP encoder for PNG→ctex conversion. Ships alongside BaseLib and ModAnalyzers.
-
Standalone dotnet tool — Simpler to build, less integrated. Developers wire it into their build manually.
-
Extend the existing ModTemplate csproj targets — Add the packer as a build step in the template, removing the need for Godot export entirely for simple content mods.
Benefits
- No Godot editor needed for simple content mods (cards, relics, potions with art + localization)
- CI/CD friendly —
dotnet build produces everything needed
- Lower barrier to entry for new mod developers
- Consistent with existing BaseLib ecosystem (NuGet-based toolchain)
Offer
Happy to implement this as a PR if it fits the project's direction — either as part of BaseLib, a companion NuGet package, or an addition to the mod template. Let me know what you think and where you'd want it to live.
Problem
Currently, STS2 mod developers need the Godot editor (or MegaDot fork) installed just to export a
.pckfile containing localization JSON and card art. For simple content mods that only add cards, relics, or potions, this is a heavy requirement — the actual mod code is a single.dll, but the assets need a full Godot project and export pipeline.This creates friction for new mod developers and makes CI/CD difficult (Godot headless export requires specific binaries).
Would this fit BaseLib's vision?
I ran into this while building a simple content mod (sts2-secret-script) and ended up reverse-engineering the PCK and ctex formats to avoid needing the Godot editor. I have a working proof of concept and would be happy to contribute a proper C# implementation if this fits the direction you see for BaseLib/the mod template.
If you'd prefer this lives as a separate package or in the mod template rather than BaseLib itself, I'm open to that too — just wanted to check before building it out.
Proposed Solution
A standalone PCK packer that runs as part of the
dotnet buildpipeline, potentially distributed as a NuGet package (e.g.Alchyr.Sts2.PckPackeralongside the existingAlchyr.Sts2.BaseLibandAlchyr.Sts2.ModAnalyzers).It would:
.ctexformat — lossless WebP with the GST2 header.importremap files — so Godot's resource loader finds the texturesUsage
Integrated as an MSBuild target, something like:
With a build target that runs after compile:
Technical Findings
PCK Format (Godot 4.5, format version 3)
The PCK is a simple binary archive. Header (104 bytes):
GDPC34510x02(PACK_REL_FILEBASE)File data follows immediately after the header, aligned to 32-byte boundaries. The directory index (at the end) contains per-file entries:
res://ModName/localization/eng/cards.json)ctex Format (CompressedTexture2D)
Godot cannot load raw PNGs from a PCK — they must be imported to
.ctexformat. The ctex file is a 56-byte header followed by a WebP payload:GST210x0D000000(lossless, no mipmaps)-1(0xFFFFFFFF)2(height << 16) | width05(WebP)This was reverse-engineered from BaseLib.pck and the game's own imported textures. The
compress/mode=0+lossy_quality=1.0settings used by the game correspond to lossless WebP encoding.Import Remap Files
For Godot to find textures via their original
res://ModName/images/...paths, the PCK must also contain.importremap files:What Goes in a Typical Content Mod PCK
.json.ctex.import.tscn).tscnor.scn.tres).tresProof of Concept
We have a working Python implementation (~130 lines) that successfully:
See:
pack_pck.pyin BSchneppe/sts2-secret-script — a working STS2 mod that uses this packer to build its PCK in CI without the Godot editor.Implementation Options
C# MSBuild task in a NuGet package — Best integration. Runs automatically on build. Could use
ImageSharp+ a WebP encoder for PNG→ctex conversion. Ships alongside BaseLib and ModAnalyzers.Standalone
dotnet tool— Simpler to build, less integrated. Developers wire it into their build manually.Extend the existing ModTemplate csproj targets — Add the packer as a build step in the template, removing the need for Godot export entirely for simple content mods.
Benefits
dotnet buildproduces everything neededOffer
Happy to implement this as a PR if it fits the project's direction — either as part of BaseLib, a companion NuGet package, or an addition to the mod template. Let me know what you think and where you'd want it to live.