Files
questshock/modding
ml e410d82680 Fix hacked GTK3/GLFW crash by vendoring a patched sqweek/dialog
The built hacked binary segfaults on Linux the moment a native GTK3
dialog (file/folder browse) opens while a GLFW/OpenGL context is live:
sqweek/dialog's Linux backend never calls XInitThreads() before
gtk_init(), and GLFW's own X11 backend installs a process-wide Xlib
error handler that collides with GTK's.

Vendor a pinned copy of github.com/sqweek/dialog (New BSD) into
modding/sqweek-dialog/ so it can be patched like every other vendored
source here: sqweek-dialog-patches/01-xinitthreads.patch adds the
missing XInitThreads() call, and hacked-patches/01-use-patched-dialog.patch
adds a go.mod replace directive pointing hacked's own sqweek/dialog
dependency at that local copy. build-hacked.sh now stages both hacked/
and sqweek-dialog/ into a scratch modding/build/ directory and applies
their patch series before compiling, rather than building hacked/ in
place; .gitignore picks up that new scratch directory.

Also expand modding/README.md: number its existing sections and add a
worked "Example: Editing a message" walkthrough covering Static World
Data, the Messages window's clipboard-only text editing, saving the
Mod Location, and the absolute-path requirement for run.sh's mod-folder
argument.
2026-09-26 10:37:01 +02:00
..

Modding

Tools and reference material for modding System Shock (1994) itself - distinct from the rest of this repository, which is the QuestShock VR port of the game engine. Everything modding-related lives under this folder.

Both pieces here come from the InkyBlackness project and are vendored unmodified, each under its own upstream license (see below) - neither is relicensed by this repository's own MIT license.

1. Layout

  • hacked/ - InkyBlackness HackEd, the graphical mod editor. A vendored source snapshot (New BSD License), taken from the main branch on 2026-09-26. To update it, replace this directory with a fresh checkout and update that date.
  • ss-specs/ - InkyBlackness ss-specs, the unofficial file-format specifications the editor (and any other modding tool) is written against. Reference documentation only, not built. A vendored snapshot (CC BY-NC-SA 4.0 - non-commercial, unlike the rest of this repository), taken from the main branch on 2026-09-26.
  • hacked-build-image/ - the Dockerfile (and supporting scripts) for the hacked build environment: the Go toolchain plus every dependency hacked/go.mod pins, fetched once at image-build time so the actual build needs no network access. Mirrors the main project's own build-image/ (see the repository root's README.md section 4) one level down, for this subproject.
  • hacked-build-image.sh / hacked-build-run-image.sh / hacked-build-upload-image.sh - build the image, run it to compile hacked/, and push it to a registry, respectively. Same pattern as the root project's own build-image.sh/run-image.sh/upload-image.sh.
  • Makefile - hacked (default) builds hacked/ via the image; build-image (re)builds the image itself; clean removes dist/.
  • dist/ - build output (git-ignored), created by make hacked.

Shockolate (the engine ../engine/ vendors) already has its own modding support (level/resource files, res/data/); this folder is about the external tools that create and inspect that content, not about changing the engine itself.

2. Building hacked

Packages dist/<version>.linux64.tgz and dist/<version>.win64.zip (native Linux build, Windows amd64 cross-compiled via mingw-w64 - both from the same source, in one run).

Prerequisites: Docker - same as the root project, nothing modding-specific to install locally.

cd modding

# 1. Build the hacked-build-image (once, or after hacked-build-image/ or
#    hacked/go.mod|go.sum changes)
./hacked-build-image.sh

# 2. Compile hacked/ for Linux and Windows
make hacked

<version> is hacked-<date>, not an InkyBlackness release version: hacked/ is a vendored snapshot here, not its own git checkout, so there is no tag to derive a real version from (see hacked-build-image/build-hacked.sh's own comment).

Run the result: dist/linux/hacked/hacked on Linux, dist\win\hacked\hacked.exe on Windows. Needs OpenGL 3.2; usage is documented on hacked's own wiki.

2.1. Publishing the build-image

Same registry as the root project's own build-image (see the repository root's registry.env.example), under a separate image name so the two don't collide:

./hacked-build-upload-image.sh

Reads REGISTRY/REGISTRY_USER/REGISTRY_PASSWORD and (optionally) HACKED_REGISTRY_IMAGE from ../registry.env, same as the root scripts. Don't bump hacked-build-image/VERSION just because the Dockerfile changed - only once a build with the current version has actually succeeded, same policy as the root project's own build-image/VERSION.

3. Example: Editing a message

hacked has no inline text editor - every text field is edited by right-click -> Copy to Clipboard, editing the text in an external editor, then right-click -> Copy from Clipboard back into the field. Example: changing Rebecca Lansing's first email.

  1. Run dist/linux/hacked/hacked (or the Windows build).
  2. Window -> Project. Under Static World Data, Add... and browse to the game's whole res/assets/ss_ee/data/ directory (see the root README.md section 3 for where that comes from), so every .res/.dat file is available.
  3. Window -> Messages (F5). Message Type: Mails. Index: 26 (Rebecca's first mail). Edit Sender/Subject/Title/the message text via the clipboard round-trip above.
  4. Back in the Project window, under Mod Location, click Save (first time: Browse... to an empty folder, for example ./modding/mymod).
  5. Test it from the root project's desktop build:
    ./dist/run.sh "$(pwd)/modding/mymod"
    
    The mod-folder argument must be an absolute path: run.sh cds into dist/ before launching the engine, so a relative path resolves against the wrong directory and the mod silently fails to load (the engine's ProcessModDirectory() reports nothing on a bad path). When the path is right, the terminal shows ProcessModDirectory ... / Found resource file: ... / Loading mod file ... for confirmation.