Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Keeps a release pull request open with the next version and its changelog, worked out by
# release-please from the Conventional Commits pushed to main. Merging that pull request tags the
# version and publishes a GitHub release with its changelog; the builds for each system are then
# attached to it, with a file of their SHA-256 checksums, and the changes contributors made are
# credited to them in its notes. Each archive, and each executable in it, gets a build provenance
# attestation, which `gh attestation verify` checks. The builds hold no game files: the editor
# needs OpenReliant and your own copy of StarLancer.
#
# Run by hand from the Actions tab, it builds everything and keeps the archives as the run's
# artifacts, but publishes nothing and makes no attestations.
#
# The builds are attached after release-please has published the release, so the repository's
# immutable releases must stay off: GitHub refuses files for an immutable release once it is
# published, as OpenReliant found.
name: Release

on:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: write
issues: write
pull-requests: write

jobs:
release-please:
runs-on: ubuntu-latest
outputs:
created: ${{ steps.release.outputs.release_created }}
tag: ${{ steps.release.outputs.tag_name }}
steps:
- uses: googleapis/release-please-action@v5
id: release
with:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
target-branch: ${{ github.ref_name }}

build:
needs: release-please
if: needs.release-please.outputs.created == 'true' || github.event_name == 'workflow_dispatch'
strategy:
fail-fast: false
matrix:
include:
- { name: linux-x86_64, os: ubuntu-latest, target: x86_64-linux-gnu }
- { name: linux-aarch64, os: ubuntu-latest, target: aarch64-linux-gnu }
- { name: windows-x86_64, os: windows-latest, target: x86_64-windows-gnu }
- { name: windows-aarch64, os: windows-latest, target: aarch64-windows-gnu }
- { name: macos-x86_64, os: macos-latest, target: x86_64-macos }
- { name: macos-aarch64, os: macos-latest, target: aarch64-macos }
runs-on: ${{ matrix.os }}
# The build only reads the repository. The attestations need a token from GitHub's OIDC provider,
# to get a signing certificate from Sigstore, and the rights `actions/attest` asks for to store
# them.
permissions:
contents: read
id-token: write
attestations: write
artifact-metadata: write
steps:
# The whole history with its tags, so that the build can name the commit a build by hand is
# past the last release.
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: mlugg/setup-zig@v2
with:
version: 0.17.0
# An explicit target builds for the architecture's baseline processor, so the binary runs on
# any machine of that kind, not just ones like the runner.
- run: zig build --release=fast -Dstrip -Dtarget=${{ matrix.target }}
- name: Package
shell: bash
env:
VERSION: ${{ needs.release-please.outputs.tag || github.ref_name }}
run: |
name="openreliant-editor-$VERSION-${{ matrix.name }}"
mkdir -p "$name" dist
for file in README.md LICENSE CHANGELOG.md; do
if [ -f "$file" ]; then cp "$file" "$name"/; fi
done
# The licences of the libraries and fonts whose text has to go with every copy.
cp zig-out/LICENSE-*.txt "$name"/
case "${{ matrix.target }}" in
*windows*)
cp zig-out/bin/openreliant-editor.exe "$name"/
7z a -tzip "dist/$name.zip" "$name" > /dev/null
;;
*)
cp zig-out/bin/openreliant-editor "$name"/
tar -czf "dist/$name.tar.gz" "$name"
;;
esac
# For a release, the archive and the executable in it get a build provenance attestation,
# signed through Sigstore, which names the workflow run that built them and its commit.
- if: needs.release-please.outputs.created == 'true'
uses: actions/attest@v4
with:
subject-path: |
dist/*
zig-out/bin/*
- uses: actions/upload-artifact@v7
with:
name: ${{ matrix.name }}
path: dist/*

attach:
needs: [release-please, build]
if: needs.release-please.outputs.created == 'true'
runs-on: ubuntu-latest
steps:
# For the script that credits the contributors.
- uses: actions/checkout@v7
- uses: actions/download-artifact@v8
with:
path: dist
merge-multiple: true
# The SHA-256 of each archive, in the format `sha256sum --check` reads.
- name: Write the checksums of the archives
working-directory: dist
env:
TAG: ${{ needs.release-please.outputs.tag }}
run: sha256sum -- *.tar.gz *.zip > "openreliant-editor-$TAG-sha256sums.txt"
# Each change a contributor made gets their handle in the notes (`release-credits.sh`).
- name: Attach the builds to the release, and credit the contributors
shell: bash
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ needs.release-please.outputs.tag }}
run: |
gh release upload "$TAG" dist/* --repo "$GITHUB_REPOSITORY" --clobber
changelog="$(gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json body --jq .body | scripts/release-credits.sh)"
note="OpenReliant Editor needs OpenReliant and your own copy of StarLancer: see the README. The macOS builds are not signed, so macOS blocks them at first; run \`xattr -d com.apple.quarantine openreliant-editor\` once to allow them. To check a download, compare it with \`openreliant-editor-$TAG-sha256sums.txt\`, or run \`gh attestation verify <file> --repo $GITHUB_REPOSITORY\`."
gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --notes "$note

$changelog"
31 changes: 31 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Builds the editor and runs the tests on Linux, macOS and Windows for every pull request and every
# push to main, and checks the Zig code's formatting and the repository's files.
name: Tests

on:
push:
branches: [main]
pull_request:

jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
- uses: mlugg/setup-zig@v2
with:
version: 0.17.0
# The formatting and the files are the same on every system, so they're checked once.
- if: runner.os == 'Linux'
run: zig fmt --check src build.zig
- if: runner.os == 'Linux'
run: scripts/check-files.sh
- run: zig build --summary all
- run: zig build test --summary all
# Releases will be built ReleaseFast, without the safety checks, so the tests run in that mode
# too.
- run: zig build test --release=fast --summary all
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Zig's build output, its cache, and the packages it fetches into the project.
/zig-out/
/.zig-cache/
/zig-pkg/

# The game's files and what's made from them: never commit these. `scripts/check-files.sh`, run by
# the pre-commit hook and by CI, refuses them too.
/game/
*.[hH][oO][gG]
*.[dD][tT][eE]
*.[sS][hH][pP]
*.[fF][mM]8
*.[sS][pP][rR]
*.[bB][iI][kK]
*.[eE][xX][eE]
*.[dD][lL][lL]

# The pictures the editor takes of its screens with --screenshot.
/shots/
1 change: 1 addition & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
23 changes: 23 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Notes for coding agents

[CONTRIBUTING.md](CONTRIBUTING.md) holds the project's conventions: follow it in full, and
OpenReliant's own [CONTRIBUTING.md](https://github.com/OpenReliant/openreliant/blob/main/CONTRIBUTING.md)
where this one points to it. These notes add how the maintainer works with an agent.

- **Starting an issue.** Begin with `gh issue view N --comments`, and read the comments on related
closed issues too, in this repository and in OpenReliant's.
- **Trying a change.** When the maintainer tries a change, build and launch the editor right away:
`make run ARGS='<mod folder>'`. Once they are happy with it, run the checks and commit.
- **Checking a screen.** `openreliant-editor <mod folder> --screenshot <file.png>` draws without a
window and saves the frame, for checking a screen against `design/` without showing a window on
the maintainer's screen. `--show`, `--line` and `--game` set up what it shows.
- **Pull requests.** Push the feature branch and open the pull request when the change is ready.
The maintainer merges it. See one pull request merged before starting the next feature.
- **Attribution.** Commits and pull requests carry the maintainer's git identity alone. End commit
messages and pull request bodies with their content, leaving out trailers such as
`Co-Authored-By` and "Generated with" footers.
- **Gaps.** File an issue for each gap you leave, and name the issues in your reply.
- **Plain English.** Write docs, comments, messages, issues, pull requests and replies in plain,
simple technical English, the way you would explain the code to a colleague: normal word order,
common words, short sentences.
- **Replies.** Use the docs' punctuation in replies too: no em or en dashes.
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@AGENTS.md
@CONTRIBUTING.md
116 changes: 116 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Contributing to OpenReliant Editor

OpenReliant Editor is a mission editor, script debugger and mod editor for
[OpenReliant](https://github.com/OpenReliant/openreliant). It follows OpenReliant's conventions for
its Zig, its documentation and its history, as OpenReliant's
[CONTRIBUTING.md](https://github.com/OpenReliant/openreliant/blob/main/CONTRIBUTING.md) gives them.
This guide gives what is the editor's own, and is written for people and coding agents alike:
`AGENTS.md` and `CLAUDE.md` point agents here.

## Getting started

- Install [Zig 0.17](https://ziglang.org). `zig build` builds the editor, `zig build test` runs the
tests, and `zig build check -fincremental --watch` reports compile errors moments after a save.
The first build fetches OpenReliant and the libraries `build.zig.zon` names, and builds the C and
C++ ones.
- Run `make hooks` once. It installs a pre-commit hook that keeps the game's files out of the
repository. `make help` lists the other workflows.
- `make run ARGS='<mod folder>'` opens a mod, `make run ARGS='<file>.dte'` a mission file. The editor
needs a game folder set up by `openreliant install` for the mods list and the game's own
missions ([installation guide](https://github.com/OpenReliant/openreliant/blob/main/docs/guide/installation.md)).

## How the editor is put together

[docs/architecture.md](docs/architecture.md) describes the modules: the platform, the interface
kit, the commands, the game profiles, the mission documents and the screens.

### The design is the reference

The screens in [`design/`](design/README.md) are what the editor looks like. A screen follows its
page in `design/screens`: its colours, sizes, text and order. Changing how a screen looks starts
with its page, whose picture is taken again in the same pull request (`make pictures`). Check a
screen against its page with `--screenshot`, which draws without a window:

```bash
zig-out/bin/openreliant-editor <mod folder> --screenshot script.png
```

Text goes where a browser puts the design's: the fonts draw at the design's exact sizes
(`src/ui/fonts.zig`), and `gui.textTop` places a line in the middle of its box as the stylesheet
does, its baseline on a whole pixel.

### Games come from their profile

OpenReliant will play other games than StarLancer, so the editor never names a game's commands,
conditions, records or files outside `src/game/`. The interface asks the game's profile
(`src/game.zig`), and a profile reads them from OpenReliant's own tables and builds missions with
OpenReliant's own compiler (`src/game/starlancer.zig`). A profile keeps its data, its names,
extensions, words and records, apart from what it asks of OpenReliant's library, so that profiles
can become files that a Game mode edits.

### Every action is a command

Each action is declared once in [`src/commands.zig`](src/commands.zig): its label, its icon, its
menu, and its default keys on Windows and Linux and on macOS. The menus, the toolbar, the command
palette and the Keys settings read that table, and the keys run the action through it, so an
action has the same name, icon and keys wherever it shows. An action that doesn't work yet still
shows, greyed out, with the issue that plans it (`commands.plans`).

### Text on screen

Labels and short fragments rather than sentences: `Held · line 46`, `1 problem`, `Use enemies`.
Technical terms are fine where they're the clearest word. The text on screen uses American spelling,
as OpenReliant's screens do; docs and comments use British spelling.

## Writing Zig

Write idiomatic Zig 0.17, as OpenReliant's guide describes: name every number, give an id space an
`enum` and switch over it exhaustively, use tagged unions for variants and optionals for "none",
check invariants with `comptime`, and share code rather than copy it.

C and C++ come in through two shims and one header: the text editor's
([`src/ui/text_editor`](src/ui/text_editor)), Dear ImGui's internal calls
([`src/ui/imgui_extras`](src/ui/imgui_extras)), and [`src/platform/c.h`](src/platform/c.h), which
the build translates into the `c` module with SDL3 and Dear Bindings' C API for Dear ImGui.

Add `test` blocks next to the code in the same change, with inputs built by hand so that they run
without the game's files. `--check-missions` opens each of a game's own missions as source and
builds it again, for checking a change against the stock missions:

```bash
zig-out/bin/openreliant-editor --check-missions --game <game folder>
```

## Documentation

Document what the editor does under [`docs/`](docs), in plain, present-tense reference style. Call
the engine OpenReliant and the original game StarLancer. The project's text uses colons, commas,
parentheses or a second sentence in place of em and en dashes, which `make check-files` refuses.

## Checks

Before you open a pull request, run:

```bash
make check
```

It checks the formatting, the repository's files and the tests. CI runs the same on Linux, macOS
and Windows, and the tests in ReleaseFast too.

## Commits and pull requests

- Branch from `main` (`feat/script-view`, `fix/...`, `docs/...`) and open a pull request. `main`
changes only through squash-merged pull requests.
- Title the pull request in [Conventional Commits](https://www.conventionalcommits.org) form:
`feat: the Script view builds missions as they're typed`. Keep the body short, and end it with
`Closes #N` for each issue it finishes.
- File an issue for each gap you leave, and link it from the code where the gap is.
- Releases come from [release-please](https://github.com/googleapis/release-please), as
OpenReliant's do ([`release.yml`](.github/workflows/release.yml),
[`release-please-config.json`](release-please-config.json)): it keeps a release pull request open
with the next version and its changelog, and merging it tags the version and attaches the builds
for Windows, macOS and Linux, on x86-64 and Arm, with their checksums. `build.zig.zon` holds the
version being worked towards, which `--version` reports; the first release is 0.0.1.
- The repository holds the editor and its design. The game's files, and everything extracted or
derived from them, stay out: the pre-commit hook, `make check-files` and CI see to it.
42 changes: 42 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# The editor's workflows. `make help` lists them.

.PHONY: help build run test check fmt check-files hooks pictures icon

help:
@echo "make build build the editor into zig-out/bin"
@echo "make run build and run the editor (ARGS='<mod folder>' to open one)"
@echo "make test run the tests"
@echo "make check run the checks CI runs: formatting, files, tests"
@echo "make fmt format the Zig code"
@echo "make hooks install the pre-commit hook that keeps the game's files out"
@echo "make pictures take the design's pictures again (design/pictures.sh)"
@echo "make icon make the icon's PNGs, .ico and .icns from its SVG (scripts/icon.sh)"

build:
zig build --release=safe

run:
zig build run --release=safe -- $(ARGS)

test:
zig build test --summary all

check: check-files
zig fmt --check src build.zig
zig build test --summary all

fmt:
zig fmt src build.zig

check-files:
scripts/check-files.sh

hooks:
printf '#!/bin/sh\nexec scripts/check-files.sh --staged\n' > .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit

pictures:
design/pictures.sh

icon:
scripts/icon.sh
Loading
Loading