ccc3e20902
Smoke: one rule by engine, no heat on trails, no trail on P1-SUN. Searchlights: two lamps a target, off with an empty sky. Halos fade before their reach and their sum is limited. Launch sites load chunks through the server thread, go off-map as a last resort, and reach 4000 blocks. Air defence: ranges x1.5, shots grow with urgency, claims released, /airdef lastchance, long shots on a big radar's tracks. Build: rust-toolchain.toml, airdef.py check, generator manifest and --check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
97 lines
5.5 KiB
YAML
97 lines
5.5 KiB
YAML
# Большой релиз: только по тегу vX.Y.Z (git tag v0.3.0 && git push origin v0.3.0) или вручную с готовым тегом.
|
|
# Игра-форк для Windows собирается на Linux-сервере кросс-компиляцией (x86_64-pc-windows-gnu), без Windows-раннера.
|
|
# Сервер общий (2 ядра, 4 ГБ, Gitea и боты), поэтому контейнер ограничен: при нехватке памяти убивается сборка, а не
|
|
# сервисы. Замер 2026-10-30: 20,5 минуты, 2 ГБ памяти постоянно в потолке, у сервера не меньше 726 МБ свободно.
|
|
# Обычные коммиты сюда не попадают: build.yml собирает только мод.
|
|
name: release
|
|
|
|
on:
|
|
push:
|
|
tags: ['v*']
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: Существующий тег, например v0.3.0
|
|
required: true
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: never
|
|
CARGO_BUILD_JOBS: "1"
|
|
CARGO_INCREMENTAL: "0"
|
|
CARGO_PROFILE_FAST_INCREMENTAL: "false"
|
|
CARGO_PROFILE_FAST_DEBUG: "false"
|
|
CARGO_PROFILE_FAST_STRIP: "true"
|
|
TAG: ${{ inputs.tag || github.ref_name }}
|
|
|
|
jobs:
|
|
windows:
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: catthehacker/ubuntu:act-latest
|
|
options: --memory=2g --memory-swap=4500m --cpus=1.5 --cpu-shares=128 --blkio-weight=100 --oom-score-adj=800
|
|
steps:
|
|
- name: Место на диске
|
|
run: |
|
|
FREE=$(df --output=avail -BG / | tail -1 | tr -dc 0-9)
|
|
echo "свободно: ${FREE} ГБ"
|
|
if [ "$FREE" -lt 12 ]; then echo "::error::на сервере свободно ${FREE} ГБ, нужно хотя бы 12"; exit 1; fi
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: refs/tags/${{ inputs.tag || github.ref_name }}
|
|
- name: Инструменты
|
|
run: |
|
|
SUDO=$(command -v sudo || true)
|
|
$SUDO apt-get update -qq
|
|
$SUDO apt-get install -y -qq --no-install-recommends gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 zip
|
|
curl -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain none
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
# Версия Rust берётся из rust-toolchain.toml.
|
|
- name: Цели Rust
|
|
run: rustup target add x86_64-pc-windows-gnu wasm32-unknown-unknown
|
|
- name: Форк Horizon
|
|
run: nice -n 19 python3 tools/airdef.py fork
|
|
- name: Мод
|
|
run: nice -n 19 python3 tools/airdef.py mod
|
|
- name: Игра для Windows
|
|
working-directory: horizon
|
|
run: |
|
|
# Сторож: сервер важнее сборки. Память контейнера ограничена, это на случай, если её съело что-то ещё.
|
|
( while sleep 10; do
|
|
AVAIL=$(awk '/MemAvailable/{print int($2/1024)}' /proc/meminfo)
|
|
DISK=$(df --output=avail -BG / | tail -1 | tr -dc 0-9)
|
|
if [ "$AVAIL" -lt 250 ] || [ "$DISK" -lt 6 ]; then
|
|
echo "::error::сборка остановлена: свободно ${AVAIL} МБ памяти и ${DISK} ГБ диска"
|
|
pkill -9 cargo; pkill -9 rustc; exit 1
|
|
fi
|
|
done ) &
|
|
WATCH=$!
|
|
nice -n 19 ionice -c3 cargo build --profile fast -p horizon-client --features mods --target x86_64-pc-windows-gnu
|
|
kill "$WATCH"
|
|
- name: Архив
|
|
run: |
|
|
set -e
|
|
D=airdef-windows-x86_64
|
|
T=horizon/target/x86_64-pc-windows-gnu/fast
|
|
mkdir -p "$D" out
|
|
cp "$T/horizon-client.exe" "$T/horizon-ctl.exe" airdef-mod/target/horizon-mod/airdef.hmod dist/play.bat docs/INSTALL.md "$D/"
|
|
zip -qr "out/$D.zip" "$D"
|
|
cp airdef-mod/target/horizon-mod/airdef.hmod out/
|
|
- name: Релиз
|
|
env:
|
|
TOKEN: ${{ secrets.RELEASE_TOKEN || gitea.token }}
|
|
API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
|
|
run: |
|
|
set -e
|
|
if [ -z "$TOKEN" ]; then echo "::error::нет токена: добавь секрет RELEASE_TOKEN"; exit 1; fi
|
|
# Тег с дефисом (v0.3.0-rc1) выходит как предварительный релиз; уже созданный релиз тега дополняется.
|
|
DATA=$(python3 -c 'import json,os;t=os.environ["TAG"];print(json.dumps({"tag_name":t,"name":t,"prerelease":"-" in t,"body":"Windows: распакуй airdef-windows-x86_64.zip и запусти play.bat. Нужен Minecraft Java 26.3 и лаунчер Horizon, запущенный один раз. Подробнее: docs/INSTALL.md.\n\nmacOS: сборка из исходников, python3 tools/airdef.py all."}))')
|
|
CODE=$(curl -sS -o release.json -w '%{http_code}' -H "Authorization: token $TOKEN" "$API/releases/tags/$TAG")
|
|
if [ "$CODE" != "200" ]; then
|
|
CODE=$(curl -sS -o release.json -w '%{http_code}' -X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" "$API/releases" -d "$DATA")
|
|
if [ "$CODE" != "201" ]; then echo "::error::Gitea не создала релиз (HTTP $CODE): $(cat release.json)"; exit 1; fi
|
|
fi
|
|
ID=$(python3 -c 'import json;print(json.load(open("release.json"))["id"])')
|
|
for F in airdef-windows-x86_64.zip airdef.hmod; do
|
|
curl -sf -X POST -H "Authorization: token $TOKEN" -F "attachment=@out/$F" "$API/releases/$ID/assets?name=$F" > /dev/null
|
|
done
|