Files
llamamod/docs/developers.md
T

7.0 KiB
Raw Blame History

For developers

How the code is organised, how to build and test it, and where the engineering notes are.

Build

Requirements: a JDK 25 installed (the Gradle toolchain compiles with it; there is no auto-download). Gradle itself and Spotless currently need to run on Java 21, e.g. JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 ./gradlew … on Debian/Ubuntu.

./gradlew spotlessApply build       # compile, format, run the tests
./gradlew fatJar                    # build/libs/llamamod-<ver>-all.jar
java -jar build/libs/llamamod-*-all.jar            # launcher
java -jar build/libs/llamamod-*-all.jar --editor   # the editor alone
./gradlew packageLinux              # tar.gz with its own Java runtime
./gradlew packageWindows            # zip with LlamaMod.exe + runtime (built on Linux)
./gradlew packageAll                # both systems, full and launcher (no editor) edition

Details (jlink, launch4j, editions, version and build id): notes/llamamod-app.md.

Tests that need the game. Golden and in-game-data tests read the CD folder given by -Dllamamod.cd=<…/Setup/<lang>/Cd> or the environment variable LLAMAMOD_CD (default: ~/.wine-lama/iso-dk/Setup/Eng/Cd); if that folder does not exist they are skipped. Byte-exact round trips over all level WADs (WAD, TRAK, MAP, TEXT, strat code) are the safety net for every format change.

Code map

Package root src/main/java/com/eliasmueller/llamamod/:

Package Content Notes
format WAD, TRAK, STPC, MAP, TEXT, collision, COR Reference
format.strat strat disassembler, assembler, script view, compiler Strats, notes/strat-language.md
format.stpcmerge importing object types between levels (code, models, textures, sounds, texts) notes/editor-cross-import.md
levelbuild Java level builder (LevelBuilder, LevelScript) Levels from scripts
mods mod framework (Mod, ModContext, ModManager, options) and the built-in mods notes/llamamod-app.md, notes/mod-*.md
exe patching groove.exe: PE image, code caves, a tiny x86 emitter notes/llamamod-app.md
platform install from ISO/CD, data folder, config, registry, Wine/Windows launch notes/llamamod-app.md
save KSV save games, TestLevel chapters Game files
ui launcher window
editor.model, editor.io scene model, commands/undo, project format, WAD import/build notes/editor-api.md, notes/editor-format.md
editor.render OpenGL viewport notes/editor-render.md
editor.ui editor shell and plugin API notes/editor-ui.md
editor.tools.* editor plugins: geometry, objects, environment, textures, catalog (cross-world import), strats, playtest, gltf, help notes/editor-tools-*.md, notes/editor-playtest.md

Writing a mod

A mod implements Mod: id, name, description, category (LEVELS, GAMEPLAY, VISUAL, CHEATS), options() and apply(ModContext). apply reads files of the game as earlier mods left them (ctx.read) and writes replacements (ctx.write); ctx.exe() gives access to groove.exe for patches. Mods are registered in ModRegistry. LlamaMod caches mod outputs and never touches the original files.

Good examples: mods/testworld/ (a level built in code), mods/arena/ (level

Every mod should be checked in the running game; tools/apptest.py does this unattended on Linux (Tools).

The editor manual

docs/manual/ is the editor's user manual and its built-in help: the build bundles the folder into the jar (processResources in build.gradle), the Help window renders it with its own small Markdown converter, and F1 maps editor topics to chapter anchors (editor/tools/help/context-help.txt). Rules for that folder:

  • Only the Markdown subset described at the top of index.md; every chapter must be linked from index.md; links must stay inside docs/manual (the help window cannot open other files).
  • Blocks between generated:NAME comments (shortcuts, menus, mod reference) are rewritten from the live program by ManualTest – do not edit them by hand.
  • ./gradlew test --tests '*ManualTest*' checks links, anchors and images.

Maintenance notes: notes/editor-manual.md.

Engineering notes

notes/ is the project's lab notebook: one file per format, editor area and mod, with addresses in groove.exe, confidence levels, what was verified in the game and known limits. Process material (agent briefs, review reports) is in notes/dev/.

Releasing

Releases are built by Gitea Actions (.gitea/workflows/release.yml):

  1. Add a ## <version> – … section at the top of CHANGELOG.md (it becomes the release text; the workflow fails if it is missing).
  2. git tag v<version> && git push origin v<version>

The workflow builds and tests (tests that need the game CD skip themselves on the runner), runs packageAll with -PreleaseVersion=<version> (the tag decides the version; without it build.gradle's default is used), writes SHA256SUMS.txt and creates the release with the four packages via tools/release/publish_gitea.py (standard library only; re-running replaces files of the same name). .gitea/workflows/build.yml builds every push.

Requirements on the Gitea side: Actions enabled ([actions] ENABLED = true), an act_runner with the label ubuntu-latest (an image with python3, curl/network access – the build downloads the Temurin JDK/jmods and launch4j), and an attachment size limit above ~60 MB ([attachment] MAX_SIZE in app.ini). If the built-in token may not create releases, add a repository secret RELEASE_TOKEN with write access. Locally the same packages come from ./gradlew -PreleaseVersion=<version> packageAll (output in build/dist).