Skip to content

AstraTerra Developer Guide

Build And Test

make test
make build
make package

The Makefile uses the repo-local .dotnet path and defaults to a Release build. The mod project expects VINTAGE_STORY to point at a Vintage Story install directory. If unset, it defaults to /Applications/Vintage Story.app on macOS.

For a local Vintage Story smoke test:

make deploy

Then enable AstraTerra in Vintage Story 1.22.2 and run the manual verification checklist.

Releasing

Bump the version

make bump-minor-version          # 0.1.56 -> 0.2.0
make bump-patch-version          # 0.1.56 -> 0.1.57
make bump-version VERSION=1.0.0  # explicit

The version lives in two places — modinfo.json and AstraTerraModMetadata.Version — plus GitHub issue-template placeholders. Always bump through the Makefile rather than editing any of those by hand. The Makefile calls bump-my-version, installed once with uv tool install bump-my-version. BootstrapSmokeTests.Runtime_Version_Stays_In_Sync_With_Modinfo fails if the two source files drift.

The bump targets deploy

bump-version, and therefore bump-minor-version and bump-patch-version, chain into deploy, which installs the zip package into your local Vintage Story Mods folder. Use make bump-version-files VERSION=x.y.z to update the version without deploying.

What happens on merge to main

Two workflows run from the same push, independently:

Workflow Runner Does
release-drafter.yml ubuntu-latest Reads the version from modinfo.json and creates or renames the draft release to vX.Y.Z, with notes generated from merged pull requests
tests.yml ubuntu-latest Tests, builds and packages, and — once the tests and the benchmark have passed — attaches dist/AstraTerra-X.Y.Z.zip to that draft. The zip is a workflow artifact on every run, merge or not

Release Drafter owns the notes; the packaging job only ever touches assets (gh release upload --clobber), so the two do not fight. It waits for the draft to appear, and creates one itself if Release Drafter never got there, so a build is never stranded without somewhere to land.

Publishing stays manual. Review the draft, confirm the attached zip, then publish — which is what creates the vX.Y.Z git tag.

Once that release is published, post-release-bump.yml patch-bumps main as github-actions[bot] and opens the next draft at vX.Y.Z+1. The zip for that draft is attached by the usual CI on the next merge to main.

A published release is never modified

If main moves after vX.Y.Z has already been published — that is, someone merged without bumping the version — the job logs a warning and leaves the release alone rather than overwriting a shipped asset. The package still exists as a workflow artifact. Bump the version and merge again.

Everything runs on GitHub's runners

The mod compiles against the shipped game assemblies, and CI fetches the linux-x64 client archive for them: they are managed DLLs, so no job needs a particular operating system. Nothing here depends on a machine of yours being switched on.

Only the release-package job may write to the repository, and it says so in the job rather than at the top of the workflow, so the tests and the benchmark run with read-only tokens.

Documentation Site

make docs-build
make docs-serve

The documentation site builds with ProperDocs and the MaterialX theme. The configuration lives in properdocs.yml, and the docs toolchain is pinned in docs/requirements.txt.

Install uv before running the documentation targets. make docs-build performs the same strict build used by CI. Pull requests that change the docs or their build configuration are validated without publishing; pushes to main publish the result to the AstraTerra documentation site.

Repository Layout

assets/astraterra/        Runtime JSON, handbook pages, language, shapes, recipes, and textures
src/AstraTerra/           Vintage Story code mod
tests/AstraTerra.Tests/   Unit and asset tests
tools/cataloggen/         Developer-only star catalog generator
tools/milkywaygen/        Developer-only Milky Way texture generator
tools/deepsky/            Stellarium deep-sky plate importer
docs/player/              Player-facing documentation
docs/dev/                 Developer-facing documentation

Inside src/AstraTerra/, Astronomy/ is the pure sky model, Client/ is everything that draws or reads input, Items/ is the Vintage Story item entry point, Constellations/ and Observation/ own what a book and an instrument remember, and Commands/ and Config/ are the two ways a player changes anything. Architecture goes through the boundaries between them.

Core References

Start with Architecture for the map, Celestial Model for the astronomy, and Extending if you are writing another mod against this one rather than changing it.