initial commit
All checks were successful
CI / fuzz (push) Successful in 1m41s
CI / lint (push) Successful in 16s
CI / test (push) Successful in 22s

This commit is contained in:
Kamal Tufekcic 2026-07-27 10:12:04 +03:00
commit a2922b8bad
59 changed files with 2684583 additions and 0 deletions

View file

@ -0,0 +1,132 @@
name: contribution
on:
pull_request:
paths:
- 'mappings/contributions/**'
concurrency:
group: contribution-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
contribution:
runs-on: s2-runner
env:
STEAM_APPS: /home/cs2/.steam/SteamApps
RELEASE_BASE: ${{ github.server_url }}/${{ github.repository }}/releases/download
API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
steps:
- uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Resolve the affected game and its paths
run: |
changed=$(git diff --name-only "origin/${{ github.base_ref }}...HEAD" -- 'mappings/contributions/**')
game=""
if echo "$changed" | grep -q 'contributions/csgo/'; then game=cs2; fi
if echo "$changed" | grep -q 'contributions/dota/'; then
if [ -n "$game" ]; then echo "PR touches both games — split it into one PR per game"; exit 1; fi
game=dota2
fi
if [ -z "$game" ]; then echo "no contributions/<game>/ files changed"; exit 1; fi
case "$game" in cs2) key=csgo; appid=730 ;; dota2) key=dota; appid=570 ;; esac
# The manifest carries the installed buildid + the install folder name (spaces and all).
manifest="$STEAM_APPS/appmanifest_$appid.acf"
[ -f "$manifest" ] || { echo "no manifest at $manifest — check STEAM_APPS"; exit 1; }
installdir=$(grep -oP '"installdir"\s+"\K[^"]+' "$manifest")
buildid=$(grep -oP '"buildid"\s+"\K[0-9]+' "$manifest")
game_dir="$STEAM_APPS/common/$installdir/game"
[ -d "$game_dir" ] || { echo "expected a game tree at '$game_dir' — check STEAM_APPS"; exit 1; }
{
echo "GAME=$game"
echo "KEY=$key"
echo "APPID=$appid"
echo "GAME_DIR=$game_dir"
echo "BUILDID=$buildid"
} >> "$GITHUB_ENV"
- name: Next patch number for this build
run: |
# The game-update run published <game>-<buildid>-0; each contribution on that build bumps the patch.
tags=$(curl -fsSL -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" "$API/releases?limit=100" | jq -r '.[].tag_name')
max=0
while read -r t; do
case "$t" in
"$GAME-$BUILDID-"*) p=${t##*-}; if [ "$p" -gt "$max" ] 2>/dev/null; then max=$p; fi ;;
esac
done <<< "$tags"
echo "PATCH=$((max + 1))" >> "$GITHUB_ENV"
- name: Fetch current model + seed
# Stored gzipped on the release (see derive.yml); the deriver reads plain JSON.
run: |
mkdir -p in dist work
curl -fsSL -o in/model.gz "$RELEASE_BASE/$GAME-latest/model-$GAME.json.gz"
gunzip -c in/model.gz > "in/model-$GAME.json"
curl -fsSL -o in/seed.gz "$RELEASE_BASE/$GAME-latest/seed-$GAME.json.gz"
gunzip -c in/seed.gz > "seed-$GAME.json"
- name: Fold the PR's contributions into the seed's snapshot
run: |
python3 - "$KEY" "seed-$GAME.json" "seed-$GAME.patched.json" <<'PY'
import json, sys, glob, os
key, seed_in, seed_out = sys.argv[1:4]
seed = json.load(open(seed_in))
contribs = dict(seed.get("contributions") or {})
for f in glob.glob(f"mappings/contributions/{key}/*.json"):
contribs[os.path.basename(f)] = json.load(open(f))
seed["contributions"] = contribs
json.dump(seed, open(seed_out, "w"))
PY
- name: Build the deriver
run: cargo build --release
- name: Produce — validate the contribution live (no model fold; the build is unchanged)
run: |
# The model already contains this build (derive folded it), and the forward-only guard needs the
# target to sort strictly after the model's latest. "<buildid>-<patch>" does: it shares the buildid
# prefix and is longer, and the next update's buildid still sorts above it.
ln -sfn "$GAME_DIR" "work/$BUILDID-$PATCH"
./target/release/source2rosetta --game "$GAME" produce \
--seed "seed-$GAME.patched.json" \
--corpus-model "in/model-$GAME.json" \
--target "work/$BUILDID-$PATCH" \
--game-dir "$GAME_DIR" \
--version "$GAME-$BUILDID-$PATCH" \
--out-dir dist
cp "seed-$GAME.patched.json" "dist/seed-$GAME.json"
- name: Drop the re-folded model, compress the seed
# A contribution does not change the binary, so the sidecar fold just re-folds a build the model
# already has. Publishing that would append a duplicate row and grow the model on every PR — so the
# model asset is left alone and `<game>-latest` keeps the one the last derive published.
run: |
rm -f "dist/model-$GAME.json"
gzip -6 "dist/seed-$GAME.json"
- name: Publish the immutable patch snapshot
uses: https://code.forgejo.org/actions/forgejo-release@v2
with:
direction: upload
url: ${{ github.server_url }}
repo: ${{ github.repository }}
tag: ${{ env.GAME }}-${{ env.BUILDID }}-${{ env.PATCH }}
release-dir: dist
token: ${{ secrets.GITHUB_TOKEN }}
override: true
release-notes: "${{ env.GAME }} gamedata — build ${{ env.BUILDID }}, patch ${{ env.PATCH }} (contribution PR #${{ github.event.pull_request.number }})."
- name: Move <game>-latest to this patch
uses: https://code.forgejo.org/actions/forgejo-release@v2
with:
direction: upload
url: ${{ github.server_url }}
repo: ${{ github.repository }}
tag: ${{ env.GAME }}-latest
release-dir: dist
token: ${{ secrets.GITHUB_TOKEN }}
override: true
release-notes: "Rolling ${{ env.GAME }} gamedata — currently build ${{ env.BUILDID }} patch ${{ env.PATCH }}. Stable URL; assets overwritten on each update."