Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
a43ebcd
SolLua: use sol::lua_nil instead of the sol::nil alias
MarkKropf Jun 18, 2026
3e83e20
float3: drop redundant direct streflop_cond.h include
tomjn Jun 18, 2026
517608f
SafeUtil: include <type_traits> and <memory> directly (#3025)
tomjn Jun 18, 2026
6318fb6
LuaTextures: log glTexImage failures instead of returning nil silently
iamaperson000 Jun 18, 2026
54348ff
fix: guard against already-dead reclaim targets (#3020)
bruno-dasilva Jun 19, 2026
e91a58f
CUtils: use const dirent* for the scandir selector on all platforms
tomjn Jun 20, 2026
580100a
legacy: only require X11 on non-Apple UNIX
tomjn Jun 20, 2026
d13dcd3
FindSevenZip: also accept the 7zz binary name
tomjn Jun 20, 2026
0da81b4
macOS: remove dead SDL 1.2-era SDLMain.{m,h}
tomjn Jun 19, 2026
83642b0
Fix SplinterFaction card link format
ScarylePoo Jun 21, 2026
13b6804
fix: update section min-level in place instead of appending duplicate…
bruno-dasilva Jun 22, 2026
1caa3c5
Convert `u8string_view` to `string` using explicit size
Jun 23, 2026
2186ee4
Fix inconsistent class/struct forward declarations
Jun 5, 2026
a854046
macOS: guard X11/Xlib.h include for non-X11 platforms
tomjn Jun 25, 2026
ab68d6f
fix: address sse2neon/streflop macro redefinition warning (#2999)
bruno-dasilva Jun 29, 2026
52b55cf
glad: do not build the GLX loader on macOS
tomjn Jun 29, 2026
4034d5a
docs: add ENGINE_PERFORMANCE.md with some notes on engine internals (…
bruno-dasilva Jun 29, 2026
7e07543
System: add missing <algorithm> includes for libc++
tomjn Jun 29, 2026
cf3b083
DemoTool: link nowide and fmt for their include directories
tomjn Jun 29, 2026
f898efc
Fix truncated sync checksum in demotool dump
burnhamrobertp Jun 19, 2026
8141bf2
Portability in archive handlers
tomjn Jun 30, 2026
898dd6c
docs: add BACKWARDS_COMPATIBILITY.md guidance doc for coding agents
bruno-dasilva Apr 11, 2026
487fd43
docs: improve running/testing instructions in AGENTS.md (#2917)
bruno-dasilva Jul 1, 2026
d313449
Move `isHeadless` from `Engine` to `Platform`. (#3067)
sprunk Jul 2, 2026
092cb0a
Add Lua trace ray functions (#1624)
12345swordy Jul 2, 2026
f1df2dc
Fix #3019, missing include
sprunk Jul 2, 2026
a15b7b3
Fix #2987, edge scrolling threshold
sprunk May 30, 2026
2b85283
Add type checking to ADD_FOO Lua defs macros
sprunk Apr 11, 2026
ed68dc1
Remove legacy engineoptions
sprunk May 1, 2026
615d257
fix desync
lostsquirrel1 Jul 6, 2026
c420138
SpringMath: add Catmull-Rom bicubic interpolation helpers
PtaQQ Jun 23, 2026
6eecb24
Update BARb 1.6.26
rlcevg Jul 4, 2026
62206aa
fix: links to other getting-started pages
L01sValencia Jul 8, 2026
2d4b031
Fix LuaSocket VFS mode error in LuaMenu
tomjn Jul 9, 2026
21b121c
Fix various typos in site articles (#3090)
L01sValencia Jul 10, 2026
2ccc5c0
Dump state handles resource packs
sprunk May 8, 2026
74408d1
doc/site: rename 7Z_VERSION env var so mise/Tera can parse it
tomjn Jul 10, 2026
0ea0be0
System: move float3/float4/Matrix44f str() out of line
tomjn Jul 10, 2026
c5cb63a
Remove Java AI bindings (#3059)
12345swordy Jul 10, 2026
9c2cb5f
Fix unbindaction not clearing scancode bindings
burnhamrobertp Jul 10, 2026
6c97815
fix: bump pr-downloader to suppress false positive gcc warning
bruno-dasilva Jul 13, 2026
3b76f97
`Spring.SetSkyBoxTexture` performs setup if needed
PtaQQ Jul 13, 2026
d306d39
LuaParser: run Spring.TimeCheck's callback under unitsync/dedicated
tomjn Jul 4, 2026
598d866
fix wide char to utf8 conversions. (#3100)
lostsquirrel1 Jul 14, 2026
69f829d
Add `debug.emulateFoo` input emulation API (#3097)
burnhamrobertp Jul 15, 2026
1a03e74
AIFloat3: Remove non-trivial copy constructor
rlcevg Jul 15, 2026
8ee4aa0
macOS: symbolicate arm64 crashes with `atos -arch arm64` (#3064)
tomjn Jul 15, 2026
3f7e649
Add `gadget:ResourceExcess(excessTable) -> bool`
sprunk Aug 15, 2025
c5fa84d
Add spAddTeamResourceExcessStats
keithharvey Jun 30, 2026
d5cc495
Add debug.emulateMouseWheel input emulation
burnhamrobertp Jul 15, 2026
75e64c5
Add a `cancelcommand` action
burnhamrobertp Jul 17, 2026
708f074
Update changelog.
sprunk May 6, 2026
2dd6918
feat: Add GetPrevFrameChecksum() to the Lua API (#2922)
bruno-dasilva Jul 19, 2026
e457c00
feat: add multi-platform sync testing (amd64-windows/linux + arm64-li…
bruno-dasilva Jul 19, 2026
8059a16
Bump game version in synctest.yml
bruno-dasilva Jul 20, 2026
359436d
Fix `/unbind` for keychains
burnhamrobertp Jul 20, 2026
a23be68
Fix stale `spGetActionHotKeys` returns (#3082)
burnhamrobertp Jul 21, 2026
48e9b00
Fixes to `Spring.SetMapShader` (#3127)
PtaQQ Jul 22, 2026
8e677dc
Optimize LuaPushNamedFoo using compile time key hashing (#2986)
dargem Jul 22, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/publish-site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ env:
LUA_DOC_EXTRACTOR_VERSION: "3"
EMMYLUA_DOC_CLI_VERSION: "0.8.2"
JQ_VERSION: "1.8.0"
7Z_VERSION: "24.09"
SEVENZIP_VERSION: "24.09"
RUBY_VERSION: "3.3"
MISE_ENV: "ci"
jobs:
Expand Down
273 changes: 273 additions & 0 deletions .github/workflows/synctest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
# Runs the Beyond All Reason "synctest" (/luarules synctest) against an engine
# commit on all supported platforms (amd64-linux, arm64-linux, amd64-windows).
#
# This workflow looks up the most recent successful "Build Engine v2" run for
# the target commit and downloads platform-specific artifacts. If no such run
# exists, the workflow fails fast.
# TODO: trigger after every engine build
#
# The cross-platform-check job compares hashes across architectures and is
# intended as a merge-blocking required check.
#
# See test/synctest/README.md for background and how to run locally.
name: Sync test

on:
workflow_dispatch:
inputs:
commit:
description: 'Engine commit SHA to test. Leave blank to test the head of the ref selected in the picker above.'
type: string
default: ''

permissions:
# actions:read is required to list workflow runs and download artifacts
# produced by a different workflow run (the Build Engine v2 run for the
# target commit).
actions: read
contents: read

defaults:
run:
shell: bash -euo pipefail {0}

env:
MAP: "Jade Empress 1.41"
GAME: "Beyond All Reason test-30707-555e3a1"
HASH_FILE: "synctest_synchash.json"

jobs:
setup:
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
sha: ${{ steps.resolve.outputs.sha }}
run_id: ${{ steps.engine-run.outputs.run_id }}
platforms: ${{ steps.platforms.outputs.json }}
env:
GH_TOKEN: ${{ github.token }}
steps:
- name: Define target platforms
id: platforms
# Single source of truth for the platform matrix: needed so we can check
# if we have all platforms even if a later setup step fails.
run: |
# jq -c -n validates the JSON and emits it compact, as GITHUB_OUTPUT requires.
json=$(jq -c -n '[
{"platform": "amd64-linux", "runs-on": "ubuntu-latest", "bin-suffix": ""},
{"platform": "arm64-linux", "runs-on": "ubuntu-24.04-arm", "bin-suffix": ""},
{"platform": "amd64-windows", "runs-on": "windows-latest", "bin-suffix": ".exe"}
]')
echo "json=$json" >> "$GITHUB_OUTPUT"

- name: Resolve target commit
id: resolve
env:
INPUT_COMMIT: ${{ inputs.commit }}
REPO: ${{ github.repository }}
DEFAULT_SHA: ${{ github.sha }}
run: |
target="${INPUT_COMMIT:-$DEFAULT_SHA}"

# Normalize whatever the user pasted (full sha, short sha, branch, tag)
# into a full 40-char SHA so the run lookup below is unambiguous.
full_sha=$(gh api "repos/$REPO/commits/$target" --jq '.sha')
echo "Resolved target commit: $full_sha"
echo "sha=$full_sha" >> "$GITHUB_OUTPUT"

- name: Find Build Engine v2 run for this commit
id: engine-run
env:
REPO: ${{ github.repository }}
TARGET_SHA: ${{ steps.resolve.outputs.sha }}
run: |
run_id=$(gh api \
"repos/$REPO/actions/workflows/engine-build.yml/runs?head_sha=$TARGET_SHA&status=success" \
--jq '.workflow_runs[0].id')
if [ -z "$run_id" ] || [ "$run_id" = "null" ]; then
echo "::error::No successful 'Build Engine v2' run found for commit $TARGET_SHA."
echo "::error::Trigger Build Engine v2 on that commit first (push it, or dispatch engine-build.yml manually) and retry."
exit 1
fi
echo "Using engine-build run $run_id"
echo "run_id=$run_id" >> "$GITHUB_OUTPUT"

synctest:
needs: setup
runs-on: ${{ matrix.runs-on }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.setup.outputs.platforms) }}
steps:
- name: Checkout workflow definition and test inputs
# Uses the ref picked in the dispatch UI (github.sha), NOT the target
# commit — so the startscript and any other test assets come from the
# workflow-definition ref. The target commit only controls which engine
# artifact gets downloaded below.
uses: actions/checkout@v4

- name: Download engine artifact (${{ matrix.platform }})
uses: actions/download-artifact@v4
with:
pattern: engine-artifacts-${{ matrix.platform }}*
run-id: ${{ needs.setup.outputs.run_id }}
github-token: ${{ github.token }}
path: engine-artifact
merge-multiple: true

- name: Extract install tree
run: |
mkdir -p install

# Engine is packaged with INSTALL_PORTABLE=ON (CMake default, see
# CMakeLists.txt:22), so binaries live at the install-tree root:
# install/spring-headless, install/pr-downloader, install/spring, ...
# The archive name comes from docker-build-v2/scripts/package.sh; that
# script also emits a -dbgsym.tar.zst, which this glob excludes.
#
# Windows has 7z.exe, and ubuntu currently has 7z/7zz/7za but may later
# drop to just 7zz/7za.
sevenzip=$(command -v 7z || command -v 7zz || command -v 7za || true)
if [ -z "$sevenzip" ]; then
echo "::error::no 7-Zip binary (7z/7zz/7za) found on runner"; exit 1
fi
"$sevenzip" x engine-artifact/recoil_*_${{ matrix.platform }}*.7z -oinstall

- name: Restore BAR content cache
uses: actions/cache@v4
with:
# Content-addressed and immutable, so all three platform legs share one
# entry. packages/ (the <md5>.sdp manifests) is required alongside pool/
# for the engine to mount the game. Deliberately NOT the whole write-dir:
# everything else the engine writes here is build- and platform-specific.
# rapid/ is excluded too — mutable repo metadata, a few MB, refetched so
# the pin is genuinely re-resolved each run.
path: |
bar-data/pool
bar-data/packages
bar-data/maps
# IMPORTANT:
# Bump this key in lockstep with any change to the pinned
# gametype/mapname. See test/synctest/README.md.
key: bar-data-${{ env.GAME }}-${{ env.MAP }}

- name: Fetch pinned BAR assets (no-op on warm cache)
run: |
./install/pr-downloader${{ matrix.bin-suffix }} \
--filesystem-writepath "$PWD/bar-data" \
--download-game "$GAME" \
--download-map "$MAP"
env:
PRD_RAPID_USE_STREAMER: "false"
PRD_RAPID_REPO_MASTER: "https://repos-cdn.beyondallreason.dev/repos.gz"
PRD_HTTP_SEARCH_URL: "https://files-cdn.beyondallreason.dev/find"

- name: Render startscript
run: |
# The checked-in startscript is a template: @VERSION@ is the version
# suffix of the pinned GAME (text after the last space, e.g.
# "test-29932-21b3bb0") and @MAPNAME@ is MAP.
sed -e "s/@VERSION@/${GAME##* }/g" -e "s/@MAPNAME@/$MAP/g" \
test/synctest/synctest-startscript.txt > startscript.txt

# Fail loudly here rather than letting the engine fail later with an
# opaque "can't find game/map" error.
if grep -qE '@VERSION@|@MAPNAME@' startscript.txt; then
echo "::error::startscript template was not fully rendered — leftover placeholders:"
grep -nE '@VERSION@|@MAPNAME@' startscript.txt
exit 1
fi
grep -nE 'gametype=|mapname=' startscript.txt

- name: Run synctest
run: |
./install/spring-headless${{ matrix.bin-suffix }} --isolation \
--write-dir "$PWD/bar-data" startscript.txt 2>&1 | tee infolog.txt

- name: Assert sync-hash file produced
run: |
digest=$(jq -r '.digest // empty' "bar-data/$HASH_FILE" 2>/dev/null || true)
if [ -z "$digest" ]; then
echo "::error::bar-data/$HASH_FILE is missing, empty, or has no .digest — the synctest produced no checksum output"
exit 1
fi
echo "Sync hash digest: $digest"

- name: Upload run artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: synctest-${{ matrix.platform }}-${{ needs.setup.outputs.sha }}
path: |
infolog.txt
bar-data/*.log
bar-data/${{ env.HASH_FILE }}
retention-days: 30
if-no-files-found: ignore

# Collects sync hashes from all synctest runs across platforms and fails if
# hashes diverge between architectures (cross-platform desync detection).
# This job is intended to be a required/merge-blocking status check.
cross-platform-check:
if: ${{ !cancelled() }}
needs: [setup, synctest]
runs-on: ubuntu-latest
timeout-minutes: 5
env:
TESTED_SHA: ${{ needs.setup.outputs.sha }}
steps:
- name: Assert setup produced a platform list
env:
PLATFORMS_JSON: ${{ needs.setup.outputs.platforms }}
run: |
if [ -z "$PLATFORMS_JSON" ]; then
echo "::error::setup produced no platform list — it likely failed before it ran; check the setup job."
exit 1
fi

- name: Download current run artifacts
# If every platform leg died before uploading, the pattern matches
# nothing and this step errors. That is not the failure we want to
# report, so swallow it and let the MISSING check below speak instead.
continue-on-error: true
uses: actions/download-artifact@v4
with:
pattern: synctest-*-${{ env.TESTED_SHA }}
path: artifacts

- name: Compare sync hashes across platforms
env:
PLATFORMS_JSON: ${{ needs.setup.outputs.platforms }}
run: |
# Check from the EXPECTED platform list, so if artifact uploading fails
# we will be able to detect that its missing.
for platform in $(jq -r '.[].platform' <<<"$PLATFORMS_JSON"); do
digest=$(jq -r '.digest // empty' \
"artifacts/synctest-$platform-$TESTED_SHA/bar-data/$HASH_FILE" 2>/dev/null || true)
echo "$platform ${digest:-MISSING}"
done > synchashes.txt

echo "Cross-platform determinism check:"
cat synchashes.txt

if grep -qw MISSING synchashes.txt; then
echo "::error::sync hash MISSING on at least one platform — see the per-platform jobs"
exit 1
fi
digests=$(awk '{print $2}' synchashes.txt | sort -u)
if [ "$(wc -l <<<"$digests")" -gt 1 ]; then
echo "::error::CROSS-PLATFORM DESYNC — hashes differ across architectures; the engine is not deterministic across platforms"
exit 1
fi
echo "OK across all platforms ($digests)"

# A platform can write the hash and then fail, but
# `!cancelled()` means we still run the comparison.
# So let's do a final check to make sure they all passed.
- name: Assert all synctest jobs succeeded
if: ${{ needs.synctest.result != 'success' }}
run: |
echo "::error::synctest matrix result is '${{ needs.synctest.result }}' — a platform leg did not succeed; see the per-platform jobs"
exit 1
Loading
Loading