mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-11 00:05:36 +02:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fed8605fa | ||
|
|
674124e819 | ||
|
|
9a11f459cb | ||
|
|
46fe87a715 | ||
|
|
204730450c | ||
|
|
e6fa6ea6e1 | ||
|
|
ea157b4898 | ||
|
|
df332b66bc | ||
|
|
8304ca08a4 | ||
|
|
9bb194091d | ||
|
|
ad210f2b75 |
52
.github/workflows/base.yml
vendored
52
.github/workflows/base.yml
vendored
@@ -19,13 +19,13 @@ on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
# concurrency:
|
||||
# group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
# cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: wanjohiryan/netris
|
||||
IMAGE_NAME: netrisdotme/netris
|
||||
BASE_TAG_PREFIX: base
|
||||
|
||||
jobs:
|
||||
@@ -67,7 +67,49 @@ jobs:
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
file: base.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-docker-release:
|
||||
name: Build image on release
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
|
||||
52
.github/workflows/relay.yml
vendored
52
.github/workflows/relay.yml
vendored
@@ -19,13 +19,13 @@ on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
# concurrency:
|
||||
# group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
# cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: wanjohiryan/netris
|
||||
IMAGE_NAME: netrisdotme/netris
|
||||
BASE_TAG_PREFIX: relay
|
||||
|
||||
jobs:
|
||||
@@ -67,7 +67,49 @@ jobs:
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
file: relay.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-docker-release:
|
||||
name: Build image on release
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
|
||||
52
.github/workflows/server.yml
vendored
52
.github/workflows/server.yml
vendored
@@ -23,12 +23,12 @@ on:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: wanjohiryan/netris
|
||||
IMAGE_NAME: netrisdotme/netris
|
||||
BASE_TAG_PREFIX: server
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
# concurrency:
|
||||
# group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
# cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-docker-pr:
|
||||
@@ -69,7 +69,49 @@ jobs:
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
file: server.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-docker-release:
|
||||
name: Build image on release
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
|
||||
59
.github/workflows/warp-input.yml
vendored
59
.github/workflows/warp-input.yml
vendored
@@ -16,6 +16,7 @@ on:
|
||||
paths:
|
||||
- "warp-input.Dockerfile"
|
||||
- ".github/workflows/warp-input.yml"
|
||||
- "bin/input/**"
|
||||
tags:
|
||||
- v*.*.*
|
||||
release:
|
||||
@@ -23,12 +24,12 @@ on:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: wanjohiryan/netris
|
||||
IMAGE_NAME: netrisdotme/netris
|
||||
BASE_TAG_PREFIX: warp-input
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
# concurrency:
|
||||
# group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
# cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-docker-pr:
|
||||
@@ -73,7 +74,51 @@ jobs:
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
file: warp-input.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-docker-release:
|
||||
name: Build image on release
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
@@ -176,7 +221,7 @@ jobs:
|
||||
if: ${{ matrix.settings.host == 'windows-latest' }}
|
||||
uses: svenstaro/upload-release-action@2.9.0
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
repo_token: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
file: ./bin/input/warp-input.exe
|
||||
asset_name: ${{ matrix.settings.asset_name }}
|
||||
tag: ${{ github.ref }}
|
||||
@@ -185,7 +230,7 @@ jobs:
|
||||
if: ${{ matrix.settings.host != 'windows-latest' }}
|
||||
uses: svenstaro/upload-release-action@2.9.0
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
repo_token: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
file: ./bin/input/warp-input
|
||||
asset_name: ${{ matrix.settings.asset_name }}
|
||||
tag: ${{ github.ref }}
|
||||
54
.github/workflows/warp.yml
vendored
54
.github/workflows/warp.yml
vendored
@@ -22,12 +22,12 @@ on:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: wanjohiryan/netris
|
||||
IMAGE_NAME: netrisdotme/netris
|
||||
BASE_TAG_PREFIX: warp
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
# concurrency:
|
||||
# group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }}
|
||||
# cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-docker-pr:
|
||||
@@ -72,7 +72,51 @@ jobs:
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||
#
|
||||
#tag on release, and a nightly build for 'dev'
|
||||
tags: |
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
-
|
||||
name: Build Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
file: warp.Dockerfile
|
||||
context: ./
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
build-docker-release:
|
||||
name: Build image on release
|
||||
if: ${{ github.event_name == 'release' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
-
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
-
|
||||
name: Log into registry ${{ env.REGISTRY }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GIT_MASTER_TOKEN }}
|
||||
-
|
||||
name: Extract Container metadata
|
||||
id: meta
|
||||
|
||||
@@ -60,38 +60,38 @@ sudo ln -snf /dev/ptmx /dev/tty7
|
||||
# Start DBus without systemd
|
||||
sudo /etc/init.d/dbus start
|
||||
|
||||
# Install Proton-GE for this user
|
||||
netris-proton -i
|
||||
|
||||
# Install NVIDIA userspace driver components including X graphic libraries
|
||||
if ! command -v nvidia-xconfig &>/dev/null; then
|
||||
if ! command -v nvidia-xconfig &> /dev/null; then
|
||||
# Driver version is provided by the kernel through the container toolkit
|
||||
export DRIVER_ARCH="$(dpkg --print-architecture | sed -e 's/arm64/aarch64/' -e 's/armhf/32bit-ARM/' -e 's/i.*86/x86/' -e 's/amd64/x86_64/' -e 's/unknown/x86_64/')"
|
||||
export DRIVER_VERSION="$(head -n1 </proc/driver/nvidia/version | awk '{print $8}')"
|
||||
export DRIVER_VERSION="$(head -n1 </proc/driver/nvidia/version | awk '{for(i=1;i<=NF;i++) if ($i ~ /^[0-9]+\.[0-9\.]+/) {print $i; exit}}')"
|
||||
cd /tmp
|
||||
# If version is different, new installer will overwrite the existing components
|
||||
if [ ! -f "/tmp/NVIDIA-Linux-${DRIVER_ARCH}-${DRIVER_VERSION}.run" ]; then
|
||||
# Check multiple sources in order to probe both consumer and datacenter driver versions
|
||||
curl -fsSL -O "https://international.download.nvidia.com/XFree86/Linux-${DRIVER_ARCH}/${DRIVER_VERSION}/NVIDIA-Linux-${DRIVER_ARCH}-${DRIVER_VERSION}.run" || curl -fsSL -O "https://international.download.nvidia.com/tesla/${DRIVER_VERSION}/NVIDIA-Linux-${DRIVER_ARCH}-${DRIVER_VERSION}.run" || {
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") Failed NVIDIA GPU driver download. Exiting."
|
||||
exit 1
|
||||
}
|
||||
curl -fsSL -O "https://international.download.nvidia.com/XFree86/Linux-${DRIVER_ARCH}/${DRIVER_VERSION}/NVIDIA-Linux-${DRIVER_ARCH}-${DRIVER_VERSION}.run" || curl -fsSL -O "https://international.download.nvidia.com/tesla/${DRIVER_VERSION}/NVIDIA-Linux-${DRIVER_ARCH}-${DRIVER_VERSION}.run" || { echo "Failed NVIDIA GPU driver download. Exiting."; exit 1; }
|
||||
fi
|
||||
# Extract installer before installing
|
||||
sudo sh "NVIDIA-Linux-${DRIVER_ARCH}-${DRIVER_VERSION}.run" -x
|
||||
cd "NVIDIA-Linux-${DRIVER_ARCH}-${DRIVER_VERSION}"
|
||||
# Run installation without the kernel modules and host components
|
||||
sudo ./nvidia-installer --silent \
|
||||
--no-kernel-module \
|
||||
--install-compat32-libs \
|
||||
--no-nouveau-check \
|
||||
--no-nvidia-modprobe \
|
||||
--no-rpms \
|
||||
--no-backup \
|
||||
--no-check-for-alternate-installs
|
||||
--no-kernel-module \
|
||||
--install-compat32-libs \
|
||||
--no-nouveau-check \
|
||||
--no-nvidia-modprobe \
|
||||
--no-rpms \
|
||||
--no-backup \
|
||||
--no-check-for-alternate-installs
|
||||
sudo rm -rf /tmp/NVIDIA* && cd ~
|
||||
fi
|
||||
|
||||
# Allow starting Xorg from a pseudoterminal instead of strictly on a tty console
|
||||
if [ ! -f /etc/X11/Xwrapper.config ]; then
|
||||
echo -e "allowed_users=anybody\nneeds_root_rights=yes" | sudo tee /etc/X11/Xwrapper.config >/dev/null
|
||||
echo -e "allowed_users=anybody\nneeds_root_rights=yes" | sudo tee /etc/X11/Xwrapper.config > /dev/null
|
||||
fi
|
||||
if grep -Fxq "allowed_users=console" /etc/X11/Xwrapper.config; then
|
||||
sudo sed -i "s/allowed_users=console/allowed_users=anybody/;$ a needs_root_rights=yes" /etc/X11/Xwrapper.config
|
||||
@@ -114,7 +114,7 @@ else
|
||||
fi
|
||||
|
||||
if [ -z "$GPU_SELECT" ]; then
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") No NVIDIA GPUs detected or nvidia-container-toolkit not configured. Exiting."
|
||||
echo "No NVIDIA GPUs detected or nvidia-container-toolkit not configured. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -140,30 +140,32 @@ sudo sed -i '/Driver\s\+"nvidia"/a\ Option "ModeValidation" "NoMaxPCl
|
||||
# Add custom generated modeline to the configuration
|
||||
sudo sed -i '/Section\s\+"Monitor"/a\ '"$MODELINE" /etc/X11/xorg.conf
|
||||
# Prevent interference between GPUs, add this to the host or other containers running Xorg as well
|
||||
echo -e "Section \"ServerFlags\"\n Option \"AutoAddGPU\" \"false\"\nEndSection" | sudo tee -a /etc/X11/xorg.conf >/dev/null
|
||||
echo -e "Section \"ServerFlags\"\n Option \"AutoAddGPU\" \"false\"\nEndSection" | sudo tee -a /etc/X11/xorg.conf > /dev/null
|
||||
|
||||
# Default display is :0 across the container
|
||||
export DISPLAY=":0"
|
||||
# Run Xorg server with required extensions
|
||||
/usr/bin/Xorg vt7 -noreset -novtswitch -sharevts -dpi "${DPI}" +extension "COMPOSITE" +extension "DAMAGE" +extension "GLX" +extension "RANDR" +extension "RENDER" +extension "MIT-SHM" +extension "XFIXES" +extension "XTEST" "${DISPLAY}" &
|
||||
|
||||
# Wait for X11 to start
|
||||
echo "Waiting for X socket"
|
||||
until [ -S "/tmp/.X11-unix/X${DISPLAY/:/}" ]; do sleep 1; done
|
||||
echo "X socket is ready"
|
||||
|
||||
# Wait for X11 to start
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") Waiting for X socket"
|
||||
until [ -S "/tmp/.X11-unix/X${DISPLAY/:/}" ]; do sleep 1; done
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") X socket is ready"
|
||||
|
||||
if [[ -z "${NAME}" ]]; then
|
||||
if [[ -z "${SESSION_ID}" ]]; then
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") No stream name was found, did you forget to set the env variable NAME?" && exit 1
|
||||
else
|
||||
/usr/bin/gpu-screen-recorder -w screen -c flv -f 60 -a "$(pactl get-default-sink).monitor" | ffmpeg -hide_banner -v quiet -i pipe:0 -c copy -f mp4 -movflags empty_moov+frag_every_frame+separate_moof+omit_tfhd_offset - | /usr/bin/warp --name "${NAME}" https://fst.so:4443 &
|
||||
/usr/bin/gpu-screen-recorder -w screen -c flv -f 60 -a "$(pactl get-default-sink).monitor" | ffmpeg -hide_banner -v quiet -i pipe:0 -c copy -f mp4 -movflags empty_moov+frag_every_frame+separate_moof+omit_tfhd_offset - | /usr/bin/warp --name "${SESSION_ID}" https://fst.so:4443 &
|
||||
fi
|
||||
|
||||
openbox-session &
|
||||
|
||||
#Now we can safely run our input server without permission errors
|
||||
sudo /inputtino/input-server &
|
||||
|
||||
/usr/games/gamescope -- mangohud glxgears > /dev/null &
|
||||
# /usr/games/gamescope -- mangohud glxgears > /dev/null &
|
||||
|
||||
echo "$(date +"[%Y-%m-%d %H:%M:%S]") Session Running. Press [Return] to exit."
|
||||
read
|
||||
|
||||
832
.scripts/proton
832
.scripts/proton
@@ -1,49 +1,371 @@
|
||||
#!/bin/bash
|
||||
# Version 0.0.1
|
||||
# Version 1.1
|
||||
#Copied from https://github.com/noabody/unibuild/blob/master/data/wstart
|
||||
|
||||
#Big thanks to github/@noabody
|
||||
#For his wmstart script https://github.com/noabody/unibuild/blob/master/data/wstart
|
||||
# WINEARCH win32/win64 not as good as binary wine/wine64"
|
||||
# WINEDEBUG="-all" not as good as dev/null
|
||||
|
||||
#Dependencies: git, jq, curl, vulkan & wget
|
||||
# complex command line builder to simplify command objects
|
||||
# vars bin, pfx set to wine binary, prefix dirs initially
|
||||
# menus will dynamically set bin pfx to specific targets
|
||||
# menu shows gui based 32/64-bit pe header exe via pev
|
||||
# var 'x' for unified cross-functionality
|
||||
# ${@:2} skips 'wstart' and 1st arg
|
||||
|
||||
# top level linux steam dir
|
||||
# manjaro 21.2.1
|
||||
#sudo pacman -S bash binutils findutils gendesk grep icoutils pcre2 perl yay winetricks; yay -S pev
|
||||
|
||||
# wnbin needs wine dir with: bin lib lib64 share
|
||||
# manjaro default path is /usr
|
||||
# can symlink various wnbin="$HOME/.local/opt"
|
||||
#mkdir "$HOME"/.local/opt
|
||||
#ln -sf /usr "$HOME"/.local/opt/wine
|
||||
#ln -sf /usr/share/steam/compatibilitytools.d/proton-ge-custom/files "$HOME"/.local/opt/proton
|
||||
|
||||
wnbin="/usr"
|
||||
# top level wine dir, symlink into "$HOME/.local/opt" to flatten paths
|
||||
wnpfx="$HOME"
|
||||
# top level wine prefix dir
|
||||
pntop="$HOME/.steam"
|
||||
# steamapps subdir
|
||||
# top level linux steam dir
|
||||
pnapp="$pntop/steam/steamapps"
|
||||
# proton subdir normally under top/app
|
||||
# steamapps subdir
|
||||
pnbin="$pnapp/common"
|
||||
# proton prefix subdir normally under top/app
|
||||
# proton subdir normally under top/app
|
||||
pnpfx="$pnapp/compatdata"
|
||||
# proton ge
|
||||
# proton prefix subdir normally under top/app
|
||||
pnpge="$pntop/root/compatibilitytools.d"
|
||||
# Program Files standard subdir
|
||||
# proton ge
|
||||
progs="drive_c/Program Files"
|
||||
# windows steam client subdir under progs
|
||||
# Program Files standard subdir
|
||||
stcmn="Steam/steamapps/common"
|
||||
# temp folder
|
||||
# windows steam client subdir under progs
|
||||
desk="$HOME/Desktop"
|
||||
# desktop entry folder
|
||||
icon="applications-other"
|
||||
# default icon
|
||||
temp="$HOME/Downloads"
|
||||
|
||||
# store cmdline args minus first option
|
||||
# temp folder
|
||||
clprm=("${@:2}")
|
||||
|
||||
# store cmdline args minus first option
|
||||
x="$(echo "$1" | grep -Pio '(?<=-)[wp]')"
|
||||
# 1st letter of 1st cmd line arg determines wine/proton
|
||||
if [[ -n "$x" ]]; then
|
||||
xarg="$(echo "$1" | perl -pe 's/-[wp]/-x/gi')"
|
||||
else
|
||||
xarg="$(echo "$1" | perl -pe 's/-x+/-/gi')"
|
||||
fi
|
||||
# drop 1st letter x or change to it
|
||||
xcmd=()
|
||||
i_mnus=()
|
||||
myprnt=()
|
||||
i_syms=()
|
||||
# scalable built-in programs menu
|
||||
pmenu=("Command Prompt/wineconsole.exe" "Control Panel/control.exe" "Registry Editor/regedit.exe" "Task Manager/taskmgr.exe" "Windows Explorer/explorer.exe" "Wine Configuration/winecfg.exe")
|
||||
# prevent shell inheritance of env vars we use
|
||||
# scalable built-in programs menu
|
||||
unset WINEARCH WINEDLLPATH WINEPREFIX STEAM_COMPAT_CLIENT_INSTALL_PATH STEAM_COMPAT_DATA_PATH
|
||||
# prevent shell inheritance of env vars we use
|
||||
|
||||
xarg="$1"
|
||||
|
||||
xnint() {
|
||||
xnbin="$pnbin"
|
||||
xnpfx="$pnpfx"
|
||||
dpth=(4 3)
|
||||
w_menu () {
|
||||
PS3="Please enter your choice: "
|
||||
select answer in "${i_mnus[@]}"; do
|
||||
for item in "${i_mnus[@]}"; do
|
||||
if [[ $item == "$answer" ]]; then
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
# repeating menu requires valid selection from array
|
||||
if [[ "$answer" = "quit" ]]; then
|
||||
# pop quit from end of array for menu option
|
||||
exit
|
||||
else
|
||||
xmrtn="$answer"
|
||||
fi
|
||||
unset i_mnus
|
||||
clear
|
||||
}
|
||||
|
||||
xpge() {
|
||||
# Path ordering: wine64 x64/x32 or wine32 x32 then standard
|
||||
# Order critical to proper operation
|
||||
xn64 () {
|
||||
xstrt="wine64"
|
||||
xnldl="$xnbin/lib64:$xnbin/lib"
|
||||
xndll="$xnbin/lib64/wine:$xnbin/lib/wine"
|
||||
}
|
||||
|
||||
xn32 () {
|
||||
xstrt="wine"
|
||||
xnldl="$xnbin/lib"
|
||||
xndll="$xnbin/lib/wine"
|
||||
}
|
||||
|
||||
xnint () {
|
||||
if [[ "$x" = "p" ]]; then
|
||||
xnbin="$pnbin"
|
||||
xnpfx="$pnpfx"
|
||||
dpth=(4 3)
|
||||
else
|
||||
xnbin="$wnbin"
|
||||
xnpfx="$wnpfx"
|
||||
dpth=(3 2)
|
||||
fi
|
||||
}
|
||||
|
||||
xnexe () {
|
||||
# menu installed wine/proton or exit
|
||||
readarray -t i_mnus < <(find -L "$xnbin" -maxdepth "${dpth[0]}" -type f -iname 'wine' ! \( -ipath '*/sbin*' \) 2>/dev/null | perl -pe "s|\Q$xnbin\E/(.*)[/]*bin/wine|\1| ; s|/$||" | sort ; echo "quit")
|
||||
if [[ ${#i_mnus[@]} -gt 2 ]]; then
|
||||
clear
|
||||
w_menu
|
||||
xnbin="$(realpath "$xnbin/$xmrtn")"
|
||||
unset xmrtn
|
||||
elif [[ ${#i_mnus[@]} -eq 2 ]]; then
|
||||
xnbin="$(realpath "$xnbin/${i_mnus[0]}")"
|
||||
else
|
||||
echo "No installed Wine/Proton found."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
xndef () {
|
||||
# create default prefix cross-function
|
||||
if [[ "$x" = "p" ]]; then
|
||||
if [[ ! -d "$xnpfx/0" ]]; then
|
||||
# always create default 0 prefix
|
||||
xnpfx="$xnpfx/0"
|
||||
echo "Creating default prefix: $xnpfx"
|
||||
mkdir -p "$xnpfx"
|
||||
STEAM_COMPAT_DATA_PATH="$xnpfx" "${xnbin%/*}/proton" run > /dev/null 2>&1 &
|
||||
xnpfx="$xnpfx/pfx"
|
||||
fi
|
||||
else
|
||||
if [[ ! -d "$xnpfx/.wine" ]]; then
|
||||
# always create default wine prefix
|
||||
xnpfx="$xnpfx/.wine"
|
||||
echo "Creating default prefix: $xnpfx"
|
||||
WINEPREFIX="$xnpfx" "$xnbin"/bin/winecfg > /dev/null 2>&1 &
|
||||
if [[ -d "$HOME/.wine" && "$HOME/.wine" != "$xnpfx" ]]; then
|
||||
rm -rf "$HOME"/.wine
|
||||
ln -sf "$xnpfx" "$HOME"/.wine
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
xnpre () {
|
||||
# menu wine/proton prefix
|
||||
readarray -t i_mnus < <(find "$xnpfx" -maxdepth "${dpth[1]}" -type f -iname 'system.reg' 2>/dev/null | perl -pe "s|\Q$xnpfx\E/(.*)/system.reg|\1|" | sort ; echo "quit")
|
||||
# use perl escaped Q/E to preserve special characters in path variable
|
||||
if [[ ${#i_mnus[@]} -gt 2 ]]; then
|
||||
# display menu with min two options plus quit
|
||||
# guard proton cross-function
|
||||
if [[ "$x" = "p" ]]; then
|
||||
# shellcheck disable=SC2044
|
||||
for value in $(find "$xnpfx" -maxdepth 1 -type d -ipath '*/[0-9]*' -printf "${xnpfx///compatdata}/appmanifest_%P.acf\n" 2>/dev/null); do
|
||||
test -f "$value" && myprnt+=("$(grep -Pio '^\s+\"(appid|name)\"\s+\"(.*)\"' "$value" | perl -pe 's/.*appid.+?\"(.*)\"\v|.*name.+?\"(.*)\"/\1 \2/')")
|
||||
done
|
||||
if [[ ${#myprnt[@]} -gt 0 ]]; then
|
||||
printf '%s\n' "${myprnt[@]}" | sort
|
||||
fi
|
||||
# correlate appmanifest to proton prefix and list before menu
|
||||
unset myprnt
|
||||
fi
|
||||
w_menu
|
||||
xnpfx="$xnpfx/$xmrtn"
|
||||
unset xmrtn
|
||||
elif [[ ${#i_mnus[@]} -eq 2 ]]; then
|
||||
# don't menu if only one option plus quit
|
||||
xnpfx="$xnpfx/${i_mnus[0]}"
|
||||
fi
|
||||
if [[ -d "$xnpfx/$progs (x86)" ]]; then
|
||||
xn64
|
||||
else
|
||||
xn32
|
||||
fi
|
||||
}
|
||||
|
||||
xnenv () {
|
||||
# core env vars allow proper targetting of wine/proton
|
||||
xpath="$xnbin/bin:$PATH"
|
||||
xcmd=(env PATH="$xpath" WINEDLLPATH="$xndll" LD_LIBRARY_PATH="$xnldl" WINEPREFIX="$xnpfx")
|
||||
# guard proton cross-function which adds on to core env vars
|
||||
if [[ "$x" = "p" ]]; then
|
||||
xcmd+=(STEAM_COMPAT_DATA_PATH="${xnpfx///pfx}" STEAM_COMPAT_CLIENT_INSTALL_PATH="$pntop")
|
||||
fi
|
||||
}
|
||||
|
||||
xnldr () {
|
||||
# loader default to proton as applicable, otherwise wine
|
||||
if [[ "$x" = "p" ]]; then
|
||||
read -r -p 'wine loader? [y/N] ' chse
|
||||
if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
xcmd+=("$xstrt")
|
||||
else
|
||||
xcmd+=("${xnbin%/*}/proton" "run")
|
||||
fi
|
||||
else
|
||||
xcmd+=("$xstrt")
|
||||
fi
|
||||
}
|
||||
|
||||
xnset () {
|
||||
# set cross-fuction
|
||||
xnint
|
||||
# wine/proton menu
|
||||
xnexe
|
||||
# create default prefix as required
|
||||
xndef
|
||||
# wine/proton prefix
|
||||
xnpre
|
||||
# wine/proton env vars
|
||||
xnenv
|
||||
}
|
||||
|
||||
xlnch () {
|
||||
# cross-function command line launcher
|
||||
if [[ -z "$dbg" ]]; then
|
||||
("${xcmd[@]}" > /dev/null 2>&1 &)
|
||||
else
|
||||
echo "${xcmd[@]}"
|
||||
if [[ "$dbg" = "1" ]]; then
|
||||
("${xcmd[@]}" &)
|
||||
elif [[ "$dbg" = "2" ]]; then
|
||||
(WINEDEBUG="warn+all" "${xcmd[@]}" &)
|
||||
fi
|
||||
fi
|
||||
# prepend cmd with dbg=1 to see command and default debug output
|
||||
# dbg=2 to see command and all debug output, dbg=? for command only
|
||||
}
|
||||
|
||||
allexe () {
|
||||
# unfiltered list of exe in specified path
|
||||
if [[ -n "$(stat --file-system --format=%T "$(stat --format=%m "$pedir" 2>/dev/null)" 2>/dev/null | grep -Pio 'fuse')" ]]; then
|
||||
readarray -t i_mnus < <(find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname '*.exe' 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort ; echo "quit")
|
||||
# skip exe validity tests if file is on network drive
|
||||
else
|
||||
readarray -t i_mnus < <(env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname '*.exe' -exec sh -c '(readpe -h optional "$1" 2>/dev/null | grep -Piq '0x2.*gui') && (wrestool "$1" 2>/dev/null | grep -Piq 'type=icon') && echo "$1" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|"' -- {} \; 2>/dev/null | sort ; echo "quit")
|
||||
# perform exe validity tests if file is on local drive
|
||||
fi
|
||||
}
|
||||
|
||||
fewexe () {
|
||||
# filtered list of exe in standard paths
|
||||
readarray -t i_mnus < <(env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended ! \( -ipath '*cache*' -o -ipath '*/microsoft*' -o -ipath '*/windows*' -o -ipath '*/temp*' \) ! \( -iregex '.*(capture|clokspl|helper|iexplore|install|internal|kernel|[^ ]launcher|legacypm|overlay|proxy|redist|renderer|(crash|error)reporter|serv(er|ice)|setup|streaming|tutorial|unins|update).*' \) -iname '*.exe' -exec sh -c '(readpe -h optional "$1" 2>/dev/null | grep -Piq '0x2.*gui') && (wrestool "$1" 2>/dev/null | grep -Piq 'type=icon') && echo "$1" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|"' -- {} \; 2>/dev/null | sort ; echo "quit")
|
||||
# valid exe will have gui and icon
|
||||
}
|
||||
|
||||
alloth () {
|
||||
# unfiltered list of variable type in specified path
|
||||
readarray -t i_mnus < <(find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname "$xflt" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort ; echo "quit")
|
||||
}
|
||||
|
||||
fewoth () {
|
||||
# filtered list of variable type in standard paths
|
||||
readarray -t i_mnus < <(env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended ! \( -ipath '*cache*' -o -ipath '*/microsoft*' -o -ipath '*/windows*' -o -ipath '*/temp*' \) ! \( -iregex '.*(capture|clokspl|helper|iexplore|install|internal|kernel|[^ ]launcher|legacypm|overlay|proxy|redist|renderer|(crash|error)reporter|serv(er|ice)|setup|streaming|tutorial|unins|update).*' \) -iname "$xflt" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort ; echo "quit")
|
||||
}
|
||||
|
||||
xbld () {
|
||||
# cross-function custom prefix builder
|
||||
pnpfx="$pnpfx/${clprm[0]}"
|
||||
wnpfx="$wnpfx/${clprm[0]}"
|
||||
xnint
|
||||
if [[ -z "${clprm[0]}" ]]; then
|
||||
echo "Wine/Proton prefix name required: (e.g. .wine, 0 )"
|
||||
elif [[ -d "$xnpfx" ]]; then
|
||||
echo "Wine/Proton Prefix exists: $xnpfx"
|
||||
else
|
||||
xnexe
|
||||
echo "Creating Wine/Proton Prefix: ${clprm[0]}"
|
||||
if [[ "$x" = "p" ]]; then
|
||||
xnenv
|
||||
mkdir -p "$xnpfx"
|
||||
xcmd+=(STEAM_COMPAT_DATA_PATH="$xnpfx" "${xnbin%/*}/proton" "run")
|
||||
else
|
||||
read -r -p '32-bit only? [y/N] ' chse
|
||||
if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
xn32
|
||||
xnenv
|
||||
xcmd+=(WINEARCH="win32" "$xstrt" "winecfg.exe")
|
||||
else
|
||||
xn64
|
||||
xnenv
|
||||
xcmd+=(WINEARCH="win64" "$xstrt" "winecfg.exe")
|
||||
fi
|
||||
fi
|
||||
xlnch
|
||||
fi
|
||||
}
|
||||
|
||||
xpmn () {
|
||||
# use specified exe, menu specified folder, or menu system
|
||||
if [[ -f "${clprm[0]}" ]]; then
|
||||
# parse 1st cmdline arg, queue if valid file
|
||||
pedir="$(realpath "${clprm[0]}")"
|
||||
xmrtn="$(basename "$pedir")"
|
||||
pedir="$(dirname "$pedir")"
|
||||
else
|
||||
if [[ -d "${clprm[0]}" ]]; then
|
||||
# parse 1st cmdline arg, use as path if valid
|
||||
pedir="$(realpath "${clprm[0]}")"
|
||||
test -z "$xflt" && allexe || alloth
|
||||
else
|
||||
# if no cmdline path, use prefix drive_c
|
||||
pedir="$xnpfx/drive_c"
|
||||
test -z "$xflt" && fewexe || fewoth
|
||||
fi
|
||||
# create menu, from path, of file
|
||||
test ${#i_mnus[@]} -gt 1 && w_menu
|
||||
fi
|
||||
}
|
||||
|
||||
xlyt() {
|
||||
# pe layout for launch
|
||||
# 64-bit prefix, 32-bit pe header, reset env to 32
|
||||
if [[ -n "$(readpe -h optional "$pedir/$xmrtn" 2>/dev/null | grep -Pi 'magic number.*0x10b')" && -d "$xnpfx/$progs (x86)" ]]; then
|
||||
xn32
|
||||
xnenv
|
||||
fi
|
||||
xnldr
|
||||
# if 1st arg is file/folder, skip it and run selection + remaining args
|
||||
if [[ -e "${clprm[0]}" ]];then
|
||||
xcmd+=("$pedir/$xmrtn" "${clprm[@]:1}")
|
||||
else
|
||||
xcmd+=("$pedir/$xmrtn" "${clprm[@]}")
|
||||
fi
|
||||
}
|
||||
|
||||
xstm() {
|
||||
if [[ "$x" = "p" ]]; then
|
||||
sstrt="$(realpath "$(which steam)" 2>/dev/null)"
|
||||
else
|
||||
xnset
|
||||
sstrt="$(find "$xnpfx/drive_c" -maxdepth 3 -iname 'steam.exe' 2>/dev/null)"
|
||||
if [[ -f "$sstrt" ]]; then
|
||||
pnapp="$(dirname "$sstrt")/steamapps"
|
||||
xcmd+=("$xstrt")
|
||||
fi
|
||||
fi
|
||||
# find wine/proton steam binary path, normally subdir of program files
|
||||
if [[ -f "$sstrt" ]]; then
|
||||
test -d "$pnapp" && readarray -t i_mnus < <(find "$pnapp" -maxdepth 1 -type f -iname 'appmanifest_*.acf' -exec grep -Pio '^\s+\"(appid|name)\"\s+\"(.*)\"' "{}" \; 2>/dev/null | perl -pe 's/.*appid.+?\"(.*)\"\v|.*name.+?\"(.*)\"/\1 \2/' | sort ; echo -e "steam\nquit")
|
||||
# read appmanifests to create menu entries
|
||||
test ${#i_mnus[@]} -gt 2 && w_menu && xmrtn="$(expr "$xmrtn" : '\([0-9]*\)')"
|
||||
if [[ -n "$xmrtn" ]]; then
|
||||
# lauch selection with steam
|
||||
xcmd+=("$sstrt" "-no-browser" "-applaunch" "$xmrtn")
|
||||
xlnch
|
||||
else
|
||||
# launch steam was selected
|
||||
# minigamelist (short game list) for no-browser (disabled chrome) to save memory
|
||||
xcmd+=("$sstrt" "-no-browser" "steam://open/minigameslist")
|
||||
xlnch
|
||||
fi
|
||||
else
|
||||
echo -e "Steam not found."
|
||||
fi
|
||||
}
|
||||
|
||||
xpge () {
|
||||
test -d "$pnpge" || mkdir -p "$pnpge"
|
||||
test -d "$pnbin" || mkdir -p "$pnbin"
|
||||
|
||||
@@ -79,280 +401,210 @@ xpge() {
|
||||
fi
|
||||
}
|
||||
|
||||
xn64() {
|
||||
xstrt="wine64"
|
||||
xnldl="$xnbin/lib64:$xnbin/lib"
|
||||
xndll="$xnbin/lib64/wine:$xnbin/lib/wine"
|
||||
}
|
||||
|
||||
xn32() {
|
||||
xstrt="wine"
|
||||
xnldl="$xnbin/lib"
|
||||
xndll="$xnbin/lib/wine"
|
||||
}
|
||||
|
||||
w_menu() {
|
||||
PS3="Please enter your choice: "
|
||||
select answer in "${i_mnus[@]}"; do
|
||||
for item in "${i_mnus[@]}"; do
|
||||
if [[ $item == "$answer" ]]; then
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
# repeating menu requires valid selection from array
|
||||
if [[ "$answer" = "quit" ]]; then
|
||||
# pop quit from end of array for menu option
|
||||
exit
|
||||
else
|
||||
xmrtn="$answer"
|
||||
fi
|
||||
unset i_mnus
|
||||
clear
|
||||
}
|
||||
|
||||
xnexe() {
|
||||
# menu installed wine/proton or exit
|
||||
readarray -t i_mnus < <(
|
||||
find -L "$xnbin" -maxdepth "${dpth[0]}" -type f -iname 'wine' ! \( -ipath '*/sbin*' \) 2>/dev/null | perl -pe "s|\Q$xnbin\E/(.*)[/]*bin/wine|\1| ; s|/$||" | sort
|
||||
echo "quit"
|
||||
)
|
||||
if [[ ${#i_mnus[@]} -gt 2 ]]; then
|
||||
clear
|
||||
w_menu
|
||||
xnbin="$(realpath "$xnbin/$xmrtn")"
|
||||
unset xmrtn
|
||||
elif [[ ${#i_mnus[@]} -eq 2 ]]; then
|
||||
xnbin="$(realpath "$xnbin/${i_mnus[0]}")"
|
||||
else
|
||||
echo "No installed Wine/Proton found."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
xnenv() {
|
||||
# core env vars allow proper targetting of wine/proton
|
||||
xpath="$xnbin/bin:$PATH"
|
||||
xcmd=(env PATH="$xpath" WINEDLLPATH="$xndll" LD_LIBRARY_PATH="$xnldl" WINEPREFIX="$xnpfx")
|
||||
|
||||
xcmd+=(STEAM_COMPAT_DATA_PATH="${xnpfx///pfx}" STEAM_COMPAT_CLIENT_INSTALL_PATH="$pntop")
|
||||
}
|
||||
|
||||
xlnch() {
|
||||
#command line launcher
|
||||
if [[ -z "$dbg" ]]; then
|
||||
("${xcmd[@]}" >/dev/null 2>&1 &)
|
||||
else
|
||||
if [[ "$dbg" = "1" ]]; then
|
||||
("${xcmd[@]}" &)
|
||||
elif [[ "$dbg" = "2" ]]; then
|
||||
(WINEDEBUG="warn+all" "${xcmd[@]}" &)
|
||||
fi
|
||||
fi
|
||||
# prepend cmd with dbg=1 to see command and default debug output
|
||||
# dbg=2 to see command and all debug output, dbg=? for command only
|
||||
}
|
||||
|
||||
xbld() {
|
||||
# cross-function custom prefix builder
|
||||
pnpfx="$pnpfx/${clprm[0]}"
|
||||
xnint
|
||||
|
||||
if [[ -z "${clprm[0]}" ]]; then
|
||||
echo -e "\n Proton prefix name required, use an appid from Steam: (e.g. 0, 730 ) \n"
|
||||
elif [[ -d "$xnpfx" ]]; then
|
||||
echo -e "\n Proton Prefix exists: $xnpfx \n"
|
||||
else
|
||||
xnexe
|
||||
echo "Creating Proton Prefix: ${clprm[0]}"
|
||||
|
||||
xnenv
|
||||
mkdir -p "$xnpfx"
|
||||
xcmd+=(STEAM_COMPAT_DATA_PATH="$xnpfx" "${xnbin%/*}/proton" "run")
|
||||
|
||||
xlnch
|
||||
fi
|
||||
}
|
||||
|
||||
xnpre() {
|
||||
if [[ -d "$xnpfx/$progs (x86)" ]]; then
|
||||
xn64
|
||||
else
|
||||
xn32
|
||||
fi
|
||||
}
|
||||
|
||||
xndef() {
|
||||
# create default prefix cross-function
|
||||
if [[ -z "$prfx" ]]; then
|
||||
echo "INFO: to use a specific prefix, append prfx='your prefix' to this command"
|
||||
if [[ ! -d "$xnpfx/0" ]]; then
|
||||
# always create default 0 prefix
|
||||
xnpfx="$xnpfx/0"
|
||||
echo "Creating default prefix: $xnpfx"
|
||||
mkdir -p "$xnpfx"
|
||||
STEAM_COMPAT_DATA_PATH="$xnpfx" "${xnbin%/*}/proton" run >/dev/null 2>&1 &
|
||||
xnpfx="$xnpfx/pfx"
|
||||
else
|
||||
xnpfx="$xnpfx/0"
|
||||
xnpfx="$xnpfx/pfx"
|
||||
fi
|
||||
else
|
||||
xnpfx="$xnpfx/$prfx"
|
||||
if [[ ! -d "$xnpfx" ]]; then
|
||||
echo "Creating default prefix: $xnpfx"
|
||||
mkdir -p "$xnpfx"
|
||||
STEAM_COMPAT_DATA_PATH="$xnpfx" "${xnbin%/*}/proton" run >/dev/null 2>&1 &
|
||||
xnpfx="$xnpfx/pfx"
|
||||
else
|
||||
xnpfx="$xnpfx/pfx"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
fewoth() {
|
||||
# filtered list of variable type in standard paths
|
||||
readarray -t i_mnus < <(
|
||||
env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended ! \( -ipath '*cache*' -o -ipath '*/microsoft*' -o -ipath '*/windows*' -o -ipath '*/temp*' \) ! \( -iregex '.*(capture|clokspl|helper|iexplore|install|internal|kernel|[^ ]launcher|legacypm|overlay|proxy|redist|renderer|(crash|error)reporter|serv(er|ice)|setup|streaming|tutorial|unins|update).*' \) -iname "$xflt" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort
|
||||
echo "quit"
|
||||
)
|
||||
}
|
||||
|
||||
fewexe() {
|
||||
# filtered list of exe in standard paths
|
||||
readarray -t i_mnus < <(
|
||||
env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended ! \( -ipath '*cache*' -o -ipath '*/microsoft*' -o -ipath '*/windows*' -o -ipath '*/temp*' \) ! \( -iregex '.*(capture|clokspl|helper|iexplore|install|internal|kernel|[^ ]launcher|legacypm|overlay|proxy|redist|renderer|(crash|error)reporter|serv(er|ice)|setup|streaming|tutorial|unins|update).*' \) -iname '*.exe' -exec sh -c '(readpe -h optional "$1" 2>/dev/null | grep -Piq '0x2.*gui') && (wrestool "$1" 2>/dev/null | grep -Piq 'type=icon') && echo "$1" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|"' -- {} \; 2>/dev/null | sort
|
||||
echo "quit"
|
||||
)
|
||||
# valid exe will have gui and icon
|
||||
}
|
||||
|
||||
alloth() {
|
||||
# unfiltered list of variable type in specified path
|
||||
readarray -t i_mnus < <(
|
||||
find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname "$xflt" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort
|
||||
echo "quit"
|
||||
)
|
||||
}
|
||||
|
||||
allexe() {
|
||||
# unfiltered list of exe in specified path
|
||||
if [[ -n "$(stat --file-system --format=%T "$(stat --format=%m "$pedir" 2>/dev/null)" 2>/dev/null | grep -Pio 'fuse')" ]]; then
|
||||
readarray -t i_mnus < <(
|
||||
find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname '*.exe' 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort
|
||||
echo "quit"
|
||||
)
|
||||
# skip exe validity tests if file is on network drive
|
||||
else
|
||||
readarray -t i_mnus < <(
|
||||
env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname '*.exe' -exec sh -c '(readpe -h optional "$1" 2>/dev/null | grep -Piq '0x2.*gui') && (wrestool "$1" 2>/dev/null | grep -Piq 'type=icon') && echo "$1" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|"' -- {} \; 2>/dev/null | sort
|
||||
echo "quit"
|
||||
)
|
||||
# perform exe validity tests if file is on local drive
|
||||
fi
|
||||
}
|
||||
|
||||
xpmn() {
|
||||
# use specified exe, menu specified folder, or menu system
|
||||
if [[ -f "${clprm[0]}" ]]; then
|
||||
# parse 1st cmdline arg, queue if valid file
|
||||
pedir="$(realpath "${clprm[0]}")"
|
||||
xmrtn="$(basename "$pedir")"
|
||||
pedir="$(dirname "$pedir")"
|
||||
else
|
||||
if [[ -d "${clprm[0]}" ]]; then
|
||||
# parse 1st cmdline arg, use as path if valid
|
||||
pedir="$(realpath "${clprm[0]}")"
|
||||
test -z "$xflt" && allexe || alloth
|
||||
else
|
||||
# if no cmdline path, use prefix drive_c
|
||||
pedir="$xnpfx/drive_c"
|
||||
test -z "$xflt" && fewexe || fewoth
|
||||
fi
|
||||
# create menu, from path, of file
|
||||
test ${#i_mnus[@]} -gt 1 && w_menu
|
||||
fi
|
||||
}
|
||||
|
||||
xnldr() {
|
||||
# loader default to proton as applicable, otherwise wine
|
||||
if [[ -z "$wn" ]]; then
|
||||
xcmd+=("${xnbin%/*}/proton" "run")
|
||||
else
|
||||
if [[ "$wn" = "true" ]]; then
|
||||
xcmd+=("$xstrt")
|
||||
else
|
||||
echo "unrecognised run option"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
xlyt() {
|
||||
# prepare layout for launch
|
||||
# 64-bit prefix, 32-bit prefix header, reset env to 32
|
||||
if [[ -n "$(readpe -h optional "$pedir/$xmrtn" 2>/dev/null | grep -Pi 'magic number.*0x10b')" && -d "$xnpfx/$progs (x86)" ]]; then
|
||||
xn32
|
||||
xnenv
|
||||
fi
|
||||
xnldr
|
||||
# if 1st arg is file/folder, skip it and run selection + remaining args
|
||||
if [[ -e "${clprm[0]}" ]]; then
|
||||
xcmd+=("$pedir/$xmrtn" "${clprm[@]:1}")
|
||||
else
|
||||
xcmd+=("$pedir/$xmrtn" "${clprm[@]}")
|
||||
fi
|
||||
}
|
||||
|
||||
xnset() {
|
||||
# set cross-fuction
|
||||
xnint
|
||||
# proton menu
|
||||
xnexe
|
||||
# create default prefix as required
|
||||
xndef
|
||||
# proton prefix
|
||||
xnpre
|
||||
# proton env vars
|
||||
xnenv
|
||||
xwn () {
|
||||
export WINE_BRANCH=staging
|
||||
sudo mkdir -pm755 /etc/apt/keyrings && sudo curl -fsSL -o /etc/apt/keyrings/winehq-archive.key "https://dl.winehq.org/wine-builds/winehq.key" \
|
||||
&& sudo curl -fsSL -o "/etc/apt/sources.list.d/winehq-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').sources" "https://dl.winehq.org/wine-builds/ubuntu/dists/$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"')/winehq-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').sources" \
|
||||
&& sudo apt-get update && sudo apt-get install --install-recommends -y winehq-${WINE_BRANCH} \
|
||||
&& sudo curl -fsSL -o /usr/bin/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks" \
|
||||
&& sudo chmod 755 /usr/bin/winetricks \
|
||||
&& sudo curl -fsSL -o /usr/share/bash-completion/completions/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks.bash-completion"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo -e "\n$(basename $0): ERROR - $*" 1>&2
|
||||
echo -e "\nusage: $(basename $0)\n [-i,--install] [-b,--build] [-r,--run] \n \n (install) install proton-ge \n (build) build a custom proton prefix \n (run) run an .exe program \n \n" 1>&2
|
||||
echo -e "\n$(basename $0): ERROR - $*" 1>&2
|
||||
echo -e "\nusage: $(basename $0)\n [-?a,--?add] [-?b,--?bld] [-?c,--?cmd] [-?d,--?dsk]\n [-?i,--?inf] [-?k,--?kil] [-?o,--?ovr] [-?p,--?prg]\n [-?s,--?stm] [-?t,--?trk] [-?u,--?cut] [-?v,--?ver]\n\n[?] = (p)roton, (w)ine\n (add) exe path to reg, (bld) build prefix,\n (cmd) prog menu, (dsk) desktop, (inf) exe info,\n (kil) kill wine, (ovr) overrides, (prg) exe list,\n (stm) steam, (trk) winetricks, (cut) shortcut,\n (ver) wine version\n" 1>&2
|
||||
}
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
usage "one option required!"
|
||||
usage "one option required!"
|
||||
else
|
||||
case $xarg in
|
||||
-i | --install)
|
||||
# proton ge
|
||||
xpge
|
||||
;;
|
||||
-p | --prefix)
|
||||
# prefix builder
|
||||
xbld
|
||||
;;
|
||||
-r | --run)
|
||||
# second arg should be the prefix to use.
|
||||
# run program - 1st arg valid file to run, folder to menu,
|
||||
# neither (sys menu), 2nd arg... passed to exe
|
||||
case $xarg in
|
||||
-xa|--xadd)
|
||||
# cross-fuction path add to registry based on exe
|
||||
xnint
|
||||
xnpre
|
||||
xpmn
|
||||
if [[ -n "$xmrtn" ]]; then
|
||||
ptadd="$(dirname "$pedir/$xmrtn")"
|
||||
ptadd="z:${ptadd////\\\\}"
|
||||
read -r -p 'prepend to system path? [y/N] ' chse
|
||||
clear
|
||||
if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
xnreg='System\\CurrentControlSet\\Control\\Session Manager\\Environment'
|
||||
xmrtn='system.reg'
|
||||
else
|
||||
xnreg='Environment'
|
||||
xmrtn='user.reg'
|
||||
fi
|
||||
if [[ -z "$(pcre2grep -Mio "\[\Q${xnreg,,}\E\](?s).+?\"PATH\"=str\(2\):\".+?(?=\[.+?\])(?-s)" "$xnpfx/$xmrtn")" ]]; then
|
||||
perl -0777 -pi -e "s|(\[\Q${xnreg,,}\E\](?s).+?#time=(?-s).*)(?s)(.+?)(?=\[.+?\])(?-s)|\\1\n\"PATH\"=str\(2\):\"${ptadd//\\/\\\\}\"\\2|gi" "$xnpfx/$xmrtn"
|
||||
echo -e "$( (echo "$xnreg" | grep -Pioq '\\Environment') && echo 'HKLM\\' || echo 'HKCU\\')$xnreg:\n\n $ptadd\n\nPATH created successfully\n"
|
||||
elif [[ -z "$(pcre2grep -Mio "\[\Q${xnreg,,}\E\](?s).+?\"PATH\"=str\(2\):\"(?-s).*\Q${ptadd,,}\E[\;\"](?s).+?(?=\[.+?\])(?-s)" "$xnpfx/$xmrtn")" ]]; then
|
||||
perl -0777 -pi -e "s|(\[\Q${xnreg,,}\E\](?s).+?\"PATH\"=str\(2\):\")(?-s)(.*)(?s)(.+?)(?=\[.+?\])(?-s)|\\1${ptadd//\\/\\\\}\;\\2\\3|gi" "$xnpfx/$xmrtn"
|
||||
echo -e "$( (echo "$xnreg" | grep -Pioq '\\Environment') && echo 'HKLM\\' || echo 'HKCU\\')$xnreg:\n\n $ptadd\n\nPATH added successfully\n"
|
||||
else
|
||||
echo -e "$( (echo "$xnreg" | grep -Pioq '\\Environment') && echo 'HKLM\\' || echo 'HKCU\\')$xnreg:\n\n $ptadd\n\nalready in PATH\n"
|
||||
fi
|
||||
# \Q \E adds \ to non alphanums but variable with \E ends \Q
|
||||
# lowercase ${var,,} to avoid since path/reg not case sensitive
|
||||
# linux path is case sensitive so user must not create duplicates
|
||||
fi
|
||||
;;
|
||||
-xb|--xbld)
|
||||
# cross-function prefix builder
|
||||
xbld
|
||||
;;
|
||||
-xc|--xcmd)
|
||||
# cross-function standard tools menu
|
||||
xnset
|
||||
readarray -t i_mnus < <(printf '%s\n' "${pmenu[@]}" | perl -pe 's|/.*||gi' ; echo "quit")
|
||||
w_menu
|
||||
xmrtn="$(printf '%s\n' "${pmenu[@]}" | grep -Pio "(?<=$xmrtn/).*")"
|
||||
xnldr
|
||||
if [[ -f "${clprm[0]}" ]];then
|
||||
pedir="$(realpath "${clprm[0]}")"
|
||||
cd "$(dirname "$pedir")" || exit
|
||||
xcmd+=("$xmrtn" "$pedir" "${clprm[@]:1}")
|
||||
else
|
||||
xcmd+=("$xmrtn" "${clprm[@]}")
|
||||
fi
|
||||
xlnch
|
||||
;;
|
||||
-xd|--xdsk)
|
||||
# cross-function wine desktop
|
||||
xnset
|
||||
xnldr
|
||||
xcmd+=("explorer.exe" "/desktop=shell,1024x768" "explorer.exe")
|
||||
xlnch
|
||||
;;
|
||||
-i|--install)
|
||||
# proton ge
|
||||
xpge
|
||||
xwn
|
||||
;;
|
||||
-xi|--xinf)
|
||||
# cross-fuction program info
|
||||
if [[ ! -f "${clprm[0]}" && ! -d "${clprm[0]}" ]]; then
|
||||
# don't menu prefix on supplied file or folder
|
||||
xnint
|
||||
xnpre
|
||||
fi
|
||||
if [[ ! -f "${clprm[0]}" ]]; then
|
||||
# offer to menu dll if no file given
|
||||
read -r -p 'query dll? [y/N] ' chse
|
||||
if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
xflt="*.dll"
|
||||
fi
|
||||
fi
|
||||
xpmn
|
||||
IFS=$'\n'
|
||||
if [[ -n "$xmrtn" ]]; then
|
||||
if [[ $(readpe "$pedir/$xmrtn" 2>/dev/null) ]]; then
|
||||
# if file is PE print 32/64-bit and dll references
|
||||
myprnt+=("$(readpe -h optional "$pedir/$xmrtn" 2>/dev/null | grep -Piq 'PE32\+' && echo -e "FILE:\n$xmrtn\n \nPE HEADER:\n64-bit" || echo -e "FILE:\n$xmrtn\n \nPE HEADER:\n32-bit")")
|
||||
myprnt+=("$(echo -e ' \nVersion:' ; peres -v "$pedir/$xmrtn" 2>/dev/null | grep -Pio '(?<=Product Version:).*' | tr -d ' ')")
|
||||
# find dll references, filenames without spaces
|
||||
myprnt+=("$(echo -e ' \nREFERENCES:' ; strings "$pedir/$xmrtn" | grep -Pio '[^<>:"/\\|?*\s]+\.dll' | perl -pe 's|([^/]*\Z)|lc($1)|e' | sort -u ; echo ' ')")
|
||||
else
|
||||
myprnt+=("$(echo -e ' \nNot a 32/64-bit program, no information to provide\n ')")
|
||||
fi
|
||||
else
|
||||
myprnt+=("$(echo -e ' \nNo file found\n ')")
|
||||
fi
|
||||
printf '%s\n' "${myprnt[@]}"
|
||||
unset IFS myprnt
|
||||
;;
|
||||
-xk|--xkil)
|
||||
# cross-function wine kill, must select same as running
|
||||
xnset
|
||||
xcmd+=("wineserver" "-k")
|
||||
xlnch
|
||||
;;
|
||||
-xo|--xovr)
|
||||
# cross-function prefix override list
|
||||
xnint
|
||||
xnpre
|
||||
read -r -p 'per application? [y/N] ' chse
|
||||
clear
|
||||
IFS=$'\n'
|
||||
myprnt+=("$(echo -e "Prefix:\n$xnpfx\n ")")
|
||||
if [[ "$chse" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
# show existing per-application overrides
|
||||
myprnt+=("$(echo -e 'Per-application overrides:' ; pcre2grep -Mio '\[\Qsoftware\\wine\\appdefaults\\\E[^\\]+\Q\\dlloverrides\E\](?s).+?(?=\[.+?\])(?-s)' "$xnpfx/user.reg" | grep -Pio '(?<=appdefaults..).*(?=..dlloverrides)|\".*\"' && echo ' ' || echo -e 'None found\n ')")
|
||||
else
|
||||
# show existing prefix overrides
|
||||
myprnt+=("$(echo -e 'Global overrides:' ; pcre2grep -Mio '\[\Qsoftware\\wine\\dlloverrides\E\](?s).+?(?=\[.+?\])(?-s)' "$xnpfx/user.reg" | grep -Pio '\".*\"' && echo ' ' || echo -e 'None found\n ')")
|
||||
fi
|
||||
printf '%s\n' "${myprnt[@]}"
|
||||
unset IFS myprnt
|
||||
# A command like:
|
||||
# perl -pi -e 's/(\".*msvc.*\"=\")(.*),(.*)(")/\1\3,\2\4/g' user.reg
|
||||
# Swaps msvc entries (native,builtin) to (builtin,native)
|
||||
;;
|
||||
-xr|--xrun)
|
||||
# cross-fuction run program - 1st arg valid file to run, folder to menu,
|
||||
# neither (sys menu), 2nd arg... passed to exe
|
||||
xnset
|
||||
xpmn
|
||||
if [[ -n "$xmrtn" ]]; then
|
||||
xlyt
|
||||
# change to exe dir before run
|
||||
cd "$(dirname "$pedir/$xmrtn")" || exit
|
||||
xlnch
|
||||
fi
|
||||
;;
|
||||
-xs|--xstm)
|
||||
# cross-function steam launcher
|
||||
xstm
|
||||
;;
|
||||
-xt|--xtrk)
|
||||
# cross-function winetricks
|
||||
xnset
|
||||
# winetricks for selected wine/proton prefix
|
||||
if [[ ${#clprm[@]} -gt 0 ]]; then
|
||||
xcmd+=("winetricks" "${clprm[@]}")
|
||||
dbg="1"
|
||||
# use args if supplied, otherwise gui
|
||||
else
|
||||
xcmd+=("winetricks" "--gui")
|
||||
# protontricks may work better
|
||||
fi
|
||||
xlnch
|
||||
;;
|
||||
-xu|--xcut)
|
||||
# cross-function desktop shortcut
|
||||
if [[ -d "$desk" ]]; then
|
||||
xnset
|
||||
xpmn
|
||||
if [[ -n "$xmrtn" ]]; then
|
||||
xlyt
|
||||
# change to exe dir before run
|
||||
cd "$(dirname "$pedir/$xmrtn")"
|
||||
xlnch
|
||||
xlyt
|
||||
# change to desktop dir before create icon
|
||||
cd "$desk" || exit
|
||||
read -r -e -p $'Shortcut Name?\x0a' -i "$(basename "${xmrtn/.*}")" chse
|
||||
# create desktop entry
|
||||
gendesk -f -n --name="$chse" --comment='created by wstart' --custom='Keywords=wine;proton;launcher;' --exec="bash -c 'cd \"$(dirname "$pedir/$xmrtn")\" ; $(printf '"%s" ' "${xcmd[@]}")'" --icon="$icon" --terminal=false --categories='Emulator;Game' --startupnotify=false --pkgname="$chse"
|
||||
chmod 755 "$chse".desktop
|
||||
fi
|
||||
;;
|
||||
-* | \* | *)
|
||||
# do_usage
|
||||
usage "invalid option $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
#FIXME: it won't run anything AAAArgh!
|
||||
else
|
||||
echo -e "Invalid desktop location: $desk\nPlease edit the script"
|
||||
fi
|
||||
;;
|
||||
-xv|--xver)
|
||||
# cross-function wine version
|
||||
xnint
|
||||
xnexe
|
||||
xnenv
|
||||
xcmd+=("wine" "--version")
|
||||
("${xcmd[@]}" &)
|
||||
;;
|
||||
-h|--help)
|
||||
echo -e "\n General usage: netris-proton -w? args\n -w? options for wine and -p? for proton.\n Type wstart by itself for command list.\n\n Edit script path variables as needed.\n bash, find, gendesk, grep, readpe,\n strings, winetricks, wrestool,\n pcre2grep, peres, perl needed by\n certain items.\n"
|
||||
;;
|
||||
-*|\*|*)
|
||||
# do_usage
|
||||
usage "invalid option $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
24
.scripts/startup.sh
Normal file
24
.scripts/startup.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
#TODO: Fix the warp-input startup problem
|
||||
if [ -z "$SESSION_ID" ]; then
|
||||
echo "Error: SESSION_ID environment variable is not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
xarg="$*"
|
||||
|
||||
if [ -z "$xarg" ]; then
|
||||
echo "Error: No command specified to run the game. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#Open udp port to listed for QUIC events on
|
||||
export PORT=${PORT:-"8080"}
|
||||
|
||||
escaped_xarg=$(printf '%s\n' "$xarg" | sed -e 's/[\/&]/\\&/g')
|
||||
|
||||
sudo sed -i "s|^command.*=.*$|command=bash -c \"$escaped_xarg\"|" /etc/supervisord.d/game.ini
|
||||
|
||||
sudo sed -i 's|^autostart.*=.*$|autostart=true|' /etc/supervisord.d/game.ini
|
||||
|
||||
sudo -E /usr/bin/supervisord -c /etc/supervisord.conf
|
||||
@@ -5,8 +5,12 @@ loglevel=info
|
||||
logfile=/tmp/supervisord.log
|
||||
pidfile=/tmp/supervisord.pid
|
||||
|
||||
[include]
|
||||
files = /etc/supervisord.d/*.ini
|
||||
|
||||
[program:entrypoint]
|
||||
command=/etc/entrypoint.sh
|
||||
user=netris
|
||||
logfile=/tmp/entrypoint.log
|
||||
pidfile=/tmp/entrypoint.pid
|
||||
stopsignal=INT
|
||||
@@ -25,4 +29,17 @@ stopsignal=INT
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
priority=10
|
||||
priority=10
|
||||
|
||||
[program:warp-input]
|
||||
command=bash -c "until [ -S \"/tmp/.X11-unix/X${DISPLAY/:/}\" ]; do sleep 1; done; /usr/bin/warp-input --namespace $SESSION_ID --bind '[::]:8080' https://fst.so:4443"
|
||||
logfile=/tmp/warp-input.log
|
||||
pidfile=/tmp/warp-input.pid
|
||||
stopsignal=INT
|
||||
user=netris
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY=":0",SESSION_ID="%(ENV_SESSION_ID)s"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startretries=100
|
||||
redirect_stderr=true
|
||||
priority=20
|
||||
14
.scripts/supervisord.d/game.ini
Normal file
14
.scripts/supervisord.d/game.ini
Normal file
@@ -0,0 +1,14 @@
|
||||
[program:game]
|
||||
priority=30
|
||||
autostart=false
|
||||
autorestart=true
|
||||
user=netris
|
||||
# directory=/
|
||||
command=netris-proton -r /games/AlanWake.exe
|
||||
stopsignal=INT
|
||||
logfile=/tmp/game.log
|
||||
pidfile=/tmp/game.pid
|
||||
stopsignal=INT
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
65
README.md
65
README.md
@@ -126,7 +126,67 @@ Follow these steps to get Netris up and running on your system.
|
||||
|
||||
> \[!IMPORTANT]
|
||||
>
|
||||
> Waiting on this pull request [#43][netris-pr-input] to be merged first. Sorry for the inconvenience. \~ ⚠️
|
||||
> This is our pilot, there is a lot we haven't figured out yet. Please file an issue if anything comes up. \~ 🫂
|
||||
|
||||
|
||||
> \[!TIP]
|
||||
>
|
||||
> The setup process will become much simpler with the launch of our CLI tool, so stay tuned for that! In the meantime, you'll need to follow these manual steps.
|
||||
|
||||
#### Step 1: Navigate to Your Game Directory
|
||||
|
||||
First, change your directory to the location of your `.exe` file. For Steam games, this typically means:
|
||||
|
||||
```bash
|
||||
cd $HOME/.steam/steam/steamapps
|
||||
ls -la .
|
||||
```
|
||||
|
||||
#### Step 2: Generate a Session ID
|
||||
|
||||
Create a unique session ID using the following command:
|
||||
|
||||
```bash
|
||||
head /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | head -c 16
|
||||
```
|
||||
|
||||
This command generates a random 16-character string. Be sure to note this string carefully, as you'll need it for the next step.
|
||||
|
||||
#### Step 3: Launch the Netris Server
|
||||
|
||||
With your SESSION_ID ready, insert it into the command below, replacing `<copy here>` with your actual session ID. Then, run the command to start the Netris server:
|
||||
|
||||
```
|
||||
docker run --gpus all --device=/dev/dri --name netris -it --entrypoint /bin/bash -e SESSION_ID=<copy here> -v "$(pwd)":/game -p 8080:8080/udp --cap-add=SYS_NICE --cap-add=SYS_ADMIN ghcr.io/netrisdotme/netris/server:nightly
|
||||
```
|
||||
|
||||
> \[!TIP]
|
||||
>
|
||||
> Ensure UDP port 8080 is accessible from the internet. Use `ufw allow 8080/udp` or adjust your cloud provider's security group settings accordingly.
|
||||
|
||||
#### Step 4: Configure the Game within the Container
|
||||
|
||||
After executing the previous command, you'll be in a new shell within the container (example: `netris@3f199ee68c01:~$`). Perform the following checks:
|
||||
|
||||
1. Verify the game is mounted by executing `ls -la /game`. If not, exit and ensure you've correctly mounted the game directory as a volume.
|
||||
2. Then, start the Netris server by running `/etc/startup.sh > /dev/null &`.
|
||||
|
||||
#### Step 5: Running Your Game
|
||||
|
||||
Wait for the `.X11-unix` directory to appear in `/tmp` (check with `ls -la /tmp`). Once it appears, you're ready to launch your game.
|
||||
|
||||
- With Proton-GE: `netris-proton -pr <game>.exe`
|
||||
- With Wine: `netris-proton -wr <game>.exe`
|
||||
|
||||
#### Step 6: Begin Playing
|
||||
|
||||
Finally, construct the play URL with your session ID:
|
||||
|
||||
```
|
||||
echo "https://netris.me/play/$SESSION_ID"
|
||||
```
|
||||
|
||||
Navigate to this URL in your browser, click on the page to capture your mouse pointer, and start playing!
|
||||
|
||||
|
||||
[github-release-link]: https://github.com/wanjohiryan/netris/releases
|
||||
@@ -146,5 +206,4 @@ Follow these steps to get Netris up and running on your system.
|
||||
[neko-url]: https://github.com/m1k1o/neko
|
||||
[image-star]: assets/star-us.png
|
||||
[moq-github-url]: https://quic.video
|
||||
[vmaf-cuda-link]: https://developer.nvidia.com/blog/calculating-video-quality-using-nvidia-gpus-and-vmaf-cuda/
|
||||
[netris-pr-input]: https://github.com/netrisdotme/netris/pull/43
|
||||
[vmaf-cuda-link]: https://developer.nvidia.com/blog/calculating-video-quality-using-nvidia-gpus-and-vmaf-cuda/
|
||||
@@ -5,15 +5,17 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.82"
|
||||
chrono = "0.4.38"
|
||||
clap = "4.5.4"
|
||||
enigo = "0.2.1"
|
||||
env_logger = "0.11.3"
|
||||
log = "0.4.21"
|
||||
moq-native = { git = "https://github.com/kixelated/moq-rs", version = "0.1.0" }
|
||||
moq-transport = { git = "https://github.com/kixelated/moq-rs", version = "0.5.0" }
|
||||
rand = "0.8.5"
|
||||
serde = { version="1.0.202" , features = ["derive"]}
|
||||
serde_json = "1.0.117"
|
||||
tokio = "1.37.0"
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = "0.3.18"
|
||||
url = "2.5.0"
|
||||
url = "2.5.0"
|
||||
@@ -5,7 +5,7 @@ use url::Url;
|
||||
#[derive(Parser, Clone, Debug)]
|
||||
pub struct Config {
|
||||
/// Listen for UDP packets on the given address.
|
||||
#[arg(long, default_value = "[::]:0")]
|
||||
#[arg(long, default_value = "[::]:8080")]
|
||||
pub bind: net::SocketAddr,
|
||||
|
||||
/// Connect to the given URL starting with https://
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
use anyhow::Context;
|
||||
use enigo::{
|
||||
Axis::Horizontal,
|
||||
Coordinate::Abs,
|
||||
Coordinate::Rel,
|
||||
Direction::{Press, Release},
|
||||
Enigo, Keyboard, Mouse, Settings,
|
||||
};
|
||||
use moq_transport::serve::{
|
||||
DatagramsReader, GroupsReader, ObjectsReader, StreamReader, TrackReader, TrackReaderMode,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use moq_transport::
|
||||
serve::{
|
||||
DatagramsReader, GroupsReader, ObjectsReader,
|
||||
StreamReader, TrackReader, TrackReaderMode,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub struct Subscriber {
|
||||
track: TrackReader,
|
||||
}
|
||||
@@ -28,8 +30,54 @@ impl Subscriber {
|
||||
Self { track }
|
||||
}
|
||||
|
||||
// pub async fn run(self) -> anyhow::Result<()> {
|
||||
// loop {
|
||||
// match self.track.mode().await {
|
||||
// Ok(mode) => match mode {
|
||||
// TrackReaderMode::Stream(stream) => loop {
|
||||
// if let Err(err) = Self::recv_stream(stream.clone()).await {
|
||||
// tracing::warn!("Error receiving streams: {}, retrying...", err);
|
||||
// tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// TrackReaderMode::Groups(groups) => loop {
|
||||
// if let Err(err) = Self::recv_groups(groups.clone()).await {
|
||||
// tracing::warn!("Error receiving groups: {}, retrying...", err);
|
||||
// tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// TrackReaderMode::Objects(objects) => loop {
|
||||
// if let Err(err) = Self::recv_objects(objects.clone()).await {
|
||||
// tracing::warn!("Error receiving objects: {}, retrying...", err);
|
||||
// tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// TrackReaderMode::Datagrams(datagrams) => loop {
|
||||
// if let Err(err) = Self::recv_datagrams(datagrams.clone()).await {
|
||||
// tracing::warn!("Error receiving datagrams: {}, retrying...", err);
|
||||
// tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// Err(_) => {
|
||||
// tracing::warn!("Failed to get mode, retrying...");
|
||||
// tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
// return Ok(());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
pub async fn run(self) -> anyhow::Result<()> {
|
||||
match self.track.mode().await.context("failed to get mode")? {
|
||||
match self.track.mode().await.context("failed to connect")? {
|
||||
TrackReaderMode::Stream(stream) => Self::recv_stream(stream).await,
|
||||
TrackReaderMode::Groups(groups) => Self::recv_groups(groups).await,
|
||||
TrackReaderMode::Objects(objects) => Self::recv_objects(objects).await,
|
||||
@@ -39,9 +87,7 @@ impl Subscriber {
|
||||
|
||||
async fn recv_stream(mut track: StreamReader) -> anyhow::Result<()> {
|
||||
while let Some(mut group) = track.next().await? {
|
||||
println!("received a stream");
|
||||
while let Some(object) = group.read_next().await? {
|
||||
println!("received a stream 1");
|
||||
let str = String::from_utf8_lossy(&object);
|
||||
println!("{}", str);
|
||||
}
|
||||
@@ -70,7 +116,7 @@ impl Subscriber {
|
||||
"mouse_move" => {
|
||||
if let (Some(x), Some(y)) = (parsed.delta_x, parsed.delta_y) {
|
||||
// println!("Handling mouse_move with delta_x: {}, delta_y: {}", x, y);
|
||||
enigo.move_mouse(x, y, Abs).unwrap();
|
||||
enigo.move_mouse(x, y, Rel).unwrap();
|
||||
}
|
||||
}
|
||||
"mouse_key_down" => {
|
||||
@@ -218,3 +264,14 @@ pub fn key_to_enigo(key: u8) -> Option<enigo::Key> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
//NAME="${NAME:-$(head /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | head -c 16)}"
|
||||
// let _name = env::var("NAMESPACE").unwrap_or_else(|_| {
|
||||
// let rng = rand::thread_rng();
|
||||
// let random_string: String = rng
|
||||
// .sample_iter(&rand::distributions::Alphanumeric)
|
||||
// .take(16)
|
||||
// .map(char::from)
|
||||
// .collect();
|
||||
// random_string
|
||||
// });
|
||||
@@ -1,14 +1,13 @@
|
||||
use moq_transport::{serve, session::Subscriber};
|
||||
use anyhow::Context;
|
||||
use chrono::prelude::*;
|
||||
use clap::Parser;
|
||||
use moq_native::quic;
|
||||
use moq_transport::{serve, session::Subscriber};
|
||||
use std::net;
|
||||
use url::Url;
|
||||
|
||||
use anyhow::Context;
|
||||
use clap::Parser;
|
||||
|
||||
mod input;
|
||||
|
||||
|
||||
#[derive(Parser, Clone)]
|
||||
pub struct Cli {
|
||||
/// Listen for UDP packets on the given address.
|
||||
@@ -53,24 +52,70 @@ async fn main() -> anyhow::Result<()> {
|
||||
tls,
|
||||
})?;
|
||||
|
||||
log::info!("connecting to server: url={}", config.url);
|
||||
let start = Utc::now();
|
||||
let mut now = start;
|
||||
|
||||
let session = quic.client.connect(&config.url).await?;
|
||||
loop {
|
||||
log::info!("connecting to server: url={}", config.url);
|
||||
|
||||
let (session, mut subscriber) = Subscriber::connect(session)
|
||||
.await
|
||||
.context("failed to create MoQ Transport session")?;
|
||||
let session = quic.client.connect(&config.url).await?;
|
||||
|
||||
let (prod, sub) = serve::Track::new(config.namespace, config.track).produce();
|
||||
let (session, mut subscriber) = Subscriber::connect(session)
|
||||
.await
|
||||
.context("failed to create MoQ Transport session")?;
|
||||
|
||||
let input = input::Subscriber::new(sub);
|
||||
let namespace = format!("{}input", config.namespace);
|
||||
|
||||
//TODO: Make sure to retry until the input server comes [Use Supervisord for now]
|
||||
tokio::select! {
|
||||
res = session.run() => res.context("session error")?,
|
||||
res = input.run() => res.context("input error")?,
|
||||
res = subscriber.subscribe(prod) => res.context("failed to subscribe to track")?,
|
||||
let (prod, sub) = serve::Track::new(namespace, config.track.clone()).produce();
|
||||
|
||||
let input = input::Subscriber::new(sub);
|
||||
|
||||
// let (session, mut publisher) = Publisher::connect(session)
|
||||
// .await
|
||||
// .context("failed to create MoQ Transport session")?;
|
||||
|
||||
// let (mut writer, _, reader) = serve::Tracks {
|
||||
// namespace: config.namespace.clone(),
|
||||
// }
|
||||
// .produce();
|
||||
|
||||
// let track = writer.create(&config.track).unwrap();
|
||||
// let input_publisher = input::Publisher::new(track.groups()?);
|
||||
|
||||
tokio::select! {
|
||||
res = session.run() => {
|
||||
if let Err(e) = res {
|
||||
log::error!("session error: {}", e);
|
||||
continue;
|
||||
}
|
||||
},
|
||||
res = input.run() => {
|
||||
if let Err(e) = res {
|
||||
log::error!("input subscriber error: {}", e);
|
||||
continue;
|
||||
}
|
||||
},
|
||||
// res = publisher.announce(reader) => res.context("failed to serve tracks")?,
|
||||
res = subscriber.subscribe(prod) => {
|
||||
if let Err(e) = res {
|
||||
log::error!("failed to subscribe to track: {}", e);
|
||||
continue;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
let next = now + chrono::Duration::try_minutes(1).unwrap();
|
||||
let next = next.with_second(0).unwrap().with_nanosecond(0).unwrap();
|
||||
|
||||
let delay = (next - now).to_std().unwrap();
|
||||
tokio::time::sleep(delay).await;
|
||||
|
||||
// if next.minute() - now.minute() == 10 {
|
||||
// return Ok(());
|
||||
// }
|
||||
|
||||
now = next; // just assume we didn't undersleep
|
||||
}
|
||||
|
||||
Ok(())
|
||||
// Ok(())
|
||||
}
|
||||
|
||||
3
dev/build.sh
Normal file
3
dev/build.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
docker build -t server -f server.Dockerfile .
|
||||
3
dev/run-input.sh
Normal file
3
dev/run-input.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
cargo run -- --namespace $SESSION_ID --bind "[::]:8080" https://fst.so:4443
|
||||
5
dev/run.sh
Normal file
5
dev/run.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash -e
|
||||
NAME="${NAME:-$(head /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | head -c 16)}"
|
||||
|
||||
# docker run --gpus all --device=/dev/dri --rm -it --entrypoint /bin/bash -e SESSION_ID=G4r06Kc8vDmwIXPG -v "$(pwd)":/game -p 8080:8080/udp --cap-add=SYS_NICE --cap-add=SYS_ADMIN server
|
||||
docker run --gpus all --device=/dev/dri --rm -it --entrypoint /bin/bash -e SESSION_ID=$NAME -v "$(pwd)":/game -p 8080:8080/udp --cap-add=SYS_NICE --cap-add=SYS_ADMIN server
|
||||
@@ -15,6 +15,7 @@ RUN apt-get update -y \
|
||||
&& add-apt-repository -y multiverse \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
libxnvctrl0 \
|
||||
libxdo-dev \
|
||||
libevdev2 \
|
||||
mangohud \
|
||||
gamescope \
|
||||
@@ -23,18 +24,17 @@ RUN apt-get update -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
#Install wine
|
||||
ARG WINE_BRANCH=staging
|
||||
RUN mkdir -pm755 /etc/apt/keyrings && curl -fsSL -o /etc/apt/keyrings/winehq-archive.key "https://dl.winehq.org/wine-builds/winehq.key" \
|
||||
&& curl -fsSL -o "/etc/apt/sources.list.d/winehq-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').sources" "https://dl.winehq.org/wine-builds/ubuntu/dists/$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"')/winehq-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').sources" \
|
||||
&& apt-get update && apt-get install --install-recommends -y winehq-${WINE_BRANCH} \
|
||||
&& curl -fsSL -o /usr/bin/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks" \
|
||||
&& chmod 755 /usr/bin/winetricks \
|
||||
&& curl -fsSL -o /usr/share/bash-completion/completions/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks.bash-completion"
|
||||
# ARG WINE_BRANCH=staging
|
||||
# RUN mkdir -pm755 /etc/apt/keyrings && curl -fsSL -o /etc/apt/keyrings/winehq-archive.key "https://dl.winehq.org/wine-builds/winehq.key" \
|
||||
# && curl -fsSL -o "/etc/apt/sources.list.d/winehq-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').sources" "https://dl.winehq.org/wine-builds/ubuntu/dists/$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"')/winehq-$(grep UBUNTU_CODENAME= /etc/os-release | cut -d= -f2 | tr -d '\"').sources" \
|
||||
# && apt-get update && apt-get install --install-recommends -y winehq-${WINE_BRANCH} \
|
||||
# && curl -fsSL -o /usr/bin/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks" \
|
||||
# && chmod 755 /usr/bin/winetricks \
|
||||
# && curl -fsSL -o /usr/share/bash-completion/completions/winetricks "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks.bash-completion"
|
||||
|
||||
#Install Proton
|
||||
COPY .scripts/proton /usr/bin/netris/
|
||||
RUN chmod +x /usr/bin/netris/proton \
|
||||
&& /usr/bin/netris/proton -i
|
||||
COPY .scripts/proton /usr/bin/netris-proton
|
||||
RUN chmod 755 /usr/bin/netris-proton
|
||||
|
||||
ARG USERNAME=netris \
|
||||
PUID=1000 \
|
||||
@@ -69,18 +69,18 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
&& ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" > /etc/timezone
|
||||
|
||||
COPY --from=ghcr.io/wanjohiryan/netris/warp:nightly /usr/bin/warp /usr/bin/
|
||||
COPY --from=ghcr.io/games-on-whales/inputtino:stable /inputtino/input-server /inputtino/input-server
|
||||
RUN chmod +x /usr/bin/warp
|
||||
COPY .scripts/entrypoint.sh .scripts/supervisord.conf /etc/
|
||||
RUN chmod 755 /etc/supervisord.conf /etc/entrypoint.sh
|
||||
COPY --from=ghcr.io/netrisdotme/netris/warp-input:nightly /usr/bin/warp-input /usr/bin/warp-input
|
||||
RUN chmod +x /usr/bin/warp /usr/bin/warp-input
|
||||
COPY .scripts /etc/
|
||||
RUN chmod 755 /etc/supervisord.conf /etc/entrypoint.sh /etc/startup.sh
|
||||
|
||||
USER 1000
|
||||
ENV SHELL=/bin/bash \
|
||||
USER=${USERNAME}
|
||||
#For mounting the game into the container
|
||||
VOLUME [ "/game" ]
|
||||
#For inputtino server
|
||||
EXPOSE 8080
|
||||
#For warp-input server
|
||||
EXPOSE 8080/udp
|
||||
|
||||
WORKDIR /home/${USERNAME}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user