feat: initial Elsword-GE builder
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
name: build-elsword-ge
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 4 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build-release:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
run: |
|
||||
git init .
|
||||
git config --global --add safe.directory "$PWD"
|
||||
git remote add origin "${{ gitea.server_url }}/${{ gitea.repository }}.git"
|
||||
git -c http.extraHeader="Authorization: token ${{ secrets.GITEA_TOKEN }}" fetch --depth 1 origin "${{ gitea.sha }}"
|
||||
git checkout --detach FETCH_HEAD
|
||||
|
||||
- name: Build Elsword Proton-GE 10-34 tool
|
||||
run: |
|
||||
nix develop -c ./build.sh --no-install
|
||||
|
||||
- name: Create or update Gitea release
|
||||
env:
|
||||
GITEA_SERVER_URL: ${{ gitea.server_url }}
|
||||
GITEA_REPOSITORY: ${{ gitea.repository }}
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
GITEA_SHA: ${{ gitea.sha }}
|
||||
run: |
|
||||
nix develop -c bash -lc '
|
||||
set -euo pipefail
|
||||
set -a
|
||||
. dist/package-info.env
|
||||
set +a
|
||||
|
||||
RELEASE_API="${GITEA_SERVER_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases"
|
||||
RELEASE_TAG_URL="$(python3 -c "import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=\"\"))" "$RELEASE_TAG")"
|
||||
ARCHIVE_URL_NAME="$(python3 -c "import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=\"\"))" "$ARCHIVE_FILE")"
|
||||
|
||||
HTTP_CODE="$(curl -s -o /tmp/release.json -w "%{http_code}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${RELEASE_API}/tags/${RELEASE_TAG_URL}")"
|
||||
|
||||
if [ "$HTTP_CODE" = "200" ]; then
|
||||
RELEASE_ID="$(python3 -c "import json; print(json.load(open(\"/tmp/release.json\"))[\"id\"])" )"
|
||||
elif [ "$HTTP_CODE" = "404" ]; then
|
||||
python3 -c "import json, pathlib, os; pathlib.Path(\"/tmp/release-create.json\").write_text(json.dumps({
|
||||
\"tag_name\": os.environ[\"RELEASE_TAG\"],
|
||||
\"target_commitish\": os.environ[\"GITEA_SHA\"],
|
||||
\"name\": os.environ[\"RELEASE_TAG\"],
|
||||
\"body\": pathlib.Path(\"dist/release-notes.md\").read_text(),
|
||||
\"draft\": False,
|
||||
\"prerelease\": False,
|
||||
}))"
|
||||
curl --fail-with-body \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data-binary @/tmp/release-create.json \
|
||||
"${RELEASE_API}" > /tmp/release.json
|
||||
RELEASE_ID="$(python3 -c "import json; print(json.load(open(\"/tmp/release.json\"))[\"id\"])" )"
|
||||
else
|
||||
cat /tmp/release.json
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python3 -c "import json, pathlib, os; pathlib.Path(\"/tmp/release-update.json\").write_text(json.dumps({
|
||||
\"tag_name\": os.environ[\"RELEASE_TAG\"],
|
||||
\"target_commitish\": os.environ[\"GITEA_SHA\"],
|
||||
\"name\": os.environ[\"RELEASE_TAG\"],
|
||||
\"body\": pathlib.Path(\"dist/release-notes.md\").read_text(),
|
||||
\"draft\": False,
|
||||
\"prerelease\": False,
|
||||
}))"
|
||||
curl --fail-with-body \
|
||||
-X PATCH \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data-binary @/tmp/release-update.json \
|
||||
"${RELEASE_API}/${RELEASE_ID}" > /tmp/release.json
|
||||
|
||||
curl --fail-with-body \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${RELEASE_API}/${RELEASE_ID}/assets" > /tmp/assets.json
|
||||
|
||||
EXISTING_ASSET_ID="$(python3 -c "import json, os; data=json.load(open(\"/tmp/assets.json\")); target=os.environ[\"ARCHIVE_FILE\"]; print(next((str(item[\"id\"]) for item in data if item.get(\"name\") == target), \"\"))")"
|
||||
if [ -n "$EXISTING_ASSET_ID" ]; then
|
||||
curl --fail-with-body \
|
||||
-X DELETE \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${RELEASE_API}/${RELEASE_ID}/assets/${EXISTING_ASSET_ID}"
|
||||
fi
|
||||
|
||||
curl --fail-with-body \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
--data-binary @"dist/${ARCHIVE_FILE}" \
|
||||
"${RELEASE_API}/${RELEASE_ID}/assets?name=${ARCHIVE_URL_NAME}"
|
||||
'
|
||||
@@ -0,0 +1,2 @@
|
||||
.cache/
|
||||
dist/
|
||||
@@ -0,0 +1,95 @@
|
||||
# Elsword Proton-GE Builder
|
||||
|
||||
Dieses Repo baut per Gitea Actions versionierte Proton-GE-Kompatibilitätstools
|
||||
für Elsword mit `dxvk-git` und Steam Linux Runtime 3.0 (`sniper`).
|
||||
|
||||
## Was gebaut wird
|
||||
|
||||
- Tool-Name: `Elsword-GE-(Version)`
|
||||
- Beispiel: `Elsword-GE-11-1`
|
||||
- Runtime: `1628350` (`Steam Linux Runtime 3.0`)
|
||||
- DXVK: standardmäßig `dxvk-git`
|
||||
- Ausgabe: versionierte `.tar.xz`-Archive in `dist/`
|
||||
|
||||
Ältere lokal installierte Versionen wie `Elsword-GE-10-30` bleiben bestehen,
|
||||
weil jede Build ihren eigenen Tool-Namen bekommt.
|
||||
|
||||
## Ablauf
|
||||
|
||||
1. Das Repo nutzt standardmäßig `GE-Proton10-34`.
|
||||
2. DXVK wird aus Upstream gebaut, standardmäßig als `dxvk-git`.
|
||||
3. Die GE-Basis wird auf `sniper` umgestellt.
|
||||
4. Die DXVK-DLLs in Proton-GE werden ersetzt.
|
||||
5. Das Ergebnis wird als eigenes Steam-Compatibility-Tool paketiert.
|
||||
6. Die Gitea Action erstellt oder aktualisiert ein Release und lädt das Archiv hoch.
|
||||
|
||||
## Standardverhalten
|
||||
|
||||
Ohne Parameter baut `build.sh`:
|
||||
|
||||
- `GE-Proton10-34`
|
||||
- mit `dxvk-git`
|
||||
- als Tool `Elsword-GE-(Version)`
|
||||
- mit `sniper`
|
||||
|
||||
## Lokaler Build
|
||||
|
||||
```bash
|
||||
nix develop -c ./build.sh
|
||||
```
|
||||
|
||||
Nur Archiv bauen, nicht lokal installieren:
|
||||
|
||||
```bash
|
||||
nix develop -c ./build.sh --no-install
|
||||
```
|
||||
|
||||
Einen bestimmten GE-Tag bauen:
|
||||
|
||||
```bash
|
||||
nix develop -c ./build.sh --proton-tag GE-Proton11-1
|
||||
```
|
||||
|
||||
Eigenen Tool-Namen setzen:
|
||||
|
||||
```bash
|
||||
nix develop -c ./build.sh --tool-name Elsword-GE-test
|
||||
```
|
||||
|
||||
## Wichtige Optionen
|
||||
|
||||
- `--proton-tag TAG`
|
||||
- `--proton-asset x86_64|aarch64`
|
||||
- `--dxvk-channel git|stable`
|
||||
- `--dxvk-tag TAG`
|
||||
- `--tool-prefix PREFIX`
|
||||
- `--tool-name NAME`
|
||||
- `--runtime-appid APPID`
|
||||
- `--no-install`
|
||||
|
||||
## Gitea Actions
|
||||
|
||||
Der Workflow liegt unter:
|
||||
|
||||
- `.gitea/workflows/build.yml`
|
||||
|
||||
Er läuft bei:
|
||||
|
||||
- manuellem Start per `workflow_dispatch`
|
||||
- automatischem Zeitplan täglich
|
||||
|
||||
Für Release-Uploads braucht der Workflow ein Secret:
|
||||
|
||||
- `GITEA_TOKEN`
|
||||
|
||||
Dieses Token muss Release-Schreibrechte auf das Repo haben.
|
||||
|
||||
## Release-Ausgabe
|
||||
|
||||
Nach einem Build schreibt das Skript nach `dist/`:
|
||||
|
||||
- das fertige `.tar.xz`-Archiv
|
||||
- `package-info.env`
|
||||
- `release-notes.md`
|
||||
|
||||
Die Gitea Action nutzt diese Dateien direkt für das Release.
|
||||
@@ -0,0 +1,570 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CACHE_DIR="$REPO_ROOT/.cache"
|
||||
DIST_DIR="$REPO_ROOT/dist"
|
||||
WORK_BASE="$CACHE_DIR/work"
|
||||
DXVK_CACHE_DIR="$CACHE_DIR/dxvk"
|
||||
STEAM_COMPAT_DIR="${HOME}/.local/share/Steam/compatibilitytools.d"
|
||||
UPSTREAM_REPO="GloriousEggroll/proton-ge-custom"
|
||||
PROTON_TAG="GE-Proton10-34"
|
||||
PROTON_ASSET="x86_64"
|
||||
DXVK_CHANNEL="git"
|
||||
DXVK_TAG="latest"
|
||||
RUNTIME_APPID="1628350"
|
||||
TOOL_PREFIX="Elsword-GE"
|
||||
TOOL_NAME=""
|
||||
KEEP_WORK=0
|
||||
DXVK_SRC_OVERRIDE=""
|
||||
MINGW_PTHREAD_ROOT="${MINGW_PTHREAD_ROOT:-}"
|
||||
INSTALL_TOOL=1
|
||||
DXVK_DESCRIBE=""
|
||||
DXVK_FULL_SHA=""
|
||||
DXVK_SHORT_SHA=""
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: ./build.sh [options]
|
||||
|
||||
Build a custom Proton-GE compatibility tool for Elsword and replace its bundled
|
||||
DXVK with a chosen DXVK build, defaulting to GE-Proton10-34 plus dxvk-git on
|
||||
Steam Linux Runtime 3.0 (sniper).
|
||||
|
||||
Options:
|
||||
--proton-tag TAG Build a specific Proton-GE release tag, default: GE-Proton10-34
|
||||
--proton-asset x86_64|aarch64 Choose which Proton-GE asset to use
|
||||
--dxvk-channel git|stable Choose DXVK source channel, default: git
|
||||
--dxvk-tag TAG Stable DXVK tag to use when --dxvk-channel stable
|
||||
--tool-prefix PREFIX Tool name prefix, default: Elsword-GE
|
||||
--tool-name NAME Override final tool name completely
|
||||
--runtime-appid APPID Steam Runtime appid, default: 1628350 (sniper)
|
||||
--steam-compat-dir PATH Override compatibilitytools.d path
|
||||
--dxvk-src PATH Use an existing dxvk checkout instead of cache
|
||||
--mingw-pthread-root PATH Path with x32/libpthread.a and x64/libpthread.a
|
||||
--dist-dir PATH Output directory for sendable archives
|
||||
--no-install Build/package only, do not install into Steam
|
||||
--keep-work Keep temporary work directory
|
||||
-h, --help Show this help
|
||||
EOF
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--proton-tag)
|
||||
PROTON_TAG="${2:?missing value for --proton-tag}"
|
||||
shift 2
|
||||
;;
|
||||
--proton-asset)
|
||||
PROTON_ASSET="${2:?missing value for --proton-asset}"
|
||||
shift 2
|
||||
;;
|
||||
--dxvk-channel)
|
||||
DXVK_CHANNEL="${2:?missing value for --dxvk-channel}"
|
||||
shift 2
|
||||
;;
|
||||
--dxvk-tag)
|
||||
DXVK_TAG="${2:?missing value for --dxvk-tag}"
|
||||
shift 2
|
||||
;;
|
||||
--tool-prefix)
|
||||
TOOL_PREFIX="${2:?missing value for --tool-prefix}"
|
||||
shift 2
|
||||
;;
|
||||
--tool-name)
|
||||
TOOL_NAME="${2:?missing value for --tool-name}"
|
||||
shift 2
|
||||
;;
|
||||
--runtime-appid)
|
||||
RUNTIME_APPID="${2:?missing value for --runtime-appid}"
|
||||
shift 2
|
||||
;;
|
||||
--steam-compat-dir)
|
||||
STEAM_COMPAT_DIR="${2:?missing value for --steam-compat-dir}"
|
||||
shift 2
|
||||
;;
|
||||
--dxvk-src)
|
||||
DXVK_SRC_OVERRIDE="${2:?missing value for --dxvk-src}"
|
||||
shift 2
|
||||
;;
|
||||
--mingw-pthread-root)
|
||||
MINGW_PTHREAD_ROOT="${2:?missing value for --mingw-pthread-root}"
|
||||
shift 2
|
||||
;;
|
||||
--dist-dir)
|
||||
DIST_DIR="${2:?missing value for --dist-dir}"
|
||||
shift 2
|
||||
;;
|
||||
--no-install)
|
||||
INSTALL_TOOL=0
|
||||
shift
|
||||
;;
|
||||
--keep-work)
|
||||
KEEP_WORK=1
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1" >&2
|
||||
usage >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
case "$PROTON_ASSET" in
|
||||
x86_64|aarch64) ;;
|
||||
*)
|
||||
echo "Unsupported --proton-asset: $PROTON_ASSET" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$DXVK_CHANNEL" in
|
||||
git|stable) ;;
|
||||
*)
|
||||
echo "Unsupported --dxvk-channel: $DXVK_CHANNEL" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
require_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
echo "Missing required command: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
for cmd in \
|
||||
curl \
|
||||
git \
|
||||
nix \
|
||||
tar \
|
||||
meson \
|
||||
ninja \
|
||||
python3 \
|
||||
realpath \
|
||||
glslangValidator \
|
||||
x86_64-w64-mingw32-gcc \
|
||||
x86_64-w64-mingw32-g++ \
|
||||
i686-w64-mingw32-gcc \
|
||||
i686-w64-mingw32-g++ \
|
||||
wine; do
|
||||
require_cmd "$cmd"
|
||||
done
|
||||
|
||||
mkdir -p "$CACHE_DIR" "$WORK_BASE" "$DIST_DIR"
|
||||
if [[ "$INSTALL_TOOL" -eq 1 ]]; then
|
||||
mkdir -p "$STEAM_COMPAT_DIR"
|
||||
fi
|
||||
WORK_DIR="$(mktemp -d "$WORK_BASE/build.XXXXXX")"
|
||||
|
||||
cleanup() {
|
||||
if [[ "$KEEP_WORK" -ne 1 ]]; then
|
||||
rm -rf "$WORK_DIR"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
say() {
|
||||
printf '\n==> %s\n' "$1" >&2
|
||||
}
|
||||
|
||||
tool_version_from_tag() {
|
||||
local tag="$1"
|
||||
local version="${tag#GE-Proton}"
|
||||
if [[ "$version" == "$tag" ]]; then
|
||||
printf '%s\n' "$tag"
|
||||
else
|
||||
printf '%s\n' "$version"
|
||||
fi
|
||||
}
|
||||
|
||||
get_latest_proton_tag() {
|
||||
curl -fsSL "https://api.github.com/repos/${UPSTREAM_REPO}/releases/latest" \
|
||||
| grep -oP '"tag_name":\s*"\K[^"]+' \
|
||||
| head -n1
|
||||
}
|
||||
|
||||
get_latest_dxvk_tag() {
|
||||
curl -fsSL https://api.github.com/repos/doitsujin/dxvk/releases/latest \
|
||||
| grep -oP '"tag_name":\s*"\K[^"]+' \
|
||||
| head -n1
|
||||
}
|
||||
|
||||
prepare_dxvk_cache() {
|
||||
if [[ ! -d "$DXVK_CACHE_DIR/.git" ]]; then
|
||||
say "Clone dxvk"
|
||||
git clone --recursive https://github.com/doitsujin/dxvk.git "$DXVK_CACHE_DIR" >&2
|
||||
else
|
||||
say "Update dxvk cache"
|
||||
git -C "$DXVK_CACHE_DIR" fetch --tags origin >&2
|
||||
git -C "$DXVK_CACHE_DIR" checkout master >&2
|
||||
git -C "$DXVK_CACHE_DIR" reset --hard origin/master >&2
|
||||
git -C "$DXVK_CACHE_DIR" submodule update --init --recursive >&2
|
||||
git -C "$DXVK_CACHE_DIR" clean -fdx >&2
|
||||
fi
|
||||
}
|
||||
|
||||
prepare_dxvk_repo() {
|
||||
local source_repo ref_name checkout_dir
|
||||
checkout_dir="$WORK_DIR/dxvk-src"
|
||||
|
||||
if [[ -n "$DXVK_SRC_OVERRIDE" ]]; then
|
||||
source_repo="$DXVK_SRC_OVERRIDE"
|
||||
else
|
||||
prepare_dxvk_cache
|
||||
source_repo="$DXVK_CACHE_DIR"
|
||||
fi
|
||||
|
||||
if [[ "$DXVK_CHANNEL" == "stable" ]]; then
|
||||
ref_name="$DXVK_TAG"
|
||||
if [[ -z "$ref_name" || "$ref_name" == "latest" ]]; then
|
||||
ref_name="$(get_latest_dxvk_tag)"
|
||||
fi
|
||||
if [[ -z "$ref_name" ]]; then
|
||||
echo "Failed to resolve DXVK stable tag" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
ref_name="HEAD"
|
||||
fi
|
||||
|
||||
say "Prepare DXVK source ($DXVK_CHANNEL)"
|
||||
git clone --recursive "$source_repo" "$checkout_dir" >&2
|
||||
|
||||
if [[ "$DXVK_CHANNEL" == "stable" ]]; then
|
||||
git -C "$checkout_dir" fetch --tags https://github.com/doitsujin/dxvk.git >&2
|
||||
git -C "$checkout_dir" checkout "refs/tags/$ref_name" >&2
|
||||
git -C "$checkout_dir" submodule update --init --recursive >&2
|
||||
fi
|
||||
|
||||
echo "$checkout_dir"
|
||||
}
|
||||
|
||||
build_dxvk() {
|
||||
local dxvk_src="$1"
|
||||
local dxvk_build_dir="$WORK_DIR/dxvk-out/dxvk-${DXVK_CHANNEL}"
|
||||
local toolchain_dir="$WORK_DIR/toolchain"
|
||||
local pthread_dir="$WORK_DIR/mingw-pthread"
|
||||
|
||||
DXVK_SHORT_SHA="$(git -C "$dxvk_src" rev-parse --short HEAD)"
|
||||
DXVK_FULL_SHA="$(git -C "$dxvk_src" rev-parse HEAD)"
|
||||
DXVK_DESCRIBE="$(git -C "$dxvk_src" describe --always --tags --dirty)"
|
||||
|
||||
say "Build DXVK ($DXVK_DESCRIBE)"
|
||||
rm -rf "$WORK_DIR/dxvk-out" "$toolchain_dir" "$pthread_dir"
|
||||
mkdir -p "$dxvk_build_dir" "$toolchain_dir" "$pthread_dir/x32" "$pthread_dir/x64"
|
||||
|
||||
if [[ -n "$MINGW_PTHREAD_ROOT" \
|
||||
&& -f "$MINGW_PTHREAD_ROOT/x32/libpthread.a" \
|
||||
&& -f "$MINGW_PTHREAD_ROOT/x64/libpthread.a" ]]; then
|
||||
ln -sf "$MINGW_PTHREAD_ROOT/x32/libpthread.a" "$pthread_dir/x32/libpthread.a"
|
||||
ln -sf "$MINGW_PTHREAD_ROOT/x64/libpthread.a" "$pthread_dir/x64/libpthread.a"
|
||||
else
|
||||
local mcfg32 mcfg64
|
||||
mcfg32="$(NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 nix path-info --impure nixpkgs#pkgsCross.mingw32.windows.mcfgthreads)"
|
||||
mcfg64="$(NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 nix path-info --impure nixpkgs#pkgsCross.mingwW64.windows.mcfgthreads)"
|
||||
ln -sf "$mcfg32/lib/libmcfgthread.a" "$pthread_dir/x32/libpthread.a"
|
||||
ln -sf "$mcfg64/lib/libmcfgthread.a" "$pthread_dir/x64/libpthread.a"
|
||||
fi
|
||||
|
||||
cat > "$toolchain_dir/x86_64-w64-mingw32-gcc" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
exec "$(command -v x86_64-w64-mingw32-gcc)" "\$@" -L"$pthread_dir/x64" -lmcfgthread -lpthread
|
||||
EOF
|
||||
cat > "$toolchain_dir/x86_64-w64-mingw32-g++" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
exec "$(command -v x86_64-w64-mingw32-g++)" "\$@" -L"$pthread_dir/x64" -lmcfgthread -lpthread
|
||||
EOF
|
||||
cat > "$toolchain_dir/i686-w64-mingw32-gcc" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
exec "$(command -v i686-w64-mingw32-gcc)" "\$@" -L"$pthread_dir/x32" -lmcfgthread -lpthread
|
||||
EOF
|
||||
cat > "$toolchain_dir/i686-w64-mingw32-g++" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
exec "$(command -v i686-w64-mingw32-g++)" "\$@" -L"$pthread_dir/x32" -lmcfgthread -lpthread
|
||||
EOF
|
||||
chmod +x \
|
||||
"$toolchain_dir/x86_64-w64-mingw32-gcc" \
|
||||
"$toolchain_dir/x86_64-w64-mingw32-g++" \
|
||||
"$toolchain_dir/i686-w64-mingw32-gcc" \
|
||||
"$toolchain_dir/i686-w64-mingw32-g++"
|
||||
|
||||
cat > "$toolchain_dir/build-win64-mcfg.txt" <<EOF
|
||||
[binaries]
|
||||
c = '$toolchain_dir/x86_64-w64-mingw32-gcc'
|
||||
cpp = '$toolchain_dir/x86_64-w64-mingw32-g++'
|
||||
ar = '$(command -v x86_64-w64-mingw32-ar)'
|
||||
strip = '$(command -v x86_64-w64-mingw32-strip)'
|
||||
windres = '$(command -v x86_64-w64-mingw32-windres)'
|
||||
|
||||
[properties]
|
||||
needs_exe_wrapper = true
|
||||
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
cpu_family = 'x86_64'
|
||||
cpu = 'x86_64'
|
||||
endian = 'little'
|
||||
EOF
|
||||
|
||||
cat > "$toolchain_dir/build-win32-mcfg.txt" <<EOF
|
||||
[binaries]
|
||||
c = '$toolchain_dir/i686-w64-mingw32-gcc'
|
||||
cpp = '$toolchain_dir/i686-w64-mingw32-g++'
|
||||
ar = '$(command -v i686-w64-mingw32-ar)'
|
||||
strip = '$(command -v i686-w64-mingw32-strip)'
|
||||
windres = '$(command -v i686-w64-mingw32-windres)'
|
||||
|
||||
[properties]
|
||||
needs_exe_wrapper = true
|
||||
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
cpu_family = 'x86'
|
||||
cpu = 'x86'
|
||||
endian = 'little'
|
||||
EOF
|
||||
|
||||
(
|
||||
cd "$dxvk_src"
|
||||
|
||||
meson setup --cross-file "$toolchain_dir/build-win64-mcfg.txt" \
|
||||
--buildtype release \
|
||||
--prefix "$dxvk_build_dir" \
|
||||
--strip \
|
||||
--bindir x64 \
|
||||
--libdir x64 \
|
||||
-Db_ndebug=if-release \
|
||||
"$dxvk_build_dir/build.64" >&2
|
||||
ninja -C "$dxvk_build_dir/build.64" install >&2
|
||||
|
||||
meson setup --cross-file "$toolchain_dir/build-win32-mcfg.txt" \
|
||||
--buildtype release \
|
||||
--prefix "$dxvk_build_dir" \
|
||||
--strip \
|
||||
--bindir x32 \
|
||||
--libdir x32 \
|
||||
-Db_ndebug=if-release \
|
||||
"$dxvk_build_dir/build.32" >&2
|
||||
ninja -C "$dxvk_build_dir/build.32" install >&2
|
||||
)
|
||||
|
||||
rm -f "$dxvk_build_dir/x64/"*.a "$dxvk_build_dir/x32/"*.a
|
||||
rm -rf "$dxvk_build_dir/build.64" "$dxvk_build_dir/build.32"
|
||||
|
||||
echo "$DXVK_SHORT_SHA"
|
||||
}
|
||||
|
||||
download_proton() {
|
||||
local proton_tag="$1"
|
||||
local asset_file
|
||||
local proton_tarball
|
||||
local proton_url
|
||||
|
||||
if [[ "$PROTON_ASSET" == "aarch64" ]]; then
|
||||
asset_file="${proton_tag}-aarch64.tar.gz"
|
||||
else
|
||||
asset_file="${proton_tag}.tar.gz"
|
||||
fi
|
||||
|
||||
proton_tarball="$CACHE_DIR/${asset_file}"
|
||||
proton_url="https://github.com/${UPSTREAM_REPO}/releases/download/${proton_tag}/${asset_file}"
|
||||
|
||||
if [[ ! -f "$proton_tarball" ]]; then
|
||||
say "Download Proton-GE ${proton_tag} (${PROTON_ASSET})"
|
||||
curl -fL "$proton_url" -o "$proton_tarball"
|
||||
else
|
||||
say "Reuse cached Proton tarball"
|
||||
fi
|
||||
|
||||
echo "$proton_tarball"
|
||||
}
|
||||
|
||||
replace_tree() {
|
||||
local source_dir="$1"
|
||||
local target_dir="$2"
|
||||
mkdir -p "$target_dir"
|
||||
for dll in d3d8.dll d3d9.dll d3d10core.dll d3d11.dll dxgi.dll openvr_api_dxvk.dll; do
|
||||
if [[ -f "$source_dir/$dll" ]]; then
|
||||
cp -f "$source_dir/$dll" "$target_dir/$dll"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
replace_base_dlls() {
|
||||
local source_dir="$1"
|
||||
local target_dir="$2"
|
||||
mkdir -p "$target_dir"
|
||||
for dll in d3d8.dll d3d9.dll d3d10core.dll d3d11.dll ddraw.dll dxgi.dll; do
|
||||
if [[ -f "$source_dir/$dll" ]]; then
|
||||
cp -f "$source_dir/$dll" "$target_dir/$dll"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
patch_tool() {
|
||||
local tool_root="$1"
|
||||
local tool_name="$2"
|
||||
local proton_tag="$3"
|
||||
local dxvk_src="$4"
|
||||
local dxvk_short_dir="$WORK_DIR/dxvk-out/dxvk-${DXVK_CHANNEL}"
|
||||
local timestamp
|
||||
|
||||
timestamp="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
|
||||
say "Replace DXVK payload"
|
||||
replace_tree "$dxvk_short_dir/x64" "$tool_root/files/lib/wine/dxvk/x86_64-windows"
|
||||
replace_tree "$dxvk_short_dir/x32" "$tool_root/files/lib/wine/dxvk/i386-windows"
|
||||
replace_base_dlls "$dxvk_short_dir/x64" "$tool_root/files/lib/wine/x86_64-windows"
|
||||
replace_base_dlls "$dxvk_short_dir/x32" "$tool_root/files/lib/wine/i386-windows"
|
||||
replace_base_dlls "$dxvk_short_dir/x64" "$tool_root/files/share/default_pfx/drive_c/windows/system32"
|
||||
replace_base_dlls "$dxvk_short_dir/x32" "$tool_root/files/share/default_pfx/drive_c/windows/syswow64"
|
||||
|
||||
chmod u+w \
|
||||
"$tool_root/files/lib/wine/dxvk/version" \
|
||||
"$tool_root/version" \
|
||||
"$tool_root/toolmanifest.vdf" 2>/dev/null || true
|
||||
|
||||
printf '%s dxvk (%s)\n' "$DXVK_FULL_SHA" "$DXVK_DESCRIBE" > "$tool_root/files/lib/wine/dxvk/version"
|
||||
printf '%s %s\n' "$(date +%s)" "$tool_name" > "$tool_root/version"
|
||||
|
||||
cat > "$tool_root/compatibilitytool.vdf" <<EOF
|
||||
"compatibilitytools"
|
||||
{
|
||||
"compat_tools"
|
||||
{
|
||||
"${tool_name}"
|
||||
{
|
||||
"install_path" "."
|
||||
"display_name" "${tool_name}"
|
||||
"from_oslist" "windows"
|
||||
"to_oslist" "linux"
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
cat > "$tool_root/toolmanifest.vdf" <<EOF
|
||||
"manifest"
|
||||
{
|
||||
"version" "2"
|
||||
"commandline" "/proton %verb%"
|
||||
"require_tool_appid" "${RUNTIME_APPID}"
|
||||
"use_sessions" "1"
|
||||
"compatmanager_layer_name" "proton"
|
||||
}
|
||||
EOF
|
||||
|
||||
cat > "$tool_root/BUILD-INFO.txt" <<EOF
|
||||
Tool name: ${tool_name}
|
||||
Built at: ${timestamp}
|
||||
Upstream repo: ${UPSTREAM_REPO}
|
||||
Proton-GE tag: ${proton_tag}
|
||||
Proton asset: ${PROTON_ASSET}
|
||||
DXVK source: ${dxvk_src}
|
||||
DXVK commit: ${DXVK_FULL_SHA}
|
||||
DXVK describe: ${DXVK_DESCRIBE}
|
||||
DXVK channel: ${DXVK_CHANNEL}
|
||||
Runtime appid: ${RUNTIME_APPID}
|
||||
EOF
|
||||
}
|
||||
|
||||
install_tool() {
|
||||
local tool_root="$1"
|
||||
local tool_name="$2"
|
||||
local destination="$STEAM_COMPAT_DIR/$tool_name"
|
||||
|
||||
say "Install tool"
|
||||
rm -rf "$destination"
|
||||
mv "$tool_root" "$destination"
|
||||
echo "$destination"
|
||||
}
|
||||
|
||||
package_tool() {
|
||||
local tool_root="$1"
|
||||
local tool_name="$2"
|
||||
local archive_path="$DIST_DIR/${tool_name}-dxvk-${DXVK_SHORT_SHA}.tar.xz"
|
||||
|
||||
say "Create shareable archive"
|
||||
mkdir -p "$DIST_DIR"
|
||||
rm -f "$archive_path"
|
||||
tar -C "$(dirname "$tool_root")" -cJf "$archive_path" "$(basename "$tool_root")"
|
||||
echo "$archive_path"
|
||||
}
|
||||
|
||||
write_dist_metadata() {
|
||||
local archive_path="$1"
|
||||
local tool_name="$2"
|
||||
local proton_tag="$3"
|
||||
mkdir -p "$DIST_DIR"
|
||||
|
||||
cat > "$DIST_DIR/package-info.env" <<EOF
|
||||
TOOL_NAME=${tool_name}
|
||||
PROTON_TAG=${proton_tag}
|
||||
PROTON_VERSION=$(tool_version_from_tag "$proton_tag")
|
||||
PROTON_ASSET=${PROTON_ASSET}
|
||||
DXVK_CHANNEL=${DXVK_CHANNEL}
|
||||
DXVK_TAG=${DXVK_TAG}
|
||||
DXVK_COMMIT=${DXVK_FULL_SHA}
|
||||
DXVK_DESCRIBE=${DXVK_DESCRIBE}
|
||||
RUNTIME_APPID=${RUNTIME_APPID}
|
||||
ARCHIVE_FILE=$(basename "$archive_path")
|
||||
RELEASE_TAG=${tool_name}
|
||||
EOF
|
||||
|
||||
cat > "$DIST_DIR/release-notes.md" <<EOF
|
||||
# ${tool_name}
|
||||
|
||||
- Proton-GE: \`${proton_tag}\`
|
||||
- DXVK: \`${DXVK_DESCRIBE}\`
|
||||
- Runtime appid: \`${RUNTIME_APPID}\`
|
||||
- Archive: \`$(basename "$archive_path")\`
|
||||
|
||||
This release is built for Elsword and uses Steam Linux Runtime 3.0 (sniper).
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ -z "$TOOL_NAME" ]]; then
|
||||
TOOL_NAME="${TOOL_PREFIX}-$(tool_version_from_tag "$PROTON_TAG")"
|
||||
fi
|
||||
|
||||
DXVK_SRC="$(prepare_dxvk_repo)"
|
||||
build_dxvk "$DXVK_SRC" >/dev/null
|
||||
PROTON_TARBALL="$(download_proton "$PROTON_TAG")"
|
||||
|
||||
say "Extract Proton-GE"
|
||||
mkdir -p "$WORK_DIR/proton"
|
||||
tar -xf "$PROTON_TARBALL" -C "$WORK_DIR/proton"
|
||||
TOOL_ROOT="$(find "$WORK_DIR/proton" -mindepth 1 -maxdepth 1 -type d | head -n1)"
|
||||
if [[ -z "$TOOL_ROOT" ]]; then
|
||||
echo "Could not find extracted Proton tool root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
patch_tool "$TOOL_ROOT" "$TOOL_NAME" "$PROTON_TAG" "$DXVK_SRC"
|
||||
ARCHIVE_PATH="$(package_tool "$TOOL_ROOT" "$TOOL_NAME")"
|
||||
write_dist_metadata "$ARCHIVE_PATH" "$TOOL_NAME" "$PROTON_TAG"
|
||||
|
||||
if [[ "$INSTALL_TOOL" -eq 1 ]]; then
|
||||
INSTALLED_PATH="$(install_tool "$TOOL_ROOT" "$TOOL_NAME")"
|
||||
fi
|
||||
|
||||
say "Done"
|
||||
printf 'Archive: %s\n' "$ARCHIVE_PATH"
|
||||
if [[ "$INSTALL_TOOL" -eq 1 ]]; then
|
||||
printf 'Installed: %s\n' "$INSTALLED_PATH"
|
||||
fi
|
||||
printf 'Proton-GE: %s (%s)\n' "$PROTON_TAG" "$PROTON_ASSET"
|
||||
printf 'DXVK: %s\n' "$DXVK_DESCRIBE"
|
||||
printf 'Runtime: %s\n' "$RUNTIME_APPID"
|
||||
if [[ "$INSTALL_TOOL" -eq 1 ]]; then
|
||||
printf '\nRestart Steam and choose "%s" as compatibility tool.\n' "$TOOL_NAME"
|
||||
else
|
||||
printf '\nShare the archive or unpack it into compatibilitytools.d on another system.\n'
|
||||
fi
|
||||
Generated
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1782467914,
|
||||
"narHash": "sha256-pGvFkM8N0xEkIIXDe5YYfbEAvHrk4IxBrjB/x8OomhE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e73de5be04e0eff4190a1432b946d469c794e7b4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
description = "Build versioned Elsword Proton-GE tools with DXVK and sniper runtime";
|
||||
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
|
||||
outputs = { self, nixpkgs }:
|
||||
let
|
||||
system = "x86_64-linux";
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
in
|
||||
{
|
||||
devShells.${system}.default = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
curl
|
||||
git
|
||||
glslang
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
python3
|
||||
wineWow64Packages.stable
|
||||
pkgsCross.mingw32.stdenv.cc
|
||||
pkgsCross.mingwW64.stdenv.cc
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user