This commit is contained in:
+55
-38
@@ -1,15 +1,18 @@
|
|||||||
name: build-elsword-ge
|
name: build-elsword-ge
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
push:
|
||||||
- cron: "0 4 * * *"
|
branches:
|
||||||
|
- main
|
||||||
|
tags:
|
||||||
|
- "v*"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-release:
|
build:
|
||||||
runs-on: self-hosted
|
runs-on: self-hosted
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
@@ -20,61 +23,71 @@ jobs:
|
|||||||
git -c http.extraHeader="Authorization: token ${{ secrets.GITEA_TOKEN }}" fetch --depth 1 origin "${{ gitea.sha }}"
|
git -c http.extraHeader="Authorization: token ${{ secrets.GITEA_TOKEN }}" fetch --depth 1 origin "${{ gitea.sha }}"
|
||||||
git checkout --detach FETCH_HEAD
|
git checkout --detach FETCH_HEAD
|
||||||
|
|
||||||
- name: Build Elsword Proton-GE 10-34 tool
|
- name: Build both Elsword Proton variants
|
||||||
run: |
|
run: |
|
||||||
nix develop -c ./build.sh --no-install
|
nix develop -c ./scripts/build.sh all
|
||||||
|
|
||||||
|
- name: Package release archives
|
||||||
|
run: |
|
||||||
|
nix develop -c ./scripts/create-release-archive.sh
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: elsword-ge-builds
|
||||||
|
path: |
|
||||||
|
dist/*.tar.zst
|
||||||
|
dist/*.sha256
|
||||||
|
dist/SHA256SUMS.txt
|
||||||
|
dist/release-notes.md
|
||||||
|
profiles/elsword-launch-options.md
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Create or update Gitea release
|
- name: Create or update Gitea release
|
||||||
|
if: startsWith(gitea.ref, 'refs/tags/v')
|
||||||
env:
|
env:
|
||||||
GITEA_SERVER_URL: ${{ gitea.server_url }}
|
GITEA_SERVER_URL: ${{ gitea.server_url }}
|
||||||
GITEA_REPOSITORY: ${{ gitea.repository }}
|
GITEA_REPOSITORY: ${{ gitea.repository }}
|
||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
GITEA_TAG: ${{ gitea.ref_name }}
|
||||||
GITEA_SHA: ${{ gitea.sha }}
|
GITEA_SHA: ${{ gitea.sha }}
|
||||||
run: |
|
run: |
|
||||||
nix develop -c bash -lc '
|
nix develop -c bash -lc '
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
set -a
|
|
||||||
. dist/package-info.env
|
|
||||||
set +a
|
|
||||||
|
|
||||||
RELEASE_API="${GITEA_SERVER_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases"
|
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")"
|
RELEASE_TAG_URL="$(python3 -c "import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=\"\"))" "$GITEA_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}" \
|
HTTP_CODE="$(curl -s -o /tmp/release.json -w "%{http_code}" \
|
||||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
"${RELEASE_API}/tags/${RELEASE_TAG_URL}")"
|
"${RELEASE_API}/tags/${RELEASE_TAG_URL}")"
|
||||||
|
|
||||||
if [ "$HTTP_CODE" = "200" ]; then
|
if [ "$HTTP_CODE" = "200" ]; then
|
||||||
RELEASE_ID="$(python3 -c "import json; print(json.load(open(\"/tmp/release.json\"))[\"id\"])" )"
|
RELEASE_ID="$(jq -r ".id" /tmp/release.json)"
|
||||||
elif [ "$HTTP_CODE" = "404" ]; then
|
elif [ "$HTTP_CODE" = "404" ]; then
|
||||||
python3 -c "import json, pathlib, os; pathlib.Path(\"/tmp/release-create.json\").write_text(json.dumps({
|
jq -n \
|
||||||
\"tag_name\": os.environ[\"RELEASE_TAG\"],
|
--arg tag "$GITEA_TAG" \
|
||||||
\"target_commitish\": os.environ[\"GITEA_SHA\"],
|
--arg sha "$GITEA_SHA" \
|
||||||
\"name\": os.environ[\"RELEASE_TAG\"],
|
--arg body "$(cat dist/release-notes.md)" \
|
||||||
\"body\": pathlib.Path(\"dist/release-notes.md\").read_text(),
|
"{tag_name: \$tag, target_commitish: \$sha, name: \$tag, body: \$body, draft: false, prerelease: false}" \
|
||||||
\"draft\": False,
|
> /tmp/release-create.json
|
||||||
\"prerelease\": False,
|
|
||||||
}))"
|
|
||||||
curl --fail-with-body \
|
curl --fail-with-body \
|
||||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
--data-binary @/tmp/release-create.json \
|
--data-binary @/tmp/release-create.json \
|
||||||
"${RELEASE_API}" > /tmp/release.json
|
"${RELEASE_API}" > /tmp/release.json
|
||||||
RELEASE_ID="$(python3 -c "import json; print(json.load(open(\"/tmp/release.json\"))[\"id\"])" )"
|
RELEASE_ID="$(jq -r ".id" /tmp/release.json)"
|
||||||
else
|
else
|
||||||
cat /tmp/release.json
|
cat /tmp/release.json
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
python3 -c "import json, pathlib, os; pathlib.Path(\"/tmp/release-update.json\").write_text(json.dumps({
|
jq -n \
|
||||||
\"tag_name\": os.environ[\"RELEASE_TAG\"],
|
--arg tag "$GITEA_TAG" \
|
||||||
\"target_commitish\": os.environ[\"GITEA_SHA\"],
|
--arg sha "$GITEA_SHA" \
|
||||||
\"name\": os.environ[\"RELEASE_TAG\"],
|
--arg body "$(cat dist/release-notes.md)" \
|
||||||
\"body\": pathlib.Path(\"dist/release-notes.md\").read_text(),
|
"{tag_name: \$tag, target_commitish: \$sha, name: \$tag, body: \$body, draft: false, prerelease: false}" \
|
||||||
\"draft\": False,
|
> /tmp/release-update.json
|
||||||
\"prerelease\": False,
|
|
||||||
}))"
|
|
||||||
curl --fail-with-body \
|
curl --fail-with-body \
|
||||||
-X PATCH \
|
-X PATCH \
|
||||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
@@ -86,16 +99,20 @@ jobs:
|
|||||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
"${RELEASE_API}/${RELEASE_ID}/assets" > /tmp/assets.json
|
"${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), \"\"))")"
|
for asset in dist/*.tar.zst dist/*.sha256 dist/SHA256SUMS.txt dist/release-notes.md; do
|
||||||
if [ -n "$EXISTING_ASSET_ID" ]; then
|
[ -f "$asset" ] || continue
|
||||||
|
name="$(basename "$asset")"
|
||||||
|
existing_id="$(jq -r --arg name "$name" ".[] | select(.name == \$name) | .id" /tmp/assets.json | head -n1)"
|
||||||
|
if [ -n "$existing_id" ]; then
|
||||||
|
curl --fail-with-body \
|
||||||
|
-X DELETE \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
"${RELEASE_API}/${RELEASE_ID}/assets/${existing_id}"
|
||||||
|
fi
|
||||||
|
encoded_name="$(python3 -c "import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=\"\"))" "$name")"
|
||||||
curl --fail-with-body \
|
curl --fail-with-body \
|
||||||
-X DELETE \
|
|
||||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
"${RELEASE_API}/${RELEASE_ID}/assets/${EXISTING_ASSET_ID}"
|
--data-binary @"${asset}" \
|
||||||
fi
|
"${RELEASE_API}/${RELEASE_ID}/assets?name=${encoded_name}"
|
||||||
|
done
|
||||||
curl --fail-with-body \
|
|
||||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
||||||
--data-binary @"dist/${ARCHIVE_FILE}" \
|
|
||||||
"${RELEASE_API}/${RELEASE_ID}/assets?name=${ARCHIVE_URL_NAME}"
|
|
||||||
'
|
'
|
||||||
|
|||||||
+2
-1
@@ -1,2 +1,3 @@
|
|||||||
.cache/
|
.cache/
|
||||||
dist/
|
dist/*
|
||||||
|
!dist/.gitkeep
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,95 +1,281 @@
|
|||||||
# Elsword Proton-GE Builder
|
# Elsword-GE Build Project
|
||||||
|
|
||||||
Dieses Repo baut per Gitea Actions versionierte Proton-GE-Kompatibilitätstools
|
This repository builds two custom Proton-GE 11 compatibility tools for Elsword on Linux/Steam:
|
||||||
für Elsword mit `dxvk-git` und Steam Linux Runtime 3.0 (`sniper`).
|
|
||||||
|
|
||||||
## Was gebaut wird
|
- `Elsword-GE-11-1`
|
||||||
|
- `Elsword-GE-11-1+dxvk-git`
|
||||||
|
|
||||||
- Tool-Name: `Elsword-GE-(Version)`
|
It is designed for NixOS and for hosting on a private or public Gitea server with Gitea Actions.
|
||||||
- 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,
|
## What this project does
|
||||||
weil jede Build ihren eigenen Tool-Namen bekommt.
|
|
||||||
|
|
||||||
## Ablauf
|
- Builds a Proton-GE 11 / Wine 11 based compatibility tool for Elsword.
|
||||||
|
- Uses Steam Linux Runtime 3.0 (`sniper`, appid `1628350`).
|
||||||
|
- Builds DXVK for both x86 and x64.
|
||||||
|
- Produces release archives that other users can install into Steam.
|
||||||
|
- Disables optional extras that are known to be risky for game stability by default:
|
||||||
|
- `PROTON_DISCORD_BRIDGE=0`
|
||||||
|
- `PROTON_USE_OPTISCALER=0`
|
||||||
|
- `PROTON_USE_D7VK=0`
|
||||||
|
- `MANGOHUD=0`
|
||||||
|
- `ENABLE_VKBASALT=0`
|
||||||
|
|
||||||
1. Das Repo nutzt standardmäßig `GE-Proton10-34`.
|
## What this project does not do
|
||||||
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
|
- No GameGuard bypass.
|
||||||
|
- No anti-cheat bypass.
|
||||||
|
- No patching or hooking of GameGuard.
|
||||||
|
- No hard override of `LOW_LATENCY_LAYER`.
|
||||||
|
- No global hard override of `LD_PRELOAD`.
|
||||||
|
|
||||||
Ohne Parameter baut `build.sh`:
|
## Variant difference
|
||||||
|
|
||||||
- `GE-Proton10-34`
|
- `Elsword-GE-11-1`
|
||||||
- mit `dxvk-git`
|
- Proton-GE 11 base
|
||||||
- als Tool `Elsword-GE-(Version)`
|
- DXVK stable/latest release tag
|
||||||
- mit `sniper`
|
|
||||||
|
|
||||||
## Lokaler Build
|
- `Elsword-GE-11-1+dxvk-git`
|
||||||
|
- Proton-GE 11 base
|
||||||
|
- DXVK from current upstream Git
|
||||||
|
|
||||||
```bash
|
## Repository layout
|
||||||
nix develop -c ./build.sh
|
|
||||||
|
```text
|
||||||
|
.
|
||||||
|
├── flake.nix
|
||||||
|
├── README.md
|
||||||
|
├── LICENSE
|
||||||
|
├── .gitignore
|
||||||
|
├── .gitea/
|
||||||
|
│ └── workflows/
|
||||||
|
│ └── build.yml
|
||||||
|
├── scripts/
|
||||||
|
│ ├── common.sh
|
||||||
|
│ ├── build.sh
|
||||||
|
│ ├── package.sh
|
||||||
|
│ ├── install-to-steam.sh
|
||||||
|
│ ├── validate-build.sh
|
||||||
|
│ └── create-release-archive.sh
|
||||||
|
├── patches/
|
||||||
|
│ └── proton-defaults-elsword.patch
|
||||||
|
├── profiles/
|
||||||
|
│ └── elsword-launch-options.md
|
||||||
|
└── dist/
|
||||||
```
|
```
|
||||||
|
|
||||||
Nur Archiv bauen, nicht lokal installieren:
|
## NixOS prerequisites
|
||||||
|
|
||||||
|
Use the provided flake:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix develop -c ./build.sh --no-install
|
nix develop
|
||||||
```
|
```
|
||||||
|
|
||||||
Einen bestimmten GE-Tag bauen:
|
The shell includes build dependencies such as:
|
||||||
|
|
||||||
|
- git
|
||||||
|
- bash
|
||||||
|
- coreutils
|
||||||
|
- findutils
|
||||||
|
- gnused
|
||||||
|
- gnugrep
|
||||||
|
- gawk
|
||||||
|
- jq
|
||||||
|
- curl
|
||||||
|
- wget
|
||||||
|
- tar
|
||||||
|
- zstd
|
||||||
|
- meson
|
||||||
|
- ninja
|
||||||
|
- python3
|
||||||
|
- pkg-config
|
||||||
|
- cmake
|
||||||
|
- perl
|
||||||
|
- patchelf
|
||||||
|
- binutils
|
||||||
|
- mingw-w64 toolchains for `i686` and `x86_64`
|
||||||
|
- Wine / wow64 support
|
||||||
|
|
||||||
|
## Local build
|
||||||
|
|
||||||
|
Build the stable DXVK variant:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix develop -c ./build.sh --proton-tag GE-Proton11-1
|
nix develop -c ./scripts/build.sh stable
|
||||||
```
|
```
|
||||||
|
|
||||||
Eigenen Tool-Namen setzen:
|
Build the DXVK Git variant:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix develop -c ./build.sh --tool-name Elsword-GE-test
|
nix develop -c ./scripts/build.sh dxvk-git
|
||||||
```
|
```
|
||||||
|
|
||||||
## Wichtige Optionen
|
Build both:
|
||||||
|
|
||||||
- `--proton-tag TAG`
|
```bash
|
||||||
- `--proton-asset x86_64|aarch64`
|
nix develop -c ./scripts/build.sh all
|
||||||
- `--dxvk-channel git|stable`
|
```
|
||||||
- `--dxvk-tag TAG`
|
|
||||||
- `--tool-prefix PREFIX`
|
|
||||||
- `--tool-name NAME`
|
|
||||||
- `--runtime-appid APPID`
|
|
||||||
- `--no-install`
|
|
||||||
|
|
||||||
## Gitea Actions
|
Package both into release archives:
|
||||||
|
|
||||||
Der Workflow liegt unter:
|
```bash
|
||||||
|
nix develop -c ./scripts/create-release-archive.sh
|
||||||
|
```
|
||||||
|
|
||||||
- `.gitea/workflows/build.yml`
|
## Output files
|
||||||
|
|
||||||
Er läuft bei:
|
After packaging, the main release files are:
|
||||||
|
|
||||||
- manuellem Start per `workflow_dispatch`
|
```text
|
||||||
- automatischem Zeitplan täglich
|
dist/Elsword-GE-11-1.tar.zst
|
||||||
|
dist/Elsword-GE-11-1+dxvk-git.tar.zst
|
||||||
|
dist/Elsword-GE-11-1-dxvk-git.tar.zst
|
||||||
|
dist/SHA256SUMS.txt
|
||||||
|
dist/release-notes.md
|
||||||
|
```
|
||||||
|
|
||||||
Für Release-Uploads braucht der Workflow ein Secret:
|
If `+` causes issues in a filesystem or upload target, the safe alias is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Elsword-GE-11-1-dxvk-git.tar.zst
|
||||||
|
```
|
||||||
|
|
||||||
|
The Steam compatibility tool name still remains exactly:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Elsword-GE-11-1+dxvk-git
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install into Steam
|
||||||
|
|
||||||
|
Install a built archive:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/install-to-steam.sh dist/Elsword-GE-11-1.tar.zst
|
||||||
|
./scripts/install-to-steam.sh dist/Elsword-GE-11-1+dxvk-git.tar.zst
|
||||||
|
```
|
||||||
|
|
||||||
|
Target path:
|
||||||
|
|
||||||
|
```text
|
||||||
|
~/.local/share/Steam/compatibilitytools.d/
|
||||||
|
```
|
||||||
|
|
||||||
|
After install:
|
||||||
|
|
||||||
|
1. Fully restart Steam.
|
||||||
|
2. Open Elsword properties in Steam.
|
||||||
|
3. Select the matching compatibility tool.
|
||||||
|
|
||||||
|
## Recommended Elsword launch options
|
||||||
|
|
||||||
|
The documented profiles live in [profiles/elsword-launch-options.md](/home/magges/git/Elsword-GE/profiles/elsword-launch-options.md:1).
|
||||||
|
|
||||||
|
Safe / GameGuard test:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
LD_PRELOAD="" PROTON_DISCORD_BRIDGE=0 PROTON_USE_OPTISCALER=0 PROTON_USE_D7VK=0 LOW_LATENCY_LAYER=0 MANGOHUD=0 ENABLE_VKBASALT=0 VK_INSTANCE_LAYERS="" DXVK_HUD=0 %command%
|
||||||
|
```
|
||||||
|
|
||||||
|
Performance / low-latency test:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
LD_PRELOAD="" PROTON_DISCORD_BRIDGE=0 PROTON_USE_OPTISCALER=0 PROTON_USE_D7VK=0 LOW_LATENCY_LAYER=1 MANGOHUD=0 ENABLE_VKBASALT=0 VK_INSTANCE_LAYERS="" DXVK_STATE_CACHE=1 DXVK_LOG_LEVEL=none %command%
|
||||||
|
```
|
||||||
|
|
||||||
|
Operational advice:
|
||||||
|
|
||||||
|
- Disable Steam Overlay for Elsword if possible.
|
||||||
|
- Do not launch with `gamemoderun`.
|
||||||
|
- Keep MangoHud disabled.
|
||||||
|
- Keep vkBasalt disabled.
|
||||||
|
- Keep Discord Bridge disabled.
|
||||||
|
- Keep OptiScaler disabled.
|
||||||
|
- Keep D7VK disabled.
|
||||||
|
- Test `LOW_LATENCY_LAYER=1` separately.
|
||||||
|
- If GameGuard kicks the game, go back to the Safe profile first.
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
For Proton logs:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PROTON_LOG=1 %command%
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gitea Actions behavior
|
||||||
|
|
||||||
|
Workflow file:
|
||||||
|
|
||||||
|
- [.gitea/workflows/build.yml](/home/magges/git/Elsword-GE/.gitea/workflows/build.yml:1)
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
- Push to `main`: builds both variants and stores build artifacts.
|
||||||
|
- Tag matching `v*`: builds both variants, packages them, generates checksums, and creates or updates a Gitea release with uploaded assets.
|
||||||
|
|
||||||
|
Expected secrets:
|
||||||
|
|
||||||
- `GITEA_TOKEN`
|
- `GITEA_TOKEN`
|
||||||
|
- `GITEA_SERVER_URL`
|
||||||
|
- `GITEA_REPOSITORY`
|
||||||
|
|
||||||
Dieses Token muss Release-Schreibrechte auf das Repo haben.
|
No tokens or passwords are stored in the repository.
|
||||||
|
|
||||||
## Release-Ausgabe
|
## Manual fallback if release upload needs to be done by hand
|
||||||
|
|
||||||
Nach einem Build schreibt das Skript nach `dist/`:
|
If your Gitea release upload path differs or the API step needs adjustment for your instance, build locally or through Actions and upload these files manually in the release UI:
|
||||||
|
|
||||||
- das fertige `.tar.xz`-Archiv
|
- `dist/Elsword-GE-11-1.tar.zst`
|
||||||
- `package-info.env`
|
- `dist/Elsword-GE-11-1+dxvk-git.tar.zst`
|
||||||
- `release-notes.md`
|
- `dist/Elsword-GE-11-1-dxvk-git.tar.zst`
|
||||||
|
- `dist/SHA256SUMS.txt`
|
||||||
|
- `dist/*.sha256`
|
||||||
|
- `dist/release-notes.md`
|
||||||
|
|
||||||
Die Gitea Action nutzt diese Dateien direkt für das Release.
|
## Push to Gitea
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git init
|
||||||
|
git add .
|
||||||
|
git commit -m "Initial Elsword-GE build project"
|
||||||
|
git remote add origin ssh://git@DEIN-GITEA-SERVER/USER/elsword-ge.git
|
||||||
|
git push -u origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create a release by tag
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git tag v11-1
|
||||||
|
git push origin v11-1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gitea attachment size note
|
||||||
|
|
||||||
|
Built Proton archives are usually much larger than 50 MB. Your Gitea instance may need larger release attachment limits.
|
||||||
|
|
||||||
|
Example configuration hint only; exact keys can vary by Gitea version:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[repository.upload]
|
||||||
|
FILE_MAX_SIZE = 2048
|
||||||
|
MAX_FILES = 20
|
||||||
|
|
||||||
|
[attachment]
|
||||||
|
MAX_SIZE = 2048
|
||||||
|
MAX_FILES = 20
|
||||||
|
|
||||||
|
[actions]
|
||||||
|
ENABLED = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security and anti-cheat note
|
||||||
|
|
||||||
|
This project intentionally avoids:
|
||||||
|
|
||||||
|
- GameGuard bypasses
|
||||||
|
- anti-cheat bypasses
|
||||||
|
- GameGuard patches
|
||||||
|
- GameGuard hooks
|
||||||
|
|
||||||
|
The goal is only a clean Proton-GE build with complete DXVK payloads and conservative defaults for optional extras.
|
||||||
|
|||||||
@@ -1,570 +0,0 @@
|
|||||||
#!/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
|
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
description = "Build versioned Elsword Proton-GE tools with DXVK and sniper runtime";
|
description = "Gitea-ready custom Proton-GE 11 build project for Elsword";
|
||||||
|
|
||||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
outputs = { self, nixpkgs }:
|
outputs = { nixpkgs, ... }:
|
||||||
let
|
let
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
pkgs = import nixpkgs { inherit system; };
|
pkgs = import nixpkgs { inherit system; };
|
||||||
@@ -11,13 +11,29 @@
|
|||||||
{
|
{
|
||||||
devShells.${system}.default = pkgs.mkShell {
|
devShells.${system}.default = pkgs.mkShell {
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
|
bash
|
||||||
|
binutils
|
||||||
|
cmake
|
||||||
|
coreutils
|
||||||
curl
|
curl
|
||||||
|
findutils
|
||||||
|
gawk
|
||||||
git
|
git
|
||||||
|
gnugrep
|
||||||
|
gnused
|
||||||
|
gnutar
|
||||||
glslang
|
glslang
|
||||||
|
jq
|
||||||
meson
|
meson
|
||||||
ninja
|
ninja
|
||||||
|
patchelf
|
||||||
|
perl
|
||||||
pkg-config
|
pkg-config
|
||||||
python3
|
python3
|
||||||
|
wget
|
||||||
|
which
|
||||||
|
xz
|
||||||
|
zstd
|
||||||
wineWow64Packages.stable
|
wineWow64Packages.stable
|
||||||
pkgsCross.mingw32.stdenv.cc
|
pkgsCross.mingw32.stdenv.cc
|
||||||
pkgsCross.mingwW64.stdenv.cc
|
pkgsCross.mingwW64.stdenv.cc
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
--- a/proton
|
||||||
|
+++ b/proton
|
||||||
|
@@
|
||||||
|
import os
|
||||||
|
+
|
||||||
|
+os.environ.setdefault("PROTON_DISCORD_BRIDGE", "0")
|
||||||
|
+os.environ.setdefault("PROTON_USE_OPTISCALER", "0")
|
||||||
|
+os.environ.setdefault("PROTON_USE_D7VK", "0")
|
||||||
|
+os.environ.setdefault("MANGOHUD", "0")
|
||||||
|
+os.environ.setdefault("ENABLE_VKBASALT", "0")
|
||||||
|
*** Add File: /home/magges/git/Elsword-GE/profiles/elsword-launch-options.md
|
||||||
|
# Elsword Launch Profiles
|
||||||
|
|
||||||
|
## Safe / GameGuard Test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
LD_PRELOAD="" PROTON_DISCORD_BRIDGE=0 PROTON_USE_OPTISCALER=0 PROTON_USE_D7VK=0 LOW_LATENCY_LAYER=0 MANGOHUD=0 ENABLE_VKBASALT=0 VK_INSTANCE_LAYERS="" DXVK_HUD=0 %command%
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance / Low-Latency Test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
LD_PRELOAD="" PROTON_DISCORD_BRIDGE=0 PROTON_USE_OPTISCALER=0 PROTON_USE_D7VK=0 LOW_LATENCY_LAYER=1 MANGOHUD=0 ENABLE_VKBASALT=0 VK_INSTANCE_LAYERS="" DXVK_STATE_CACHE=1 DXVK_LOG_LEVEL=none %command%
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Disable the Steam Overlay for Elsword if possible.
|
||||||
|
- Do not start Elsword through `gamemoderun`.
|
||||||
|
- Keep MangoHud disabled.
|
||||||
|
- Keep vkBasalt disabled.
|
||||||
|
- Keep the Discord bridge disabled.
|
||||||
|
- Keep OptiScaler disabled.
|
||||||
|
- Keep D7VK disabled.
|
||||||
|
- Test `LOW_LATENCY_LAYER=1` on its own before mixing other changes in.
|
||||||
|
- If GameGuard kicks or closes the game, return to the Safe profile first.
|
||||||
Executable
+238
@@ -0,0 +1,238 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/common.sh"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage:
|
||||||
|
./scripts/build.sh stable
|
||||||
|
./scripts/build.sh dxvk-git
|
||||||
|
./scripts/build.sh all
|
||||||
|
|
||||||
|
Builds one or both Elsword Proton-GE compatibility tool directories in dist/
|
||||||
|
and validates them before packaging.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_toolchain_wrappers() {
|
||||||
|
local workdir="$1"
|
||||||
|
local toolchain_dir="$workdir/toolchain"
|
||||||
|
local pthread_dir="$workdir/mingw-pthread"
|
||||||
|
local mcfg32 mcfg64
|
||||||
|
|
||||||
|
mkdir -p "$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
|
||||||
|
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.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.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
|
||||||
|
|
||||||
|
printf "%s\n" "$toolchain_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_dxvk_variant() {
|
||||||
|
local variant="$1"
|
||||||
|
local dxvk_src="$2"
|
||||||
|
local workdir="$3"
|
||||||
|
local toolchain_dir="$4"
|
||||||
|
local dxvk_build_dir="$workdir/dxvk-out/$variant"
|
||||||
|
|
||||||
|
mkdir -p "$dxvk_build_dir"
|
||||||
|
|
||||||
|
say "Build DXVK for $variant"
|
||||||
|
(
|
||||||
|
cd "$dxvk_src"
|
||||||
|
meson setup --cross-file "$toolchain_dir/build-win64.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.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"
|
||||||
|
|
||||||
|
printf "%s\n" "$dxvk_build_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
finalize_tool_tree() {
|
||||||
|
local variant="$1"
|
||||||
|
local tool_root="$2"
|
||||||
|
local tool_name="$3"
|
||||||
|
local dxvk_build_dir="$4"
|
||||||
|
local build_time="$5"
|
||||||
|
local dxvk_src="$6"
|
||||||
|
local tool_dir="$DIST_DIR/$tool_name"
|
||||||
|
local metadata_log="$tool_root/runtime-deps.log"
|
||||||
|
local dxvk_channel dxvk_tag dxvk_commit dxvk_describe
|
||||||
|
|
||||||
|
dxvk_channel="$(dxvk_channel_for_variant "$variant")"
|
||||||
|
dxvk_tag="$(dxvk_tag_for_variant "$variant")"
|
||||||
|
dxvk_commit="$(git -C "$dxvk_src" rev-parse HEAD)"
|
||||||
|
dxvk_describe="$(git -C "$dxvk_src" describe --always --tags --dirty)"
|
||||||
|
|
||||||
|
say "Patch tool tree for $tool_name"
|
||||||
|
ensure_tool_tree_writable "$tool_root"
|
||||||
|
replace_dxvk_payload "$dxvk_build_dir" "$tool_root"
|
||||||
|
mkdir -p "$tool_dir"
|
||||||
|
copy_required_runtime_dlls "$tool_root" "$dxvk_build_dir" "$metadata_log"
|
||||||
|
inject_wrapper_defaults "$tool_root/proton"
|
||||||
|
patch_tool_manifests "$tool_root" "$tool_name"
|
||||||
|
printf "%s dxvk (%s)\n" "$dxvk_commit" "$dxvk_describe" > "$tool_root/files/lib/wine/dxvk/version"
|
||||||
|
|
||||||
|
cat > "$tool_root/BUILD-INFO.txt" <<EOF
|
||||||
|
Tool name: ${tool_name}
|
||||||
|
Proton base: ${PROTON_TAG}
|
||||||
|
Wine series: ${WINE_SERIES}
|
||||||
|
Runtime appid: ${RUNTIME_APPID}
|
||||||
|
DXVK channel: ${dxvk_channel}
|
||||||
|
DXVK tag: ${dxvk_tag}
|
||||||
|
DXVK commit: ${dxvk_commit}
|
||||||
|
DXVK describe: ${dxvk_describe}
|
||||||
|
Build time: ${build_time}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
rm -rf "$tool_dir"
|
||||||
|
mv "$tool_root" "$tool_dir"
|
||||||
|
|
||||||
|
write_build_metadata \
|
||||||
|
"$variant" \
|
||||||
|
"$tool_name" \
|
||||||
|
"$tool_dir" \
|
||||||
|
"$dxvk_channel" \
|
||||||
|
"$dxvk_tag" \
|
||||||
|
"$dxvk_commit" \
|
||||||
|
"$dxvk_describe" \
|
||||||
|
"$build_time" \
|
||||||
|
"$(archive_name_for_variant "$variant")" \
|
||||||
|
"$(archive_alias_for_variant "$variant")"
|
||||||
|
|
||||||
|
"$SCRIPT_DIR/validate-build.sh" "$tool_dir" "$tool_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_variant() {
|
||||||
|
local variant="$1"
|
||||||
|
local workdir proton_tarball proton_root dxvk_src toolchain_dir dxvk_build_dir tool_name build_time
|
||||||
|
|
||||||
|
tool_name="$(tool_name_for_variant "$variant")"
|
||||||
|
build_time="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
workdir="$(workdir_for_variant "$variant")"
|
||||||
|
trap "cleanup_workdir '$workdir'" RETURN
|
||||||
|
|
||||||
|
proton_tarball="$(download_proton_tarball)"
|
||||||
|
proton_root="$(extract_proton_tool "$workdir" "$proton_tarball")"
|
||||||
|
dxvk_src="$(prepare_dxvk_source "$variant" "$workdir")"
|
||||||
|
toolchain_dir="$(prepare_toolchain_wrappers "$workdir")"
|
||||||
|
dxvk_build_dir="$(build_dxvk_variant "$variant" "$dxvk_src" "$workdir" "$toolchain_dir")"
|
||||||
|
finalize_tool_tree "$variant" "$proton_root" "$tool_name" "$dxvk_build_dir" "$build_time" "$dxvk_src"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
local mode="${1:-all}"
|
||||||
|
|
||||||
|
case "$mode" in
|
||||||
|
stable|dxvk-git|all) ;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
require_toolchain_commands
|
||||||
|
ensure_repo_layout
|
||||||
|
|
||||||
|
if [[ "$mode" == "all" ]]; then
|
||||||
|
build_variant stable
|
||||||
|
build_variant dxvk-git
|
||||||
|
else
|
||||||
|
build_variant "$mode"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Executable
+460
@@ -0,0 +1,460 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
CACHE_DIR="${CACHE_DIR:-$REPO_ROOT/.cache}"
|
||||||
|
DIST_DIR="${DIST_DIR:-$REPO_ROOT/dist}"
|
||||||
|
WORK_ROOT="${WORK_ROOT:-$CACHE_DIR/work}"
|
||||||
|
DXVK_CACHE_DIR="${DXVK_CACHE_DIR:-$CACHE_DIR/dxvk}"
|
||||||
|
METADATA_DIR="${METADATA_DIR:-$DIST_DIR/metadata}"
|
||||||
|
STEAM_COMPAT_DIR_DEFAULT="${STEAM_COMPAT_DIR_DEFAULT:-$HOME/.local/share/Steam/compatibilitytools.d}"
|
||||||
|
UPSTREAM_REPO="${UPSTREAM_REPO:-GloriousEggroll/proton-ge-custom}"
|
||||||
|
ELSWORD_GE_VERSION="${ELSWORD_GE_VERSION:-11-1}"
|
||||||
|
PROTON_TAG="${PROTON_TAG:-GE-Proton${ELSWORD_GE_VERSION}}"
|
||||||
|
PROTON_ASSET="${PROTON_ASSET:-x86_64}"
|
||||||
|
RUNTIME_APPID="${RUNTIME_APPID:-1628350}"
|
||||||
|
WINE_SERIES="${WINE_SERIES:-Wine 11}"
|
||||||
|
DXVK_STABLE_TAG_DEFAULT="${DXVK_STABLE_TAG_DEFAULT:-latest}"
|
||||||
|
DXVK_GIT_REF="${DXVK_GIT_REF:-origin/master}"
|
||||||
|
MINGW_PTHREAD_ROOT="${MINGW_PTHREAD_ROOT:-}"
|
||||||
|
|
||||||
|
SAFE_LAUNCH_OPTIONS='LD_PRELOAD="" PROTON_DISCORD_BRIDGE=0 PROTON_USE_OPTISCALER=0 PROTON_USE_D7VK=0 LOW_LATENCY_LAYER=0 MANGOHUD=0 ENABLE_VKBASALT=0 VK_INSTANCE_LAYERS="" DXVK_HUD=0 %command%'
|
||||||
|
PERF_LAUNCH_OPTIONS='LD_PRELOAD="" PROTON_DISCORD_BRIDGE=0 PROTON_USE_OPTISCALER=0 PROTON_USE_D7VK=0 LOW_LATENCY_LAYER=1 MANGOHUD=0 ENABLE_VKBASALT=0 VK_INSTANCE_LAYERS="" DXVK_STATE_CACHE=1 DXVK_LOG_LEVEL=none %command%'
|
||||||
|
|
||||||
|
DEFAULT_ENV_KEYS=(
|
||||||
|
PROTON_DISCORD_BRIDGE
|
||||||
|
PROTON_USE_OPTISCALER
|
||||||
|
PROTON_USE_D7VK
|
||||||
|
MANGOHUD
|
||||||
|
ENABLE_VKBASALT
|
||||||
|
)
|
||||||
|
|
||||||
|
runtime_dll_names=(
|
||||||
|
libstdc++-6.dll
|
||||||
|
libgcc_s_seh-1.dll
|
||||||
|
libgcc_s_dw2-1.dll
|
||||||
|
libwinpthread-1.dll
|
||||||
|
libmcfgthread-2.dll
|
||||||
|
)
|
||||||
|
|
||||||
|
say() {
|
||||||
|
printf "\n==> %s\n" "$1" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
printf "Error: %s\n" "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || die "missing required command: $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_toolchain_commands() {
|
||||||
|
local cmd
|
||||||
|
for cmd in \
|
||||||
|
bash \
|
||||||
|
curl \
|
||||||
|
git \
|
||||||
|
jq \
|
||||||
|
meson \
|
||||||
|
ninja \
|
||||||
|
objdump \
|
||||||
|
python3 \
|
||||||
|
tar \
|
||||||
|
zstd \
|
||||||
|
glslangValidator \
|
||||||
|
x86_64-w64-mingw32-gcc \
|
||||||
|
x86_64-w64-mingw32-g++ \
|
||||||
|
i686-w64-mingw32-gcc \
|
||||||
|
i686-w64-mingw32-g++; do
|
||||||
|
require_cmd "$cmd"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_repo_layout() {
|
||||||
|
mkdir -p "$CACHE_DIR" "$WORK_ROOT" "$DIST_DIR" "$METADATA_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
tool_name_for_variant() {
|
||||||
|
case "$1" in
|
||||||
|
stable) printf "Elsword-GE-%s\n" "$ELSWORD_GE_VERSION" ;;
|
||||||
|
dxvk-git) printf "Elsword-GE-%s+dxvk-git\n" "$ELSWORD_GE_VERSION" ;;
|
||||||
|
*) die "unsupported variant: $1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
variant_label() {
|
||||||
|
case "$1" in
|
||||||
|
stable) printf "stable\n" ;;
|
||||||
|
dxvk-git) printf "dxvk-git\n" ;;
|
||||||
|
*) die "unsupported variant: $1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
dxvk_channel_for_variant() {
|
||||||
|
case "$1" in
|
||||||
|
stable) printf "stable\n" ;;
|
||||||
|
dxvk-git) printf "git\n" ;;
|
||||||
|
*) die "unsupported variant: $1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
dxvk_tag_for_variant() {
|
||||||
|
case "$1" in
|
||||||
|
stable) printf "%s\n" "$DXVK_STABLE_TAG_DEFAULT" ;;
|
||||||
|
dxvk-git) printf "git\n" ;;
|
||||||
|
*) die "unsupported variant: $1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
archive_name_for_variant() {
|
||||||
|
case "$1" in
|
||||||
|
stable) printf "Elsword-GE-%s.tar.zst\n" "$ELSWORD_GE_VERSION" ;;
|
||||||
|
dxvk-git) printf "Elsword-GE-%s+dxvk-git.tar.zst\n" "$ELSWORD_GE_VERSION" ;;
|
||||||
|
*) die "unsupported variant: $1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
archive_alias_for_variant() {
|
||||||
|
case "$1" in
|
||||||
|
stable) printf "%s\n" "$(archive_name_for_variant "$1")" ;;
|
||||||
|
dxvk-git) printf "Elsword-GE-%s-dxvk-git.tar.zst\n" "$ELSWORD_GE_VERSION" ;;
|
||||||
|
*) die "unsupported variant: $1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata_file_for_variant() {
|
||||||
|
printf "%s/%s.env\n" "$METADATA_DIR" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
release_title() {
|
||||||
|
printf "Elsword Proton-GE %s\n" "$ELSWORD_GE_VERSION"
|
||||||
|
}
|
||||||
|
|
||||||
|
workdir_for_variant() {
|
||||||
|
local variant="$1"
|
||||||
|
mktemp -d "$WORK_ROOT/${variant}.XXXXXX"
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_workdir() {
|
||||||
|
local dir="$1"
|
||||||
|
if [[ -n "$dir" && -d "$dir" ]]; then
|
||||||
|
rm -rf "$dir"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_latest_dxvk_tag() {
|
||||||
|
curl -fsSL https://api.github.com/repos/doitsujin/dxvk/releases/latest \
|
||||||
|
| jq -r '.tag_name'
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_dxvk_cache() {
|
||||||
|
if [[ ! -d "$DXVK_CACHE_DIR/.git" ]]; then
|
||||||
|
say "Clone DXVK cache"
|
||||||
|
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 "$DXVK_GIT_REF" >&2
|
||||||
|
git -C "$DXVK_CACHE_DIR" submodule update --init --recursive >&2
|
||||||
|
git -C "$DXVK_CACHE_DIR" clean -fdx >&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_dxvk_source() {
|
||||||
|
local variant="$1"
|
||||||
|
local workdir="$2"
|
||||||
|
local channel tag checkout_dir
|
||||||
|
channel="$(dxvk_channel_for_variant "$variant")"
|
||||||
|
tag="$(dxvk_tag_for_variant "$variant")"
|
||||||
|
checkout_dir="$workdir/dxvk-src"
|
||||||
|
|
||||||
|
prepare_dxvk_cache
|
||||||
|
say "Prepare DXVK source ($(variant_label "$variant"))"
|
||||||
|
git clone --recursive "$DXVK_CACHE_DIR" "$checkout_dir" >&2
|
||||||
|
|
||||||
|
if [[ "$channel" == "stable" ]]; then
|
||||||
|
if [[ "$tag" == "latest" ]]; then
|
||||||
|
tag="$(get_latest_dxvk_tag)"
|
||||||
|
fi
|
||||||
|
[[ -n "$tag" ]] || die "failed to resolve DXVK stable tag"
|
||||||
|
git -C "$checkout_dir" fetch --tags https://github.com/doitsujin/dxvk.git >&2
|
||||||
|
git -C "$checkout_dir" checkout "refs/tags/$tag" >&2
|
||||||
|
git -C "$checkout_dir" submodule update --init --recursive >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%s\n" "$checkout_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
download_proton_tarball() {
|
||||||
|
local asset proton_tarball proton_url
|
||||||
|
|
||||||
|
if [[ "$PROTON_ASSET" == "aarch64" ]]; then
|
||||||
|
asset="${PROTON_TAG}-aarch64.tar.gz"
|
||||||
|
else
|
||||||
|
asset="${PROTON_TAG}.tar.gz"
|
||||||
|
fi
|
||||||
|
|
||||||
|
proton_tarball="$CACHE_DIR/$asset"
|
||||||
|
proton_url="https://github.com/${UPSTREAM_REPO}/releases/download/${PROTON_TAG}/${asset}"
|
||||||
|
|
||||||
|
if [[ ! -f "$proton_tarball" ]]; then
|
||||||
|
say "Download Proton-GE ${PROTON_TAG}"
|
||||||
|
curl -fL "$proton_url" -o "$proton_tarball"
|
||||||
|
else
|
||||||
|
say "Reuse cached Proton tarball"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%s\n" "$proton_tarball"
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_proton_tool() {
|
||||||
|
local workdir="$1"
|
||||||
|
local tarball="$2"
|
||||||
|
local proton_root tool_root
|
||||||
|
|
||||||
|
proton_root="$workdir/proton"
|
||||||
|
mkdir -p "$proton_root"
|
||||||
|
tar -xf "$tarball" -C "$proton_root"
|
||||||
|
tool_root="$(find "$proton_root" -mindepth 1 -maxdepth 1 -type d | head -n1)"
|
||||||
|
[[ -n "$tool_root" ]] || die "could not find extracted Proton root"
|
||||||
|
printf "%s\n" "$tool_root"
|
||||||
|
}
|
||||||
|
|
||||||
|
inject_wrapper_defaults() {
|
||||||
|
local proton_wrapper="$1"
|
||||||
|
|
||||||
|
[[ -f "$proton_wrapper" ]] || die "missing proton wrapper: $proton_wrapper"
|
||||||
|
|
||||||
|
python3 - "$proton_wrapper" <<'PY'
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
path = Path(sys.argv[1])
|
||||||
|
text = path.read_text()
|
||||||
|
marker = 'os.environ.setdefault("PROTON_DISCORD_BRIDGE", "0")'
|
||||||
|
if marker in text:
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
block = (
|
||||||
|
'os.environ.setdefault("PROTON_DISCORD_BRIDGE", "0")\n'
|
||||||
|
'os.environ.setdefault("PROTON_USE_OPTISCALER", "0")\n'
|
||||||
|
'os.environ.setdefault("PROTON_USE_D7VK", "0")\n'
|
||||||
|
'os.environ.setdefault("MANGOHUD", "0")\n'
|
||||||
|
'os.environ.setdefault("ENABLE_VKBASALT", "0")\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
needle = "import os\n"
|
||||||
|
if needle not in text:
|
||||||
|
raise SystemExit("Could not patch proton wrapper: missing import os")
|
||||||
|
|
||||||
|
text = text.replace(needle, needle + "\n" + block + "\n", 1)
|
||||||
|
path.write_text(text)
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_runtime_dll_path() {
|
||||||
|
local arch="$1"
|
||||||
|
local dll="$2"
|
||||||
|
local compiler result nix_attr store_path
|
||||||
|
|
||||||
|
case "$arch" in
|
||||||
|
x86_64) compiler="x86_64-w64-mingw32-g++" ;;
|
||||||
|
x86) compiler="i686-w64-mingw32-g++" ;;
|
||||||
|
*) die "unsupported arch for runtime lookup: $arch" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
result="$("$compiler" -print-file-name="$dll")"
|
||||||
|
if [[ -n "$result" && "$result" != "$dll" && -f "$result" ]]; then
|
||||||
|
printf "%s\n" "$result"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$dll" == "libmcfgthread-2.dll" ]]; then
|
||||||
|
case "$arch" in
|
||||||
|
x86_64) nix_attr="pkgsCross.mingwW64.windows.mcfgthreads" ;;
|
||||||
|
x86) nix_attr="pkgsCross.mingw32.windows.mcfgthreads" ;;
|
||||||
|
esac
|
||||||
|
store_path="$(NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 nix path-info --impure "nixpkgs#${nix_attr}")"
|
||||||
|
result="$(find "$store_path" -name "$dll" -type f | head -n1 || true)"
|
||||||
|
if [[ -n "$result" && -f "$result" ]]; then
|
||||||
|
printf "%s\n" "$result"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_dll_to_targets() {
|
||||||
|
local dll_path="$1"
|
||||||
|
shift
|
||||||
|
local target_dir
|
||||||
|
|
||||||
|
for target_dir in "$@"; do
|
||||||
|
mkdir -p "$target_dir"
|
||||||
|
cp -f "$dll_path" "$target_dir/$(basename "$dll_path")"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
replace_dxvk_payload() {
|
||||||
|
local dxvk_build_dir="$1"
|
||||||
|
local tool_root="$2"
|
||||||
|
local source_x64="$dxvk_build_dir/x64"
|
||||||
|
local source_x32="$dxvk_build_dir/x32"
|
||||||
|
local dll
|
||||||
|
|
||||||
|
mkdir -p \
|
||||||
|
"$tool_root/files/lib/wine/dxvk/x86_64-windows" \
|
||||||
|
"$tool_root/files/lib/wine/dxvk/i386-windows" \
|
||||||
|
"$tool_root/files/lib/wine/x86_64-windows" \
|
||||||
|
"$tool_root/files/lib/wine/i386-windows" \
|
||||||
|
"$tool_root/files/share/default_pfx/drive_c/windows/system32" \
|
||||||
|
"$tool_root/files/share/default_pfx/drive_c/windows/syswow64"
|
||||||
|
|
||||||
|
for dll in d3d8.dll d3d9.dll d3d10core.dll d3d11.dll dxgi.dll; do
|
||||||
|
cp -f "$source_x64/$dll" "$tool_root/files/lib/wine/dxvk/x86_64-windows/$dll"
|
||||||
|
cp -f "$source_x32/$dll" "$tool_root/files/lib/wine/dxvk/i386-windows/$dll"
|
||||||
|
cp -f "$source_x64/$dll" "$tool_root/files/lib/wine/x86_64-windows/$dll"
|
||||||
|
cp -f "$source_x32/$dll" "$tool_root/files/lib/wine/i386-windows/$dll"
|
||||||
|
cp -f "$source_x64/$dll" "$tool_root/files/share/default_pfx/drive_c/windows/system32/$dll"
|
||||||
|
cp -f "$source_x32/$dll" "$tool_root/files/share/default_pfx/drive_c/windows/syswow64/$dll"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
patch_tool_manifests() {
|
||||||
|
local tool_root="$1"
|
||||||
|
local tool_name="$2"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
printf "%s %s\n" "$(date +%s)" "$tool_name" > "$tool_root/version"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_tool_tree_writable() {
|
||||||
|
local tool_root="$1"
|
||||||
|
local path
|
||||||
|
local paths=(
|
||||||
|
"$tool_root/proton"
|
||||||
|
"$tool_root/compatibilitytool.vdf"
|
||||||
|
"$tool_root/toolmanifest.vdf"
|
||||||
|
"$tool_root/version"
|
||||||
|
"$tool_root/files/lib/wine/dxvk/version"
|
||||||
|
"$tool_root/BUILD-INFO.txt"
|
||||||
|
)
|
||||||
|
|
||||||
|
for path in "${paths[@]}"; do
|
||||||
|
if [[ -e "$path" ]]; then
|
||||||
|
chmod u+w "$path"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_required_runtime_dlls() {
|
||||||
|
local tool_root="$1"
|
||||||
|
local dxvk_build_dir="$2"
|
||||||
|
local metadata_log="$3"
|
||||||
|
local arch dll source_path required
|
||||||
|
local deps targets source_dir dxvk_dll
|
||||||
|
|
||||||
|
: > "$metadata_log"
|
||||||
|
|
||||||
|
for arch in x86_64 x86; do
|
||||||
|
if [[ "$arch" == "x86_64" ]]; then
|
||||||
|
source_dir="$dxvk_build_dir/x64"
|
||||||
|
targets=(
|
||||||
|
"$tool_root/files/lib/wine/dxvk/x86_64-windows"
|
||||||
|
"$tool_root/files/lib/wine/x86_64-windows"
|
||||||
|
"$tool_root/files/share/default_pfx/drive_c/windows/system32"
|
||||||
|
)
|
||||||
|
printf "[x86_64]\n" >> "$metadata_log"
|
||||||
|
else
|
||||||
|
source_dir="$dxvk_build_dir/x32"
|
||||||
|
targets=(
|
||||||
|
"$tool_root/files/lib/wine/dxvk/i386-windows"
|
||||||
|
"$tool_root/files/lib/wine/i386-windows"
|
||||||
|
"$tool_root/files/share/default_pfx/drive_c/windows/syswow64"
|
||||||
|
)
|
||||||
|
printf "[x86]\n" >> "$metadata_log"
|
||||||
|
fi
|
||||||
|
|
||||||
|
deps=""
|
||||||
|
for dxvk_dll in d3d9.dll dxgi.dll d3d10core.dll d3d11.dll; do
|
||||||
|
deps+=$'\n'"$(objdump -p "$source_dir/$dxvk_dll" | grep 'DLL Name:' | awk '{print $3}')"
|
||||||
|
done
|
||||||
|
deps="$(printf "%s\n" "$deps" | sed '/^$/d' | sort -u)"
|
||||||
|
printf "%s\n" "$deps" >> "$metadata_log"
|
||||||
|
|
||||||
|
for dll in "${runtime_dll_names[@]}"; do
|
||||||
|
required=0
|
||||||
|
if grep -Fxq "$dll" <<<"$deps"; then
|
||||||
|
required=1
|
||||||
|
fi
|
||||||
|
if [[ "$required" -eq 1 ]]; then
|
||||||
|
source_path="$(resolve_runtime_dll_path "$arch" "$dll" || true)"
|
||||||
|
[[ -n "$source_path" ]] || die "missing runtime dependency $dll for $arch"
|
||||||
|
copy_dll_to_targets "$source_path" "${targets[@]}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
write_build_metadata() {
|
||||||
|
local variant="$1"
|
||||||
|
local tool_name="$2"
|
||||||
|
local tool_root="$3"
|
||||||
|
local dxvk_channel="$4"
|
||||||
|
local dxvk_tag="$5"
|
||||||
|
local dxvk_commit="$6"
|
||||||
|
local dxvk_describe="$7"
|
||||||
|
local build_time="$8"
|
||||||
|
local archive_name="$9"
|
||||||
|
local archive_alias="${10}"
|
||||||
|
|
||||||
|
cat > "$(metadata_file_for_variant "$variant")" <<EOF
|
||||||
|
VARIANT='${variant}'
|
||||||
|
TOOL_NAME='${tool_name}'
|
||||||
|
PROTON_TAG='${PROTON_TAG}'
|
||||||
|
PROTON_ASSET='${PROTON_ASSET}'
|
||||||
|
WINE_SERIES='${WINE_SERIES}'
|
||||||
|
RUNTIME_APPID='${RUNTIME_APPID}'
|
||||||
|
DXVK_CHANNEL='${dxvk_channel}'
|
||||||
|
DXVK_TAG='${dxvk_tag}'
|
||||||
|
DXVK_COMMIT='${dxvk_commit}'
|
||||||
|
DXVK_DESCRIBE='${dxvk_describe}'
|
||||||
|
BUILD_TIME='${build_time}'
|
||||||
|
TOOL_DIR='${tool_root}'
|
||||||
|
ARCHIVE_NAME='${archive_name}'
|
||||||
|
ARCHIVE_ALIAS='${archive_alias}'
|
||||||
|
SAFE_LAUNCH_OPTIONS='${SAFE_LAUNCH_OPTIONS}'
|
||||||
|
PERFORMANCE_LAUNCH_OPTIONS='${PERF_LAUNCH_OPTIONS}'
|
||||||
|
EOF
|
||||||
|
}
|
||||||
Executable
+88
@@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/common.sh"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
local stable_meta git_meta now stable_alias git_alias
|
||||||
|
|
||||||
|
ensure_repo_layout
|
||||||
|
"$SCRIPT_DIR/package.sh" all
|
||||||
|
|
||||||
|
stable_meta="$(metadata_file_for_variant stable)"
|
||||||
|
git_meta="$(metadata_file_for_variant dxvk-git)"
|
||||||
|
[[ -f "$stable_meta" && -f "$git_meta" ]] || die "build metadata missing; run ./scripts/build.sh all first"
|
||||||
|
|
||||||
|
source "$stable_meta"
|
||||||
|
local stable_tool_name="$TOOL_NAME"
|
||||||
|
local stable_dxvk="$DXVK_DESCRIBE"
|
||||||
|
local stable_commit="$DXVK_COMMIT"
|
||||||
|
local stable_archive="$ARCHIVE_NAME"
|
||||||
|
stable_alias="$ARCHIVE_ALIAS"
|
||||||
|
|
||||||
|
source "$git_meta"
|
||||||
|
local git_tool_name="$TOOL_NAME"
|
||||||
|
local git_dxvk="$DXVK_DESCRIBE"
|
||||||
|
local git_commit="$DXVK_COMMIT"
|
||||||
|
local git_archive="$ARCHIVE_NAME"
|
||||||
|
git_alias="$ARCHIVE_ALIAS"
|
||||||
|
|
||||||
|
say "Generate checksums"
|
||||||
|
(
|
||||||
|
cd "$DIST_DIR"
|
||||||
|
sha256sum \
|
||||||
|
"$stable_archive" \
|
||||||
|
"$git_archive" \
|
||||||
|
"$stable_alias" \
|
||||||
|
"$git_alias" > SHA256SUMS.txt
|
||||||
|
awk '{print $1 " " $2}' SHA256SUMS.txt | while read -r sum file; do
|
||||||
|
printf "%s %s\n" "$sum" "$file" > "${file}.sha256"
|
||||||
|
done
|
||||||
|
)
|
||||||
|
|
||||||
|
now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
cat > "$DIST_DIR/release-notes.md" <<EOF
|
||||||
|
# $(release_title)
|
||||||
|
|
||||||
|
Build timestamp: \`${now}\`
|
||||||
|
|
||||||
|
## Variants
|
||||||
|
|
||||||
|
- \`${stable_tool_name}\`
|
||||||
|
- Proton base: \`${PROTON_TAG}\`
|
||||||
|
- Wine series: \`${WINE_SERIES}\`
|
||||||
|
- DXVK: \`${stable_dxvk}\`
|
||||||
|
- DXVK commit: \`${stable_commit}\`
|
||||||
|
- Archive: \`${stable_archive}\`
|
||||||
|
|
||||||
|
- \`${git_tool_name}\`
|
||||||
|
- Proton base: \`${PROTON_TAG}\`
|
||||||
|
- Wine series: \`${WINE_SERIES}\`
|
||||||
|
- DXVK: \`${git_dxvk}\`
|
||||||
|
- DXVK commit: \`${git_commit}\`
|
||||||
|
- Archive: \`${git_archive}\`
|
||||||
|
- Alias: \`${git_alias}\`
|
||||||
|
|
||||||
|
## Checksums
|
||||||
|
|
||||||
|
See \`SHA256SUMS.txt\` and the matching \`.sha256\` files in this release.
|
||||||
|
|
||||||
|
## Recommended Elsword launch options
|
||||||
|
|
||||||
|
### Safe / GameGuard Test
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
${SAFE_LAUNCH_OPTIONS}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### Performance / Low-Latency Test
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
${PERF_LAUNCH_OPTIONS}
|
||||||
|
\`\`\`
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Executable
+41
@@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
STEAM_COMPAT_DIR="${STEAM_COMPAT_DIR:-$HOME/.local/share/Steam/compatibilitytools.d}"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage:
|
||||||
|
./scripts/install-to-steam.sh dist/Elsword-GE-11-1.tar.zst
|
||||||
|
./scripts/install-to-steam.sh dist/Elsword-GE-11-1+dxvk-git.tar.zst
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
archive="${1:-}"
|
||||||
|
[[ -n "$archive" ]] || {
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -f "$archive" ]] || {
|
||||||
|
printf "Archive not found: %s\n" "$archive" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p "$STEAM_COMPAT_DIR"
|
||||||
|
mapfile -t archive_entries < <(tar -tf "$archive")
|
||||||
|
tool_name="${archive_entries[0]%%/*}"
|
||||||
|
[[ -n "$tool_name" ]] || {
|
||||||
|
printf "Could not determine tool name from archive: %s\n" "$archive" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
install_path="$STEAM_COMPAT_DIR/$tool_name"
|
||||||
|
rm -rf "$install_path"
|
||||||
|
tar --zstd -xf "$archive" -C "$STEAM_COMPAT_DIR"
|
||||||
|
|
||||||
|
printf "Installed tool: %s\n" "$tool_name"
|
||||||
|
printf "Installed path: %s\n" "$install_path"
|
||||||
|
printf "Steam fully restart required.\n"
|
||||||
|
printf "In Steam, open Elsword and select this compatibility tool.\n"
|
||||||
Executable
+65
@@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/common.sh"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage:
|
||||||
|
./scripts/package.sh stable
|
||||||
|
./scripts/package.sh dxvk-git
|
||||||
|
./scripts/package.sh all
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
package_variant() {
|
||||||
|
local variant="$1"
|
||||||
|
local metadata_file tool_name tool_dir archive_name archive_alias archive_path alias_path
|
||||||
|
|
||||||
|
metadata_file="$(metadata_file_for_variant "$variant")"
|
||||||
|
[[ -f "$metadata_file" ]] || die "missing metadata for variant $variant, run build first"
|
||||||
|
source "$metadata_file"
|
||||||
|
|
||||||
|
tool_name="$(tool_name_for_variant "$variant")"
|
||||||
|
tool_dir="$DIST_DIR/$tool_name"
|
||||||
|
archive_name="$(archive_name_for_variant "$variant")"
|
||||||
|
archive_alias="$(archive_alias_for_variant "$variant")"
|
||||||
|
archive_path="$DIST_DIR/$archive_name"
|
||||||
|
alias_path="$DIST_DIR/$archive_alias"
|
||||||
|
|
||||||
|
[[ -d "$tool_dir" ]] || die "missing built tool dir: $tool_dir"
|
||||||
|
|
||||||
|
say "Package $tool_name"
|
||||||
|
rm -f "$archive_path" "$alias_path"
|
||||||
|
tar --zstd -cf "$archive_path" -C "$DIST_DIR" "$tool_name"
|
||||||
|
|
||||||
|
if [[ "$archive_alias" != "$archive_name" ]]; then
|
||||||
|
cp -f "$archive_path" "$alias_path"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
local mode="${1:-all}"
|
||||||
|
ensure_repo_layout
|
||||||
|
|
||||||
|
case "$mode" in
|
||||||
|
stable) package_variant stable ;;
|
||||||
|
dxvk-git) package_variant dxvk-git ;;
|
||||||
|
all)
|
||||||
|
package_variant stable
|
||||||
|
package_variant dxvk-git
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Executable
+111
@@ -0,0 +1,111 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/common.sh"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage:
|
||||||
|
./scripts/validate-build.sh dist/Elsword-GE-11-1 Elsword-GE-11-1
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
tool_dir="${1:-}"
|
||||||
|
tool_name="${2:-}"
|
||||||
|
[[ -n "$tool_dir" && -n "$tool_name" ]] || {
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pass() {
|
||||||
|
printf "[ok] %s\n" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
printf "[fail] %s\n" "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
check_exists() {
|
||||||
|
local path="$1"
|
||||||
|
local label="$2"
|
||||||
|
[[ -e "$path" ]] && pass "$label" || fail "$label"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_contains() {
|
||||||
|
local path="$1"
|
||||||
|
local needle="$2"
|
||||||
|
local label="$3"
|
||||||
|
grep -Fq "$needle" "$path" && pass "$label" || fail "$label"
|
||||||
|
}
|
||||||
|
|
||||||
|
dump_dll_report() {
|
||||||
|
local dll_path="$1"
|
||||||
|
local label="$2"
|
||||||
|
local deps arch
|
||||||
|
|
||||||
|
arch="$(objdump -f "$dll_path" | awk -F'file format ' '/file format/ {print $2}' | head -n1)"
|
||||||
|
deps="$(objdump -p "$dll_path" | awk '/DLL Name:/ {print $3}' | sort -u | paste -sd',' -)"
|
||||||
|
printf "[dll] %s arch=%s deps=%s\n" "$label" "${arch:-unknown}" "${deps:-none}"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_packaged_runtime_deps() {
|
||||||
|
local dll_path="$1"
|
||||||
|
local search_dir="$2"
|
||||||
|
local dep
|
||||||
|
|
||||||
|
while read -r dep; do
|
||||||
|
[[ -n "$dep" ]] || continue
|
||||||
|
if ! printf '%s\n' "${runtime_dll_names[@]}" | grep -Fxq "$dep"; then
|
||||||
|
printf "[dep] %s requires %s ... provided by Wine/Windows runtime\n" "$(basename "$dll_path")" "$dep"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
printf "[dep] %s requires %s ... " "$(basename "$dll_path")" "$dep"
|
||||||
|
if [[ -f "$search_dir/$dep" || -f "$(dirname "$dll_path")/$dep" ]]; then
|
||||||
|
printf "present\n"
|
||||||
|
else
|
||||||
|
printf "missing\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done < <(objdump -p "$dll_path" | awk '/DLL Name:/ {print $3}')
|
||||||
|
}
|
||||||
|
|
||||||
|
check_exists "$tool_dir/compatibilitytool.vdf" "compatibilitytool.vdf exists"
|
||||||
|
check_exists "$tool_dir/proton" "proton wrapper exists"
|
||||||
|
[[ -x "$tool_dir/proton" ]] && pass "proton wrapper executable" || fail "proton wrapper executable"
|
||||||
|
check_contains "$tool_dir/compatibilitytool.vdf" "\"$tool_name\"" "tool name in compatibilitytool.vdf matches"
|
||||||
|
check_contains "$tool_dir/compatibilitytool.vdf" "\"display_name\" \"$tool_name\"" "display_name in compatibilitytool.vdf matches"
|
||||||
|
|
||||||
|
for dll in d3d9.dll dxgi.dll d3d10core.dll d3d11.dll; do
|
||||||
|
check_exists "$tool_dir/files/lib/wine/dxvk/i386-windows/$dll" "$dll x86 exists"
|
||||||
|
check_exists "$tool_dir/files/lib/wine/dxvk/x86_64-windows/$dll" "$dll x64 exists"
|
||||||
|
done
|
||||||
|
|
||||||
|
check_contains "$tool_dir/proton" 'os.environ.setdefault("PROTON_DISCORD_BRIDGE", "0")' "PROTON_DISCORD_BRIDGE default 0 in wrapper"
|
||||||
|
check_contains "$tool_dir/proton" 'os.environ.setdefault("PROTON_USE_OPTISCALER", "0")' "PROTON_USE_OPTISCALER default 0 in wrapper"
|
||||||
|
check_contains "$tool_dir/proton" 'os.environ.setdefault("PROTON_USE_D7VK", "0")' "PROTON_USE_D7VK default 0 in wrapper"
|
||||||
|
check_contains "$tool_dir/proton" 'os.environ.setdefault("MANGOHUD", "0")' "MANGOHUD default 0 in wrapper"
|
||||||
|
check_contains "$tool_dir/proton" 'os.environ.setdefault("ENABLE_VKBASALT", "0")' "ENABLE_VKBASALT default 0 in wrapper"
|
||||||
|
if grep -Fq 'LOW_LATENCY_LAYER' "$tool_dir/proton" && grep -Fq 'LOW_LATENCY_LAYER", "0"' "$tool_dir/proton"; then
|
||||||
|
fail "LOW_LATENCY_LAYER must not be hard-disabled"
|
||||||
|
else
|
||||||
|
pass "LOW_LATENCY_LAYER not hard-disabled"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for dll in d3d9.dll dxgi.dll d3d10core.dll d3d11.dll; do
|
||||||
|
dump_dll_report "$tool_dir/files/lib/wine/dxvk/i386-windows/$dll" "x86 $dll"
|
||||||
|
dump_dll_report "$tool_dir/files/lib/wine/dxvk/x86_64-windows/$dll" "x64 $dll"
|
||||||
|
check_packaged_runtime_deps "$tool_dir/files/lib/wine/dxvk/i386-windows/$dll" "$tool_dir/files/share/default_pfx/drive_c/windows/syswow64"
|
||||||
|
check_packaged_runtime_deps "$tool_dir/files/lib/wine/dxvk/x86_64-windows/$dll" "$tool_dir/files/share/default_pfx/drive_c/windows/system32"
|
||||||
|
done
|
||||||
|
|
||||||
|
for runtime_dll in "${runtime_dll_names[@]}"; do
|
||||||
|
if objdump -p "$tool_dir/files/lib/wine/dxvk/i386-windows/"*.dll | grep -Fq "$runtime_dll"; then
|
||||||
|
check_exists "$tool_dir/files/share/default_pfx/drive_c/windows/syswow64/$runtime_dll" "$runtime_dll present for x86 if needed"
|
||||||
|
fi
|
||||||
|
if objdump -p "$tool_dir/files/lib/wine/dxvk/x86_64-windows/"*.dll | grep -Fq "$runtime_dll"; then
|
||||||
|
check_exists "$tool_dir/files/share/default_pfx/drive_c/windows/system32/$runtime_dll" "$runtime_dll present for x64 if needed"
|
||||||
|
fi
|
||||||
|
done
|
||||||
Reference in New Issue
Block a user