A Gitea job that checks each new Rust staging build in the seven days before the monthly forced wipe: - tools/drill/static.sh: staging's managed assemblies (DepotDownloader) and Oxide's staging build; whether Oxide has caught up (fieldlist --oxide-behind), the swap's field list compared, and the plugin compiled. - tools/drill/drill.js: window (D318), gate (one check per depot manifest), live (rust-staging runs rnt.run all; rust-carbon is stopped and restarted when both 6000-map rigs run, D309) and report (one issue per build, state on the drill branch; a build waits up to three days for Oxide, D317). - tools/drill/rig-start.sh: the rig's startup; installs the branch and Oxide's build for it, and refuses to start a mismatched pair. - RunicNpcTest 0.7.2: stage 5's five fights look for a field with room for their 280 m line (D319), and the spawn check names what did not spawn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
146 lines
6.4 KiB
Bash
146 lines
6.4 KiB
Bash
#!/bin/bash
|
|
# The staging drill's static half (docs/runicnpc/PLAN.md D308). Never shipped.
|
|
#
|
|
# tools/drill/static.sh (WORK=drill-work BRANCH=staging by default)
|
|
#
|
|
# Needs no server. It downloads only RustDedicated_Data/Managed/*.dll from a Steam branch, and
|
|
# Oxide's build for that branch, and:
|
|
#
|
|
# 1. asks whether Oxide's build has caught up with Rust's (tools/fieldlist --oxide-behind). Until it
|
|
# has, an Oxide server on that branch dies at boot, so the drill waits for it (D317);
|
|
# 2. regenerates the swap's field list (tools/fieldlist, D232) from Rust's own Assembly-CSharp.dll
|
|
# and compares it with the one plugin/RunicNPC.cs carries;
|
|
# 3. compiles plugin/RunicNPC.cs against those assemblies with Oxide's laid over them, as an Oxide
|
|
# server would. Oxide's patched Assembly-CSharp.dll is needed: the plugin uses members Rust
|
|
# ships non-public (IAISenses, for one).
|
|
#
|
|
# It writes $WORK/static.json and, beside it, oxide-behind.txt, fields.diff and compile.txt. In
|
|
# static.json, oxideBehind is a count (-1: not measured), fields "same"/"differs", compile
|
|
# "ok"/"errors", and either is "error" when its step could not run. The script exits 0 whenever it
|
|
# ran; what it found is in static.json. DEPOTDOWNLOADER and DOTNET point at other copies (on
|
|
# Windows, DEPOTDOWNLOADER=…/DepotDownloader.exe from Git Bash).
|
|
|
|
set -uo pipefail
|
|
|
|
ROOT=$(cd "$(dirname "$0")/../.." && pwd)
|
|
WORK=${WORK:-$ROOT/drill-work}
|
|
BRANCH=${BRANCH:-staging}
|
|
if [ "$BRANCH" = public ]; then
|
|
OXIDE_URL=${OXIDE_URL:-https://github.com/OxideMod/Oxide.Rust/releases/latest/download/Oxide.Rust-linux.zip}
|
|
else
|
|
OXIDE_URL=${OXIDE_URL:-https://downloads.oxidemod.com/artifacts/Oxide.Rust/$BRANCH/Oxide.Rust-linux.zip}
|
|
fi
|
|
DD_URL=https://github.com/SteamRE/DepotDownloader/releases/download/DepotDownloader_3.4.0/DepotDownloader-linux-x64.zip
|
|
DOTNET=${DOTNET:-dotnet}
|
|
|
|
mkdir -p "$WORK"
|
|
rm -rf "$WORK/depot" "$WORK/oxide" "$WORK/refs" "$WORK/fields"
|
|
rm -f "$WORK"/static.json "$WORK"/oxide-behind.txt "$WORK"/fields.diff "$WORK"/compile.txt
|
|
|
|
managed=error
|
|
behind=-1
|
|
fields=error
|
|
compile=error
|
|
note=""
|
|
oxide_modified=""
|
|
manifest=""
|
|
manifest_date=""
|
|
|
|
finish() {
|
|
printf '{"branch":"%s","manifest":"%s","manifestDate":"%s","managed":"%s","oxideBehind":%s,"fields":"%s","compile":"%s","oxideModified":"%s","note":"%s"}\n' \
|
|
"$BRANCH" "$manifest" "$manifest_date" "$managed" "$behind" "$fields" "$compile" "$oxide_modified" "$note" > "$WORK/static.json"
|
|
cat "$WORK/static.json"
|
|
exit 0
|
|
}
|
|
|
|
# Git Bash does not translate paths inside a response file; elsewhere this is the path as it is.
|
|
native() { if command -v cygpath > /dev/null; then cygpath -m "$1"; else printf '%s' "$1"; fi; }
|
|
|
|
# ---- Rust's managed assemblies, from Steam (no login: the dedicated server is anonymous) ----
|
|
|
|
DD=${DEPOTDOWNLOADER:-}
|
|
if [ -z "$DD" ]; then
|
|
curl -sSL --fail -o "$WORK/dd.zip" "$DD_URL" && unzip -oq "$WORK/dd.zip" -d "$WORK/dd" && chmod +x "$WORK/dd/DepotDownloader" \
|
|
|| { note="DepotDownloader could not be fetched"; finish; }
|
|
DD=$WORK/dd/DepotDownloader
|
|
fi
|
|
|
|
printf 'regex:^RustDedicated_Data/Managed/[^/]+\\.dll$\n' > "$WORK/files.txt"
|
|
"$DD" -app 258550 -depot 258552 -branch "$BRANCH" -filelist "$WORK/files.txt" -dir "$WORK/depot" -os linux \
|
|
> "$WORK/depot.txt" 2>&1
|
|
MANAGED=$WORK/depot/RustDedicated_Data/Managed
|
|
# Which build this is, from Steam itself: the Linux depot's manifest and its date. (api.steamcmd.net
|
|
# answered a build id a day stale on 2026-10-06, so the drill does not ask it.)
|
|
manifest=$(tr -d '\r' < "$WORK/depot.txt" | sed -n 's/^Manifest \([0-9]*\) (\(.*\))$/\1/p' | head -1)
|
|
manifest_date=$(tr -d '\r' < "$WORK/depot.txt" | sed -n 's/^Manifest \([0-9]*\) (\(.*\))$/\2/p' | head -1)
|
|
if [ ! -f "$MANAGED/Assembly-CSharp.dll" ]; then
|
|
note="no Assembly-CSharp.dll from Steam's $BRANCH branch: $(tail -3 "$WORK/depot.txt" | tr '\n"' ' ')"
|
|
finish
|
|
fi
|
|
managed=ok
|
|
|
|
# ---- Oxide's build for the branch ----
|
|
|
|
oxide_modified=$(curl -sSIL "$OXIDE_URL" | tr -d '\r' | sed -n 's/^[Ll]ast-[Mm]odified: //p' | tail -1)
|
|
if ! { curl -sSL --fail -o "$WORK/oxide.zip" "$OXIDE_URL" && unzip -oq "$WORK/oxide.zip" -d "$WORK/oxide"; }; then
|
|
note="Oxide's $BRANCH build could not be downloaded"
|
|
finish
|
|
fi
|
|
OXIDE_MANAGED=$WORK/oxide/RustDedicated_Data/Managed
|
|
|
|
# The tool is built once, here, so a build failure is not mistaken for anything it reports.
|
|
if ! "$DOTNET" build "$ROOT/tools/fieldlist" -c Release -o "$WORK/fieldlist" > "$WORK/fieldlist-build.txt" 2>&1; then
|
|
note="tools/fieldlist did not build: $(grep -m1 'error' "$WORK/fieldlist-build.txt" | tr '"' ' ')"
|
|
finish
|
|
fi
|
|
FIELDLIST=("$DOTNET" "$WORK/fieldlist/FieldList.dll")
|
|
|
|
# ---- 1. Has Oxide caught up? ----
|
|
|
|
if "${FIELDLIST[@]}" --oxide-behind "$MANAGED" "$OXIDE_MANAGED/Assembly-CSharp.dll" > "$WORK/oxide-behind.txt" 2>&1; then
|
|
behind=$(sed -n 's/^behind \([0-9]*\)$/\1/p' "$WORK/oxide-behind.txt" | head -1)
|
|
behind=${behind:--1}
|
|
fi
|
|
|
|
# ---- 2. The swap's field list (D232) ----
|
|
|
|
mkdir -p "$WORK/fields"
|
|
cp "$ROOT/plugin/RunicNPC.cs" "$WORK/fields/RunicNPC.cs"
|
|
block() { sed -n '/\/\/ <fieldlist>/,/\/\/ <\/fieldlist>/p' "$1" | grep -v "Generated by tools/fieldlist" | tr -d '\r'; }
|
|
if "${FIELDLIST[@]}" "$MANAGED" "$WORK/fields/RunicNPC.cs" > "$WORK/fields/run.txt" 2>&1; then
|
|
if diff -u --label carried <(block "$ROOT/plugin/RunicNPC.cs") --label "$BRANCH" <(block "$WORK/fields/RunicNPC.cs") > "$WORK/fields.diff"; then
|
|
fields=same
|
|
else
|
|
fields=differs
|
|
fi
|
|
else
|
|
cp "$WORK/fields/run.txt" "$WORK/fields.diff"
|
|
fi
|
|
|
|
# ---- 3. Compile against the branch with Oxide's build laid over ----
|
|
|
|
mkdir -p "$WORK/refs"
|
|
cp "$MANAGED"/*.dll "$WORK/refs/"
|
|
cp "$OXIDE_MANAGED"/*.dll "$WORK/refs/"
|
|
# Oxide.References.dll bundles its own older copy of Newtonsoft.Json, which Oxide's compiler never
|
|
# references; with it, every JObject is ambiguous.
|
|
rm -f "$WORK/refs/Oxide.References.dll"
|
|
|
|
DOTNET_DIR=$(dirname "$(readlink -f "$(command -v "$DOTNET")")")
|
|
CSC=$(ls "$DOTNET_DIR"/sdk/*/Roslyn/bincore/csc.dll 2>/dev/null | tail -1)
|
|
if [ -z "$CSC" ]; then
|
|
note="no csc.dll under $DOTNET_DIR/sdk"
|
|
finish
|
|
fi
|
|
|
|
# A response file: some 250 references outgrow a Windows command line.
|
|
for f in "$WORK/refs"/*.dll; do printf '"-r:%s"\n' "$(native "$f")"; done > "$WORK/refs.rsp"
|
|
if "$DOTNET" "$CSC" -nologo -noconfig -nostdlib -target:library -nowarn:1701,1702 -warn:0 \
|
|
-out:"$WORK/RunicNPC.dll" "@$WORK/refs.rsp" "$ROOT/plugin/RunicNPC.cs" > "$WORK/compile.txt" 2>&1; then
|
|
compile=ok
|
|
else
|
|
compile=errors
|
|
fi
|
|
|
|
finish
|