Compare commits
4 commits
main
...
feature/se
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3094b03746 | ||
|
|
1f7db5c5df | ||
|
|
45f1b7b267 | ||
|
|
c28f47b632 |
3
.github/workflows/LANCommander.Cache.yml
vendored
|
|
@ -55,9 +55,6 @@ jobs:
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: '20'
|
||||||
|
|
||||||
- name: Generate PowerShell Completions
|
|
||||||
run: dotnet run --project ./LANCommander.CompletionGenerator/LANCommander.CompletionGenerator.csproj -- ./LANCommander.UI/Components/MonacoCodeEditor/PowerShellCompletions.g.ts
|
|
||||||
|
|
||||||
# Parallel UI builds
|
# Parallel UI builds
|
||||||
- name: Build UI Components
|
- name: Build UI Components
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
2
.github/workflows/LANCommander.Debug.yml
vendored
|
|
@ -56,8 +56,6 @@ jobs:
|
||||||
uses: actions/setup-node@v3.8.1
|
uses: actions/setup-node@v3.8.1
|
||||||
|
|
||||||
# UI
|
# UI
|
||||||
- name: Generate PowerShell Completions
|
|
||||||
run: dotnet run --project ./LANCommander.CompletionGenerator/LANCommander.CompletionGenerator.csproj -- ./LANCommander.UI/Components/MonacoCodeEditor/PowerShellCompletions.g.ts
|
|
||||||
- run: cd ./LANCommander.UI; npm install; npm run package
|
- run: cd ./LANCommander.UI; npm install; npm run package
|
||||||
- run: cd ./LANCommander.Server; npm install
|
- run: cd ./LANCommander.Server; npm install
|
||||||
|
|
||||||
|
|
|
||||||
254
.github/workflows/LANCommander.Development.yml
vendored
|
|
@ -1,254 +0,0 @@
|
||||||
name: LANCommander Development
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- development
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: ghcr.io
|
|
||||||
IMAGE_NAME: lancommander/lancommander
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
packages: write
|
|
||||||
id-token: write
|
|
||||||
attestations: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
# --------------------------------------------------------------------------
|
|
||||||
# 1) PREP JOB: figure out the latest semver, build development version,
|
|
||||||
# check if there are commits since the last development tag. If none,
|
|
||||||
# skip the rest of the workflow.
|
|
||||||
# --------------------------------------------------------------------------
|
|
||||||
prep:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
version_semver: ${{ steps.set_version.outputs.VERSION_SEMVER }}
|
|
||||||
version_tag: ${{ steps.set_version.outputs.VERSION_TAG }}
|
|
||||||
changed: ${{ steps.check_diff.outputs.changed }}
|
|
||||||
build_dotnet_version: 9.0.102
|
|
||||||
steps:
|
|
||||||
- name: Check out code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
# Ensure we get all tags so we can find the latest
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Determine last semver and build development version
|
|
||||||
id: set_version
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
# Fetch all tags
|
|
||||||
git fetch --tags
|
|
||||||
|
|
||||||
# Grab the last semver-ish tag (e.g., "v1.2.3", "v1.2.3-debug", or "1.2.3-development")
|
|
||||||
LAST_SEMVER_TAG="$(git tag --list --sort=-v:refname | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+' | head -n1)"
|
|
||||||
|
|
||||||
if [ -z "$LAST_SEMVER_TAG" ]; then
|
|
||||||
echo "No semver tag found; defaulting to 0.0.0"
|
|
||||||
LAST_SEMVER_TAG="0.0.0"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Remove prefix 'v' and any suffix like "-debug", "-development", etc.
|
|
||||||
CLEAN_TAG="$(echo "${LAST_SEMVER_TAG#v}" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+')"
|
|
||||||
|
|
||||||
# Build a development version string, e.g., "1.2.3-development.20250127"
|
|
||||||
DATE=$(date +'%Y%m%d')
|
|
||||||
FINAL_VERSION="${CLEAN_TAG}-development.${DATE}"
|
|
||||||
|
|
||||||
echo "Last semver tag: $LAST_SEMVER_TAG"
|
|
||||||
echo "Clean semver tag: $CLEAN_TAG"
|
|
||||||
echo "Development version: $FINAL_VERSION"
|
|
||||||
|
|
||||||
# Set output variables for GitHub Actions
|
|
||||||
echo "VERSION_SEMVER=$CLEAN_TAG" >> $GITHUB_ENV
|
|
||||||
echo "VERSION_TAG=$FINAL_VERSION" >> $GITHUB_ENV
|
|
||||||
echo "::set-output name=VERSION_SEMVER::$CLEAN_TAG"
|
|
||||||
echo "::set-output name=VERSION_TAG::$FINAL_VERSION"
|
|
||||||
|
|
||||||
- name: Check if commits since last development tag
|
|
||||||
id: check_diff
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
# Fetch the last development tag
|
|
||||||
LAST_DEVELOPMENT_TAG="$(git tag --list --sort=-v:refname | grep -E 'development\.20[0-9]+' | head -n1 || true)"
|
|
||||||
|
|
||||||
if [ -z "$LAST_DEVELOPMENT_TAG" ]; then
|
|
||||||
echo "No previous development tag found. Marking as changed."
|
|
||||||
echo "::set-output name=changed::true"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check for commits since that tag
|
|
||||||
set +e # Disable exit on error temporarily
|
|
||||||
COMMITS=$(git log "${LAST_DEVELOPMENT_TAG}"..HEAD --oneline 2>/dev/null || true)
|
|
||||||
set -e # Re-enable exit on error
|
|
||||||
|
|
||||||
if [ -z "$COMMITS" ]; then
|
|
||||||
echo "No commits since last development tag: $LAST_DEVELOPMENT_TAG"
|
|
||||||
echo "::set-output name=changed::false"
|
|
||||||
else
|
|
||||||
echo "Found commits since $LAST_DEVELOPMENT_TAG"
|
|
||||||
echo "::set-output name=changed::true"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
|
||||||
# 2) BUILD JOBS (Server/Launcher) - only run if changes == 'true'
|
|
||||||
# Each calls your local workflow YAML with correct indentation
|
|
||||||
# --------------------------------------------------------------------------
|
|
||||||
build_server_linux_x64:
|
|
||||||
needs: [prep]
|
|
||||||
if: needs.prep.outputs.changed == 'true'
|
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
|
||||||
with:
|
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
|
||||||
version_semver: ${{ needs.prep.outputs.version_semver }}
|
|
||||||
version_tag: ${{ needs.prep.outputs.version_tag }}
|
|
||||||
build_runtime: linux-x64
|
|
||||||
build_arch: x64
|
|
||||||
build_platform: Linux
|
|
||||||
build_configuration: Debug
|
|
||||||
|
|
||||||
build_server_win_x64:
|
|
||||||
needs: [prep]
|
|
||||||
if: needs.prep.outputs.changed == 'true'
|
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
|
||||||
with:
|
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
|
||||||
version_semver: ${{ needs.prep.outputs.version_semver }}
|
|
||||||
version_tag: ${{ needs.prep.outputs.version_tag }}
|
|
||||||
build_runtime: win-x64
|
|
||||||
build_arch: x64
|
|
||||||
build_platform: Windows
|
|
||||||
build_configuration: Debug
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
|
||||||
# 3) FINALIZE: if changes == 'true', gather artifacts + push Docker:development
|
|
||||||
# --------------------------------------------------------------------------
|
|
||||||
publish_docker_image:
|
|
||||||
needs:
|
|
||||||
- prep
|
|
||||||
- build_server_linux_x64
|
|
||||||
- build_server_win_x64
|
|
||||||
if: needs.prep.outputs.changed == 'true'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
# 3c) Build and push Docker image with tag "development"
|
|
||||||
- name: Checkout Repo for Docker build
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Log in to the container registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Extract metadata for Docker
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
tags: |
|
|
||||||
type=raw,value=development
|
|
||||||
type=raw,value=${{ needs.prep.outputs.version_tag }}
|
|
||||||
|
|
||||||
- name: Download Server x64 Artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: LANCommander.Server-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
path: ./
|
|
||||||
|
|
||||||
- name: Extract Server Artifacts
|
|
||||||
run: |
|
|
||||||
mkdir -p ./LANCommander.Server/published
|
|
||||||
unzip ./LANCommander.Server-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip -d ./LANCommander.Server/published
|
|
||||||
|
|
||||||
# - name: Download Server arm64 Artifacts
|
|
||||||
# uses: actions/download-artifact@v4
|
|
||||||
# with:
|
|
||||||
# name: LANCommander.Server-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
# path: ./published
|
|
||||||
|
|
||||||
# - name: Set up QEMU
|
|
||||||
# uses: docker/setup-qemu-action@v2
|
|
||||||
- name: Setup buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
with:
|
|
||||||
platforms: linux/amd64
|
|
||||||
|
|
||||||
- name: Build and push Docker image
|
|
||||||
id: push
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: ./LANCommander.Server
|
|
||||||
file: ./LANCommander.Server/Dockerfile
|
|
||||||
push: true
|
|
||||||
platforms: linux/amd64
|
|
||||||
tags: |
|
|
||||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}:development
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
build-args: |
|
|
||||||
VERSION=${{ needs.prep.outputs.version_tag }}
|
|
||||||
BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
||||||
provenance: true
|
|
||||||
|
|
||||||
- name: Generate artifact attestation
|
|
||||||
uses: actions/attest-build-provenance@v2
|
|
||||||
with:
|
|
||||||
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
|
|
||||||
subject-digest: ${{ steps.push.outputs.digest }}
|
|
||||||
push-to-registry: true
|
|
||||||
|
|
||||||
- name: Save version to artifact
|
|
||||||
run: echo "${{ needs.prep.outputs.version_tag }}" > version.txt
|
|
||||||
|
|
||||||
- name: Upload version artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: version.${{ needs.prep.outputs.version_tag }}
|
|
||||||
path: version.txt
|
|
||||||
publish_development_release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- prep
|
|
||||||
- publish_docker_image
|
|
||||||
steps:
|
|
||||||
- name: Create Temp Directory
|
|
||||||
run: mkdir -p artifacts
|
|
||||||
|
|
||||||
- name: Download Server Linux x64
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: LANCommander.Server-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
path: artifacts
|
|
||||||
|
|
||||||
- name: Download Server Windows x64
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: LANCommander.Server-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
path: artifacts
|
|
||||||
|
|
||||||
- name: Delete existing release assets
|
|
||||||
uses: dev-drprasad/delete-tag-and-release@v1.1
|
|
||||||
with:
|
|
||||||
tag_name: development
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Create development release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
with:
|
|
||||||
tag_name: development
|
|
||||||
name: Development Build v${{ needs.prep.outputs.version_tag }}
|
|
||||||
draft: false
|
|
||||||
prerelease: true
|
|
||||||
generate_release_notes: true
|
|
||||||
body: This is the latest development build. These builds are generated automatically and should be considered unstable.
|
|
||||||
files: |
|
|
||||||
artifacts/LANCommander.Server-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
artifacts/LANCommander.Server-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
28
.github/workflows/LANCommander.Documentation.yml
vendored
|
|
@ -1,28 +0,0 @@
|
||||||
name: Publish Documentation Updates
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
paths:
|
|
||||||
- "LANCommander.Documentation/**"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
dispatch:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Dispatch to Docusaurus repo
|
|
||||||
env:
|
|
||||||
DISPATCH_TOKEN: ${{ secrets.DOCUMENTATION_DISPATCH_TOKEN }}
|
|
||||||
run: |
|
|
||||||
curl -sS -X POST \
|
|
||||||
-H "Accept: application/vnd.github+json" \
|
|
||||||
-H "Authorization: Bearer ${DISPATCH_TOKEN}" \
|
|
||||||
https://api.github.com/repos/LANCommander/LANCommander.Documentation/dispatches \
|
|
||||||
-d '{
|
|
||||||
"event_type": "docs-sources-updated",
|
|
||||||
"client_payload": {
|
|
||||||
"repo": "'"${GITHUB_REPOSITORY}"'",
|
|
||||||
"sha": "'"${GITHUB_SHA}"'",
|
|
||||||
"ref": "'"${GITHUB_REF}"'"
|
|
||||||
}
|
|
||||||
}'
|
|
||||||
125
.github/workflows/LANCommander.Launcher.Legacy.yml
vendored
|
|
@ -1,125 +0,0 @@
|
||||||
name: LANCommander.Launcher.Legacy
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main, feature/legacy-launcher]
|
|
||||||
paths:
|
|
||||||
- 'LANCommander.Launcher.Legacy/**'
|
|
||||||
- 'LANCommander.SDK.Cpp/**'
|
|
||||||
- '.github/workflows/LANCommander.Launcher.Legacy.yml'
|
|
||||||
pull_request:
|
|
||||||
branches: [main]
|
|
||||||
paths:
|
|
||||||
- 'LANCommander.Launcher.Legacy/**'
|
|
||||||
- 'LANCommander.SDK.Cpp/**'
|
|
||||||
- '.github/workflows/LANCommander.Launcher.Legacy.yml'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-win9x:
|
|
||||||
name: Build (Win9x / MinGW-w64 i686)
|
|
||||||
runs-on: windows-latest
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: msys2 {0}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
# MSYS2 with MinGW32 (i686) toolchain
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
- name: Setup MSYS2
|
|
||||||
uses: msys2/setup-msys2@v2
|
|
||||||
with:
|
|
||||||
msystem: MINGW32
|
|
||||||
update: false
|
|
||||||
install: >-
|
|
||||||
mingw-w64-i686-gcc
|
|
||||||
mingw-w64-i686-cmake
|
|
||||||
mingw-w64-i686-make
|
|
||||||
make
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
# Vendor dependencies (cJSON, miniz, Allegro 4 source)
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
- name: Download vendor dependencies
|
|
||||||
shell: pwsh
|
|
||||||
run: ./setup-vendor.ps1
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
# Build Allegro 4 from source (static, no addons)
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
- name: Build Allegro 4
|
|
||||||
run: |
|
|
||||||
ALLEGRO_SRC="LANCommander.Launcher.Legacy/vendor/allegro4/allegro5-4.4.3.1"
|
|
||||||
ALLEGRO_BUILD="LANCommander.Launcher.Legacy/build-allegro-win9x"
|
|
||||||
ALLEGRO_PREFIX="$(pwd)/LANCommander.Launcher.Legacy/allegro4-win9x"
|
|
||||||
|
|
||||||
cmake -S "$ALLEGRO_SRC" -B "$ALLEGRO_BUILD" \
|
|
||||||
-G "MinGW Makefiles" \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DCMAKE_INSTALL_PREFIX="$ALLEGRO_PREFIX" \
|
|
||||||
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
|
||||||
-DSHARED=OFF \
|
|
||||||
-DWANT_EXAMPLES=OFF \
|
|
||||||
-DWANT_TOOLS=OFF \
|
|
||||||
-DWANT_TESTS=OFF \
|
|
||||||
-DWANT_ALLEGROGL=OFF \
|
|
||||||
-DWANT_LOADPNG=OFF \
|
|
||||||
-DWANT_LOGG=OFF \
|
|
||||||
-DWANT_JPGALLEG=OFF \
|
|
||||||
-DWANT_FRAMEWORKS=OFF
|
|
||||||
|
|
||||||
mingw32-make -C "$ALLEGRO_BUILD" -j$(nproc)
|
|
||||||
mingw32-make -C "$ALLEGRO_BUILD" install
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
# Build the launcher
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
- name: Build launcher
|
|
||||||
run: |
|
|
||||||
LAUNCHER_DIR="LANCommander.Launcher.Legacy"
|
|
||||||
LAUNCHER_BUILD="$LAUNCHER_DIR/build-win9x"
|
|
||||||
ALLEGRO_PREFIX="$(pwd)/$LAUNCHER_DIR/allegro4-win9x"
|
|
||||||
|
|
||||||
cmake -S "$LAUNCHER_DIR" -B "$LAUNCHER_BUILD" \
|
|
||||||
-G "MinGW Makefiles" \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DALLEGRO_STATIC=ON \
|
|
||||||
-DTARGET_WIN9X=ON \
|
|
||||||
-DALLEGRO_ROOT="$ALLEGRO_PREFIX"
|
|
||||||
|
|
||||||
mingw32-make -C "$LAUNCHER_BUILD" -j$(nproc)
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
# Package
|
|
||||||
# ---------------------------------------------------------------
|
|
||||||
- name: Package artifacts
|
|
||||||
run: |
|
|
||||||
mkdir -p out-win9x
|
|
||||||
|
|
||||||
LAUNCHER_EXE=$(find LANCommander.Launcher.Legacy/build-win9x -name "launcher.exe" | head -1)
|
|
||||||
cp "$LAUNCHER_EXE" out-win9x/LANCommander.exe
|
|
||||||
strip out-win9x/LANCommander.exe
|
|
||||||
|
|
||||||
# Bundle GDI+ redistributable (MinGW CRT is statically linked)
|
|
||||||
if [ -f "$MINGW_PREFIX/bin/gdiplus.dll" ]; then
|
|
||||||
cp "$MINGW_PREFIX/bin/gdiplus.dll" out-win9x/
|
|
||||||
echo "Bundled: gdiplus.dll"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Show PE info for verification
|
|
||||||
objdump -p out-win9x/LANCommander.exe | grep -i "Version\|Subsystem" || true
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
ls -lh out-win9x/
|
|
||||||
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: LANCommander-Legacy-Win9x
|
|
||||||
path: out-win9x/
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
@ -1,127 +0,0 @@
|
||||||
name: LANCommander Launcher Tests — PR Visual Diff Comment
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
pr_number:
|
|
||||||
description: 'Pull request number to comment on'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
artifact_run_id:
|
|
||||||
description: 'Workflow run ID that produced the launcher-visual-artifacts artifact'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write # push diff PNGs to the gh-visual-diffs branch
|
|
||||||
pull-requests: write # post / update the comment
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
comment:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout for branch push
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Download visual artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: launcher-visual-artifacts
|
|
||||||
path: visual
|
|
||||||
run-id: ${{ inputs.artifact_run_id }}
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Read regression manifest
|
|
||||||
id: manifest
|
|
||||||
run: |
|
|
||||||
if [ ! -f visual/regressions.json ]; then
|
|
||||||
echo "no manifest — assuming no visual run"
|
|
||||||
echo "count=0" >> "$GITHUB_OUTPUT"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
count=$(jq '.regressed_count' visual/regressions.json)
|
|
||||||
echo "count=$count" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Skip when no regressions
|
|
||||||
if: steps.manifest.outputs.count == '0'
|
|
||||||
run: echo "No visual regressions; nothing to comment."
|
|
||||||
|
|
||||||
# Push diff/actual/baseline PNGs to an orphan branch so raw.githubusercontent.com
|
|
||||||
# URLs render inline in the PR comment. One folder per (PR, run).
|
|
||||||
- name: Push diffs to gh-visual-diffs branch
|
|
||||||
if: steps.manifest.outputs.count != '0'
|
|
||||||
env:
|
|
||||||
PR: ${{ inputs.pr_number }}
|
|
||||||
RUN: ${{ inputs.artifact_run_id }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
git config user.name "github-actions[bot]"
|
|
||||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
||||||
|
|
||||||
# Worktree off an orphan branch so we never touch the source tree.
|
|
||||||
if git ls-remote --exit-code --heads origin gh-visual-diffs >/dev/null; then
|
|
||||||
git fetch origin gh-visual-diffs
|
|
||||||
git worktree add /tmp/visual gh-visual-diffs
|
|
||||||
else
|
|
||||||
git worktree add --detach /tmp/visual
|
|
||||||
cd /tmp/visual
|
|
||||||
git checkout --orphan gh-visual-diffs
|
|
||||||
git rm -rf . 2>/dev/null || true
|
|
||||||
cd -
|
|
||||||
fi
|
|
||||||
|
|
||||||
DEST="/tmp/visual/pr-${PR}/run-${RUN}"
|
|
||||||
mkdir -p "$DEST"
|
|
||||||
cp -r visual/diffs "$DEST/" 2>/dev/null || true
|
|
||||||
cp -r visual/screenshots "$DEST/" 2>/dev/null || true
|
|
||||||
cp -r visual/baselines "$DEST/" 2>/dev/null || true
|
|
||||||
|
|
||||||
cd /tmp/visual
|
|
||||||
git add -A
|
|
||||||
git -c user.name=github-actions -c user.email=github-actions@github.com \
|
|
||||||
commit -m "Visual diffs for PR #${PR} run ${RUN}"
|
|
||||||
git push origin gh-visual-diffs
|
|
||||||
|
|
||||||
- name: Post / update PR comment
|
|
||||||
if: steps.manifest.outputs.count != '0'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
PR: ${{ inputs.pr_number }}
|
|
||||||
RUN: ${{ inputs.artifact_run_id }}
|
|
||||||
REPO: ${{ github.repository }}
|
|
||||||
MARKER: '<!-- launcher-visual-diff-comment -->'
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
base="https://raw.githubusercontent.com/${REPO}/gh-visual-diffs/pr-${PR}/run-${RUN}"
|
|
||||||
|
|
||||||
body=$(mktemp)
|
|
||||||
{
|
|
||||||
echo "$MARKER"
|
|
||||||
echo "## :art: Launcher visual regressions"
|
|
||||||
echo
|
|
||||||
echo "$(jq '.regressed_count' visual/regressions.json) baseline(s) drifted in [run ${RUN}](https://github.com/${REPO}/actions/runs/${RUN})."
|
|
||||||
echo
|
|
||||||
jq -r '.regressions[] | .name' visual/regressions.json | while read -r name; do
|
|
||||||
echo "<details><summary><strong>${name}</strong></summary>"
|
|
||||||
echo
|
|
||||||
echo "| Baseline | Actual | Diff |"
|
|
||||||
echo "| --- | --- | --- |"
|
|
||||||
echo "|  |  |  |"
|
|
||||||
echo
|
|
||||||
echo "</details>"
|
|
||||||
echo
|
|
||||||
done
|
|
||||||
echo "_If these changes are intentional, run the **Update Visual Baselines** workflow to refresh._"
|
|
||||||
} >> "$body"
|
|
||||||
|
|
||||||
# Find an existing comment with our marker; update it if present.
|
|
||||||
existing=$(gh api repos/${REPO}/issues/${PR}/comments --paginate \
|
|
||||||
--jq ".[] | select(.body | startswith(\"${MARKER}\")) | .id" | head -1)
|
|
||||||
|
|
||||||
if [ -n "$existing" ]; then
|
|
||||||
gh api -X PATCH "repos/${REPO}/issues/comments/${existing}" --field "body=@${body}"
|
|
||||||
else
|
|
||||||
gh api -X POST "repos/${REPO}/issues/${PR}/comments" --field "body=@${body}"
|
|
||||||
fi
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
name: LANCommander Launcher Tests — Update Visual Baselines
|
|
||||||
|
|
||||||
# Operator-triggered: re-renders every visual test on the CI host and commits the
|
|
||||||
# new screenshots over the committed Baselines/. Only runs when a human dispatches
|
|
||||||
# it from the Actions tab — never on push or PR — so accidental drift can't slip in.
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
branch:
|
|
||||||
description: 'Branch to commit refreshed baselines to'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
default: 'main'
|
|
||||||
build_dotnet_version:
|
|
||||||
description: 'Build .NET Version'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: '9.0.102'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
refresh:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: ${{ inputs.branch }}
|
|
||||||
submodules: true
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Setup .NET
|
|
||||||
uses: actions/setup-dotnet@v4
|
|
||||||
with:
|
|
||||||
dotnet-version: ${{ inputs.build_dotnet_version }}
|
|
||||||
|
|
||||||
- name: Install rendering prereqs
|
|
||||||
run: |
|
|
||||||
sudo apt-get update -qq
|
|
||||||
sudo apt-get install -y --no-install-recommends \
|
|
||||||
libfontconfig1 libfreetype6 libice6 libsm6 libx11-6 libxcb1 libxext6
|
|
||||||
|
|
||||||
- name: Restore + build visual test project
|
|
||||||
run: |
|
|
||||||
dotnet restore LANCommander.Launcher.Tests/LANCommander.Launcher.Tests.csproj
|
|
||||||
dotnet build LANCommander.Launcher.Tests/LANCommander.Launcher.Tests.csproj -c Debug --no-restore
|
|
||||||
|
|
||||||
# Run visual tests, ignore failures (regressions are expected here — that's
|
|
||||||
# the whole point of refreshing). Then promote every captured screenshot
|
|
||||||
# to be the new baseline.
|
|
||||||
- name: Capture fresh screenshots
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
|
||||||
dotnet test LANCommander.Launcher.Tests/LANCommander.Launcher.Tests.csproj \
|
|
||||||
-c Debug --no-build --no-restore \
|
|
||||||
--logger "console;verbosity=normal"
|
|
||||||
|
|
||||||
- name: Promote captures to baselines
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
src=LANCommander.Launcher.Tests/bin/Debug/net10.0/Screenshots
|
|
||||||
dst=LANCommander.Launcher.Tests/Baselines
|
|
||||||
|
|
||||||
if [ ! -d "$src" ]; then
|
|
||||||
echo "::error::No screenshots captured at $src — visual tests didn't run."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p "$dst"
|
|
||||||
cp -v "$src"/*.png "$dst"/
|
|
||||||
|
|
||||||
echo "## Updated baselines" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
echo "" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
ls -1 "$dst"/*.png | xargs -n1 basename | sed 's/^/- /' >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
|
|
||||||
- name: Commit + push refreshed baselines
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
git config user.name "github-actions[bot]"
|
|
||||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
||||||
|
|
||||||
if git diff --quiet -- LANCommander.Launcher.Tests/Baselines; then
|
|
||||||
echo "Baselines unchanged — nothing to commit."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
git add LANCommander.Launcher.Tests/Baselines
|
|
||||||
git commit -m "Refresh launcher visual baselines from CI run ${GITHUB_RUN_ID}"
|
|
||||||
git push origin HEAD:${{ inputs.branch }}
|
|
||||||
170
.github/workflows/LANCommander.Launcher.Tests.yml
vendored
|
|
@ -1,170 +0,0 @@
|
||||||
name: LANCommander Launcher Tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
build_dotnet_version:
|
|
||||||
description: 'Build .NET Version'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
outputs:
|
|
||||||
visual_diff_count:
|
|
||||||
description: 'Number of visual baselines that regressed in this run'
|
|
||||||
value: ${{ jobs.test.outputs.visual_diff_count }}
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
build_dotnet_version:
|
|
||||||
description: 'Build .NET Version'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: '9.0.102'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
name: Run Launcher Tests
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
visual_diff_count: ${{ steps.summarize.outputs.visual_diff_count }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
|
|
||||||
- name: Setup .NET
|
|
||||||
uses: actions/setup-dotnet@v4
|
|
||||||
with:
|
|
||||||
dotnet-version: ${{ inputs.build_dotnet_version }}
|
|
||||||
|
|
||||||
# Avalonia headless rendering uses Skia + the Inter font. Install
|
|
||||||
# font + GPU prereqs so screenshots render consistently.
|
|
||||||
- name: Install rendering prereqs
|
|
||||||
run: |
|
|
||||||
sudo apt-get update -qq
|
|
||||||
sudo apt-get install -y --no-install-recommends \
|
|
||||||
libfontconfig1 libfreetype6 libice6 libsm6 libx11-6 libxcb1 libxext6
|
|
||||||
|
|
||||||
- name: Restore
|
|
||||||
run: dotnet restore
|
|
||||||
|
|
||||||
# ---- Unit + integration test projects ---------------------------------
|
|
||||||
# Services.Tests and IntegrationTests build cleanly without the
|
|
||||||
# Server/UI npm+pwsh chain. Launcher.Tests likewise just needs Skia.
|
|
||||||
|
|
||||||
- name: Build test projects
|
|
||||||
run: |
|
|
||||||
dotnet build LANCommander.Launcher.Services.Tests/LANCommander.Launcher.Services.Tests.csproj -c Debug --no-restore
|
|
||||||
dotnet build LANCommander.Launcher.IntegrationTests/LANCommander.Launcher.IntegrationTests.csproj -c Debug --no-restore
|
|
||||||
dotnet build LANCommander.Launcher.Tests/LANCommander.Launcher.Tests.csproj -c Debug --no-restore
|
|
||||||
|
|
||||||
- name: Run Services unit tests
|
|
||||||
run: |
|
|
||||||
dotnet test LANCommander.Launcher.Services.Tests/LANCommander.Launcher.Services.Tests.csproj \
|
|
||||||
-c Debug --no-build --no-restore \
|
|
||||||
--logger "trx;LogFileName=services.trx" \
|
|
||||||
--logger "console;verbosity=normal" \
|
|
||||||
--results-directory test-results \
|
|
||||||
--collect:"XPlat Code Coverage"
|
|
||||||
|
|
||||||
- name: Run integration tests
|
|
||||||
run: |
|
|
||||||
dotnet test LANCommander.Launcher.IntegrationTests/LANCommander.Launcher.IntegrationTests.csproj \
|
|
||||||
-c Debug --no-build --no-restore \
|
|
||||||
--logger "trx;LogFileName=integration.trx" \
|
|
||||||
--logger "console;verbosity=normal" \
|
|
||||||
--results-directory test-results \
|
|
||||||
--collect:"XPlat Code Coverage"
|
|
||||||
|
|
||||||
# Visual tests are continued-on-error so a baseline regression doesn't
|
|
||||||
# mask any earlier failure and so we always reach the artifact-upload
|
|
||||||
# + summary steps below. The summary step re-asserts the failure for CI.
|
|
||||||
- name: Run visual tests
|
|
||||||
id: visual_tests
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
|
||||||
dotnet test LANCommander.Launcher.Tests/LANCommander.Launcher.Tests.csproj \
|
|
||||||
-c Debug --no-build --no-restore \
|
|
||||||
--logger "trx;LogFileName=visual.trx" \
|
|
||||||
--logger "console;verbosity=normal" \
|
|
||||||
--results-directory test-results
|
|
||||||
|
|
||||||
# ---- Visual artifact collection --------------------------------------
|
|
||||||
# Aggregate every screenshot + diff PNG into top-level folders so the
|
|
||||||
# PR-comment job downstream can find them by predictable name.
|
|
||||||
|
|
||||||
- name: Collect visual artifacts
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
mkdir -p visual/screenshots visual/diffs visual/baselines
|
|
||||||
cp -r LANCommander.Launcher.Tests/bin/Debug/net10.0/Screenshots/. visual/screenshots/ 2>/dev/null || true
|
|
||||||
cp -r LANCommander.Launcher.Tests/bin/Debug/net10.0/Diffs/. visual/diffs/ 2>/dev/null || true
|
|
||||||
cp -r LANCommander.Launcher.Tests/Baselines/. visual/baselines/ 2>/dev/null || true
|
|
||||||
|
|
||||||
- name: Summarize visual diffs
|
|
||||||
id: summarize
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
shopt -s nullglob
|
|
||||||
diffs=(visual/diffs/*.diff.png)
|
|
||||||
count=${#diffs[@]}
|
|
||||||
|
|
||||||
echo "visual_diff_count=$count" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "## Visual test summary" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
echo "" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
echo "$count baseline(s) regressed." >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
|
|
||||||
# JSON manifest the PR-comment job consumes
|
|
||||||
python3 - "$count" <<'PY' > visual/regressions.json
|
|
||||||
import json, os, sys
|
|
||||||
count = int(sys.argv[1])
|
|
||||||
diffs = sorted(os.listdir("visual/diffs")) if os.path.isdir("visual/diffs") else []
|
|
||||||
data = {
|
|
||||||
"regressed_count": count,
|
|
||||||
"regressions": [
|
|
||||||
{
|
|
||||||
"name": d.replace(".diff.png", ""),
|
|
||||||
"diff": f"visual/diffs/{d}",
|
|
||||||
"actual": f"visual/screenshots/{d.replace('.diff.png', '.png')}",
|
|
||||||
"baseline": f"visual/baselines/{d.replace('.diff.png', '.png')}",
|
|
||||||
}
|
|
||||||
for d in diffs
|
|
||||||
],
|
|
||||||
}
|
|
||||||
print(json.dumps(data, indent=2))
|
|
||||||
PY
|
|
||||||
|
|
||||||
cat visual/regressions.json
|
|
||||||
|
|
||||||
- name: Upload visual artifacts
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: launcher-visual-artifacts
|
|
||||||
path: |
|
|
||||||
visual/screenshots/**
|
|
||||||
visual/diffs/**
|
|
||||||
visual/baselines/**
|
|
||||||
visual/regressions.json
|
|
||||||
if-no-files-found: warn
|
|
||||||
retention-days: 14
|
|
||||||
|
|
||||||
- name: Upload TRX + coverage
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: launcher-test-results
|
|
||||||
path: test-results/**
|
|
||||||
if-no-files-found: warn
|
|
||||||
retention-days: 14
|
|
||||||
|
|
||||||
# Re-assert the visual test outcome so CI fails when baselines diverge,
|
|
||||||
# after artifacts are guaranteed uploaded.
|
|
||||||
- name: Fail if visual tests regressed
|
|
||||||
if: always() && steps.visual_tests.outcome == 'failure'
|
|
||||||
run: |
|
|
||||||
echo "::error::Visual tests reported regressions. See the launcher-visual-artifacts artifact."
|
|
||||||
exit 1
|
|
||||||
276
.github/workflows/LANCommander.Launcher.yml
vendored
|
|
@ -45,18 +45,27 @@ env:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ${{ inputs.build_platform == 'Linux' && inputs.build_arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- uses: frabert/replace-string-action@v2
|
||||||
|
name: Swap Path Backslashes
|
||||||
|
id: swap_path_backslashes
|
||||||
|
with:
|
||||||
|
string: '${{ github.workspace }}'
|
||||||
|
pattern: '\\'
|
||||||
|
replace-with: '/'
|
||||||
|
flags: g
|
||||||
|
|
||||||
# Checkout code
|
# Checkout code
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
# .NET Setup
|
# .NET Setup and Caching
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v4
|
uses: actions/setup-dotnet@v4
|
||||||
with:
|
with:
|
||||||
|
|
@ -65,243 +74,64 @@ jobs:
|
||||||
- name: Restore dependencies
|
- name: Restore dependencies
|
||||||
run: dotnet restore --locked-mode
|
run: dotnet restore --locked-mode
|
||||||
|
|
||||||
- name: Publish Launcher
|
# Node.js Setup and Caching
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v3.8.1
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install Node Packages
|
||||||
run: |
|
run: |
|
||||||
# Strip leading 'v' if present
|
npm install --prefix ./LANCommander.UI
|
||||||
RAW_VERSION="${{ inputs.version_tag }}" # e.g. v2.0.0-rc1
|
npm install --prefix ./LANCommander.Launcher
|
||||||
SEMVER="${RAW_VERSION#v}" # 2.0.0-rc1
|
|
||||||
|
|
||||||
# Numeric part only for Assembly/FileVersion
|
- name: Package Frontend
|
||||||
NUMERIC="${SEMVER%%-*}" # 2.0.0
|
|
||||||
ASSEMBLY_VERSION="${NUMERIC}.0" # 2.0.0.0
|
|
||||||
|
|
||||||
echo "SEMVER=$SEMVER"
|
|
||||||
echo "ASSEMBLY_VERSION=$ASSEMBLY_VERSION"
|
|
||||||
|
|
||||||
dotnet publish "./LANCommander.Launcher/LANCommander.Launcher.csproj" \
|
|
||||||
-c "${{ inputs.build_configuration }}" \
|
|
||||||
--self-contained \
|
|
||||||
--runtime "${{ inputs.build_runtime }}" \
|
|
||||||
-p:Version="$SEMVER" \
|
|
||||||
-p:AssemblyVersion="$ASSEMBLY_VERSION" \
|
|
||||||
-p:FileVersion="$ASSEMBLY_VERSION" \
|
|
||||||
-p:InformationalVersion="$SEMVER" \
|
|
||||||
-p:PublishSingleFile=true \
|
|
||||||
-p:IncludeNativeLibrariesForSelfExtract=true \
|
|
||||||
-p:IncludeAllContentForSelfExtract=true \
|
|
||||||
-p:EnableCompressionInSingleFile=true \
|
|
||||||
-p:DebugType=embedded
|
|
||||||
|
|
||||||
- name: Bundle libvlc (Linux)
|
|
||||||
if: inputs.build_platform == 'Linux'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
PUBLISH_DIR="LANCommander.Launcher/bin/${{ inputs.build_configuration }}/net10.0/${{ inputs.build_runtime }}/publish"
|
npm run package --prefix ./LANCommander.UI
|
||||||
VLC_DIR="$PUBLISH_DIR/libvlc/${{ inputs.build_runtime }}"
|
npm run package --prefix ./LANCommander.Launcher
|
||||||
mkdir -p "$VLC_DIR"
|
|
||||||
|
|
||||||
if [ "${{ inputs.build_arch }}" = "arm64" ]; then
|
# .NET builds
|
||||||
# Enable arm64 multiarch and add Ubuntu Ports repository so apt can
|
- name: Publish Components
|
||||||
# download arm64 packages on this x64 runner.
|
run: |
|
||||||
sudo dpkg --add-architecture arm64
|
dotnet publish "./LANCommander.AutoUpdater/LANCommander.AutoUpdater.csproj" -c ${{ inputs.build_configuration }} --self-contained --runtime ${{ inputs.build_runtime }} -p:Version="${{ inputs.version_tag }}" -p:AssemblyVersion="${{ inputs.version_semver }}"
|
||||||
CODENAME=$(lsb_release -cs)
|
dotnet publish "./LANCommander.Launcher/LANCommander.Launcher.csproj" -c ${{ inputs.build_configuration }} --self-contained --runtime ${{ inputs.build_runtime }} -p:Version="${{ inputs.version_tag }}" -p:AssemblyVersion="${{ inputs.version_semver }}"
|
||||||
echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports ${CODENAME} main restricted universe" \
|
dotnet publish "./LANCommander.Launcher.CLI/LANCommander.Launcher.CLI.csproj" -c ${{ inputs.build_configuration }} --self-contained --runtime ${{ inputs.build_runtime }} -p:Version="${{ inputs.version_tag }}" -p:AssemblyVersion="${{ inputs.version_semver }}"
|
||||||
| sudo tee /etc/apt/sources.list.d/ubuntu-ports-arm64.list > /dev/null
|
|
||||||
echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports ${CODENAME}-updates main restricted universe" \
|
|
||||||
| sudo tee -a /etc/apt/sources.list.d/ubuntu-ports-arm64.list > /dev/null
|
|
||||||
sudo apt-get update -qq
|
|
||||||
|
|
||||||
sudo apt-get download libvlc5:arm64 libvlccore9:arm64 vlc-plugin-base:arm64
|
|
||||||
|
|
||||||
mkdir -p vlc-extracted
|
|
||||||
for deb in libvlc5_*arm64.deb libvlccore9_*arm64.deb vlc-plugin-base_*arm64.deb; do
|
|
||||||
dpkg -x "$deb" vlc-extracted/
|
|
||||||
done
|
|
||||||
|
|
||||||
LIB_DIR="vlc-extracted/usr/lib/aarch64-linux-gnu"
|
|
||||||
PLUGINS_SRC="$LIB_DIR/vlc/plugins"
|
|
||||||
else
|
|
||||||
sudo apt-get install -y --no-install-recommends libvlc5 libvlccore9 vlc-plugin-base
|
|
||||||
LIB_DIR="/usr/lib/x86_64-linux-gnu"
|
|
||||||
PLUGINS_SRC="$LIB_DIR/vlc/plugins"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Copy the two core shared libraries, dereferencing symlinks so their
|
|
||||||
# content is preserved correctly when zipped.
|
|
||||||
for lib in libvlc.so.5 libvlccore.so.9; do
|
|
||||||
src=$(find "$LIB_DIR" -maxdepth 1 -name "${lib}*" | sort | head -1)
|
|
||||||
if [ -n "$src" ]; then
|
|
||||||
cp -L "$src" "$VLC_DIR/$lib"
|
|
||||||
echo "Bundled: $lib"
|
|
||||||
else
|
|
||||||
echo "WARNING: $lib not found in $LIB_DIR" >&2
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Copy VLC plugins (vlc-plugin-base covers common codecs and demuxers)
|
|
||||||
if [ -d "$PLUGINS_SRC" ]; then
|
|
||||||
mkdir -p "$VLC_DIR/plugins"
|
|
||||||
cp -rL "$PLUGINS_SRC/." "$VLC_DIR/plugins/"
|
|
||||||
echo "Bundled $(find "$VLC_DIR/plugins" -name "*.so" | wc -l) plugin(s)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Bundle and Clean
|
- name: Bundle and Clean
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
$BasePath = "LANCommander.Launcher/bin/${{ inputs.build_configuration }}/net10.0/${{ inputs.build_runtime }}/publish"
|
Copy-Item -Force -Recurse -Verbose LANCommander.AutoUpdater/bin/${{ inputs.build_configuration }}/net9.0/${{ inputs.build_runtime }}/publish/* LANCommander.Launcher/bin/${{ inputs.build_configuration }}/net9.0/${{ inputs.build_runtime }}/publish/
|
||||||
|
Copy-Item -Force -Recurse -Verbose LANCommander.Launcher.CLI/bin/${{ inputs.build_configuration }}/net9.0/${{ inputs.build_runtime }}/publish/* LANCommander.Launcher/bin/${{ inputs.build_configuration }}/net9.0/${{ inputs.build_runtime }}/publish/
|
||||||
# Remove unnecessary files
|
|
||||||
|
# Remove unnecessary files in a single operation
|
||||||
$PathsToRemove = @(
|
$PathsToRemove = @(
|
||||||
'*.pdb'
|
'wwwroot/_content/BootstrapBlazor.PdfReader/compat',
|
||||||
|
'wwwroot/_content/BootstrapBlazor.PdfReader/2.*',
|
||||||
|
'wwwroot/_content/BootstrapBlazor.PdfReader/build/pdf.sandbox.js',
|
||||||
|
'wwwroot/_content/BootstrapBlazor.PdfReader/build/*.map',
|
||||||
|
'wwwroot/_content/BootstrapBlazor.PdfReader/web/*.map',
|
||||||
|
'wwwroot/_content/AntDesign/less',
|
||||||
|
'wwwroot/_content/BlazorMonaco/lib/monaco-editor/min-maps',
|
||||||
|
'wwwroot/Identity/lib/bootstrap',
|
||||||
|
'LANCommander.ico',
|
||||||
|
'LANCommanderDark.ico',
|
||||||
|
'package-lock.json',
|
||||||
|
'package.json',
|
||||||
|
'*.pdb',
|
||||||
|
'hostfxr.dll.bak',
|
||||||
|
'Libraries/locales'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
$BasePath = "LANCommander.Launcher/bin/${{ inputs.build_configuration }}/net9.0/${{ inputs.build_runtime }}/publish"
|
||||||
foreach ($path in $PathsToRemove) {
|
foreach ($path in $PathsToRemove) {
|
||||||
Remove-Item -Recurse -Force -ErrorAction Continue "$BasePath/$path"
|
Remove-Item -Recurse -Force -ErrorAction Continue "$BasePath/$path"
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: Bundle macOS .app
|
|
||||||
if: inputs.build_platform == 'macOS'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Strip leading 'v' and reduce to numeric x.y.z for the bundle version keys.
|
|
||||||
RAW_VERSION="${{ inputs.version_tag }}"
|
|
||||||
SEMVER="${RAW_VERSION#v}"
|
|
||||||
NUMERIC="${SEMVER%%-*}"
|
|
||||||
|
|
||||||
APP_NAME="LANCommander Launcher"
|
|
||||||
EXECUTABLE="LANCommander.Launcher"
|
|
||||||
BUNDLE_ID="app.lancommander.launcher"
|
|
||||||
ICON_SRC="LANCommander.Launcher/Assets/icon.icns"
|
|
||||||
|
|
||||||
PUBLISH_DIR="LANCommander.Launcher/bin/${{ inputs.build_configuration }}/net10.0/${{ inputs.build_runtime }}/publish"
|
|
||||||
APP_DIR="${EXECUTABLE}.app"
|
|
||||||
|
|
||||||
# Lay out the bundle skeleton.
|
|
||||||
mkdir -p "$APP_DIR/Contents/MacOS" "$APP_DIR/Contents/Resources"
|
|
||||||
cp -a "$PUBLISH_DIR/." "$APP_DIR/Contents/MacOS/"
|
|
||||||
cp "$ICON_SRC" "$APP_DIR/Contents/Resources/AppIcon.icns"
|
|
||||||
|
|
||||||
# Write Info.plist.
|
|
||||||
cat > "$APP_DIR/Contents/Info.plist" <<PLIST
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>${APP_NAME}</string>
|
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>${APP_NAME}</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>${BUNDLE_ID}</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>${EXECUTABLE}</string>
|
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string>AppIcon</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>${NUMERIC}</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>${SEMVER}</string>
|
|
||||||
<key>LSMinimumSystemVersion</key>
|
|
||||||
<string>11.0</string>
|
|
||||||
<key>NSHighResolutionCapable</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
PLIST
|
|
||||||
|
|
||||||
# Ensure the entrypoint is executable, then zip while preserving the
|
|
||||||
# permission bits (Compress-Archive drops the exec bit).
|
|
||||||
chmod +x "$APP_DIR/Contents/MacOS/${EXECUTABLE}"
|
|
||||||
zip -ry "LANCommander.Launcher-${{ inputs.build_platform }}-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.zip" "$APP_DIR"
|
|
||||||
|
|
||||||
- name: Build AppImage (Linux)
|
|
||||||
if: inputs.build_platform == 'Linux'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
PUBLISH_DIR="LANCommander.Launcher/bin/${{ inputs.build_configuration }}/net10.0/${{ inputs.build_runtime }}/publish"
|
|
||||||
APP_NAME="LANCommander.Launcher"
|
|
||||||
APPDIR="AppDir"
|
|
||||||
|
|
||||||
# appimagetool / runtime architecture identifiers
|
|
||||||
if [ "${{ inputs.build_arch }}" = "arm64" ]; then
|
|
||||||
AI_ARCH="aarch64"
|
|
||||||
else
|
|
||||||
AI_ARCH="x86_64"
|
|
||||||
fi
|
|
||||||
export ARCH="$AI_ARCH"
|
|
||||||
|
|
||||||
# --- Assemble the AppDir ---------------------------------------------
|
|
||||||
rm -rf "$APPDIR"
|
|
||||||
mkdir -p "$APPDIR/usr/bin" "$APPDIR/usr/share/applications" \
|
|
||||||
"$APPDIR/usr/share/icons/hicolor/scalable/apps"
|
|
||||||
|
|
||||||
cp -r "$PUBLISH_DIR/." "$APPDIR/usr/bin/"
|
|
||||||
chmod +x "$APPDIR/usr/bin/$APP_NAME"
|
|
||||||
|
|
||||||
# Icon (use the prebuilt 256x256 project icon)
|
|
||||||
ICON_SRC="LANCommander.Launcher/Assets/icon.png"
|
|
||||||
ICON_DIR="$APPDIR/usr/share/icons/hicolor/256x256/apps"
|
|
||||||
mkdir -p "$ICON_DIR"
|
|
||||||
cp "$ICON_SRC" "$ICON_DIR/lancommander.png"
|
|
||||||
|
|
||||||
cp "$ICON_DIR/lancommander.png" "$APPDIR/lancommander.png"
|
|
||||||
ln -sf lancommander.png "$APPDIR/.DirIcon"
|
|
||||||
|
|
||||||
# Desktop entry
|
|
||||||
cat > "$APPDIR/usr/share/applications/lancommander.desktop" <<'EOF'
|
|
||||||
[Desktop Entry]
|
|
||||||
Type=Application
|
|
||||||
Name=LANCommander Launcher
|
|
||||||
Comment=LANCommander Launcher
|
|
||||||
Exec=LANCommander.Launcher
|
|
||||||
Icon=lancommander
|
|
||||||
Categories=Game;
|
|
||||||
Terminal=false
|
|
||||||
EOF
|
|
||||||
cp "$APPDIR/usr/share/applications/lancommander.desktop" "$APPDIR/lancommander.desktop"
|
|
||||||
|
|
||||||
# AppRun entry point
|
|
||||||
cat > "$APPDIR/AppRun" <<'EOF'
|
|
||||||
#!/bin/bash
|
|
||||||
HERE="$(dirname "$(readlink -f "${0}")")"
|
|
||||||
export PATH="${HERE}/usr/bin:${PATH}"
|
|
||||||
export LD_LIBRARY_PATH="${HERE}/usr/bin:${LD_LIBRARY_PATH:-}"
|
|
||||||
exec "${HERE}/usr/bin/LANCommander.Launcher" "$@"
|
|
||||||
EOF
|
|
||||||
chmod +x "$APPDIR/AppRun"
|
|
||||||
|
|
||||||
# --- Fetch appimagetool ----------------------------------------------
|
|
||||||
TOOL_URL="https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${AI_ARCH}.AppImage"
|
|
||||||
curl -L -o appimagetool "$TOOL_URL"
|
|
||||||
chmod +x appimagetool
|
|
||||||
|
|
||||||
# --- Build the AppImage ----------------------------------------------
|
|
||||||
OUT="LANCommander.Launcher-Linux-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.AppImage"
|
|
||||||
./appimagetool --appimage-extract-and-run "$APPDIR" "$OUT"
|
|
||||||
|
|
||||||
echo "Produced $OUT"
|
|
||||||
|
|
||||||
- name: Upload AppImage Artifact (Linux)
|
|
||||||
if: inputs.build_platform == 'Linux'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
path: LANCommander.Launcher-Linux-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.AppImage
|
|
||||||
name: LANCommander.Launcher-Linux-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.AppImage
|
|
||||||
|
|
||||||
- name: Compress Build Output
|
- name: Compress Build Output
|
||||||
if: inputs.build_platform != 'macOS'
|
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
$compress = @{
|
$compress = @{
|
||||||
Path = "LANCommander.Launcher/bin/${{ inputs.build_configuration }}/net10.0/${{ inputs.build_runtime }}/publish/*"
|
Path = "LANCommander.Launcher/bin/${{ inputs.build_configuration }}/net9.0/${{ inputs.build_runtime }}/publish/*"
|
||||||
DestinationPath = "LANCommander.Launcher-${{ inputs.build_platform }}-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.zip"
|
DestinationPath = "LANCommander.Launcher-${{ inputs.build_platform }}-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.zip"
|
||||||
CompressionLevel = "Fastest"
|
CompressionLevel = "Fastest"
|
||||||
}
|
}
|
||||||
|
|
@ -311,4 +141,4 @@ jobs:
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: LANCommander.Launcher-${{ inputs.build_platform }}-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.zip
|
path: LANCommander.Launcher-${{ inputs.build_platform }}-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.zip
|
||||||
name: LANCommander.Launcher-${{ inputs.build_platform }}-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.zip
|
name: LANCommander.Launcher-${{ inputs.build_platform }}-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.zip
|
||||||
134
.github/workflows/LANCommander.Nightly.yml
vendored
|
|
@ -29,7 +29,7 @@ jobs:
|
||||||
version_semver: ${{ steps.set_version.outputs.VERSION_SEMVER }}
|
version_semver: ${{ steps.set_version.outputs.VERSION_SEMVER }}
|
||||||
version_tag: ${{ steps.set_version.outputs.VERSION_TAG }}
|
version_tag: ${{ steps.set_version.outputs.VERSION_TAG }}
|
||||||
changed: ${{ steps.check_diff.outputs.changed }}
|
changed: ${{ steps.check_diff.outputs.changed }}
|
||||||
build_dotnet_version: 10.0.100
|
build_dotnet_version: 9.0.102
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
@ -101,7 +101,7 @@ jobs:
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
build_server_linux_arm64:
|
build_server_linux_arm64:
|
||||||
needs: [prep]
|
needs: [prep]
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
if: needs.prep.outputs.changed == 'true'
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
uses: ./.github/workflows/LANCommander.Server.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -114,7 +114,7 @@ jobs:
|
||||||
|
|
||||||
build_server_linux_x64:
|
build_server_linux_x64:
|
||||||
needs: [prep]
|
needs: [prep]
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
if: needs.prep.outputs.changed == 'true'
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
uses: ./.github/workflows/LANCommander.Server.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -127,7 +127,7 @@ jobs:
|
||||||
|
|
||||||
build_server_osx_arm64:
|
build_server_osx_arm64:
|
||||||
needs: [prep]
|
needs: [prep]
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
if: needs.prep.outputs.changed == 'true'
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
uses: ./.github/workflows/LANCommander.Server.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -140,7 +140,7 @@ jobs:
|
||||||
|
|
||||||
build_server_osx_x64:
|
build_server_osx_x64:
|
||||||
needs: [prep]
|
needs: [prep]
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
if: needs.prep.outputs.changed == 'true'
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
uses: ./.github/workflows/LANCommander.Server.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -153,7 +153,7 @@ jobs:
|
||||||
|
|
||||||
build_server_win_arm64:
|
build_server_win_arm64:
|
||||||
needs: [prep]
|
needs: [prep]
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
if: needs.prep.outputs.changed == 'true'
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
uses: ./.github/workflows/LANCommander.Server.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -166,7 +166,7 @@ jobs:
|
||||||
|
|
||||||
build_server_win_x64:
|
build_server_win_x64:
|
||||||
needs: [prep]
|
needs: [prep]
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
if: needs.prep.outputs.changed == 'true'
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
uses: ./.github/workflows/LANCommander.Server.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -179,7 +179,7 @@ jobs:
|
||||||
|
|
||||||
build_launcher_linux_arm64:
|
build_launcher_linux_arm64:
|
||||||
needs: [prep]
|
needs: [prep]
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
if: needs.prep.outputs.changed == 'true'
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
uses: ./.github/workflows/LANCommander.Launcher.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -192,7 +192,7 @@ jobs:
|
||||||
|
|
||||||
build_launcher_linux_x64:
|
build_launcher_linux_x64:
|
||||||
needs: [prep]
|
needs: [prep]
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
if: needs.prep.outputs.changed == 'true'
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
uses: ./.github/workflows/LANCommander.Launcher.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -205,7 +205,7 @@ jobs:
|
||||||
|
|
||||||
build_launcher_osx_arm64:
|
build_launcher_osx_arm64:
|
||||||
needs: [prep]
|
needs: [prep]
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
if: needs.prep.outputs.changed == 'true'
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
uses: ./.github/workflows/LANCommander.Launcher.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -218,7 +218,7 @@ jobs:
|
||||||
|
|
||||||
build_launcher_osx_x64:
|
build_launcher_osx_x64:
|
||||||
needs: [prep]
|
needs: [prep]
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
if: needs.prep.outputs.changed == 'true'
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
uses: ./.github/workflows/LANCommander.Launcher.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -231,7 +231,7 @@ jobs:
|
||||||
|
|
||||||
build_launcher_win_arm64:
|
build_launcher_win_arm64:
|
||||||
needs: [prep]
|
needs: [prep]
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
if: needs.prep.outputs.changed == 'true'
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
uses: ./.github/workflows/LANCommander.Launcher.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -244,7 +244,7 @@ jobs:
|
||||||
|
|
||||||
build_launcher_win_x64:
|
build_launcher_win_x64:
|
||||||
needs: [prep]
|
needs: [prep]
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
if: needs.prep.outputs.changed == 'true'
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
uses: ./.github/workflows/LANCommander.Launcher.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -267,7 +267,13 @@ jobs:
|
||||||
- build_server_osx_x64
|
- build_server_osx_x64
|
||||||
- build_server_win_arm64
|
- build_server_win_arm64
|
||||||
- build_server_win_x64
|
- build_server_win_x64
|
||||||
if: needs.prep.outputs.changed == 'true' && github.repository_owner == 'LANCommander'
|
- build_launcher_linux_arm64
|
||||||
|
- build_launcher_linux_x64
|
||||||
|
- build_launcher_osx_arm64
|
||||||
|
- build_launcher_osx_x64
|
||||||
|
- build_launcher_win_arm64
|
||||||
|
- build_launcher_win_x64
|
||||||
|
if: needs.prep.outputs.changed == 'true'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
# 3c) Build and push Docker image with tag "nightly"
|
# 3c) Build and push Docker image with tag "nightly"
|
||||||
|
|
@ -296,29 +302,23 @@ jobs:
|
||||||
name: LANCommander.Server-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
name: LANCommander.Server-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
path: ./
|
path: ./
|
||||||
|
|
||||||
- name: Download Server arm64 Artifacts
|
- name: Extract Server Artifacts
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: LANCommander.Server-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
path: ./
|
|
||||||
|
|
||||||
- name: Extract Server Artifacts x64
|
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ./LANCommander.Server/published-amd64
|
mkdir -p ./LANCommander.Server/published
|
||||||
unzip ./LANCommander.Server-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip -d ./LANCommander.Server/published-amd64
|
unzip ./LANCommander.Server-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip -d ./LANCommander.Server/published
|
||||||
|
|
||||||
- name: Extract Server Artifacts arm64
|
# - name: Download Server arm64 Artifacts
|
||||||
run: |
|
# uses: actions/download-artifact@v4
|
||||||
mkdir -p ./LANCommander.Server/published-arm64
|
# with:
|
||||||
unzip ./LANCommander.Server-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip -d ./LANCommander.Server/published-arm64
|
# name: LANCommander.Server-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
# path: ./published
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
|
|
||||||
|
# - name: Set up QEMU
|
||||||
|
# uses: docker/setup-qemu-action@v2
|
||||||
- name: Setup buildx
|
- name: Setup buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
with:
|
with:
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
id: push
|
id: push
|
||||||
|
|
@ -327,7 +327,7 @@ jobs:
|
||||||
context: ./LANCommander.Server
|
context: ./LANCommander.Server
|
||||||
file: ./LANCommander.Server/Dockerfile
|
file: ./LANCommander.Server/Dockerfile
|
||||||
push: true
|
push: true
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64
|
||||||
tags: |
|
tags: |
|
||||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}:nightly
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}:nightly
|
||||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}:v${{ needs.prep.outputs.version_tag }}
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}:v${{ needs.prep.outputs.version_tag }}
|
||||||
|
|
@ -359,16 +359,7 @@ jobs:
|
||||||
needs:
|
needs:
|
||||||
- prep
|
- prep
|
||||||
- publish_docker_image
|
- publish_docker_image
|
||||||
- build_launcher_linux_arm64
|
|
||||||
- build_launcher_linux_x64
|
|
||||||
- build_launcher_osx_arm64
|
|
||||||
- build_launcher_osx_x64
|
|
||||||
- build_launcher_win_arm64
|
|
||||||
- build_launcher_win_x64
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Create Temp Directory
|
- name: Create Temp Directory
|
||||||
run: mkdir -p artifacts
|
run: mkdir -p artifacts
|
||||||
|
|
||||||
|
|
@ -443,40 +434,33 @@ jobs:
|
||||||
with:
|
with:
|
||||||
name: LANCommander.Launcher-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
name: LANCommander.Launcher-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
- name: Download Launcher Linux ARM64 AppImage
|
- name: Delete existing release assets
|
||||||
uses: actions/download-artifact@v4
|
uses: dev-drprasad/delete-tag-and-release@v1.1
|
||||||
with:
|
with:
|
||||||
name: LANCommander.Launcher-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.AppImage
|
tag_name: nightly
|
||||||
path: artifacts
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Create nightly release
|
||||||
- name: Download Launcher Linux x64 AppImage
|
uses: softprops/action-gh-release@v2
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
with:
|
||||||
name: LANCommander.Launcher-Linux-x64-v${{ needs.prep.outputs.version_tag }}.AppImage
|
tag_name: nightly
|
||||||
path: artifacts
|
name: Nightly Build v${{ needs.prep.outputs.version_tag }}
|
||||||
|
draft: false
|
||||||
- name: Create or update nightly release
|
prerelease: true
|
||||||
|
generate_release_notes: true
|
||||||
|
body: This is the latest nightly build. These builds are generated automatically and should be considered unstable.
|
||||||
|
files: |
|
||||||
|
artifacts/LANCommander.Server-Windows-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
artifacts/LANCommander.Server-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
artifacts/LANCommander.Server-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
artifacts/LANCommander.Server-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
artifacts/LANCommander.Server-macOS-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
artifacts/LANCommander.Server-macOS-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
artifacts/LANCommander.Launcher-Windows-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
artifacts/LANCommander.Launcher-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
artifacts/LANCommander.Launcher-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
artifacts/LANCommander.Launcher-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
artifacts/LANCommander.Launcher-macOS-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
artifacts/LANCommander.Launcher-macOS-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
|
||||||
# Create the release if it doesn't exist, otherwise update its metadata
|
|
||||||
if gh release view nightly > /dev/null 2>&1; then
|
|
||||||
# Remove all existing assets so only this nightly's files remain
|
|
||||||
gh release view nightly --json assets -q '.assets[].name' | while read -r asset; do
|
|
||||||
gh release delete-asset nightly "$asset" -y
|
|
||||||
done
|
|
||||||
|
|
||||||
gh release edit nightly \
|
|
||||||
--prerelease \
|
|
||||||
--title "Nightly Build v${{ needs.prep.outputs.version_tag }}" \
|
|
||||||
--notes "This is the latest nightly build. These builds are generated automatically and should be considered unstable."
|
|
||||||
else
|
|
||||||
gh release create nightly \
|
|
||||||
--prerelease \
|
|
||||||
--title "Nightly Build v${{ needs.prep.outputs.version_tag }}" \
|
|
||||||
--notes "This is the latest nightly build. These builds are generated automatically and should be considered unstable."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Upload new artifacts
|
|
||||||
gh release upload nightly artifacts/*
|
|
||||||
229
.github/workflows/LANCommander.PR.yml
vendored
|
|
@ -1,229 +0,0 @@
|
||||||
name: LANCommander Pull Request
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- synchronize
|
|
||||||
- reopened
|
|
||||||
- ready_for_review
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
packages: read
|
|
||||||
checks: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
prep:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
version_semver: ${{ steps.set_version.outputs.version_semver }}
|
|
||||||
version_tag: ${{ steps.set_version.outputs.version_tag }}
|
|
||||||
build_dotnet_version: 9.0.102
|
|
||||||
steps:
|
|
||||||
- name: Check out code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Determine build metadata
|
|
||||||
id: set_version
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
||||||
RUN_NUMBER: ${{ github.run_number }}
|
|
||||||
run: |
|
|
||||||
TIMESTAMP=$(date -u +"%Y%m%d%H%M")
|
|
||||||
TIME_COMPONENT=$(date -u +"%H%M")
|
|
||||||
TIME_COMPONENT=$((10#$TIME_COMPONENT))
|
|
||||||
|
|
||||||
if [ -n "$PR_NUMBER" ]; then
|
|
||||||
BUILD_COMPONENT=$((PR_NUMBER % 65535))
|
|
||||||
if [ "$BUILD_COMPONENT" -eq 0 ]; then
|
|
||||||
BUILD_COMPONENT=1
|
|
||||||
fi
|
|
||||||
VERSION_SEMVER="0.0.${BUILD_COMPONENT}.${TIME_COMPONENT}"
|
|
||||||
VERSION_TAG="0.0.${BUILD_COMPONENT}-pr.${PR_NUMBER}.${TIMESTAMP}"
|
|
||||||
else
|
|
||||||
BUILD_COMPONENT=$((RUN_NUMBER % 65535))
|
|
||||||
if [ "$BUILD_COMPONENT" -eq 0 ]; then
|
|
||||||
BUILD_COMPONENT=1
|
|
||||||
fi
|
|
||||||
VERSION_SEMVER="0.0.${BUILD_COMPONENT}.${TIME_COMPONENT}"
|
|
||||||
VERSION_TAG="0.0.${BUILD_COMPONENT}-ci.${RUN_NUMBER}.${TIMESTAMP}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "version_semver=$VERSION_SEMVER" >> $GITHUB_OUTPUT
|
|
||||||
echo "version_tag=$VERSION_TAG" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
ui_tests:
|
|
||||||
needs: [prep]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Check out code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup .NET
|
|
||||||
uses: actions/setup-dotnet@v4
|
|
||||||
with:
|
|
||||||
dotnet-version: ${{ needs.prep.outputs.build_dotnet_version }}
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
|
|
||||||
- name: Install Node packages
|
|
||||||
run: |
|
|
||||||
npm install --prefix ./LANCommander.UI
|
|
||||||
npm install --prefix ./LANCommander.Server
|
|
||||||
|
|
||||||
# The Monaco editor's PowerShell completions are generated (gitignored) and
|
|
||||||
# required by the frontend webpack build. The in-build MSBuild target uses
|
|
||||||
# Windows-style paths, so generate explicitly here for the Linux runner.
|
|
||||||
- name: Generate PowerShell Completions
|
|
||||||
run: dotnet run --project ./LANCommander.CompletionGenerator/LANCommander.CompletionGenerator.csproj -- ./LANCommander.UI/Components/MonacoCodeEditor/PowerShellCompletions.g.ts
|
|
||||||
|
|
||||||
- name: Restore dependencies
|
|
||||||
run: dotnet restore LANCommander.Server.UI.Tests
|
|
||||||
|
|
||||||
- name: Build test project
|
|
||||||
run: dotnet build LANCommander.Server.UI.Tests --no-restore --configuration Release
|
|
||||||
|
|
||||||
- name: Install Playwright browsers
|
|
||||||
run: pwsh LANCommander.Server.UI.Tests/bin/Release/net10.0/playwright.ps1 install --with-deps chromium
|
|
||||||
|
|
||||||
- name: Run UI tests
|
|
||||||
run: dotnet test LANCommander.Server.UI.Tests --no-build --configuration Release --logger "trx;LogFileName=ui-test-results.trx" --results-directory ./TestResults
|
|
||||||
env:
|
|
||||||
SCREENSHOT_DIR: ${{ github.workspace }}/TestResults/Screenshots
|
|
||||||
|
|
||||||
- name: Test report
|
|
||||||
if: always()
|
|
||||||
uses: dorny/test-reporter@v1
|
|
||||||
with:
|
|
||||||
name: UI Test Results
|
|
||||||
path: ./TestResults/ui-test-results.trx
|
|
||||||
reporter: dotnet-trx
|
|
||||||
|
|
||||||
- name: Upload test results
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ui-test-results
|
|
||||||
path: ./TestResults
|
|
||||||
retention-days: 7
|
|
||||||
|
|
||||||
build_server_linux_arm64:
|
|
||||||
needs: [prep]
|
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
|
||||||
with:
|
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
|
||||||
version_semver: ${{ needs.prep.outputs.version_semver }}
|
|
||||||
version_tag: ${{ needs.prep.outputs.version_tag }}
|
|
||||||
build_runtime: linux-arm64
|
|
||||||
build_arch: arm64
|
|
||||||
build_platform: Linux
|
|
||||||
build_configuration: Debug
|
|
||||||
|
|
||||||
build_server_linux_x64:
|
|
||||||
needs: [prep]
|
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
|
||||||
with:
|
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
|
||||||
version_semver: ${{ needs.prep.outputs.version_semver }}
|
|
||||||
version_tag: ${{ needs.prep.outputs.version_tag }}
|
|
||||||
build_runtime: linux-x64
|
|
||||||
build_arch: x64
|
|
||||||
build_platform: Linux
|
|
||||||
build_configuration: Debug
|
|
||||||
|
|
||||||
build_server_osx_arm64:
|
|
||||||
needs: [prep]
|
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
|
||||||
with:
|
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
|
||||||
version_semver: ${{ needs.prep.outputs.version_semver }}
|
|
||||||
version_tag: ${{ needs.prep.outputs.version_tag }}
|
|
||||||
build_runtime: osx-arm64
|
|
||||||
build_arch: arm64
|
|
||||||
build_platform: macOS
|
|
||||||
build_configuration: Debug
|
|
||||||
|
|
||||||
build_server_osx_x64:
|
|
||||||
needs: [prep]
|
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
|
||||||
with:
|
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
|
||||||
version_semver: ${{ needs.prep.outputs.version_semver }}
|
|
||||||
version_tag: ${{ needs.prep.outputs.version_tag }}
|
|
||||||
build_runtime: osx-x64
|
|
||||||
build_arch: x64
|
|
||||||
build_platform: macOS
|
|
||||||
build_configuration: Debug
|
|
||||||
|
|
||||||
build_server_win_arm64:
|
|
||||||
needs: [prep]
|
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
|
||||||
with:
|
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
|
||||||
version_semver: ${{ needs.prep.outputs.version_semver }}
|
|
||||||
version_tag: ${{ needs.prep.outputs.version_tag }}
|
|
||||||
build_runtime: win-arm64
|
|
||||||
build_arch: arm64
|
|
||||||
build_platform: Windows
|
|
||||||
build_configuration: Debug
|
|
||||||
|
|
||||||
build_server_win_x64:
|
|
||||||
needs: [prep]
|
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
|
||||||
with:
|
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
|
||||||
version_semver: ${{ needs.prep.outputs.version_semver }}
|
|
||||||
version_tag: ${{ needs.prep.outputs.version_tag }}
|
|
||||||
build_runtime: win-x64
|
|
||||||
build_arch: x64
|
|
||||||
build_platform: Windows
|
|
||||||
build_configuration: Debug
|
|
||||||
|
|
||||||
build_launcher_linux_x64:
|
|
||||||
needs: [prep]
|
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
|
||||||
with:
|
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
|
||||||
version_semver: ${{ needs.prep.outputs.version_semver }}
|
|
||||||
version_tag: ${{ needs.prep.outputs.version_tag }}
|
|
||||||
build_runtime: linux-x64
|
|
||||||
build_arch: x64
|
|
||||||
build_platform: Linux
|
|
||||||
build_configuration: Debug
|
|
||||||
|
|
||||||
build_launcher_win_x64:
|
|
||||||
needs: [prep]
|
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
|
||||||
with:
|
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
|
||||||
version_semver: ${{ needs.prep.outputs.version_semver }}
|
|
||||||
version_tag: ${{ needs.prep.outputs.version_tag }}
|
|
||||||
build_runtime: win-x64
|
|
||||||
build_arch: x64
|
|
||||||
build_platform: Windows
|
|
||||||
build_configuration: Debug
|
|
||||||
|
|
||||||
launcher_tests:
|
|
||||||
needs: [prep]
|
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.Tests.yml
|
|
||||||
with:
|
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
|
||||||
|
|
||||||
launcher_tests_pr_comment:
|
|
||||||
# Always run after the test job — even on failure — so visual regressions
|
|
||||||
# show up as a PR comment instead of being buried in the artifact.
|
|
||||||
needs: [launcher_tests]
|
|
||||||
if: always() && needs.launcher_tests.result != 'cancelled' && github.event.pull_request.number != null
|
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.Tests.PRComment.yml
|
|
||||||
with:
|
|
||||||
pr_number: ${{ github.event.pull_request.number }}
|
|
||||||
artifact_run_id: ${{ github.run_id }}
|
|
||||||
100
.github/workflows/LANCommander.Packager.yml
vendored
|
|
@ -1,100 +0,0 @@
|
||||||
name: LANCommander Packager Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
version_semver:
|
|
||||||
description: "Semantic Version"
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
version_tag:
|
|
||||||
description: 'Version Tag'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
build_dotnet_version:
|
|
||||||
description: 'Build .NET Version'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: '10.0.x'
|
|
||||||
build_configuration:
|
|
||||||
description: 'Build Configuration (Debug/Release)'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: 'Release'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
env:
|
|
||||||
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/package
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: windows-latest
|
|
||||||
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
|
|
||||||
- name: Setup .NET
|
|
||||||
uses: actions/setup-dotnet@v4
|
|
||||||
with:
|
|
||||||
dotnet-version: ${{ inputs.build_dotnet_version }}
|
|
||||||
|
|
||||||
- name: Restore dependencies
|
|
||||||
run: dotnet restore
|
|
||||||
|
|
||||||
- name: Publish Packager
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
# Strip leading 'v' if present
|
|
||||||
$RawVersion = "${{ inputs.version_tag }}"
|
|
||||||
$Semver = $RawVersion -replace '^v', ''
|
|
||||||
|
|
||||||
# Numeric part only for Assembly/FileVersion
|
|
||||||
$Numeric = ($Semver -split '-')[0]
|
|
||||||
$AssemblyVersion = "$Numeric.0"
|
|
||||||
|
|
||||||
Write-Host "SEMVER=$Semver"
|
|
||||||
Write-Host "ASSEMBLY_VERSION=$AssemblyVersion"
|
|
||||||
|
|
||||||
dotnet publish "./LANCommander.Packager/LANCommander.Packager.csproj" `
|
|
||||||
-c "${{ inputs.build_configuration }}" `
|
|
||||||
--self-contained `
|
|
||||||
--runtime win-x86 `
|
|
||||||
-p:Version="$Semver" `
|
|
||||||
-p:AssemblyVersion="$AssemblyVersion" `
|
|
||||||
-p:FileVersion="$AssemblyVersion" `
|
|
||||||
-p:InformationalVersion="$Semver" `
|
|
||||||
-p:PublishSingleFile=true `
|
|
||||||
-p:IncludeNativeLibrariesForSelfExtract=true `
|
|
||||||
-p:IncludeAllContentForSelfExtract=true `
|
|
||||||
-p:EnableCompressionInSingleFile=true `
|
|
||||||
-p:DebugType=embedded
|
|
||||||
|
|
||||||
- name: Clean
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
$BasePath = "LANCommander.Packager/bin/${{ inputs.build_configuration }}/net10.0/win-x86/publish"
|
|
||||||
Remove-Item -Recurse -Force -ErrorAction Continue "$BasePath/*.pdb"
|
|
||||||
|
|
||||||
- name: Compress Build Output
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
$compress = @{
|
|
||||||
Path = "LANCommander.Packager/bin/${{ inputs.build_configuration }}/net10.0/win-x86/publish/*"
|
|
||||||
DestinationPath = "LANCommander.Packager-Windows-x86-v${{ inputs.version_tag }}.zip"
|
|
||||||
CompressionLevel = "Fastest"
|
|
||||||
}
|
|
||||||
Compress-Archive @compress
|
|
||||||
|
|
||||||
- name: Upload Artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
path: LANCommander.Packager-Windows-x86-v${{ inputs.version_tag }}.zip
|
|
||||||
name: LANCommander.Packager-Windows-x86-v${{ inputs.version_tag }}.zip
|
|
||||||
134
.github/workflows/LANCommander.Release.yml
vendored
|
|
@ -3,12 +3,7 @@ name: LANCommander Release
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- 'v*.*.*'
|
- 'v[0-9]+.[0-9]+.[0-9]+'
|
||||||
- 'v*.*.*-*'
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: docker.io
|
|
||||||
IMAGE_NAME: lancommander/lancommander
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
@ -16,26 +11,18 @@ permissions:
|
||||||
id-token: write
|
id-token: write
|
||||||
attestations: write
|
attestations: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: docker.io
|
||||||
|
IMAGE_NAME: lancommander/lancommander
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# --------------------------------------------------------------------------
|
|
||||||
# 1) PREP JOB: figure out the latest semver, build nightly version,
|
|
||||||
# check if there are commits since the last nightly tag. If none,
|
|
||||||
# skip the rest of the workflow.
|
|
||||||
# --------------------------------------------------------------------------
|
|
||||||
prep:
|
prep:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
version_tag: ${{ steps.trim_tag_ref.outputs.replaced }}
|
version_tag: ${{ steps.trim_tag_ref.outputs.replaced }}
|
||||||
version_semver: ${{ steps.trim_tag_ref.outputs.replaced }}
|
version_semver: ${{ steps.trim_tag_ref.outputs.replaced }}
|
||||||
is_prerelease: ${{ steps.check_prerelease.outputs.is_prerelease }}
|
|
||||||
build_dotnet_version: 9.0.102
|
build_dotnet_version: 9.0.102
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
# Ensure we get all tags so we can find the latest
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- uses: frabert/replace-string-action@v2
|
- uses: frabert/replace-string-action@v2
|
||||||
name: Trim Tag Ref
|
name: Trim Tag Ref
|
||||||
id: trim_tag_ref
|
id: trim_tag_ref
|
||||||
|
|
@ -44,19 +31,9 @@ jobs:
|
||||||
pattern: 'refs/tags/v'
|
pattern: 'refs/tags/v'
|
||||||
replace-with: ''
|
replace-with: ''
|
||||||
|
|
||||||
- name: Check if pre-release
|
|
||||||
id: check_prerelease
|
|
||||||
run: |
|
|
||||||
VERSION="${{ steps.trim_tag_ref.outputs.replaced }}"
|
|
||||||
if [[ "$VERSION" == *-* ]]; then
|
|
||||||
echo "is_prerelease=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "is_prerelease=false" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Server
|
# Server
|
||||||
build_server_linux_arm64:
|
build_server_linux_arm64:
|
||||||
needs: [prep]
|
needs: prep
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
uses: ./.github/workflows/LANCommander.Server.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -68,7 +45,7 @@ jobs:
|
||||||
build_configuration: Release
|
build_configuration: Release
|
||||||
|
|
||||||
build_server_linux_x64:
|
build_server_linux_x64:
|
||||||
needs: [prep]
|
needs: prep
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
uses: ./.github/workflows/LANCommander.Server.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -80,7 +57,7 @@ jobs:
|
||||||
build_configuration: Release
|
build_configuration: Release
|
||||||
|
|
||||||
build_server_osx_arm64:
|
build_server_osx_arm64:
|
||||||
needs: [prep]
|
needs: prep
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
uses: ./.github/workflows/LANCommander.Server.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -92,7 +69,7 @@ jobs:
|
||||||
build_configuration: Release
|
build_configuration: Release
|
||||||
|
|
||||||
build_server_osx_x64:
|
build_server_osx_x64:
|
||||||
needs: [prep]
|
needs: prep
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
uses: ./.github/workflows/LANCommander.Server.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -104,7 +81,7 @@ jobs:
|
||||||
build_configuration: Release
|
build_configuration: Release
|
||||||
|
|
||||||
build_server_win_arm64:
|
build_server_win_arm64:
|
||||||
needs: [prep]
|
needs: prep
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
uses: ./.github/workflows/LANCommander.Server.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -116,7 +93,7 @@ jobs:
|
||||||
build_configuration: Release
|
build_configuration: Release
|
||||||
|
|
||||||
build_server_win_x64:
|
build_server_win_x64:
|
||||||
needs: [prep]
|
needs: prep
|
||||||
uses: ./.github/workflows/LANCommander.Server.yml
|
uses: ./.github/workflows/LANCommander.Server.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -129,7 +106,7 @@ jobs:
|
||||||
|
|
||||||
# Launcher
|
# Launcher
|
||||||
build_launcher_linux_arm64:
|
build_launcher_linux_arm64:
|
||||||
needs: [prep]
|
needs: prep
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
uses: ./.github/workflows/LANCommander.Launcher.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -141,7 +118,7 @@ jobs:
|
||||||
build_configuration: Release
|
build_configuration: Release
|
||||||
|
|
||||||
build_launcher_linux_x64:
|
build_launcher_linux_x64:
|
||||||
needs: [prep]
|
needs: prep
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
uses: ./.github/workflows/LANCommander.Launcher.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -153,7 +130,7 @@ jobs:
|
||||||
build_configuration: Release
|
build_configuration: Release
|
||||||
|
|
||||||
build_launcher_osx_arm64:
|
build_launcher_osx_arm64:
|
||||||
needs: [prep]
|
needs: prep
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
uses: ./.github/workflows/LANCommander.Launcher.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -165,7 +142,7 @@ jobs:
|
||||||
build_configuration: Release
|
build_configuration: Release
|
||||||
|
|
||||||
build_launcher_osx_x64:
|
build_launcher_osx_x64:
|
||||||
needs: [prep]
|
needs: prep
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
uses: ./.github/workflows/LANCommander.Launcher.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -177,7 +154,7 @@ jobs:
|
||||||
build_configuration: Release
|
build_configuration: Release
|
||||||
|
|
||||||
build_launcher_win_arm64:
|
build_launcher_win_arm64:
|
||||||
needs: [prep]
|
needs: prep
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
uses: ./.github/workflows/LANCommander.Launcher.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -189,7 +166,7 @@ jobs:
|
||||||
build_configuration: Release
|
build_configuration: Release
|
||||||
|
|
||||||
build_launcher_win_x64:
|
build_launcher_win_x64:
|
||||||
needs: [prep]
|
needs: prep
|
||||||
uses: ./.github/workflows/LANCommander.Launcher.yml
|
uses: ./.github/workflows/LANCommander.Launcher.yml
|
||||||
with:
|
with:
|
||||||
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
build_dotnet_version: ${{ needs.prep.outputs.build_dotnet_version }}
|
||||||
|
|
@ -200,16 +177,6 @@ jobs:
|
||||||
build_platform: Windows
|
build_platform: Windows
|
||||||
build_configuration: Release
|
build_configuration: Release
|
||||||
|
|
||||||
# Packager (Windows x86 only)
|
|
||||||
build_packager:
|
|
||||||
needs: [prep]
|
|
||||||
uses: ./.github/workflows/LANCommander.Packager.yml
|
|
||||||
with:
|
|
||||||
build_dotnet_version: '10.0.x'
|
|
||||||
version_semver: ${{ needs.prep.outputs.version_semver }}
|
|
||||||
version_tag: ${{ needs.prep.outputs.version_tag }}
|
|
||||||
build_configuration: Release
|
|
||||||
|
|
||||||
build_release:
|
build_release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
|
|
@ -226,7 +193,6 @@ jobs:
|
||||||
- build_launcher_osx_x64
|
- build_launcher_osx_x64
|
||||||
- build_launcher_win_arm64
|
- build_launcher_win_arm64
|
||||||
- build_launcher_win_x64
|
- build_launcher_win_x64
|
||||||
- build_packager
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Create Temp Directory
|
- name: Create Temp Directory
|
||||||
|
|
@ -268,7 +234,6 @@ jobs:
|
||||||
name: LANCommander.Server-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
name: LANCommander.Server-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
# Launcher artifacts
|
|
||||||
- name: Download Launcher Linux ARM64
|
- name: Download Launcher Linux ARM64
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|
@ -305,24 +270,6 @@ jobs:
|
||||||
name: LANCommander.Launcher-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
name: LANCommander.Launcher-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
- name: Download Launcher Linux ARM64 AppImage
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: LANCommander.Launcher-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.AppImage
|
|
||||||
path: artifacts
|
|
||||||
|
|
||||||
- name: Download Launcher Linux x64 AppImage
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: LANCommander.Launcher-Linux-x64-v${{ needs.prep.outputs.version_tag }}.AppImage
|
|
||||||
path: artifacts
|
|
||||||
|
|
||||||
- name: Download Packager Windows x86
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: LANCommander.Packager-Windows-x86-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
path: artifacts
|
|
||||||
|
|
||||||
- name: Debug - List Artifact Files
|
- name: Debug - List Artifact Files
|
||||||
run: |
|
run: |
|
||||||
echo "Contents of ./artifacts:"
|
echo "Contents of ./artifacts:"
|
||||||
|
|
@ -334,7 +281,6 @@ jobs:
|
||||||
name: v${{ needs.prep.outputs.version_tag }}
|
name: v${{ needs.prep.outputs.version_tag }}
|
||||||
generate_release_notes: true
|
generate_release_notes: true
|
||||||
draft: true
|
draft: true
|
||||||
prerelease: ${{ needs.prep.outputs.is_prerelease == 'true' }}
|
|
||||||
files: |
|
files: |
|
||||||
artifacts/LANCommander.Server-Windows-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
artifacts/LANCommander.Server-Windows-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
artifacts/LANCommander.Server-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
artifacts/LANCommander.Server-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
|
@ -342,15 +288,12 @@ jobs:
|
||||||
artifacts/LANCommander.Server-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
artifacts/LANCommander.Server-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
artifacts/LANCommander.Server-macOS-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
artifacts/LANCommander.Server-macOS-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
artifacts/LANCommander.Server-macOS-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
artifacts/LANCommander.Server-macOS-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
artifacts/LANCommander.Launcher-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
artifacts/LANCommander.Launcher-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
artifacts/LANCommander.Launcher-macOS-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
artifacts/LANCommander.Launcher-macOS-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
artifacts/LANCommander.Launcher-Windows-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
artifacts/LANCommander.Launcher-Windows-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
artifacts/LANCommander.Launcher-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
artifacts/LANCommander.Launcher-Windows-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
artifacts/LANCommander.Launcher-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.AppImage
|
artifacts/LANCommander.Launcher-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
artifacts/LANCommander.Launcher-Linux-x64-v${{ needs.prep.outputs.version_tag }}.AppImage
|
artifacts/LANCommander.Launcher-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
artifacts/LANCommander.Packager-Windows-x86-v${{ needs.prep.outputs.version_tag }}.zip
|
artifacts/LANCommander.Launcher-macOS-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
artifacts/LANCommander.Launcher-macOS-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
|
|
||||||
- name: Checkout Repo for Docker build
|
- name: Checkout Repo for Docker build
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
@ -382,35 +325,18 @@ jobs:
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
type=raw,value=latest,enable={{is_default_branch}}
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
|
||||||
- name: Download Server x64 Artifacts
|
# - name: Download Server arm64 Artifacts
|
||||||
uses: actions/download-artifact@v4
|
# uses: actions/download-artifact@v4
|
||||||
with:
|
# with:
|
||||||
name: LANCommander.Server-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip
|
# name: LANCommander.Server-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
||||||
path: ./
|
# path: ./published
|
||||||
|
|
||||||
- name: Download Server arm64 Artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: LANCommander.Server-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip
|
|
||||||
path: ./
|
|
||||||
|
|
||||||
- name: Extract Server Artifacts x64
|
|
||||||
run: |
|
|
||||||
mkdir -p ./LANCommander.Server/published-amd64
|
|
||||||
unzip ./LANCommander.Server-Linux-x64-v${{ needs.prep.outputs.version_tag }}.zip -d ./LANCommander.Server/published-amd64
|
|
||||||
|
|
||||||
- name: Extract Server Artifacts arm64
|
|
||||||
run: |
|
|
||||||
mkdir -p ./LANCommander.Server/published-arm64
|
|
||||||
unzip ./LANCommander.Server-Linux-arm64-v${{ needs.prep.outputs.version_tag }}.zip -d ./LANCommander.Server/published-arm64
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
|
|
||||||
|
# - name: Set up QEMU
|
||||||
|
# uses: docker/setup-qemu-action@v2
|
||||||
- name: Setup buildx
|
- name: Setup buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
with:
|
with:
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
id: push
|
id: push
|
||||||
|
|
@ -421,8 +347,8 @@ jobs:
|
||||||
push: true
|
push: true
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
tags: |
|
tags: |
|
||||||
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}:latest
|
||||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}:v${{ needs.prep.outputs.version_tag }}
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}:v${{ needs.prep.outputs.version_tag }}
|
||||||
${{ needs.prep.outputs.is_prerelease == 'true' && format('{0}/{1}:prerelease', env.REGISTRY, env.IMAGE_NAME) || format('{0}/{1}:latest', env.REGISTRY, env.IMAGE_NAME) }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
|
|
||||||
15
.github/workflows/LANCommander.SDK.Release.yml
vendored
|
|
@ -1,8 +1,9 @@
|
||||||
name: LANCommander SDK Release
|
name: LANCommander SDK Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
push:
|
||||||
types: [published]
|
tags:
|
||||||
|
- 'v[0-9]+.[0-9]+.[0-9]+'
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
@ -12,7 +13,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
version_tag: ${{ steps.trim_tag_ref.outputs.replaced }}
|
version_tag: ${{ steps.trim_tag_ref.outputs.replaced }}
|
||||||
version_semver: ${{ steps.extract_semver.outputs.replaced }}
|
version_semver: ${{ steps.trim_tag_ref.outputs.replaced }}
|
||||||
steps:
|
steps:
|
||||||
- uses: frabert/replace-string-action@v2
|
- uses: frabert/replace-string-action@v2
|
||||||
name: Trim Tag Ref
|
name: Trim Tag Ref
|
||||||
|
|
@ -22,14 +23,6 @@ jobs:
|
||||||
pattern: 'refs/tags/v'
|
pattern: 'refs/tags/v'
|
||||||
replace-with: ''
|
replace-with: ''
|
||||||
|
|
||||||
- uses: frabert/replace-string-action@v2
|
|
||||||
name: Extract SemVer (strip prerelease suffix for AssemblyVersion)
|
|
||||||
id: extract_semver
|
|
||||||
with:
|
|
||||||
string: '${{ steps.trim_tag_ref.outputs.replaced }}'
|
|
||||||
pattern: '-.*$'
|
|
||||||
replace-with: ''
|
|
||||||
|
|
||||||
publish:
|
publish:
|
||||||
needs: prep
|
needs: prep
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
|
||||||
111
.github/workflows/LANCommander.Server.yml
vendored
|
|
@ -45,7 +45,7 @@ env:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ${{ inputs.build_platform == 'Linux' && inputs.build_arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
@ -85,9 +85,6 @@ jobs:
|
||||||
npm install --prefix ./LANCommander.UI
|
npm install --prefix ./LANCommander.UI
|
||||||
npm install --prefix ./LANCommander.Server
|
npm install --prefix ./LANCommander.Server
|
||||||
|
|
||||||
- name: Generate PowerShell Completions
|
|
||||||
run: dotnet run --project ./LANCommander.CompletionGenerator/LANCommander.CompletionGenerator.csproj -- ./LANCommander.UI/Components/MonacoCodeEditor/PowerShellCompletions.g.ts
|
|
||||||
|
|
||||||
- name: Package Frontend
|
- name: Package Frontend
|
||||||
run: |
|
run: |
|
||||||
npm run package --prefix ./LANCommander.UI
|
npm run package --prefix ./LANCommander.UI
|
||||||
|
|
@ -96,47 +93,13 @@ jobs:
|
||||||
# .NET builds
|
# .NET builds
|
||||||
- name: Publish Updater and Server
|
- name: Publish Updater and Server
|
||||||
run: |
|
run: |
|
||||||
# Strip leading 'v' if present
|
dotnet publish "./LANCommander.AutoUpdater/LANCommander.AutoUpdater.csproj" -c ${{ inputs.build_configuration }} --self-contained --runtime ${{ inputs.build_runtime }} -p:Version="${{ inputs.version_tag }}" -p:AssemblyVersion="${{ inputs.version_semver }}"
|
||||||
RAW_VERSION="${{ inputs.version_tag }}" # e.g. v2.0.0-rc1
|
dotnet publish "./LANCommander.Server/LANCommander.Server.csproj" -c ${{ inputs.build_configuration }} --self-contained --runtime ${{ inputs.build_runtime }} -p:Version="${{ inputs.version_tag }}" -p:AssemblyVersion="${{ inputs.version_semver }}"
|
||||||
SEMVER="${RAW_VERSION#v}" # 2.0.0-rc1
|
|
||||||
|
|
||||||
# Numeric part only for Assembly/FileVersion
|
|
||||||
NUMERIC="${SEMVER%%-*}" # 2.0.0
|
|
||||||
ASSEMBLY_VERSION="${NUMERIC}.0" # 2.0.0.0
|
|
||||||
|
|
||||||
echo "SEMVER=$SEMVER"
|
|
||||||
echo "ASSEMBLY_VERSION=$ASSEMBLY_VERSION"
|
|
||||||
|
|
||||||
dotnet publish "./LANCommander.AutoUpdater/LANCommander.AutoUpdater.csproj" \
|
|
||||||
-c "${{ inputs.build_configuration }}" \
|
|
||||||
--self-contained \
|
|
||||||
--runtime "${{ inputs.build_runtime }}" \
|
|
||||||
-p:Version="$SEMVER" \
|
|
||||||
-p:AssemblyVersion="$ASSEMBLY_VERSION" \
|
|
||||||
-p:FileVersion="$ASSEMBLY_VERSION" \
|
|
||||||
-p:InformationalVersion="$SEMVER"
|
|
||||||
|
|
||||||
# Disable NetBeauty on ARM64 runners — nbeauty2 only ships x64 native binaries
|
|
||||||
DISABLE_BEAUTY="False"
|
|
||||||
if [ "${{ inputs.build_arch }}" = "arm64" ] && [ "${{ inputs.build_platform }}" = "Linux" ]; then
|
|
||||||
DISABLE_BEAUTY="True"
|
|
||||||
fi
|
|
||||||
|
|
||||||
dotnet publish "./LANCommander.Server/LANCommander.Server.csproj" \
|
|
||||||
-c "${{ inputs.build_configuration }}" \
|
|
||||||
--self-contained \
|
|
||||||
--runtime "${{ inputs.build_runtime }}" \
|
|
||||||
-p:Version="$SEMVER" \
|
|
||||||
-p:AssemblyVersion="$ASSEMBLY_VERSION" \
|
|
||||||
-p:FileVersion="$ASSEMBLY_VERSION" \
|
|
||||||
-p:InformationalVersion="$SEMVER" \
|
|
||||||
-p:DisableBeauty="$DISABLE_BEAUTY"
|
|
||||||
|
|
||||||
|
|
||||||
- name: Bundle and Clean
|
- name: Bundle and Clean
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
Copy-Item -Force -Recurse -Verbose LANCommander.AutoUpdater/bin/${{ inputs.build_configuration }}/net10.0/${{ inputs.build_runtime }}/publish/* LANCommander.Server/bin/${{ inputs.build_configuration }}/net10.0/${{ inputs.build_runtime }}/publish/
|
Copy-Item -Force -Recurse -Verbose LANCommander.AutoUpdater/bin/${{ inputs.build_configuration }}/net9.0/${{ inputs.build_runtime }}/publish/* LANCommander.Server/bin/${{ inputs.build_configuration }}/net9.0/${{ inputs.build_runtime }}/publish/
|
||||||
|
|
||||||
# Remove unnecessary files in a single operation
|
# Remove unnecessary files in a single operation
|
||||||
$PathsToRemove = @(
|
$PathsToRemove = @(
|
||||||
|
|
@ -157,78 +120,16 @@ jobs:
|
||||||
'Libraries/locales'
|
'Libraries/locales'
|
||||||
)
|
)
|
||||||
|
|
||||||
$BasePath = "LANCommander.Server/bin/${{ inputs.build_configuration }}/net10.0/${{ inputs.build_runtime }}/publish"
|
$BasePath = "LANCommander.Server/bin/${{ inputs.build_configuration }}/net9.0/${{ inputs.build_runtime }}/publish"
|
||||||
foreach ($path in $PathsToRemove) {
|
foreach ($path in $PathsToRemove) {
|
||||||
Remove-Item -Recurse -Force -ErrorAction Continue "$BasePath/$path"
|
Remove-Item -Recurse -Force -ErrorAction Continue "$BasePath/$path"
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: Bundle macOS .app
|
|
||||||
if: inputs.build_platform == 'macOS'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Strip leading 'v' and reduce to numeric x.y.z for the bundle version keys.
|
|
||||||
RAW_VERSION="${{ inputs.version_tag }}"
|
|
||||||
SEMVER="${RAW_VERSION#v}"
|
|
||||||
NUMERIC="${SEMVER%%-*}"
|
|
||||||
|
|
||||||
APP_NAME="LANCommander Server"
|
|
||||||
EXECUTABLE="LANCommander.Server"
|
|
||||||
BUNDLE_ID="app.lancommander.server"
|
|
||||||
ICON_SRC="LANCommander.Server/icon.icns"
|
|
||||||
|
|
||||||
PUBLISH_DIR="LANCommander.Server/bin/${{ inputs.build_configuration }}/net10.0/${{ inputs.build_runtime }}/publish"
|
|
||||||
APP_DIR="${EXECUTABLE}.app"
|
|
||||||
|
|
||||||
# Lay out the bundle skeleton.
|
|
||||||
mkdir -p "$APP_DIR/Contents/MacOS" "$APP_DIR/Contents/Resources"
|
|
||||||
cp -a "$PUBLISH_DIR/." "$APP_DIR/Contents/MacOS/"
|
|
||||||
cp "$ICON_SRC" "$APP_DIR/Contents/Resources/AppIcon.icns"
|
|
||||||
|
|
||||||
# Write Info.plist.
|
|
||||||
cat > "$APP_DIR/Contents/Info.plist" <<PLIST
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>${APP_NAME}</string>
|
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>${APP_NAME}</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>${BUNDLE_ID}</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>${EXECUTABLE}</string>
|
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string>AppIcon</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>${NUMERIC}</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>${SEMVER}</string>
|
|
||||||
<key>LSMinimumSystemVersion</key>
|
|
||||||
<string>11.0</string>
|
|
||||||
<key>NSHighResolutionCapable</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
PLIST
|
|
||||||
|
|
||||||
# Ensure the entrypoint is executable, then zip while preserving the
|
|
||||||
# permission bits (Compress-Archive drops the exec bit).
|
|
||||||
chmod +x "$APP_DIR/Contents/MacOS/${EXECUTABLE}"
|
|
||||||
zip -ry "LANCommander.Server-${{ inputs.build_platform }}-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.zip" "$APP_DIR"
|
|
||||||
|
|
||||||
- name: Compress Build Output
|
- name: Compress Build Output
|
||||||
if: inputs.build_platform != 'macOS'
|
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
$compress = @{
|
$compress = @{
|
||||||
Path = "LANCommander.Server/bin/${{ inputs.build_configuration }}/net10.0/${{ inputs.build_runtime }}/publish/*"
|
Path = "LANCommander.Server/bin/${{ inputs.build_configuration }}/net9.0/${{ inputs.build_runtime }}/publish/*"
|
||||||
DestinationPath = "LANCommander.Server-${{ inputs.build_platform }}-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.zip"
|
DestinationPath = "LANCommander.Server-${{ inputs.build_platform }}-${{ inputs.build_arch }}-v${{ inputs.version_tag }}.zip"
|
||||||
CompressionLevel = "Fastest"
|
CompressionLevel = "Fastest"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ jobs:
|
||||||
arch: ['x64', 'arm64']
|
arch: ['x64', 'arm64']
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Get version
|
- name: Get version
|
||||||
id: get_version
|
id: get_version
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
@ -33,19 +33,13 @@ jobs:
|
||||||
# Install Inno Setup
|
# Install Inno Setup
|
||||||
- name: Install Inno Setup
|
- name: Install Inno Setup
|
||||||
run: |
|
run: |
|
||||||
curl -L -o innosetup.exe https://github.com/jrsoftware/issrc/releases/download/is-6_7_3/innosetup-6.7.3.exe
|
curl -L -o innosetup.exe https://files.jrsoftware.org/is/6/innosetup-6.2.2.exe
|
||||||
.\innosetup.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART
|
.\innosetup.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART
|
||||||
shell: cmd
|
shell: cmd
|
||||||
|
|
||||||
# Create Inno Setup script
|
# Create Inno Setup script
|
||||||
- name: Create installer script
|
- name: Create installer script
|
||||||
run: |
|
run: |
|
||||||
$appId = if ('${{ matrix.app }}' -eq 'Server') {
|
|
||||||
'2C58E237-1D69-42A0-B702-F995B75B8A5E'
|
|
||||||
} else {
|
|
||||||
'A3D4F8E1-7B2C-4E5D-9F1A-6C8B3D7E2F4A'
|
|
||||||
}
|
|
||||||
|
|
||||||
@"
|
@"
|
||||||
#define MyAppName "LANCommander ${{ matrix.app }}"
|
#define MyAppName "LANCommander ${{ matrix.app }}"
|
||||||
#define MyAppVersion "${{ env.VERSION }}"
|
#define MyAppVersion "${{ env.VERSION }}"
|
||||||
|
|
@ -55,7 +49,7 @@ jobs:
|
||||||
#define Architecture "${{ matrix.arch }}"
|
#define Architecture "${{ matrix.arch }}"
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppId={{$appId}
|
AppId={{$(New-Guid)}}
|
||||||
AppName={#MyAppName}
|
AppName={#MyAppName}
|
||||||
AppVersion={#MyAppVersion}
|
AppVersion={#MyAppVersion}
|
||||||
AppPublisher={#MyAppPublisher}
|
AppPublisher={#MyAppPublisher}
|
||||||
|
|
@ -100,6 +94,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
app: ['Server', 'Launcher']
|
app: ['Server', 'Launcher']
|
||||||
|
arch: ['x64', 'arm64']
|
||||||
steps:
|
steps:
|
||||||
- name: Get version
|
- name: Get version
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
@ -108,14 +103,8 @@ jobs:
|
||||||
$version = $tag.TrimStart('v')
|
$version = $tag.TrimStart('v')
|
||||||
echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Append
|
echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||||
|
|
||||||
- name: Install wingetcreate
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
Invoke-WebRequest -Uri "https://aka.ms/wingetcreate/latest" -OutFile wingetcreate.exe
|
|
||||||
|
|
||||||
- name: Submit package to Windows Package Manager Community Repository
|
- name: Submit package to Windows Package Manager Community Repository
|
||||||
run: |
|
run: |
|
||||||
$x64Url = "https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/LANCommander.${{ matrix.app }}-${env:VERSION}-x64-Setup.exe"
|
$installerUrl = "https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/LANCommander.${{ matrix.app }}-${env:VERSION}-${{ matrix.arch }}-Setup.exe"
|
||||||
$arm64Url = "https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/LANCommander.${{ matrix.app }}-${env:VERSION}-arm64-Setup.exe"
|
wingetcreate submit --token ${{ secrets.GITHUB_TOKEN }} --urls "$installerUrl" --version ${env:VERSION} LANCommander.LANCommander.${{ matrix.app }}.${{ matrix.arch }}
|
||||||
.\wingetcreate.exe update --submit --token "${{ secrets.WINGET_TOKEN }}" --urls $x64Url $arm64Url --version ${env:VERSION} LANCommander.${{ matrix.app }}
|
shell: pwsh
|
||||||
shell: pwsh
|
|
||||||
22
.gitignore
vendored
|
|
@ -17,6 +17,10 @@
|
||||||
mono_crash.*
|
mono_crash.*
|
||||||
|
|
||||||
# Build results
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
x64/
|
x64/
|
||||||
x86/
|
x86/
|
||||||
[Aa][Rr][Mm]/
|
[Aa][Rr][Mm]/
|
||||||
|
|
@ -364,21 +368,3 @@ LANCommander.Server/LANCommander.db*
|
||||||
LANCommander.Server/wwwroot/css/custom.css
|
LANCommander.Server/wwwroot/css/custom.css
|
||||||
LANCommander.Server/wwwroot/css/app.css*
|
LANCommander.Server/wwwroot/css/app.css*
|
||||||
LANCommander.Launcher/wwwroot/css/app.css*
|
LANCommander.Launcher/wwwroot/css/app.css*
|
||||||
LANCommander.Launcher/wwwroot/css/main.js
|
|
||||||
LANCommander.Server/wwwroot/css/main.js
|
|
||||||
|
|
||||||
.aspire
|
|
||||||
LANCommander.Server/config/
|
|
||||||
LANCommander.UI/wwwroot/
|
|
||||||
LANCommander.UI/Components/MonacoCodeEditor/PowerShellCompletions.g.ts
|
|
||||||
LANCommander.Server/Data/
|
|
||||||
|
|
||||||
LANCommander.Launcher.Avalonia/Data/
|
|
||||||
|
|
||||||
Data/
|
|
||||||
|
|
||||||
# Visual test output — screenshots & diffs are CI artifacts, not committed.
|
|
||||||
# Baselines/ is committed; everything else is transient.
|
|
||||||
LANCommander.Launcher.Avalonia.Tests/Screenshots/
|
|
||||||
LANCommander.Launcher.Avalonia.Tests/Diffs/
|
|
||||||
visual-test-output/
|
|
||||||
|
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
# Contributing to LANCommander
|
|
||||||
|
|
||||||
Thanks for your interest in contributing to LANCommander! This project is primarily developed by a single developer, so community contributions are greatly appreciated.
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
- [.NET 10.0 SDK](https://dotnet.microsoft.com/download/dotnet/10.0)
|
|
||||||
- [Node.js](https://nodejs.org/) (for the server UI's TypeScript/SCSS assets)
|
|
||||||
- A code editor such as [Visual Studio](https://visualstudio.microsoft.com/), [Rider](https://www.jetbrains.com/rider/), or [VS Code](https://code.visualstudio.com/)
|
|
||||||
|
|
||||||
### Building the Project
|
|
||||||
|
|
||||||
1. Clone the repository:
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/LANCommander/LANCommander.git
|
|
||||||
cd LANCommander
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Restore dependencies:
|
|
||||||
```bash
|
|
||||||
dotnet restore
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Build the server:
|
|
||||||
```bash
|
|
||||||
dotnet build LANCommander.Server
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Build the launcher:
|
|
||||||
```bash
|
|
||||||
dotnet build LANCommander.Launcher
|
|
||||||
```
|
|
||||||
|
|
||||||
### Running Locally
|
|
||||||
|
|
||||||
To run the server in development mode:
|
|
||||||
```bash
|
|
||||||
dotnet run --project LANCommander.Server
|
|
||||||
```
|
|
||||||
|
|
||||||
The server will be available at `http://localhost:1337` by default.
|
|
||||||
|
|
||||||
## How to Contribute
|
|
||||||
|
|
||||||
### Reporting Bugs
|
|
||||||
|
|
||||||
Use the [GitHub Issues](https://github.com/LANCommander/LANCommander/issues) page with the bug report template. Include:
|
|
||||||
- Steps to reproduce the issue
|
|
||||||
- Expected vs. actual behavior
|
|
||||||
- Your OS and LANCommander version
|
|
||||||
- Relevant logs or screenshots
|
|
||||||
|
|
||||||
### Submitting Changes
|
|
||||||
|
|
||||||
1. Fork the repository
|
|
||||||
2. Create a feature branch from `main` (`git checkout -b my-feature`)
|
|
||||||
3. Make your changes
|
|
||||||
4. Test your changes locally
|
|
||||||
5. Commit with a clear, descriptive message
|
|
||||||
6. Push to your fork and open a Pull Request
|
|
||||||
|
|
||||||
### What to Work On
|
|
||||||
|
|
||||||
- Check [open issues](https://github.com/LANCommander/LANCommander/issues) for bugs or feature requests
|
|
||||||
- Documentation improvements are always welcome at our [documentation site](https://docs.lancommander.app/)
|
|
||||||
- Game packaging scripts and guides for the community
|
|
||||||
|
|
||||||
### Code Guidelines
|
|
||||||
|
|
||||||
- Follow existing code style and conventions in the project
|
|
||||||
- Keep PRs focused, one feature or fix per PR when possible
|
|
||||||
- Include screenshots in your PR if you're changing UI
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
| Directory | Description |
|
|
||||||
|-----------|-------------|
|
|
||||||
| `LANCommander.Server` | ASP.NET Blazor web application (server/admin) |
|
|
||||||
| `LANCommander.Launcher` | Avalonia desktop client (launcher) |
|
|
||||||
| `LANCommander.Packager` | Game packaging tool |
|
|
||||||
| `LANCommander.SDK` | .NET SDK for building custom clients |
|
|
||||||
| `LANCommander.Server.Data` | Entity Framework data models and migrations |
|
|
||||||
| `LANCommander.Server.Services` | Server business logic |
|
|
||||||
| `LANCommander.Documentation` | Docusaurus documentation site |
|
|
||||||
|
|
||||||
## Community
|
|
||||||
|
|
||||||
- [Discord](https://discord.gg/vDEEWVt8EM): Best place for discussion, help, and sharing game packages
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
By contributing to LANCommander, you agree that your contributions will be licensed under the [MIT License](LICENSE).
|
|
||||||
|
|
@ -1,191 +0,0 @@
|
||||||
<Project>
|
|
||||||
<PropertyGroup>
|
|
||||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup Label="Aspire">
|
|
||||||
<PackageVersion Include="Aspire.Hosting.AppHost" Version="9.5.0" />
|
|
||||||
<PackageVersion Include="AvaloniaUI.DiagnosticsSupport" Version="2.1.1" />
|
|
||||||
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
|
||||||
<PackageVersion Include="EasyMDE.Blazor" Version="1.0.5" />
|
|
||||||
<PackageVersion Include="HotAvalonia" Version="3.1.0" />
|
|
||||||
<PackageVersion Include="LiveChartsCore" Version="2.0.0-rc5.4" />
|
|
||||||
<PackageVersion Include="LiveChartsCore.SkiaSharpView" Version="2.0.0-rc5.4" />
|
|
||||||
<PackageVersion Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.0-rc5.4" />
|
|
||||||
<PackageVersion Include="Markdig" Version="0.44.0" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Logging.Configuration" Version="9.0.8" />
|
|
||||||
<PackageVersion Include="Notify.NET" Version="1.1.0" />
|
|
||||||
<PackageVersion Include="Svrooij.PowerShell.DI" Version="1.3.4" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="AutoMapper">
|
|
||||||
<PackageVersion Include="AutoMapper" Version="14.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="AntDesign">
|
|
||||||
<PackageVersion Include="AntDesign" Version="1.5.0" />
|
|
||||||
<PackageVersion Include="AntDesign.Charts" Version="0.8.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="Blazor">
|
|
||||||
<PackageVersion Include="BlazorMonaco" Version="3.4.0" />
|
|
||||||
<PackageVersion Include="BootstrapBlazor.PdfReader" Version="9.0.1" />
|
|
||||||
<PackageVersion Include="PSC.Blazor.Components.MarkdownEditor" Version="8.0.8" />
|
|
||||||
<PackageVersion Include="Razor.Templating.Core" Version="2.1.0" />
|
|
||||||
<PackageVersion Include="XtermBlazor" Version="2.1.2" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="Utility">
|
|
||||||
<PackageVersion Include="ByteSize" Version="2.1.2" />
|
|
||||||
<PackageVersion Include="CaseConverter" Version="2.0.1" />
|
|
||||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
|
||||||
<PackageVersion Include="HtmlAgilityPack" Version="1.11.72" />
|
|
||||||
<PackageVersion Include="Crc32.NET" Version="1.2.0" />
|
|
||||||
<PackageVersion Include="Emzi0767.NtfsDataStreams" Version="1.0.0" />
|
|
||||||
<PackageVersion Include="PeanutButter.INI" Version="3.0.396" />
|
|
||||||
<PackageVersion Include="Superpower" Version="3.1.0" />
|
|
||||||
<PackageVersion Include="RegParserDotNet" Version="1.1.1" />
|
|
||||||
<PackageVersion Include="nulastudio.NetBeauty" Version="2.1.4.6" />
|
|
||||||
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
|
|
||||||
<PackageVersion Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="ASP.NET Core">
|
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Components.Web" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.0" />
|
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.1" />
|
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Identity.UI" Version="9.0.1" />
|
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.1" />
|
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="9.0.1" />
|
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.1" />
|
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client.SourceGenerator" Version="7.0.0-preview.7.22376.6" />
|
|
||||||
<PackageVersion Include="Scalar.AspNetCore" Version="2.0.11" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="Code Analysis">
|
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis" Version="4.12.0" />
|
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="4.12.0" />
|
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
|
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.12.0" />
|
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.12.0" />
|
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Features" Version="4.12.0" />
|
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Scripting.Common" Version="4.12.0" />
|
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.12.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="Testing">
|
|
||||||
<PackageVersion Include="bunit" Version="1.40.0" />
|
|
||||||
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
|
|
||||||
<PackageVersion Include="Microsoft.Playwright" Version="1.51.0" />
|
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
|
||||||
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
|
|
||||||
<PackageVersion Include="Microsoft.TypeScript.MSBuild" Version="5.7.1" />
|
|
||||||
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
|
|
||||||
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0" />
|
|
||||||
<PackageVersion Include="Moq" Version="4.20.72" />
|
|
||||||
<PackageVersion Include="Shouldly" Version="4.3.0" />
|
|
||||||
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.11" />
|
|
||||||
<PackageVersion Include="Syncfusion.PdfToImageConverter.Net" Version="28.2.4" />
|
|
||||||
<PackageVersion Include="Xunit.Extensions.TestDependency" Version="1.1.0" />
|
|
||||||
<PackageVersion Include="xunit" Version="2.9.3" />
|
|
||||||
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="External">
|
|
||||||
<PackageVersion Include="CoreRCON" Version="5.0.5" />
|
|
||||||
<PackageVersion Include="LANCommander.HQ.SDK" Version="1.0.1" />
|
|
||||||
<PackageVersion Include="craftersmine.SteamGridDB.Net" Version="1.1.7" />
|
|
||||||
<PackageVersion Include="YoutubeExplode" Version="6.4.3" />
|
|
||||||
<PackageVersion Include="Docker.DotNet.Enhanced" Version="3.129.0" />
|
|
||||||
<PackageVersion Include="Facepunch.Steamworks" Version="2.3.3" />
|
|
||||||
<PackageVersion Include="IGDB" Version="6.1.0" />
|
|
||||||
<PackageVersion Include="IPXRelayDotNet" Version="1.1.3" />
|
|
||||||
<PackageVersion Include="LANCommander.Interposer" Version="1.0.7" />
|
|
||||||
<PackageVersion Include="Octokit" Version="14.0.0" />
|
|
||||||
<PackageVersion Include="RestSharp" Version="112.1.0" />
|
|
||||||
<PackageVersion Include="rix0rrr.BeaconLib" Version="1.0.2" />
|
|
||||||
<PackageVersion Include="Semver" Version="3.0.0" />
|
|
||||||
<PackageVersion Include="SharpCompress" Version="0.50.0" />
|
|
||||||
<PackageVersion Include="SteamWebAPI2" Version="4.4.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="Entity Framework Core">
|
|
||||||
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0" />
|
|
||||||
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="Hangfire">
|
|
||||||
<PackageVersion Include="Hangfire.AspNetCore" Version="1.8.17" />
|
|
||||||
<PackageVersion Include="Hangfire.Core" Version="1.8.17" />
|
|
||||||
<PackageVersion Include="Hangfire.InMemory" Version="1.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="PowerShell">
|
|
||||||
<PackageVersion Include="Microsoft.PowerShell.Commands.Diagnostics" Version="7.4.7" />
|
|
||||||
<PackageVersion Include="Microsoft.PowerShell.SDK" Version="7.4.7" />
|
|
||||||
<PackageVersion Include="System.Management.Automation" Version="7.4.7" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="Microsoft Extensions">
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="9.0.8" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.1" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Hosting.Systemd" Version="9.0.1" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.1" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.0" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="9.7.0" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Localization" Version="9.0.0" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.1" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.1" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.9" />
|
|
||||||
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="9.4.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="OpenTelemetry">
|
|
||||||
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
|
|
||||||
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
|
|
||||||
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
|
|
||||||
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
|
|
||||||
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="LibVLC">
|
|
||||||
<PackageVersion Include="LibVLCSharp" Version="3.8.5" />
|
|
||||||
<PackageVersion Include="LibVLCSharp.Avalonia" Version="3.8.5" />
|
|
||||||
<PackageVersion Include="VideoLAN.LibVLC.Windows" Version="3.0.23.1" />
|
|
||||||
<PackageVersion Include="VideoLAN.LibVLC.Mac" Version="3.1.3.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="SDL">
|
|
||||||
<PackageVersion Include="ppy.SDL3-CS" Version="2026.520.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="Photino">
|
|
||||||
<PackageVersion Include="AsyncImageLoader.Avalonia" Version="3.3.0" />
|
|
||||||
<PackageVersion Include="Avalonia" Version="11.2.3" />
|
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.2.3" />
|
|
||||||
<PackageVersion Include="Avalonia.Headless" Version="11.2.3" />
|
|
||||||
<PackageVersion Include="Avalonia.Headless.XUnit" Version="11.2.3" />
|
|
||||||
<PackageVersion Include="Avalonia.Themes.Fluent" Version="11.2.3" />
|
|
||||||
<PackageVersion Include="Avalonia.Fonts.Inter" Version="11.2.3" />
|
|
||||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.3" />
|
|
||||||
<PackageVersion Include="Avalonia.Controls.ItemsRepeater" Version="11.1.5" />
|
|
||||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.2.0.2" />
|
|
||||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
|
||||||
<PackageVersion Include="PDFtoImage" Version="4.1.1" />
|
|
||||||
<PackageVersion Include="Photino.Blazor" Version="4.0.13" />
|
|
||||||
<PackageVersion Include="Photino.Blazor.CustomWindow" Version="1.3.1" />
|
|
||||||
<PackageVersion Include="Photino.NET" Version="4.0.16" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="System">
|
|
||||||
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.1" />
|
|
||||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.3.1" />
|
|
||||||
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.0" />
|
|
||||||
<PackageVersion Include="System.Text.Json" Version="9.0.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="Caching">
|
|
||||||
<PackageVersion Include="ZiggyCreatures.FusionCache" Version="2.1.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Label="Overlay">
|
|
||||||
<PackageVersion Include="Avalonia.Skia" Version="11.2.3" />
|
|
||||||
<PackageVersion Include="Reloaded.Hooks" Version="4.3.0" />
|
|
||||||
<PackageVersion Include="DNNE" Version="2.1.0" />
|
|
||||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
BIN
Docs/AddGame.gif
Normal file
|
After Width: | Height: | Size: 2.9 MiB |
BIN
Docs/ArchiveUploading.gif
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
Docs/ChangeKey.png
Normal file
|
After Width: | Height: | Size: 647 KiB |
BIN
Docs/Dashboard.gif
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
Docs/EditingScript.gif
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
Docs/GamesList.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
Docs/InstallingGames.gif
Normal file
|
After Width: | Height: | Size: 12 MiB |
BIN
Docs/KeyManagement.gif
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
Docs/PlayniteAuthentication.png
Normal file
|
After Width: | Height: | Size: 119 KiB |
|
|
@ -4,14 +4,14 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<UserSecretsId>0899617b-b319-465d-aaaf-aac7ea333029</UserSecretsId>
|
<UserSecretsId>0899617b-b319-465d-aaaf-aac7ea333029</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Aspire.Hosting.AppHost" />
|
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.4.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<PublishSingleFile>true</PublishSingleFile>
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\LANCommander.SDK\LANCommander.SDK.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
|
|
@ -1,512 +0,0 @@
|
||||||
using System.Management.Automation;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using LANCommander.SDK.PowerShell.Extensions;
|
|
||||||
|
|
||||||
if (args.Length == 0)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine("Usage: LANCommander.CompletionGenerator <output-path>");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var outputPath = args[0];
|
|
||||||
|
|
||||||
var assembly = typeof(InitialSessionStateExtensions).Assembly;
|
|
||||||
|
|
||||||
var cmdletTypes = assembly.GetTypes()
|
|
||||||
.Where(t => t.GetCustomAttribute<CmdletAttribute>() != null)
|
|
||||||
.OrderBy(t => t.GetCustomAttribute<CmdletAttribute>()!.VerbName + "-" + t.GetCustomAttribute<CmdletAttribute>()!.NounName);
|
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.AppendLine("// Auto-generated by LANCommander.CompletionGenerator — do not edit manually");
|
|
||||||
sb.AppendLine();
|
|
||||||
sb.AppendLine("export interface CmdletParameter {");
|
|
||||||
sb.AppendLine(" name: string;");
|
|
||||||
sb.AppendLine(" type: string;");
|
|
||||||
sb.AppendLine(" mandatory: boolean;");
|
|
||||||
sb.AppendLine(" position: number | null;");
|
|
||||||
sb.AppendLine(" helpMessage: string | null;");
|
|
||||||
sb.AppendLine(" aliases: string[];");
|
|
||||||
sb.AppendLine("}");
|
|
||||||
sb.AppendLine();
|
|
||||||
sb.AppendLine("export interface CmdletDefinition {");
|
|
||||||
sb.AppendLine(" name: string;");
|
|
||||||
sb.AppendLine(" description: string | null;");
|
|
||||||
sb.AppendLine(" outputType: string | null;");
|
|
||||||
sb.AppendLine(" parameters: CmdletParameter[];");
|
|
||||||
sb.AppendLine("}");
|
|
||||||
sb.AppendLine();
|
|
||||||
sb.AppendLine("export const cmdlets: CmdletDefinition[] = [");
|
|
||||||
|
|
||||||
foreach (var type in cmdletTypes)
|
|
||||||
{
|
|
||||||
var cmdletAttr = type.GetCustomAttribute<CmdletAttribute>()!;
|
|
||||||
var name = $"{cmdletAttr.VerbName}-{cmdletAttr.NounName}";
|
|
||||||
|
|
||||||
var outputTypeAttr = type.GetCustomAttribute<OutputTypeAttribute>();
|
|
||||||
string? outputType = null;
|
|
||||||
if (outputTypeAttr?.Type?.Length > 0)
|
|
||||||
outputType = GetFriendlyTypeName(outputTypeAttr.Type[0].Type);
|
|
||||||
|
|
||||||
// Use XML doc summary if available via the Summary property pattern, otherwise use null
|
|
||||||
var descriptionLines = type.GetCustomAttributes()
|
|
||||||
.Where(a => a.GetType().Name == "DescriptionAttribute")
|
|
||||||
.Select(a => a.GetType().GetProperty("Description")?.GetValue(a)?.ToString())
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
// Fall back to XML summary comment — not available via reflection, use class summary convention
|
|
||||||
string? description = descriptionLines;
|
|
||||||
|
|
||||||
sb.AppendLine(" {");
|
|
||||||
sb.AppendLine($" name: {JsonEncode(name)},");
|
|
||||||
sb.AppendLine($" description: {JsonEncode(description)},");
|
|
||||||
sb.AppendLine($" outputType: {JsonEncode(outputType)},");
|
|
||||||
sb.AppendLine(" parameters: [");
|
|
||||||
|
|
||||||
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
|
||||||
.Where(p => p.GetCustomAttribute<ParameterAttribute>() != null)
|
|
||||||
.OrderBy(p =>
|
|
||||||
{
|
|
||||||
var pa = p.GetCustomAttribute<ParameterAttribute>()!;
|
|
||||||
return pa.Position == int.MinValue ? int.MaxValue : pa.Position;
|
|
||||||
})
|
|
||||||
.ThenBy(p => p.Name);
|
|
||||||
|
|
||||||
foreach (var prop in properties)
|
|
||||||
{
|
|
||||||
var paramAttr = prop.GetCustomAttribute<ParameterAttribute>()!;
|
|
||||||
var aliasAttr = prop.GetCustomAttribute<AliasAttribute>();
|
|
||||||
var aliases = aliasAttr?.AliasNames?.ToArray() ?? Array.Empty<string>();
|
|
||||||
var position = paramAttr.Position == int.MinValue ? (int?)null : paramAttr.Position;
|
|
||||||
|
|
||||||
sb.AppendLine(" {");
|
|
||||||
sb.AppendLine($" name: {JsonEncode(prop.Name)},");
|
|
||||||
sb.AppendLine($" type: {JsonEncode(GetFriendlyTypeName(prop.PropertyType))},");
|
|
||||||
sb.AppendLine($" mandatory: {(paramAttr.Mandatory ? "true" : "false")},");
|
|
||||||
sb.AppendLine($" position: {(position.HasValue ? position.Value.ToString() : "null")},");
|
|
||||||
sb.AppendLine($" helpMessage: {JsonEncode(paramAttr.HelpMessage)},");
|
|
||||||
sb.AppendLine($" aliases: [{string.Join(", ", aliases.Select(a => JsonEncode(a)))}],");
|
|
||||||
sb.AppendLine(" },");
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine(" ],");
|
|
||||||
sb.AppendLine(" },");
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine("];");
|
|
||||||
sb.AppendLine();
|
|
||||||
|
|
||||||
// Generate built-in PowerShell cmdlet completions from core modules
|
|
||||||
var builtinCmdletNames = new HashSet<string>(cmdletTypes.Select(t =>
|
|
||||||
{
|
|
||||||
var a = t.GetCustomAttribute<CmdletAttribute>()!;
|
|
||||||
return $"{a.VerbName}-{a.NounName}";
|
|
||||||
}));
|
|
||||||
|
|
||||||
Console.WriteLine("Enumerating built-in PowerShell cmdlets...");
|
|
||||||
|
|
||||||
sb.AppendLine("export const builtinCmdlets: CmdletDefinition[] = [");
|
|
||||||
|
|
||||||
var builtinCount = 0;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Use external pwsh process for full module metadata and help access
|
|
||||||
var psScript = @"
|
|
||||||
$commonParams = @(
|
|
||||||
'Verbose','Debug','ErrorAction','WarningAction','InformationAction',
|
|
||||||
'ErrorVariable','WarningVariable','InformationVariable','OutVariable',
|
|
||||||
'OutBuffer','PipelineVariable','ProgressAction','Confirm','WhatIf'
|
|
||||||
)
|
|
||||||
|
|
||||||
$modules = @(
|
|
||||||
'Microsoft.PowerShell.Management',
|
|
||||||
'Microsoft.PowerShell.Utility',
|
|
||||||
'Microsoft.PowerShell.Security',
|
|
||||||
'Microsoft.PowerShell.Archive'
|
|
||||||
)
|
|
||||||
|
|
||||||
$results = @()
|
|
||||||
|
|
||||||
# Get command names from core modules, then resolve each individually for full metadata
|
|
||||||
$commandNames = Get-Command -CommandType Cmdlet,Function -Module $modules -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name -Unique
|
|
||||||
|
|
||||||
foreach ($cmdName in $commandNames) {
|
|
||||||
$cmd = Get-Command $cmdName -ErrorAction SilentlyContinue
|
|
||||||
if (-not $cmd) { continue }
|
|
||||||
|
|
||||||
$synopsis = $null
|
|
||||||
try {
|
|
||||||
$h = Get-Help $cmdName -ErrorAction SilentlyContinue
|
|
||||||
if ($h -and $h.Synopsis) {
|
|
||||||
$s = $h.Synopsis.Trim()
|
|
||||||
# Skip if synopsis is just the cmdlet name, or looks like syntax (contains parameter notation)
|
|
||||||
if ($s -ne $cmdName -and $s -notmatch '\[[-<]' -and $s -notmatch '-\w+\s+<') {
|
|
||||||
$synopsis = $s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
$outputType = $null
|
|
||||||
if ($cmd.OutputType -and $cmd.OutputType.Count -gt 0 -and $cmd.OutputType[0].Type) {
|
|
||||||
$outputType = $cmd.OutputType[0].Type.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
$params = @()
|
|
||||||
if ($cmd.Parameters) {
|
|
||||||
foreach ($key in $cmd.Parameters.Keys) {
|
|
||||||
if ($key -in $commonParams) { continue }
|
|
||||||
|
|
||||||
$p = $cmd.Parameters[$key]
|
|
||||||
$pAttr = $p.Attributes | Where-Object { $_ -is [System.Management.Automation.ParameterAttribute] } | Select-Object -First 1
|
|
||||||
$mandatory = $false
|
|
||||||
$position = $null
|
|
||||||
$helpMsg = $null
|
|
||||||
|
|
||||||
if ($pAttr) {
|
|
||||||
$mandatory = [bool]$pAttr.Mandatory
|
|
||||||
if ($pAttr.Position -ne [int]::MinValue) {
|
|
||||||
$position = $pAttr.Position
|
|
||||||
}
|
|
||||||
if ($pAttr.HelpMessage) {
|
|
||||||
$helpMsg = $pAttr.HelpMessage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$aliases = @($p.Aliases)
|
|
||||||
|
|
||||||
$params += @{
|
|
||||||
n = $key
|
|
||||||
t = $p.ParameterType.Name
|
|
||||||
m = $mandatory
|
|
||||||
pos = $position
|
|
||||||
h = $helpMsg
|
|
||||||
a = $aliases
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$results += @{
|
|
||||||
name = $cmdName
|
|
||||||
desc = $synopsis
|
|
||||||
out = $outputType
|
|
||||||
params = $params
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$results | ConvertTo-Json -Depth 4 -Compress
|
|
||||||
";
|
|
||||||
|
|
||||||
// Write the script to a temp file to avoid stdin encoding issues
|
|
||||||
var tempScript = Path.GetTempFileName() + ".ps1";
|
|
||||||
File.WriteAllText(tempScript, psScript, new UTF8Encoding(false));
|
|
||||||
|
|
||||||
var psi = new System.Diagnostics.ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = "pwsh",
|
|
||||||
Arguments = $"-NoProfile -NonInteractive -ExecutionPolicy Bypass -File \"{tempScript}\"",
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
UseShellExecute = false,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clear .NET SDK environment variables that can interfere with pwsh's module loading
|
|
||||||
foreach (var key in Environment.GetEnvironmentVariables().Keys.Cast<string>()
|
|
||||||
.Where(k => k.StartsWith("DOTNET_", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
k.StartsWith("MSBuild", StringComparison.OrdinalIgnoreCase)))
|
|
||||||
{
|
|
||||||
psi.Environment[key] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var process = System.Diagnostics.Process.Start(psi)!;
|
|
||||||
|
|
||||||
var json = process.StandardOutput.ReadToEnd();
|
|
||||||
var stderr = process.StandardError.ReadToEnd();
|
|
||||||
process.WaitForExit(120_000);
|
|
||||||
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(stderr))
|
|
||||||
Console.Error.WriteLine($" pwsh stderr: {stderr.Trim()}");
|
|
||||||
|
|
||||||
try { File.Delete(tempScript); } catch { }
|
|
||||||
|
|
||||||
if (process.ExitCode != 0)
|
|
||||||
throw new Exception($"pwsh exited with code {process.ExitCode}");
|
|
||||||
|
|
||||||
using var doc = JsonDocument.Parse(json);
|
|
||||||
var root = doc.RootElement;
|
|
||||||
|
|
||||||
// Handle both array and single-object responses
|
|
||||||
var elements = root.ValueKind == JsonValueKind.Array
|
|
||||||
? root.EnumerateArray().ToList()
|
|
||||||
: new List<JsonElement> { root };
|
|
||||||
|
|
||||||
foreach (var cmd in elements.OrderBy(e => e.GetProperty("name").GetString()))
|
|
||||||
{
|
|
||||||
var name = cmd.GetProperty("name").GetString()!;
|
|
||||||
if (builtinCmdletNames.Contains(name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
string? description = null;
|
|
||||||
if (cmd.TryGetProperty("desc", out var descEl) && descEl.ValueKind == JsonValueKind.String)
|
|
||||||
description = descEl.GetString();
|
|
||||||
|
|
||||||
string? outputTypeName = null;
|
|
||||||
if (cmd.TryGetProperty("out", out var outEl) && outEl.ValueKind == JsonValueKind.String)
|
|
||||||
outputTypeName = MapTypeName(outEl.GetString()!);
|
|
||||||
|
|
||||||
sb.AppendLine(" {");
|
|
||||||
sb.AppendLine($" name: {JsonEncode(name)},");
|
|
||||||
sb.AppendLine($" description: {JsonEncode(description)},");
|
|
||||||
sb.AppendLine($" outputType: {JsonEncode(outputTypeName)},");
|
|
||||||
sb.AppendLine(" parameters: [");
|
|
||||||
|
|
||||||
if (cmd.TryGetProperty("params", out var paramsEl) && paramsEl.ValueKind == JsonValueKind.Array)
|
|
||||||
{
|
|
||||||
// Sort: positional first, then alphabetical
|
|
||||||
var paramList = paramsEl.EnumerateArray().ToList();
|
|
||||||
paramList.Sort((a, b) =>
|
|
||||||
{
|
|
||||||
var posA = a.TryGetProperty("pos", out var pa) && pa.ValueKind == JsonValueKind.Number ? pa.GetInt32() : int.MaxValue;
|
|
||||||
var posB = b.TryGetProperty("pos", out var pb) && pb.ValueKind == JsonValueKind.Number ? pb.GetInt32() : int.MaxValue;
|
|
||||||
var cmp = posA.CompareTo(posB);
|
|
||||||
if (cmp != 0) return cmp;
|
|
||||||
return string.Compare(
|
|
||||||
a.GetProperty("n").GetString(),
|
|
||||||
b.GetProperty("n").GetString(),
|
|
||||||
StringComparison.Ordinal);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var param in paramList)
|
|
||||||
{
|
|
||||||
var paramName = param.GetProperty("n").GetString()!;
|
|
||||||
var typeName = MapTypeName(param.GetProperty("t").GetString() ?? "object");
|
|
||||||
var mandatory = param.TryGetProperty("m", out var mEl) && mEl.ValueKind == JsonValueKind.True;
|
|
||||||
|
|
||||||
string? posStr = "null";
|
|
||||||
if (param.TryGetProperty("pos", out var posEl) && posEl.ValueKind == JsonValueKind.Number)
|
|
||||||
posStr = posEl.GetInt32().ToString();
|
|
||||||
|
|
||||||
string? helpMessage = null;
|
|
||||||
if (param.TryGetProperty("h", out var hEl) && hEl.ValueKind == JsonValueKind.String)
|
|
||||||
helpMessage = hEl.GetString();
|
|
||||||
|
|
||||||
var aliases = new List<string>();
|
|
||||||
if (param.TryGetProperty("a", out var aEl) && aEl.ValueKind == JsonValueKind.Array)
|
|
||||||
{
|
|
||||||
foreach (var alias in aEl.EnumerateArray())
|
|
||||||
{
|
|
||||||
if (alias.ValueKind == JsonValueKind.String)
|
|
||||||
aliases.Add(alias.GetString()!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine(" {");
|
|
||||||
sb.AppendLine($" name: {JsonEncode(paramName)},");
|
|
||||||
sb.AppendLine($" type: {JsonEncode(typeName)},");
|
|
||||||
sb.AppendLine($" mandatory: {(mandatory ? "true" : "false")},");
|
|
||||||
sb.AppendLine($" position: {posStr},");
|
|
||||||
sb.AppendLine($" helpMessage: {JsonEncode(helpMessage)},");
|
|
||||||
sb.AppendLine($" aliases: [{string.Join(", ", aliases.Select(a => JsonEncode(a)))}],");
|
|
||||||
sb.AppendLine(" },");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine(" ],");
|
|
||||||
sb.AppendLine(" },");
|
|
||||||
builtinCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine($"Warning: Failed to enumerate built-in cmdlets: {ex.Message}");
|
|
||||||
Console.Error.WriteLine("Ensure 'pwsh' (PowerShell 7+) is installed and on PATH.");
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine("];");
|
|
||||||
sb.AppendLine();
|
|
||||||
|
|
||||||
// Generate type definitions for complex objects used as script variables
|
|
||||||
var variableTypes = new Dictionary<string, Type>
|
|
||||||
{
|
|
||||||
["GameManifest"] = typeof(LANCommander.SDK.Models.Manifest.Game),
|
|
||||||
["ToolManifest"] = typeof(LANCommander.SDK.Models.Manifest.Tool),
|
|
||||||
["RedistributableManifest"] = typeof(LANCommander.SDK.Models.Manifest.Redistributable),
|
|
||||||
["Server"] = typeof(LANCommander.SDK.Models.Server),
|
|
||||||
["Game"] = typeof(LANCommander.SDK.Models.Game),
|
|
||||||
["User"] = typeof(LANCommander.SDK.Models.User),
|
|
||||||
["Tool"] = typeof(LANCommander.SDK.Models.Tool),
|
|
||||||
["Redistributable"] = typeof(LANCommander.SDK.Models.Redistributable),
|
|
||||||
};
|
|
||||||
|
|
||||||
sb.AppendLine("export interface TypeProperty {");
|
|
||||||
sb.AppendLine(" name: string;");
|
|
||||||
sb.AppendLine(" type: string;");
|
|
||||||
sb.AppendLine("}");
|
|
||||||
sb.AppendLine();
|
|
||||||
sb.AppendLine("export interface TypeDefinition {");
|
|
||||||
sb.AppendLine(" name: string;");
|
|
||||||
sb.AppendLine(" properties: TypeProperty[];");
|
|
||||||
sb.AppendLine("}");
|
|
||||||
sb.AppendLine();
|
|
||||||
sb.AppendLine("export const variableTypes: TypeDefinition[] = [");
|
|
||||||
|
|
||||||
foreach (var (typeName, clrType) in variableTypes.OrderBy(kv => kv.Key))
|
|
||||||
{
|
|
||||||
sb.AppendLine(" {");
|
|
||||||
sb.AppendLine($" name: {JsonEncode(typeName)},");
|
|
||||||
sb.AppendLine(" properties: [");
|
|
||||||
|
|
||||||
var props = clrType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
|
||||||
.Where(p => p.CanRead)
|
|
||||||
.OrderBy(p => p.Name);
|
|
||||||
|
|
||||||
foreach (var prop in props)
|
|
||||||
{
|
|
||||||
sb.AppendLine(" {");
|
|
||||||
sb.AppendLine($" name: {JsonEncode(prop.Name)},");
|
|
||||||
sb.AppendLine($" type: {JsonEncode(GetPropertyTypeName(prop.PropertyType))},");
|
|
||||||
sb.AppendLine(" },");
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine(" ],");
|
|
||||||
sb.AppendLine(" },");
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine("];");
|
|
||||||
sb.AppendLine();
|
|
||||||
|
|
||||||
// Generate ScriptType enum values
|
|
||||||
sb.AppendLine("export const scriptTypeValues: string[] = [");
|
|
||||||
foreach (var value in Enum.GetNames<LANCommander.SDK.Enums.ScriptType>())
|
|
||||||
{
|
|
||||||
sb.AppendLine($" {JsonEncode(value)},");
|
|
||||||
}
|
|
||||||
sb.AppendLine("];");
|
|
||||||
|
|
||||||
var directory = Path.GetDirectoryName(outputPath);
|
|
||||||
if (!string.IsNullOrEmpty(directory))
|
|
||||||
Directory.CreateDirectory(directory);
|
|
||||||
|
|
||||||
File.WriteAllText(outputPath, sb.ToString(), Encoding.UTF8);
|
|
||||||
|
|
||||||
Console.WriteLine($"Generated completions for {cmdletTypes.Count()} LANCommander cmdlets, {builtinCount} built-in cmdlets, and {variableTypes.Count} variable types -> {outputPath}");
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
static string JsonEncode(string? value)
|
|
||||||
{
|
|
||||||
if (value == null) return "null";
|
|
||||||
return JsonSerializer.Serialize(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static string GetPropertyTypeName(Type type)
|
|
||||||
{
|
|
||||||
var underlying = Nullable.GetUnderlyingType(type);
|
|
||||||
if (underlying != null)
|
|
||||||
return GetPropertyTypeName(underlying) + "?";
|
|
||||||
|
|
||||||
if (type.IsArray)
|
|
||||||
return GetPropertyTypeName(type.GetElementType()!) + "[]";
|
|
||||||
|
|
||||||
if (type.IsGenericType)
|
|
||||||
{
|
|
||||||
var genericDef = type.GetGenericTypeDefinition();
|
|
||||||
if (genericDef == typeof(IEnumerable<>) || genericDef == typeof(ICollection<>) ||
|
|
||||||
genericDef == typeof(List<>) || genericDef == typeof(IList<>))
|
|
||||||
{
|
|
||||||
var elementType = type.GetGenericArguments()[0];
|
|
||||||
return GetPropertyTypeName(elementType) + "[]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check non-generic IEnumerable
|
|
||||||
if (type != typeof(string) && type.GetInterfaces().Any(i =>
|
|
||||||
i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
|
|
||||||
{
|
|
||||||
var elementType = type.GetInterfaces()
|
|
||||||
.First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
|
||||||
.GetGenericArguments()[0];
|
|
||||||
return GetPropertyTypeName(elementType) + "[]";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == typeof(string)) return "string";
|
|
||||||
if (type == typeof(int) || type == typeof(long)) return "int";
|
|
||||||
if (type == typeof(uint)) return "uint";
|
|
||||||
if (type == typeof(double) || type == typeof(float)) return "double";
|
|
||||||
if (type == typeof(bool)) return "bool";
|
|
||||||
if (type == typeof(Guid)) return "Guid";
|
|
||||||
if (type == typeof(DateTime)) return "DateTime";
|
|
||||||
if (type == typeof(Uri)) return "Uri";
|
|
||||||
if (type.IsEnum) return type.Name;
|
|
||||||
|
|
||||||
return type.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string MapTypeName(string typeName) => typeName switch
|
|
||||||
{
|
|
||||||
"String" => "string",
|
|
||||||
"Int32" => "int",
|
|
||||||
"Int64" => "long",
|
|
||||||
"UInt32" => "uint",
|
|
||||||
"Double" => "double",
|
|
||||||
"Single" => "float",
|
|
||||||
"Boolean" => "bool",
|
|
||||||
"Byte" => "byte",
|
|
||||||
"Guid" => "Guid",
|
|
||||||
"Uri" => "Uri",
|
|
||||||
"DateTime" => "DateTime",
|
|
||||||
"Object" => "object",
|
|
||||||
"SwitchParameter" => "SwitchParameter",
|
|
||||||
"SecureString" => "SecureString",
|
|
||||||
"String[]" => "string[]",
|
|
||||||
"Int32[]" => "int[]",
|
|
||||||
"Object[]" => "object[]",
|
|
||||||
"Byte[]" => "byte[]",
|
|
||||||
"PSObject" => "object",
|
|
||||||
"PSObject[]" => "object[]",
|
|
||||||
"Hashtable" => "Hashtable",
|
|
||||||
"ScriptBlock" => "ScriptBlock",
|
|
||||||
"TimeSpan" => "TimeSpan",
|
|
||||||
"PSCredential" => "PSCredential",
|
|
||||||
_ => typeName,
|
|
||||||
};
|
|
||||||
|
|
||||||
static string GetFriendlyTypeName(Type? type)
|
|
||||||
{
|
|
||||||
if (type == null) return "object";
|
|
||||||
|
|
||||||
// Handle nullable types
|
|
||||||
var underlying = Nullable.GetUnderlyingType(type);
|
|
||||||
if (underlying != null)
|
|
||||||
return GetFriendlyTypeName(underlying) + "?";
|
|
||||||
|
|
||||||
// Handle arrays
|
|
||||||
if (type.IsArray)
|
|
||||||
return GetFriendlyTypeName(type.GetElementType()) + "[]";
|
|
||||||
|
|
||||||
// Handle SwitchParameter
|
|
||||||
if (type == typeof(SwitchParameter))
|
|
||||||
return "SwitchParameter";
|
|
||||||
|
|
||||||
// Handle common types
|
|
||||||
if (type == typeof(string)) return "string";
|
|
||||||
if (type == typeof(int)) return "int";
|
|
||||||
if (type == typeof(long)) return "long";
|
|
||||||
if (type == typeof(uint)) return "uint";
|
|
||||||
if (type == typeof(double)) return "double";
|
|
||||||
if (type == typeof(float)) return "float";
|
|
||||||
if (type == typeof(bool)) return "bool";
|
|
||||||
if (type == typeof(byte)) return "byte";
|
|
||||||
if (type == typeof(byte[])) return "byte[]";
|
|
||||||
if (type == typeof(Guid)) return "Guid";
|
|
||||||
if (type == typeof(Uri)) return "Uri";
|
|
||||||
if (type == typeof(object)) return "object";
|
|
||||||
|
|
||||||
// Handle SecureString
|
|
||||||
if (type == typeof(System.Security.SecureString))
|
|
||||||
return "SecureString";
|
|
||||||
|
|
||||||
return type.Name;
|
|
||||||
}
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
---
|
|
||||||
id: GettingStarted
|
|
||||||
sidebar_label: Getting Started
|
|
||||||
sidebar_position: 2
|
|
||||||
---
|
|
||||||
|
|
||||||
# Getting Started
|
|
||||||
|
|
||||||
This guide will walk you through setting up LANCommander from scratch — from installing the server to connecting your first client and adding games to your library.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Install the Server
|
|
||||||
|
|
||||||
The LANCommander server is available as pre-built binaries for Windows, Linux, and macOS (x86 and ARM), as well as a Docker container.
|
|
||||||
|
|
||||||
### Docker (Recommended)
|
|
||||||
|
|
||||||
The easiest way to get started is with Docker. See the [Docker deployment guide](/Server/Installation/Docker) for a full walkthrough, including a sample `docker-compose.yml`.
|
|
||||||
|
|
||||||
### Binary
|
|
||||||
|
|
||||||
1. Download the latest release for your platform from the [GitHub Releases page](https://github.com/LANCommander/LANCommander/releases).
|
|
||||||
2. Extract the archive to a directory of your choice (e.g. `C:\LANCommander` on Windows or `/opt/lancommander` on Linux).
|
|
||||||
3. Run the server executable:
|
|
||||||
- **Windows:** `LANCommander.Server.exe`
|
|
||||||
- **Linux / macOS:** `./LANCommander.Server`
|
|
||||||
4. The server will start and listen on port **1337** by default.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Initial Server Setup
|
|
||||||
|
|
||||||
Once the server is running, open a browser and navigate to `http://<server-address>:1337`.
|
|
||||||
|
|
||||||
On first launch you will be prompted to create an administrator account. Fill in a username and password, then click **Create**. These credentials will be used to log in to the server's web interface.
|
|
||||||
|
|
||||||
After creating your account you will be taken to the main dashboard where you can begin configuring your library.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Install the Launcher
|
|
||||||
|
|
||||||
The LANCommander launcher is the desktop client your users will use to browse, install, and play games.
|
|
||||||
|
|
||||||
1. Download the latest launcher release for your platform from the [GitHub Releases page](https://github.com/LANCommander/LANCommander/releases).
|
|
||||||
2. Extract and run the launcher executable.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Connect the Launcher to the Server
|
|
||||||
|
|
||||||
When the launcher opens for the first time you will be presented with a login screen.
|
|
||||||
|
|
||||||
1. Enter the address of your LANCommander server (e.g. `http://192.168.1.100:1337`).
|
|
||||||
- If the launcher is on the same network as the server and beaconing is enabled, the server will appear automatically in the **Discovered Servers** list.
|
|
||||||
2. Enter your username and password, then click **Login**.
|
|
||||||
- If you don't have an account yet, click **Register** to create one (requires registration to be enabled on the server).
|
|
||||||
3. After logging in, the launcher will sync your accessible game library from the server.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Add Games to the Library
|
|
||||||
|
|
||||||
Games are managed from the server's web interface.
|
|
||||||
|
|
||||||
1. Log in to the server at `http://<server-address>:1337`.
|
|
||||||
2. Navigate to **Games** in the sidebar.
|
|
||||||
3. Click **Add Game** and fill in the game's details (title, metadata, cover art, etc.).
|
|
||||||
4. Upload the game archive or point to an existing archive on disk.
|
|
||||||
5. Optionally configure [scripts](/Scripting/Overview) (install, uninstall, key change, etc.) for the game.
|
|
||||||
|
|
||||||
Once a game is added and made accessible to users, it will appear in the launcher after the next sync.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
- [Server Documentation](/Server/Overview) — detailed server configuration, redistributables, collections, and more
|
|
||||||
- [Launcher Documentation](/Launcher/Overview) — launcher features including the download queue, filtering, and script debugging
|
|
||||||
- [Scripting](/Scripting/Overview) — automate game setup with PowerShell scripts
|
|
||||||
- [SDK Documentation](/SDK/Overview) — integrate LANCommander into your own applications
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
# Launcher
|
|
||||||
## Overview
|
|
||||||
The official LANCommander launcher is a desktop application built in ASP.NET Blazor and was designed to be easy to use and familiar. By providing a custom launcher, LANCommander is able to provide a tight integration between the server and any authenticated client.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Logging In
|
|
||||||
When opening the launcher for the first time, users will be presented with an authentication screen. From here they will have to enter the LANCommander server address and their credentials. If the launcher is running on the same network as the server, the **Discovered Servers** pane will show any available servers (if beaconing is enabled. See [Server / Settings](/docs/Server/Settings) for more details).
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
If the user does not have an account registered on the server, they can register either directly in-launcher by clicking the **Register** button, or the server's web UI.
|
|
||||||
|
|
||||||
After logging in, the launcher will immediately start syncing the user's accessible games from the server. Once the sync is complete the user is free to start installing any games listed.
|
|
||||||
|
|
||||||
## Changing the Install Location
|
|
||||||
By default, the launcher will install games to `C:\Games` on Windows. This can be changed in settings by hovering over your username in the top right and clicking **Settings** in the dropdown.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
If you have more than one storage path specified for games, you will be asked upon install which path you would like to install the game to.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Filtering Games
|
|
||||||
By clicking the filter icon in the bottom right, you can filter games based on specific criteria. This metadata is pulled in directly from the game's configuration on the server.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Download Queue
|
|
||||||
The launcher has the ability to queue up multiple game installs by utilizing a download queue. Simply start installing multiple games and click the bottom bar to see the queue's current progress.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Refreshing Games
|
|
||||||
If a new game is available or a user's list of accessible games has changed, click the import button at the top of the application next to the user's name to sync the list of games from the server.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Script Debugging
|
|
||||||
Developing scripts for games is often a process of trial and error. When the setting **Enable Script Debugging** is enabled in the launcher, users will be given the ability to execute any configured scripts for a game without having to reinstall.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Additionally, a terminal will show at the bottom of the launcher after the script has executed. This is a limited PowerShell runspace and will allow for basic debugging of scripts and provides a history of the execution. Any variables that were passed into the script are also listed for visibility.
|
|
||||||
|
|
||||||

|
|
||||||
|
Before Width: | Height: | Size: 558 KiB |
|
Before Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 195 KiB |
|
|
@ -1,30 +0,0 @@
|
||||||
---
|
|
||||||
sidebar_label: Overview
|
|
||||||
sidebar_position: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
# Introduction
|
|
||||||
LANCommander is an open source digital game distribution platform. In essence, it's a ways to self-host your own game library ala Steam, GOG, Epic, etc.
|
|
||||||
|
|
||||||
Both the server and custom launcher applications are built using the ASP.NET Blazor web application framework. Binaries are provided for Windows, Linux, and macOS supporting both x86 and ARM architectures. The server also has a preconfigured Docker container for easier deployment.
|
|
||||||
|
|
||||||
The platform is designed to work on local networks and loads no assets from the internet when installing games from the launcher. It was originally developer to help assist deploying games at a LAN party where the local network was closed circuit and no internet access was permitted. The server can also be accessed publicly, though use of a reverse proxy or VPN is recommended.
|
|
||||||
|
|
||||||
# Development
|
|
||||||
Code can be viewed over at the project's [GitHub page](https://github.com/LANCommander/LANCommander). This is where new releases will be posted and also serves as the main issue tracker.
|
|
||||||
|
|
||||||
The Docker container is available over at [Docker Hub](https://hub.docker.com/r/lancommander/lancommander) and automatically gets updated with each version release through our CI/CD pipeline.
|
|
||||||
|
|
||||||
# Community
|
|
||||||
The community behind LANCommander is small, but extremely knowledgeable. Most support and troubleshooting questions stem from discussions in the official [Discord server](https://discord.gg/vDEEWVt8EM). There is also a forum within the server where users post freeware and shareware games that can be directly imported into your LANCommander server.
|
|
||||||
|
|
||||||
If you would like to support the project, there is a [Patreon page](https://patreon.com/LANCommander) available with a couple paid tiers as well as a free tier. This also serves as a general blog for the project with news about development.
|
|
||||||
|
|
||||||
# Installation and Use
|
|
||||||
This site serves as the main documentation platform for the project. As such, it is recommended to check out the following resources:
|
|
||||||
- [Getting Started](/GettingStarted)
|
|
||||||
- [Server](/Server/Overview)
|
|
||||||
- [Launcher](/Launcher/Overview)
|
|
||||||
- [Packager](/Packager/Overview)
|
|
||||||
- [Scripting](/Scripting/Overview)
|
|
||||||
- [SDK Documentation](/SDK/Overview)
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
---
|
|
||||||
sidebar_label: Getting Started
|
|
||||||
sidebar_position: 2
|
|
||||||
---
|
|
||||||
|
|
||||||
# Getting Started
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- **Windows 10 or later** (x86 or x64)
|
|
||||||
- **Administrator privileges** - the Packager requires elevation to monitor installer processes via DLL injection
|
|
||||||
|
|
||||||
The Packager is distributed as a single 32-bit executable (`LANCommander.Packager.exe`). No installation is required.
|
|
||||||
|
|
||||||
## Download
|
|
||||||
|
|
||||||
Download the latest release from the [GitHub Releases page](https://github.com/LANCommander/LANCommander/releases). The Packager artifact is named `LANCommander.Packager-Windows-x86-v{VERSION}.zip`.
|
|
||||||
|
|
||||||
Extract the archive to a directory of your choice and run `LANCommander.Packager.exe`.
|
|
||||||
|
|
||||||
## Command-Line Usage
|
|
||||||
|
|
||||||
The Packager can optionally accept arguments to skip the initial file picker dialog:
|
|
||||||
|
|
||||||
```
|
|
||||||
LANCommander.Packager.exe [installer-path] [-o output-path]
|
|
||||||
```
|
|
||||||
|
|
||||||
| Argument | Description |
|
|
||||||
|:--------:|:------------|
|
|
||||||
| `installer-path` | Path to the installer executable to monitor |
|
|
||||||
| `-o`, `--output` | Path for the output `.lcx` file |
|
|
||||||
|
|
||||||
If no installer path is provided, a file picker dialog will appear on launch.
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
---
|
|
||||||
sidebar_label: LCX Package Format
|
|
||||||
sidebar_position: 4
|
|
||||||
---
|
|
||||||
|
|
||||||
# LCX Package Format
|
|
||||||
|
|
||||||
An `.LCX` file is a standard ZIP archive containing everything needed to install and configure a game through LANCommander. The Packager generates this format automatically, but understanding its structure is useful for troubleshooting or manual editing.
|
|
||||||
|
|
||||||
## Archive Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
package.lcx (ZIP)
|
|
||||||
├── manifest.yaml # Game metadata (YAML)
|
|
||||||
├── Archives/
|
|
||||||
│ └── {guid} # Inner ZIP containing game files
|
|
||||||
└── Scripts/
|
|
||||||
├── {guid} # Install script (PowerShell)
|
|
||||||
└── {guid} # Uninstall script (PowerShell)
|
|
||||||
```
|
|
||||||
|
|
||||||
### manifest.yaml
|
|
||||||
|
|
||||||
The manifest is a YAML file describing the game's metadata, actions, archive references, and script references. It follows the LANCommander SDK's `Game` manifest schema and includes:
|
|
||||||
|
|
||||||
- **Title, Sort Title, Version, Description, Notes** - basic metadata
|
|
||||||
- **Released On, Singleplayer** - classification
|
|
||||||
- **Directory Name** - the expected install directory name
|
|
||||||
- **Actions** - launch configurations (name, executable path, arguments, primary flag)
|
|
||||||
- **Archives** - references to inner archive entries with compressed/uncompressed sizes
|
|
||||||
- **Scripts** - references to script entries with type (Install/Uninstall) and admin requirements
|
|
||||||
|
|
||||||
### Archives
|
|
||||||
|
|
||||||
The `Archives/` directory contains one or more inner ZIP files, each identified by a GUID. The inner archive holds the game files with paths relative to the install directory root.
|
|
||||||
|
|
||||||
### Scripts
|
|
||||||
|
|
||||||
The `Scripts/` directory contains PowerShell scripts identified by GUID. The Packager generates up to two scripts:
|
|
||||||
|
|
||||||
**Install Script** - Recreates registry keys and values captured during monitoring. If the Patch GameSpy option was enabled, it also includes an `Edit-PatchGameSpy` call. Scripts assume `$InstallDirectory` is available in the execution environment (provided by the launcher's PowerShell runtime).
|
|
||||||
|
|
||||||
**Uninstall Script** - Removes the registry keys and values that were created by the install script.
|
|
||||||
|
|
||||||
## Importing into LANCommander
|
|
||||||
|
|
||||||
`.LCX` packages can be imported directly through the LANCommander server's web interface. The server reads the manifest, extracts the archive and scripts, and creates the corresponding game entry with all metadata, actions, and scripts pre-configured.
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
---
|
|
||||||
sidebar_label: Overview
|
|
||||||
sidebar_position: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
# Packager
|
|
||||||
|
|
||||||
The LANCommander Packager is a standalone Windows utility that automates the creation of `.LCX` game packages. It monitors a game installer as it runs, captures all file and registry changes, and guides you through a wizard to produce a ready-to-import package for your LANCommander server.
|
|
||||||
|
|
||||||
Instead of manually creating archives, writing install scripts, and filling out metadata by hand, the Packager handles all of this in a single guided workflow.
|
|
||||||
|
|
||||||
- [Getting Started](/Packager/Getting%20Started) - requirements, download, and command-line usage
|
|
||||||
- [Wizard Walkthrough](/Packager/Wizard) - step-by-step guide through the seven wizard stages
|
|
||||||
- [LCX Package Format](/Packager/LCX%20Format) - internal structure of `.LCX` files
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
---
|
|
||||||
sidebar_label: Wizard Walkthrough
|
|
||||||
sidebar_position: 3
|
|
||||||
---
|
|
||||||
|
|
||||||
# Wizard Walkthrough
|
|
||||||
|
|
||||||
The Packager walks you through seven steps to create a complete `.LCX` package. Each step is shown in the sidebar with a progress indicator.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 1: Monitor Installer
|
|
||||||
|
|
||||||
After selecting an installer executable, the Packager launches it and monitors all file and registry activity using native DLL injection (Interposer). A real-time log displays captured events as the installer runs.
|
|
||||||
|
|
||||||
The Packager automatically:
|
|
||||||
- Detects the installer's architecture (32-bit or 64-bit) and injects the appropriate Interposer DLL
|
|
||||||
- Monitors child processes spawned by the installer
|
|
||||||
- Filters out writes to system directories (Windows, temp folders)
|
|
||||||
- Captures both file writes and registry key/value creation
|
|
||||||
|
|
||||||
Once the installer exits, the captured data is summarized in the status bar. Click **Next** to continue.
|
|
||||||
|
|
||||||
:::info
|
|
||||||
The log view continues to show captured events for reference. All diagnostic output is also written to `packager.log` in the application directory.
|
|
||||||
:::
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 2: Install Directory
|
|
||||||
|
|
||||||
The Packager analyzes the captured file writes to detect the game's installation directory. This is determined by finding the most common non-system directory among the written files.
|
|
||||||
|
|
||||||
If the detected directory is incorrect, click **Browse** to manually select the correct location. This directory becomes the root of the game archive.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 3: Select Files
|
|
||||||
|
|
||||||
All files within the install directory are displayed in a tree view with checkboxes. By default, every file is selected.
|
|
||||||
|
|
||||||
- **Check/uncheck a directory** to toggle all files within it
|
|
||||||
- **Select All** / **Select None** buttons at the top for bulk operations
|
|
||||||
- The counter at the top shows how many files are currently selected
|
|
||||||
|
|
||||||
Files outside the install directory (if any were captured) are listed by their full paths. Only files that still exist on disk at this point are shown.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 4: Registry Entries
|
|
||||||
|
|
||||||
All captured registry writes are displayed in a tree view organized by hive and key path. Entries are deduplicated so if the same key and value were written multiple times during installation, only one entry is shown.
|
|
||||||
|
|
||||||
Each leaf entry displays an indicator:
|
|
||||||
- **Green +** - the entry was created during installation
|
|
||||||
- **Yellow ~** - the entry was updated (written to an existing key)
|
|
||||||
|
|
||||||
Selected entries will be included in the auto-generated install and uninstall scripts. The install script recreates the registry keys and values; the uninstall script removes them.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 5: Game Metadata
|
|
||||||
|
|
||||||
Enter basic information about the game. The title is pre-populated from the installer's filename.
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
|:------|:------------|
|
|
||||||
| **Title** | Display name of the game (required) |
|
|
||||||
| **Sort Title** | Optional override for alphabetical sorting |
|
|
||||||
| **Version** | Game version, defaults to `1.0` |
|
|
||||||
| **Released On** | Release date of the game |
|
|
||||||
| **Singleplayer** | Whether the game supports singleplayer |
|
|
||||||
| **Description** | A description of the game |
|
|
||||||
| **Notes** | Private notes (admin-only, not shown to users) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 6: Game Executable
|
|
||||||
|
|
||||||
The Packager scans your selected files for `.exe` files and filters out common installer/redistributable executables (e.g. `vcredist`, `dxsetup`, `setup`, `unins`). The remaining executables are displayed in a list.
|
|
||||||
|
|
||||||
Select the primary game executable. This is the file the launcher will run when the user clicks "Play". You can also customize:
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
|:------|:------------|
|
|
||||||
| **Action Name** | Label shown on the play button, defaults to `Play` |
|
|
||||||
| **Arguments** | Command-line arguments passed when launching |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 7: Generate Package
|
|
||||||
|
|
||||||
Configure the output path for the `.LCX` file and optionally adjust packaging options before generating.
|
|
||||||
|
|
||||||
### Output Path
|
|
||||||
|
|
||||||
The default output path is based on the game title in the current working directory. Click **Browse** to choose a different location.
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
Expand the **Options** panel to configure additional settings:
|
|
||||||
|
|
||||||
| Option | Description |
|
|
||||||
|:-------|:------------|
|
|
||||||
| **Patch GameSpy** | Adds an `Edit-PatchGameSpy -Path $InstallDirectory` call to the install script. This scans the install directory for GameSpy references and patches them for OpenSpy compatibility. |
|
|
||||||
| **Compression Level** | Controls the trade-off between archive size and packaging speed. Options: Optimal (default), Fastest, No Compression, Smallest Size. |
|
|
||||||
| **Write Summary Log** | Writes a `.Package.log` file alongside the `.LCX` output documenting the source installer, selected files, registry entries, metadata, and options used. |
|
|
||||||
|
|
||||||
Click **Generate .LCX** to build the package. A progress bar shows the current stage:
|
|
||||||
1. Creating game files archive
|
|
||||||
2. Generating scripts
|
|
||||||
3. Writing manifest
|
|
||||||
|
|
||||||
On completion, the output path and file size are displayed.
|
|
||||||
|
|
@ -1,175 +0,0 @@
|
||||||
---
|
|
||||||
title: 1.0.0
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
|
|
||||||
# Server
|
|
||||||
## Database Overhaul
|
|
||||||
For some big news, the server now supports MySQL and PostgreSQL as database providers! SQLite support is still available as well for anyone that wants to keep their setup simple.
|
|
||||||
|
|
||||||
In order to support multiple database providers, the data layer of the application has been rebuilt from the ground up. Due to the way that Blazor SSR handles database contexts, this was a necessary and arduous process and was the source of the most time put into this release. That being said, lazy loading in Entity Framework has been removed. This means that almost every query across the application has been optimized and will run faster while consuming fewer resources.
|
|
||||||
|
|
||||||
:::info
|
|
||||||
Support for MySQL and PostgreSQL should be considered experimental. Make sure to keep regular backups as there is a non-zero chance of data loss.
|
|
||||||
:::
|
|
||||||
|
|
||||||
#### Caching
|
|
||||||
Many areas of the application now utilize a cache where speed is paramount. Most of these improvements will be seen in the API and loading data from the server in the launcher. Redis support is also being looked at for taking one more step to allowing distributed server configurations.
|
|
||||||
|
|
||||||
#### Authentication
|
|
||||||
OAuth/OIDC identity providers can now be defined in Settings. No restrictions are imposed, and an "Account Link" functionality has been added to the web UI for existing users. Yes, you read that right, there's no SSO tax!
|
|
||||||
|
|
||||||
Some provider templates have been provided, but have not been fully vetted. Keep in mind that most IDPs require SSL for authentication. We'll talk about that a little later, but it's still recommend to use a reverse proxy or products like Cloudflare Zero Trust to provide a robust and secure solution.
|
|
||||||
|
|
||||||
### New Login / Registration Design
|
|
||||||
The login and registration pages have been redesigned to be a bit more attractive while supporting new authentication features. A new button for downloading the launcher has been added as well!
|
|
||||||
|
|
||||||
These downloads can be provided directly via the server if **Host Client Updates** is set under Settings / Launcher. Your supported architectures and platforms can be customized as well.
|
|
||||||
|
|
||||||
:::info
|
|
||||||
Support for launchers on Linux and macOS are still experimental
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Logging
|
|
||||||
The available logging providers are now able to be fully configured from Settings / Logging. Support for remote logging with Seq or Elastic search has been added. For now this only is supported on the server, but in the future this information may be broadcasted to clients using the launcher in order to collect user logs if desired.
|
|
||||||
|
|
||||||
## Redistributable Scripting
|
|
||||||
Additional script types of Name Change, Before Start, and After Stop are now available to redistributables. These script types work the same as if they were defined for games, but they are shared with any game that has the redistributable as a dependency.
|
|
||||||
|
|
||||||
Redistributable archives will now be extracted to the game's `.lancommander` directory under its own directory matching its ID (e.g. `.lancommander\d3355f4a-870e-4964-a5a3-832a8d8a6b3f\Files`). These files are then cleaned up once install has completed.
|
|
||||||
|
|
||||||
## Game Custom Fields
|
|
||||||
Custom fields have been added to games and can be used in scripts (game and redistributable), actions (games and servers), and save paths. These are loaded like any other variable with their name set as-is. For example, if you wanted to have a game custom field of `AppId`, you could use it in a script as `$AppId` or in an action/save path as `{AppId}`.
|
|
||||||
|
|
||||||
## Server Process Tracking
|
|
||||||
Some game servers would fail to have their process tracked correctly. This has been revamped and the server's entire process tree will now be tracked. This should resolve any issue previously seen where a server could be started from LANCommander, and then would immediately stop while still actually running on the host machine.
|
|
||||||
|
|
||||||
## Datatables
|
|
||||||
Most datatables throughout the web UI have been reworked and should be faster, while supporting column customization. This is an area that will be continued to be improved upon with the potential for individual column searching and filtering being a possiblity in the future.
|
|
||||||
|
|
||||||
## Image Optimization
|
|
||||||
Images for media are now optimized on application start and upload. This results in faster downloads for the launcher. The following optimizations are currently implemented:
|
|
||||||
- PNGs with no alpha pixels are converted to JPG
|
|
||||||
- "Thumbnails" are generated with a JPG quality of 75
|
|
||||||
- "Thumbnails" are generated with a max width/height based on type. Refer to [Thumbnail Generation]() for more information.
|
|
||||||
|
|
||||||
## Multiple Upload Locations
|
|
||||||
An often-requested feature has been to allow for the uploading of archives to multiple locations on the host. This has now been implemented and is available for configuration in the First Time Setup or Settings / Archives.
|
|
||||||
|
|
||||||
Please note that in order to keep track of archives properly, a random GUID is still used as the uploaded archive's name. It is not recommended to alter these files once they've been uploaded.
|
|
||||||
|
|
||||||
## HTTPS Support
|
|
||||||
SSL support for Kestrel (the underlying HTTP server) can now be defined in Settings / General. Most OAuth/OIDC providers will require HTTPS for redirects.
|
|
||||||
|
|
||||||
## Stylesheets
|
|
||||||
The CSS for the web UI can now be customized under Settings / Appearance. A separate stylesheet only for Pages can also be defined.
|
|
||||||
|
|
||||||
## PowerShell Scripting
|
|
||||||
The following cmdlets have been added to the scripting engine:
|
|
||||||
- `Get-HorizontalFov`
|
|
||||||
- `Get-VerticalFov`
|
|
||||||
- `Out-PlayerAvatar`
|
|
||||||
|
|
||||||
Review the [Cmdlets](/Scripting/Cmdlets) documentation for more information and usage.
|
|
||||||
|
|
||||||
## Fixes and Minor Improvements
|
|
||||||
- Updated to .NET 9
|
|
||||||
- Text alignment in select inputs has been fixed
|
|
||||||
- Uploading large files with the chunk uploader should now be more reliable
|
|
||||||
- Archive file sizes will now calculate properly on upload
|
|
||||||
- Searched images can now be double clicked to select
|
|
||||||
- Login / registration pages have been reworked to support authentication providers
|
|
||||||
- Documentation and social icons have been added to the main menu
|
|
||||||
- Cookie policy can now be customized in Settings
|
|
||||||
- Fatal errors in the UI should now be caught without having to reload the page
|
|
||||||
- Scripts for installing the application as a service have been provided
|
|
||||||
|
|
||||||
## Breaking Changes
|
|
||||||
- In supporting multiple upload paths, configuration has moved from `Settings.yml` to the database. Your current path should have migrated on update, but you should probably double check it.
|
|
||||||
- Redistributable scripts will now execute out of the game's `.lancommander\<Redistributable ID>\Files` directory
|
|
||||||
|
|
||||||
# Launcher
|
|
||||||
## Depot and User Library
|
|
||||||
On start of the launcher, you'll probably notice that you have no games listed. Fear not! Your games are not gone, your library is just empty. By clicking on the "Depot" button you'll be able to browse and filter the games from the server. From here games can be installed directly or added to your library.
|
|
||||||
|
|
||||||
User libraries are tracked by the server and synced locally to the launcher. This also means that logging into the launcher on another machine will sync your user library. For admins, games in the depot will also be filtered based on accessible collections and role permissions so you can curate as much or as little as needed.
|
|
||||||
|
|
||||||
## Addon Installation
|
|
||||||
When installing a game that has expansions and/or mods defined, a new dialog will display allowing you to select what to install:
|
|
||||||

|
|
||||||
Keep in mind that this does not apply to standalone expansions or standalone mods. For a refresher on game types, check out [Server / Games](/Server/Games).
|
|
||||||
|
|
||||||
This dialog will show expected download and install sizes in addition to selectable install directories (if configured). Did you forget to select an addon when first installing? No worries! Under the game's context menu use the "Modify" option to display this dialog again. You can even move the game to another defined location if so desired.
|
|
||||||
|
|
||||||
## File Validation
|
|
||||||
A new tool for validating files has been added to the game context menu. This will compare the game files on your local install to contents of the game's archive on the server. Individual files can be selected for restore. File validation on install has now been improved to increase download speed in the case valid existing files are found on disk. This is fairly basic at the moment, but should hopefully help to fix some broken game installs.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Authentication / Offline Mode
|
|
||||||
The main authentication form has been redesigned to allow for OAuth/OIDC authentication providers defined by the server. As is customary with these sorts of implementations, you will first have to put in your server address (or select from beaconing servers) and then you will be presented with all login options.
|
|
||||||
|
|
||||||
Offline mode has been revamped and should work more consistently. The launcher will actively monitor its connection to the server and automatically turn on offline mode if the connection is lost.
|
|
||||||
|
|
||||||
## Importing
|
|
||||||
Speed improvements and optimizations have been made to importing to drastically reduce the time to do a full import. Hovering over the import icon will also display an import status progress popup. Individual game information is cached server-side, so subsequent imports by other users should be faster.
|
|
||||||
|
|
||||||
## Save Management
|
|
||||||
A new dialog for save management is now accessible under the game's context menu. This can be used to download or delete specific saves from the server, or upload the current machine's save files to the server.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Fixes and Minor Improvements
|
|
||||||
- Updated to .NET 9
|
|
||||||
- Redistributable installs will now show download progress
|
|
||||||
- Linux/macOS builds should now load assets correctly (non-Windows builds are still experimental)
|
|
||||||
- Game process tracking will now track the entire process tree
|
|
||||||
- Play Session recording has been fixed
|
|
||||||
- Download / install size is now displayed in the game's status bar
|
|
||||||
- Filtering, sorting, and grouping should be more reliable
|
|
||||||
- Progress will now be shown for in-progress installs of mods and expansions
|
|
||||||
- Game status should now be reflected properly in the main action button
|
|
||||||
- Server-defined actions should now display properly
|
|
||||||
- Total play session status displayed per game will now only show the authenticated user's total
|
|
||||||
- Loading game info on library list click should now be much faster
|
|
||||||
- Library image assets should now download from server's optimized image files, reducing download time and overall size
|
|
||||||
- A search field has been added to the library list and filter
|
|
||||||
- Library items can now be sorted
|
|
||||||
- Errors when searching for lobbies will now gracefully fail
|
|
||||||
- Fatal errors will no longer completely hang the UI
|
|
||||||
|
|
||||||
# Infrastructure
|
|
||||||
|
|
||||||
## Nightlies
|
|
||||||
Nightly builds are now available over at [GitHub](https://github.com/LANCommander/LANCommander/actions/workflows/LANCommander.Nightly.yml). Docker images are also available via [GitHub Packages](https://github.com/LANCommander/LANCommander/pkgs/container/lancommander).
|
|
||||||
|
|
||||||
## Docker Multi-Architecture Support
|
|
||||||
The Docker images pushed to Docker Hub now support Linux/ARM64! That's it!
|
|
||||||
|
|
||||||
## WinGet
|
|
||||||
An effort is being made to make the server and launcher available as WinGet packages with the names `LANCommander.Server` and `LANCommander.Launcher`. These packages are generated on the fly as part of the CI/CD pipeline, so the latest version should always be available.
|
|
||||||
|
|
||||||
# On Deck
|
|
||||||
There's a few large features being worked on / designed that will possibly make it into future builds as we kick off 2025:
|
|
||||||
- Docker support for game servers
|
|
||||||
- Game server config templates / structured forms (human-friendly UI for server configs!)
|
|
||||||
- VPN integrations
|
|
||||||
- P2P / distributed file transfers
|
|
||||||
- Script templates
|
|
||||||
- Friend list / chat
|
|
||||||
- Game overlay
|
|
||||||
- Rebuilt autoupdater
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v1.1.0" />
|
|
||||||
|
|
||||||
# Community
|
|
||||||
Lastly, I'd like to shout out the community. This was LANCommander's biggest year of growth in users and features. We saw the introduction of a new launcher, the deprecation of the Playnite extension, and tons of features added along the way. Many of these came as suggestions from our community, and seeing all of your LAN parties has really shown that there's something to this little project.
|
|
||||||
|
|
||||||
There's one part of the community I'd like to give a shoutout to. A group of Aussies have banded together to establish a support network for men called **DadLAN**. They've been able to grow substantially over the past couple of years and have been making headlines down under. I really feel like they represent what LAN parties are all about and why they're so important to gaming culture. For more information, check out their site over at https://dadlan.au/!
|
|
||||||
|
|
||||||
I'd also like to take this moment to shill a bit and ask for any contribution you can spare. Whether it's contributing on [GitHub](https://github.com/LANCommander/LANCommander), helping out in the [Discord](https://discord.gg/vDEEWVt8EM), or, if you're able, subscribing to one of the paid [Patreon](https://www.patreon.com/c/LANCommander) tiers. Any amount of effort goes a long way towards bringing you this excellent piece of software!
|
|
||||||
|
|
||||||
Until next time, keep on being Bawlers!
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
---
|
|
||||||
title: 1.1.5
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
|
|
||||||
## Server
|
|
||||||
- Fixed an issue where the IPX relay would cause high CPU usage if started/stopped multiple times (#200)
|
|
||||||
- Fixed the autostart of the IPX relay (#188)
|
|
||||||
- Fixed save uploading (#190)
|
|
||||||
- Settings / Scripts are now saved properly (#194)
|
|
||||||
- Game servers will now be more responsive when using the start/stop control buttons (#198)
|
|
||||||
- Fixed importing of companies when importing metadata from IGDB (#201)
|
|
||||||
- Fixed importing of games from local files (#203)
|
|
||||||
- Fixed first time setup creation of administrator user (#206)
|
|
||||||
- Added graceful error handling for Depot (#210)
|
|
||||||
- Added additional paths to first time setup
|
|
||||||
- Fixed error when adding media (#216)
|
|
||||||
- Fixed update of tables on various entities (#218, #224)
|
|
||||||
- Updated Dockerfile to be based off Microsoft's official .NET base Docker images
|
|
||||||
- Administrator step is skipped on first time setup if one already exists
|
|
||||||
- Fixed user custom fields not being shown when editing a user
|
|
||||||
- Moved the "Restrict Games By Collection" switch to Settings / Library
|
|
||||||
- Users datatable is now searchable
|
|
||||||
- Fixed logging on IPX relay if enabled
|
|
||||||
- Fixed some areas where the Created By and Created On fields were not getting populated
|
|
||||||
- Added API menu item to Settings for OpenAPI/Scalar integration
|
|
||||||
- Reworked downloading of launcher artifacts from GitHub (note, this is still iffy. It's hard to test this until releases are actually posted. Downloading launchers for nightlies is still a WIP)
|
|
||||||
- Times are now rendered as local time based on the user's browser locale.
|
|
||||||
|
|
||||||
## Launcher
|
|
||||||
- New: The server address field will now also try other possible valid URLs if the address input is invalid or incomplete. See [#208](https://github.com/LANCommander/LANCommander/issues/208#issuecomment-2712374078) for more details
|
|
||||||
- Fixed: The "Manage Saves" dialog no longer crashes when opened (#207)
|
|
||||||
- The library list will now display a button to clear the filter instead of the "Browse Depot" button (#193)
|
|
||||||
- Fixed "Register" button (#214)
|
|
||||||
- Rebuilt save packing to be more reliable
|
|
||||||
|
|
||||||
## Nightlies
|
|
||||||
Nightly builds of both the launcher and server are now being hosted on GitHub under [action runs](https://github.com/LANCommander/LANCommander/actions/workflows/LANCommander.Nightly.yml). Docker builds are also being pushed to [GitHub Packages](https://github.com/LANCommander/LANCommander/pkgs/container/lancommander). As all nightlies go, these are unstable builds and may not work as expected.
|
|
||||||
|
|
||||||
## Breaking Changes
|
|
||||||
The mounting paths for the Docker container have changed in v1.1.5. Directories that were in `/config` now live at `/app/config`. Please update your bindings accordingly.
|
|
||||||
|
|
||||||
## WinGet Packages
|
|
||||||
LANCommander is now available to install via WinGet! These packages are included in our CI, so releases will get automatically pushed to the public Microsoft source.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v1.1.5" />
|
|
||||||
|
|
||||||
## New Contributors
|
|
||||||
* @simonmarklar made their first contribution in https://github.com/LANCommander/LANCommander/pull/192
|
|
||||||
* @eliaswen made their first contribution in https://github.com/LANCommander/LANCommander/pull/202
|
|
||||||
* @PGHJA991id12 made their first contribution in https://github.com/LANCommander/LANCommander/pull/222
|
|
||||||
|
|
||||||
**Full Changelog**: https://github.com/LANCommander/LANCommander/compare/v1.1.4...v1.1.5
|
|
||||||
|
|
@ -1,119 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.0.0-rc1
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
|
|
||||||
# LANCommander 2.0.0-rc1 Release Notes
|
|
||||||
LANCommander 2.0.0 is up there as one of the largest updates in the project's history. This release represents over nine months of development, with more individual contributors than previous versions. The jump from 1.x to 2.x reflects substantial architectural changes, new features, and significant improvements in the server, launcher, and SDK.
|
|
||||||
|
|
||||||
Additionally, documentation has now been moved to Docusaurus and is being hosted on GitHub Pages. Documentation can now live in the same repository as the rest of the application, ensuring that documentation is versioned and up to date.
|
|
||||||
|
|
||||||
## Breaking Changes
|
|
||||||
|
|
||||||
### Settings
|
|
||||||
Settings have previously been implemented with custom code parsing the `Settings.yml` file. They are now implemented using standard .NET configuration practices.
|
|
||||||
|
|
||||||
A migration has been put in place to adapt to the new format, but as with any migration some settings may not carry over from previous installs.
|
|
||||||
|
|
||||||
### Import/Export
|
|
||||||
Importing and exporting has been rebuilt from the ground up. An effort to allow the import of legacy LCX files has been made, but this may vary based on the age of the export file.
|
|
||||||
|
|
||||||
### User Data Paths
|
|
||||||
In previous versions of LANCommander, user data files/directories such as the database, settings, media, and uploads were thrown into the same directory as the main executable (for both server and launcher). In 2.0.0 a new directory called "Data" will be created and used for all user data. This change should make it easier to create backups and map Docker volumes.
|
|
||||||
|
|
||||||
A migration has been written to assist with this change, but as always make sure you backup your data before upgrading. **For Docker users**: Before updating to 2.0.0, make sure you map `/app/Data` _with_ your volumes from previous versions. The migration will do its best attempt at discovering if this directory is mapped before moving any data.
|
|
||||||
|
|
||||||
### Logging
|
|
||||||
Previous versions have relied on Serilog to provide logging for both the server and launcher. An effort is being made to update this to more modern practices by integrating OpenTelemetry. As of right now, logging support for Seq and ElasticSearch is non-functional.
|
|
||||||
|
|
||||||
### SDK Changes
|
|
||||||
The SDK has been refactored to utilize dependency injection instead of relying on a monolithic singleton client. I'm not aware of any other projects using the SDK, but it's worth noting at this time.
|
|
||||||
|
|
||||||
## Major Changes / features
|
|
||||||
|
|
||||||
### Import/Export
|
|
||||||
As mentioned, importing and exporting has been rebuilt from the ground up, and as such the manifest format for LCX files has gone through some significant changes. Ultimately, this change reflects a closer parity between export files and the database schema, which should allow for extensibility in the future.
|
|
||||||
|
|
||||||
The core concept that drove this rewrite is **selective importing/exporting**. Now when you go to export or import a game, server, or redistributable you may choose which data you want to import or export. This includes metadata, archives, media, and user data such as save games or play sessions. This should make it easier to share only the data you want or to selectively migrate from one system to another.
|
|
||||||
|
|
||||||
### Launcher Authentication/Stability
|
|
||||||
A large effort was put into 2.0.0 to make the launcher more stable. A core issue has always been the authentication flow. While this still can be improved upon, the core changes put in should reduce the amount of soft-locking that could previously happen within the launcher.
|
|
||||||
|
|
||||||
### Chat
|
|
||||||
A bare-bones chat system has been added to the platform. As of right now this probably isn't entirely useful, but there's a good base for improvements in future versions.
|
|
||||||
|
|
||||||
### Packaging Scripts
|
|
||||||
Games now support a new script type called **Package**. These scripts are designed to run on the server to package up a game automatically. Package scripts are run on a recurring schedule, so they can be used to keep games up to date. Refer to the scripting documentation for more details.
|
|
||||||
|
|
||||||
### SteamCMD
|
|
||||||
The server now supports a basic integration with SteamCMD. Currently, you can authenticate to multiple Steam profiles. This pairs great with packaging scripts to keep your games up to date!
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
The Docker image has been updated to support the new user data pathing. In addition, scripts have been added to allow the installation of both SteamCMD and WINE. These may be useful for writing packaging scripts or hosting dedicated servers in Docker-hosted environments.
|
|
||||||
|
|
||||||
For Docker Compose users, refer to the [sample docker-compose.yml](https://github.com/LANCommander/LANCommander/blob/v2.0.0-rc1/LANCommander.Server/docker-compose.yml) file in the repository.
|
|
||||||
|
|
||||||
## Bug Fixes / Misc Improvements
|
|
||||||
As if there weren't already enough changes in this release, here's a list of notable bug fixes that have been made in 2.0.0:
|
|
||||||
- Game process tracking is now more reliable and less prone to memory leaks
|
|
||||||
- Downloads now buffer correctly and file writes should happen asynchronously
|
|
||||||
- Metadata and libraries are now caching more effectively, resulting in faster response times
|
|
||||||
- API requests are now being prioritized over downloads. Users should see an increase in responsiveness while other users are downloading from the server.
|
|
||||||
- Game saves should now be more reliable on both upload and download
|
|
||||||
- Launcher authentication state should now be more reliable
|
|
||||||
- An unresponsive server should no longer cause fatal errors when trying to launch games
|
|
||||||
- The discovery beacon has been rebuilt from the ground up and should no longer cause hard crashes
|
|
||||||
- Thumbnail sizes can now be customized in settings
|
|
||||||
- IGDB metadata importing should now be more consistent
|
|
||||||
- Taxonomy metadata such as genre or tags is no longer being lost when updating other game information
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.0.0-rc1" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
As mentioned previously, this update had the most outside contributions over any other version. A big thanks to the following contributors and their pull requests:
|
|
||||||
|
|
||||||
[aaronpowell](https://github.com/aaronpowell)
|
|
||||||
- [#390](https://github.com/LANCommander/LANCommander/pull/390) Skipping nightly CI if it's not the lancommander main repo
|
|
||||||
- [#387](https://github.com/LANCommander/LANCommander/pull/387) Launcher import fixes
|
|
||||||
- [#386](https://github.com/LANCommander/LANCommander/pull/386) Evolving Migrations
|
|
||||||
- [#385](https://github.com/LANCommander/LANCommander/pull/385) Download endpoints get correct paths
|
|
||||||
- [#384](https://github.com/LANCommander/LANCommander/pull/384) Ensuring media path is correct
|
|
||||||
- [#383](https://github.com/LANCommander/LANCommander/pull/383) Adding SQLite database migration step
|
|
||||||
- [#382](https://github.com/LANCommander/LANCommander/pull/382) tags input fixes
|
|
||||||
|
|
||||||
[Mavyre](https://github.com/Mavyre)
|
|
||||||
- [#337](https://github.com/LANCommander/LANCommander/pull/337) Corrected Auto-updater
|
|
||||||
- [#336](https://github.com/LANCommander/LANCommander/pull/336) Added redistributables to Games API and Games manifest
|
|
||||||
- [#335](https://github.com/LANCommander/LANCommander/pull/335) Fixing scripts not saved anymore in Launcher
|
|
||||||
- [#334](https://github.com/LANCommander/LANCommander/pull/334) Save Games no longer shared between user
|
|
||||||
- [#327](https://github.com/LANCommander/LANCommander/pull/327) Corrected routes for Play Sessions tracking
|
|
||||||
|
|
||||||
[RattleSN4K3](https://github.com/RattleSN4K3)
|
|
||||||
- [#322](https://github.com/LANCommander/LANCommander/pull/322) Re-implement registry save paths game save creation in Launcher
|
|
||||||
- [#321](https://github.com/LANCommander/LANCommander/pull/321) Fix game end lag caused by generating game save
|
|
||||||
- [#319](https://github.com/LANCommander/LANCommander/pull/319) Fix editing collection and other metadata pages
|
|
||||||
- [#318](https://github.com/LANCommander/LANCommander/pull/318) Fix generating of thumbnails on importing games
|
|
||||||
- [#316](https://github.com/LANCommander/LANCommander/pull/316) Error messaging for login/register via Launcher
|
|
||||||
- [#308](https://github.com/LANCommander/LANCommander/pull/308) Bypass password policy on first-time-setup for administrator creation
|
|
||||||
- [#307](https://github.com/LANCommander/LANCommander/pull/307) Launcher: Fix connecting to hostname:port Uri
|
|
||||||
- [#306](https://github.com/LANCommander/LANCommander/pull/306) Launcher: Rework on offline mode and connection timeout
|
|
||||||
- [#305](https://github.com/LANCommander/LANCommander/pull/305) Launcher: Configure logger with log level from debug settings
|
|
||||||
- [#303](https://github.com/LANCommander/LANCommander/pull/303) Fix context menu items not triggering on click
|
|
||||||
- [#291](https://github.com/LANCommander/LANCommander/pull/291) Library changes to addon installation
|
|
||||||
- [#290](https://github.com/LANCommander/LANCommander/pull/290) Update archive's file sizes for a specific archive/game
|
|
||||||
- [#289](https://github.com/LANCommander/LANCommander/pull/289) Depot game changes to update view
|
|
||||||
- [#287](https://github.com/LANCommander/LANCommander/pull/287) Remove games via dialog for dependent games
|
|
||||||
- [#286](https://github.com/LANCommander/LANCommander/pull/286) Fix crash of base game removal of user Library
|
|
||||||
- [#283](https://github.com/LANCommander/LANCommander/pull/283) Fix Avatar uploading
|
|
||||||
- [#282](https://github.com/LANCommander/LANCommander/pull/282) Fix packaging and uploading save games by Launcher
|
|
||||||
- [#281](https://github.com/LANCommander/LANCommander/pull/281) Fix storing several entities (such as Gamesaves) properly
|
|
||||||
- [#277](https://github.com/LANCommander/LANCommander/pull/277) Fix importing tags on Lookup from IGDB
|
|
||||||
- [#272](https://github.com/LANCommander/LANCommander/pull/272) Standalone mods/expansions as Base Game
|
|
||||||
- [#271](https://github.com/LANCommander/LANCommander/pull/271) Fix changing base game of a game
|
|
||||||
- [#269](https://github.com/LANCommander/LANCommander/pull/269) Option to delete selected Media entries
|
|
||||||
- [#268](https://github.com/LANCommander/LANCommander/pull/268) Expiring Archives cache after recalculating/updating archives
|
|
||||||
- [#260](https://github.com/LANCommander/LANCommander/pull/260) Utilizing MadMilkman.INI for ini parsing
|
|
||||||
- [#257](https://github.com/LANCommander/LANCommander/pull/257) Fix "Name Change Script" from context menu nulling username in game files
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.0.0-rc2
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
|
|
||||||
# LANCommander 2.0.0-rc2 Release Notes
|
|
||||||
This page only covers updates/fixes included in v2.0.0-rc2. For more information on other v2.0.0 changes, head over to the [v2.0.0-rc1 release notes](/Releases/2.0.0-rc1).
|
|
||||||
|
|
||||||
## Bug Fixes / Misc Improvements
|
|
||||||
- Launcher now starts properly on fresh installs
|
|
||||||
- Exporting a game no longer redirects you to a 404 page
|
|
||||||
- Added a better not found page for the admin UI
|
|
||||||
- Fixed scrolling in depot
|
|
||||||
- Fixed scrolling in library list / selected game details
|
|
||||||
- Fixed log viewer installation in admin UI
|
|
||||||
- Moved IGDB and SteamGridDB credential settings under "Integrations" in admin UI
|
|
||||||
- Fixed width of game details in depot
|
|
||||||
- Fixed "Add to Library" button in depot
|
|
||||||
- Fixed opening of chat window
|
|
||||||
- Display logo instead of authentication form when starting launcher
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.0.0-rc2" />
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.0.0-rc3
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
|
|
||||||
# LANCommander 2.0.0-rc3 Release Notes
|
|
||||||
This page only covers updates/fixes included in v2.0.0-rc3. For more information on other v2.0.0 changes, head over to previous releases:
|
|
||||||
- [v2.0.0-rc1](/Releases/2.0.0-rc1)
|
|
||||||
- [v2.0.0-rc2](/Releases/2.0.0-rc2)
|
|
||||||
|
|
||||||
## Bug Fixes / Misc Improvements
|
|
||||||
- SteamCMD credentials are now persisted when enabling SteamCMD in the Docker container
|
|
||||||
- Fix default path for scripting snippets
|
|
||||||
- Added basic PowerShell module for SteamCMD
|
|
||||||
- Auto-detect SteamCMD path if possible when loading the Steam integration page under settings
|
|
||||||
- Better error handling/reporting when working with SteamCMD
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.0.0-rc3" />
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.0.0-rc4
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
|
|
||||||
# LANCommander 2.0.0-rc4 Release Notes
|
|
||||||
This page only covers updates/fixes included in v2.0.0-rc4. For more information on other v2.0.0 changes, head over to previous releases:
|
|
||||||
- [v2.0.0-rc1](/Releases/2.0.0-rc1)
|
|
||||||
- [v2.0.0-rc2](/Releases/2.0.0-rc2)
|
|
||||||
- [v2.0.0-rc3](/Releases/2.0.0-rc3)
|
|
||||||
|
|
||||||
## Bug Fixes / Misc Improvements
|
|
||||||
- Added PowerShell cmdlets for various SteamCMD/Steam store functions. See [Cmdlets](/Scripting/Cmdlets) for more information.
|
|
||||||
- Fix import issues with scripts, archives, and even-older legacy LCX files
|
|
||||||
- Added tooltips for archive editor buttons
|
|
||||||
- Fixed file manager styling
|
|
||||||
- Fixed redistributable and server script editors
|
|
||||||
- Added packaging scripts for redistributables
|
|
||||||
- Fixed export button for redistributables and servers
|
|
||||||
- Exports now download with a useful name
|
|
||||||
- Incomplete chat component for web UI has been temporarily disabled
|
|
||||||
- Fixed login redirecting to logout after logout
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.0.0-rc4" />
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.0.0-rc5
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
|
|
||||||
# LANCommander 2.0.0-rc5 Release Notes
|
|
||||||
This page only covers updates/fixes included in v2.0.0-rc5. For more information on other v2.0.0 changes, head over to previous releases:
|
|
||||||
- [v2.0.0-rc1](/Releases/2.0.0-rc1)
|
|
||||||
- [v2.0.0-rc2](/Releases/2.0.0-rc2)
|
|
||||||
- [v2.0.0-rc3](/Releases/2.0.0-rc3)
|
|
||||||
- [v2.0.0-rc4](/Releases/2.0.0-rc4)
|
|
||||||
|
|
||||||
## Bug Fixes / Misc Improvements
|
|
||||||
- Reworked Steam cmdlets, review the [documentation](/Scripting/Cmdlets) for a list of available cmdlets.
|
|
||||||
- Added better logging for PowerShell scripts
|
|
||||||
- Fixed the save editor so it no longer throws an error if there are no archives available for a game.
|
|
||||||
- Fixed first time login on launcher being stuck at loading screen.
|
|
||||||
- Fix chat window opening with library view instead of chat.
|
|
||||||
|
|
||||||
## Game Servers
|
|
||||||
An effort is being made to create Docker images to assist in hosting dedicated servers for various games. A list of these containers can be found under [Game Servers](/GameServers).
|
|
||||||
|
|
||||||
These servers should still be considered a work in progress. They will eventually get better integration into the platform. The aim is to provide a set of base containers and remove as much work as possible for each individual game. The current aim is to implement:
|
|
||||||
- OverlayFS to allow multiple servers to share the same base files
|
|
||||||
- A built in HTTP server (via nginx) for FastDL support
|
|
||||||
- Documentation for each image, including useful configuration of the game server itself
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
This documentation site now resides under our [LANCommander.Documentation](https://github.com/LANCommander/LANCommander.Documentation) GitHub repository, with the actual contents being fed from the organization's other repositories. Any contribution to the documentation can be submitted to the child repositories. They will automatically be published to the documentation repo on merge.
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.0.0-rc5" />
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.0.0-rc6
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
|
|
||||||
# LANCommander 2.0.0-rc6 Release Notes
|
|
||||||
This page only covers updates/fixes included in v2.0.0-rc6. For more information on other v2.0.0 changes, head over to previous releases:
|
|
||||||
- [v2.0.0-rc1](/Releases/2.0.0-rc1)
|
|
||||||
- [v2.0.0-rc2](/Releases/2.0.0-rc2)
|
|
||||||
- [v2.0.0-rc3](/Releases/2.0.0-rc3)
|
|
||||||
- [v2.0.0-rc4](/Releases/2.0.0-rc4)
|
|
||||||
- [v2.0.0-rc5](/Releases/2.0.0-rc5)
|
|
||||||
|
|
||||||
## Bug Fixes / Misc Improvements
|
|
||||||
- Fixed the archive editor in redistributables
|
|
||||||
- Fixed console/HTTP path editing in servers
|
|
||||||
- Removed old export methods from servers, redistributables
|
|
||||||
- Fixed export initialization for servers and redistributables
|
|
||||||
- Fixed alignment of action buttons in list pages
|
|
||||||
- Fixed logo being shown on launcher settings page, blocking certain controls
|
|
||||||
- Fixed missing auth provider templates crashing the server in some cases
|
|
||||||
- Increased buffer size for downloads and avoid throttling large responses. This should result in some faster download speeds across the board.
|
|
||||||
|
|
||||||
## Tools
|
|
||||||
LANCommander now supports the ability to manage tools that may be useful for games. This feature is intended to allow admins to upload applications such as map editors, save editors, trainers, alternate configuration tools, etc. Tools can be tied to games and will be available to select upon install of the game in the launcher. This feature is still very new and experimental.
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.0.0-rc6" />
|
|
||||||
|
|
@ -1,132 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.0.0
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
|
|
||||||
# LANCommander 2.0.0 Release Notes
|
|
||||||
LANCommander 2.0.0 is up there as one of the largest updates in the project's history. This release represents over ten months of development, with more individual contributors than previous versions. The jump from 1.x to 2.x reflects substantial architectural changes, new features, and significant improvements in the server, launcher, and SDK.
|
|
||||||
|
|
||||||
Additionally, documentation has now been moved to Docusaurus and is being hosted on GitHub Pages. Documentation can now live in the same repository as the rest of the application, ensuring that documentation is versioned and up to date.
|
|
||||||
|
|
||||||
## Breaking Changes
|
|
||||||
|
|
||||||
### Settings
|
|
||||||
Settings have previously been implemented with custom code parsing the `Settings.yml` file. They are now implemented using standard .NET configuration practices.
|
|
||||||
|
|
||||||
A migration has been put in place to adapt to the new format, but as with any migration some settings may not carry over from previous installs.
|
|
||||||
|
|
||||||
### Import/Export
|
|
||||||
Importing and exporting has been rebuilt from the ground up. An effort to allow the import of legacy LCX files has been made, but this may vary based on the age of the export file.
|
|
||||||
|
|
||||||
### User Data Paths
|
|
||||||
In previous versions of LANCommander, user data files/directories such as the database, settings, media, and uploads were thrown into the same directory as the main executable (for both server and launcher). In 2.0.0 a new directory called "Data" will be created and used for all user data. This change should make it easier to create backups and map Docker volumes.
|
|
||||||
|
|
||||||
A migration has been written to assist with this change, but as always make sure you backup your data before upgrading. **For Docker users**: Before updating to 2.0.0, make sure you map `/app/Data` _with_ your volumes from previous versions. The migration will do its best attempt at discovering if this directory is mapped before moving any data.
|
|
||||||
|
|
||||||
### Logging
|
|
||||||
Previous versions have relied on Serilog to provide logging for both the server and launcher. An effort is being made to update this to more modern practices by integrating OpenTelemetry. As of right now, logging support for Seq and ElasticSearch is non-functional.
|
|
||||||
|
|
||||||
### SDK Changes
|
|
||||||
The SDK has been refactored to utilize dependency injection instead of relying on a monolithic singleton client. I'm not aware of any other projects using the SDK, but it's worth noting at this time.
|
|
||||||
|
|
||||||
## Major Changes / features
|
|
||||||
|
|
||||||
### Import/Export
|
|
||||||
As mentioned, importing and exporting has been rebuilt from the ground up, and as such the manifest format for LCX files has gone through some significant changes. Ultimately, this change reflects a closer parity between export files and the database schema, which should allow for extensibility in the future.
|
|
||||||
|
|
||||||
The core concept that drove this rewrite is **selective importing/exporting**. Now when you go to export or import a game, server, or redistributable you may choose which data you want to import or export. This includes metadata, archives, media, and user data such as save games or play sessions. This should make it easier to share only the data you want or to selectively migrate from one system to another.
|
|
||||||
|
|
||||||
### Launcher Authentication/Stability
|
|
||||||
A large effort was put into 2.0.0 to make the launcher more stable. A core issue has always been the authentication flow. While this still can be improved upon, the core changes put in should reduce the amount of soft-locking that could previously happen within the launcher.
|
|
||||||
|
|
||||||
### Chat
|
|
||||||
A bare-bones chat system has been added to the platform. As of right now this probably isn't entirely useful, but there's a good base for improvements in future versions.
|
|
||||||
|
|
||||||
### Packaging Scripts
|
|
||||||
Games and redistributables now support a new script type called **Package**. These scripts are designed to run on the server to package up a game/redistributable automatically. Package scripts are run on a recurring schedule, so they can be used to keep things up to date. Refer to the scripting documentation for more details.
|
|
||||||
|
|
||||||
### SteamCMD
|
|
||||||
The server now supports a basic integration with SteamCMD. Currently, you can authenticate to multiple Steam profiles. This pairs great with packaging scripts to keep your games up to date!
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
The Docker image has been updated to support the new user data pathing. In addition, scripts have been added to allow the installation of both SteamCMD and WINE. These may be useful for writing packaging scripts or hosting dedicated servers in Docker-hosted environments.
|
|
||||||
|
|
||||||
For Docker Compose users, refer to the [sample docker-compose.yml](https://github.com/LANCommander/LANCommander/blob/v2.0.0-rc1/LANCommander.Server/docker-compose.yml) file in the repository.
|
|
||||||
|
|
||||||
### Metadata Retrieval
|
|
||||||
In previous versions, metadata retrieval was only possible through IGDB and you had to accept whatever it gave you. This has been retooled and you now have the option of importing metadata from either IGDB or PCGamingWiki. Once you select the correct game, you are also able to select which data you would like to pull. This is built on the back of the new import functionality, so it should be more stable as well! The framework has also been laid out where it should be easier to integrate other metadata sources in the future.
|
|
||||||
|
|
||||||
## Bug Fixes / Misc Improvements
|
|
||||||
As if there weren't already enough changes in this release, here's a list of notable bug fixes that have been made in 2.0.0:
|
|
||||||
- Game process tracking is now more reliable and less prone to memory leaks
|
|
||||||
- Downloads now buffer correctly and file writes should happen asynchronously. This should increase download speeds while preventing long load times in the web UI.
|
|
||||||
- Metadata and libraries are now caching more effectively, resulting in faster response times
|
|
||||||
- API requests are now being prioritized over downloads. Users should see an increase in responsiveness while other users are downloading from the server.
|
|
||||||
- Game saves should now be more reliable on both upload and download
|
|
||||||
- Launcher authentication state should now be more reliable
|
|
||||||
- An unresponsive server should no longer cause fatal errors when trying to launch games
|
|
||||||
- The discovery beacon has been rebuilt from the ground up and should no longer cause hard crashes
|
|
||||||
- Thumbnail sizes can now be customized in settings
|
|
||||||
- IGDB metadata importing should now be more consistent
|
|
||||||
- Taxonomy metadata such as genre or tags is no longer being lost when updating other game information
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.0.0" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
As mentioned previously, this update had the most outside contributions over any other version. A big thanks to the following contributors and their pull requests:
|
|
||||||
|
|
||||||
[aaronpowell](https://github.com/aaronpowell)
|
|
||||||
- [#390](https://github.com/LANCommander/LANCommander/pull/390) Skipping nightly CI if it's not the lancommander main repo
|
|
||||||
- [#387](https://github.com/LANCommander/LANCommander/pull/387) Launcher import fixes
|
|
||||||
- [#386](https://github.com/LANCommander/LANCommander/pull/386) Evolving Migrations
|
|
||||||
- [#385](https://github.com/LANCommander/LANCommander/pull/385) Download endpoints get correct paths
|
|
||||||
- [#384](https://github.com/LANCommander/LANCommander/pull/384) Ensuring media path is correct
|
|
||||||
- [#383](https://github.com/LANCommander/LANCommander/pull/383) Adding SQLite database migration step
|
|
||||||
- [#382](https://github.com/LANCommander/LANCommander/pull/382) tags input fixes
|
|
||||||
|
|
||||||
[Mavyre](https://github.com/Mavyre)
|
|
||||||
- [#337](https://github.com/LANCommander/LANCommander/pull/337) Corrected Auto-updater
|
|
||||||
- [#336](https://github.com/LANCommander/LANCommander/pull/336) Added redistributables to Games API and Games manifest
|
|
||||||
- [#335](https://github.com/LANCommander/LANCommander/pull/335) Fixing scripts not saved anymore in Launcher
|
|
||||||
- [#334](https://github.com/LANCommander/LANCommander/pull/334) Save Games no longer shared between user
|
|
||||||
- [#327](https://github.com/LANCommander/LANCommander/pull/327) Corrected routes for Play Sessions tracking
|
|
||||||
|
|
||||||
[RattleSN4K3](https://github.com/RattleSN4K3)
|
|
||||||
- [#322](https://github.com/LANCommander/LANCommander/pull/322) Re-implement registry save paths game save creation in Launcher
|
|
||||||
- [#321](https://github.com/LANCommander/LANCommander/pull/321) Fix game end lag caused by generating game save
|
|
||||||
- [#319](https://github.com/LANCommander/LANCommander/pull/319) Fix editing collection and other metadata pages
|
|
||||||
- [#318](https://github.com/LANCommander/LANCommander/pull/318) Fix generating of thumbnails on importing games
|
|
||||||
- [#316](https://github.com/LANCommander/LANCommander/pull/316) Error messaging for login/register via Launcher
|
|
||||||
- [#308](https://github.com/LANCommander/LANCommander/pull/308) Bypass password policy on first-time-setup for administrator creation
|
|
||||||
- [#307](https://github.com/LANCommander/LANCommander/pull/307) Launcher: Fix connecting to hostname:port Uri
|
|
||||||
- [#306](https://github.com/LANCommander/LANCommander/pull/306) Launcher: Rework on offline mode and connection timeout
|
|
||||||
- [#305](https://github.com/LANCommander/LANCommander/pull/305) Launcher: Configure logger with log level from debug settings
|
|
||||||
- [#303](https://github.com/LANCommander/LANCommander/pull/303) Fix context menu items not triggering on click
|
|
||||||
- [#291](https://github.com/LANCommander/LANCommander/pull/291) Library changes to addon installation
|
|
||||||
- [#290](https://github.com/LANCommander/LANCommander/pull/290) Update archive's file sizes for a specific archive/game
|
|
||||||
- [#289](https://github.com/LANCommander/LANCommander/pull/289) Depot game changes to update view
|
|
||||||
- [#287](https://github.com/LANCommander/LANCommander/pull/287) Remove games via dialog for dependent games
|
|
||||||
- [#286](https://github.com/LANCommander/LANCommander/pull/286) Fix crash of base game removal of user Library
|
|
||||||
- [#283](https://github.com/LANCommander/LANCommander/pull/283) Fix Avatar uploading
|
|
||||||
- [#282](https://github.com/LANCommander/LANCommander/pull/282) Fix packaging and uploading save games by Launcher
|
|
||||||
- [#281](https://github.com/LANCommander/LANCommander/pull/281) Fix storing several entities (such as Gamesaves) properly
|
|
||||||
- [#277](https://github.com/LANCommander/LANCommander/pull/277) Fix importing tags on Lookup from IGDB
|
|
||||||
- [#272](https://github.com/LANCommander/LANCommander/pull/272) Standalone mods/expansions as Base Game
|
|
||||||
- [#271](https://github.com/LANCommander/LANCommander/pull/271) Fix changing base game of a game
|
|
||||||
- [#269](https://github.com/LANCommander/LANCommander/pull/269) Option to delete selected Media entries
|
|
||||||
- [#268](https://github.com/LANCommander/LANCommander/pull/268) Expiring Archives cache after recalculating/updating archives
|
|
||||||
- [#260](https://github.com/LANCommander/LANCommander/pull/260) Utilizing MadMilkman.INI for ini parsing
|
|
||||||
- [#257](https://github.com/LANCommander/LANCommander/pull/257) Fix "Name Change Script" from context menu nulling username in game files
|
|
||||||
|
|
||||||
More contributions are always welcome! If you would like to know how to help and have any of these skills, please reach out via Discord!
|
|
||||||
- Documentation maintenance
|
|
||||||
- ASP.NET Blazor development
|
|
||||||
- Discord moderation
|
|
||||||
- Docker image maintenance (we need more game servers!)
|
|
||||||
- Localization translation
|
|
||||||
- Avalonia development
|
|
||||||
|
|
||||||
And as always with a shameless plug, donations are welcome. Currently the best way to support the project is to [sign up over at Patreon](https://www.patreon.com/LANCommander). There's currently no special tiers for higher members other than getting a special "Bawler" role in the Discord and any locked posts are still accessible via the free tier.
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.0.1
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
|
|
||||||
# LANCommander 2.0.1 Release Notes
|
|
||||||
|
|
||||||
## New Features
|
|
||||||
### Remote Server Engine
|
|
||||||
A new "Remote" server engine has been added as a way to link multiple LANCommander servers together. This can be configured from Settings -> Servers. Once configured / authenticated, servers defined in one instance can reference a server in the other. For example, if your main instance is hosted on a Linux host, you can add servers from another LANCommander instance running on a Windows host. All of the standard autostart / launcher integration features apply as well!
|
|
||||||
|
|
||||||
## Bug Fixes / Misc Improvements
|
|
||||||
- Script saving has been fixed across the board
|
|
||||||
- Media thumbnails should be loaded after new media is added via the media editor
|
|
||||||
- Imported addons will now be linked to their base game upon import, if the base game already exists
|
|
||||||
- The launcher's play button should now report correct state when games are starting/running
|
|
||||||
- Games should now take less time to start
|
|
||||||
- Avatar downloading in the launcher has been fixed
|
|
||||||
- The dropdown for changing default role now correctly shows the selected value
|
|
||||||
- Games larger than 10GB will now extract properly
|
|
||||||
- UI stutter during game extraction should be reduced
|
|
||||||
- The time to import games on the launcher should now be substantially reduced
|
|
||||||
- Admin scripts written to disk now follow the standard PowerShell RunAsAdministrator directive
|
|
||||||
- Admin scripts now execute properly and can be debugged in the launcher
|
|
||||||
- An issue causing scripts not to save properly upon download has been fixed
|
|
||||||
- Lobby actions for games have had their functionality restored in the launcher
|
|
||||||
- Server variables (`{ServerHost}`, `{ServerPort}`) should now be populated correctly when starting an action
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.0.1" />
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.0.2
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
|
|
||||||
# LANCommander 2.0.2 Release Notes
|
|
||||||
|
|
||||||
## Bug Fixes / Misc Improvements
|
|
||||||
- Fixed an issue where large scripts could not be added or updated
|
|
||||||
- Fixed actions dialog in launcher to only show actions for installed addons
|
|
||||||
- Reworked the script editor to ensure changes are being captured reliably
|
|
||||||
- Fixed installation of redistributables
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.0.2" />
|
|
||||||
|
|
@ -1,195 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.0-rc1
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ScreenshotCarousel from '@site/src/components/ScreenshotCarousel';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.0 Release Candidate 1 Release Notes
|
|
||||||
|
|
||||||
## Breaking Changes
|
|
||||||
|
|
||||||
### .NET 10
|
|
||||||
LANCommander has been upgraded from .NET 8 to .NET 10. This should be a seamless transition as all LANCommander binaries are self-contained and include the appropriate .NET runtime. However, if you are running an older version of Windows that does not support .NET 10, you may encounter issues running this version of LANCommander. The minimum supported Windows version is now Windows 10 version 1809.
|
|
||||||
|
|
||||||
## Launching Into the Future
|
|
||||||
To kick things off, LANCommander 2.1.0 introduces a new launcher. As a recap, the previous launcher was built using .NET Blazor and wrapped into a Webview2 chrome using the open source project [Photino](https://www.tryphotino.io/). This decision was originally made in an effort to maintain a somewhat shared codebase with the server web UI.
|
|
||||||
|
|
||||||
Unfortunately, over time limitations of the platform made it apparent that a change had to be made. Community member [aaronpowell](https://github.com/aaronpowell) stepped up and built out a proof of concept for a launcher using Avalonia, an open-source native cross-platform UI framework for .NET. The potential was immediately clear and the decision was made to jump in head first. The following months saw the project refocus on build a new launcher with a major emphasis on performance, reliability, design, and feature parity.
|
|
||||||
|
|
||||||
The result is, well, a project that went off a little off the rails in the best possible fashion:
|
|
||||||
|
|
||||||
<ScreenshotCarousel screenshots={[
|
|
||||||
{ src: require('./_Assets/2.1.0 - Launcher.jpg').default, alt: 'Launcher', label: 'Launcher', caption: 'The brand new Avalonia-based launcher' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Shelf.jpg').default, alt: 'Shelf View', label: 'Shelf View', caption: 'Browse your library in the new shelf layout' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Depot.jpg').default, alt: 'Depot', label: 'Depot', caption: 'The redesigned depot with categorization carousels' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Screenshot.jpg').default, alt: 'Game Details', label: 'Game Details', caption: 'Screenshots and videos displayed right in the detail view' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Downloads.png').default, alt: 'Download Queue', label: 'Download Queue', caption: 'Track every step of the installation process' },
|
|
||||||
]} />
|
|
||||||
|
|
||||||
I think the screenshots speak for themselves. Okay, not quite, there's a lot of fun stuff in this build so let's dive right in!
|
|
||||||
|
|
||||||
### User Library
|
|
||||||
Previous versions of the launcher attempted to bring the art of a game to the forefront. These views are where most players spend their time interacting with the application. However, everyone's tastes are different. As such the library now contains three main views; cover grid, list, and shelf.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Game Details
|
|
||||||
Browsing the user library is great and all, but the detail view is where a game really gets to shine. Metadata has shifted to the right-hand side, descriptions now support more complex formatting with Markdown rendering support, and _finally_ videos and screenshots are displayed in a carousel. A lightbox viewer lets you zoom in on screenshots, watch videos, and even read game manuals right from the detail view thanks to the new built-in PDF viewer.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
This is really just the start of something new. Expect this part of the launcher to be built out more in the future with better publishing tools and metadata expansion.
|
|
||||||
|
|
||||||
### Depot
|
|
||||||
The depot has been overhauled too, probably more than any other part of the launcher. Previous iterations have been _fine_, but with large game sets it was hard to find just what you needed. The new depot puts a focus on categorization while maintaining granular filtering tools to get you exactly where you need to go.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
As you can see, this section more than any other benefits from high quality metadata. We'll get into that later, but first let's talk about game installation.
|
|
||||||
|
|
||||||
### Download Queue
|
|
||||||
Game installation and downloading has been the hardest component to develop in the entire LANCommander platform. And rightly so! Without game installation, all you get is a fancy web UI and a pretty launcher that can't launch any games.
|
|
||||||
|
|
||||||
The LANCommander launcher is essentially a UI wrapper for the LANCommander SDK. The SDK is a .NET library that provides all of the useful bits of communicating with a LANCommander server install. Authentication, script execution, save management, game installation and so much more are provided through this library. In previous iterations, the SDK had a very strict execution plan for installing games. Often times this would lead to deadlocks and outright failures.
|
|
||||||
|
|
||||||
To resolve this in 2.1.0, the game install process has moved to a two-layer queuing system. The first layer of the queue manages what actually enters the download queue. This could be a game, redistributable, tool, or addon. The second layer handles any subprocessing step such as executing the different script types, save downloading, existing file verification, etc. The result is a system that is more transparent and reliable.
|
|
||||||
|
|
||||||
This queuing system has been exposed somewhat in the download queue:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Each entry in the download queue will now report each step of the process during a game installation. In addition to looking a bit less mystical, this should give users an idea of what _exactly_ is happening during a game installation.
|
|
||||||
|
|
||||||
### Discord Rich Presence
|
|
||||||
The launcher now integrates with Discord Rich Presence. When you're playing a game through LANCommander, your Discord status will update to show what you're playing. By default this will show as LANCommander with the game name as the status. If the game is mapped to the correct Discord ID (via external IDs in the server), then the game's official Discord assets will be used for a more polished presentation.
|
|
||||||
|
|
||||||
### Offline Mode
|
|
||||||
Previous attempts at an offline mode in the launcher were pretty clunky and unreliable. In 2.1.0, the launcher now has a proper offline mode that allows you to launch previously installed games even when the server is unreachable.
|
|
||||||
|
|
||||||
### Single Sign-On
|
|
||||||
SSO was supported in the previous launcher, but it was a bit of an afterthought and not super reliable. In the new launcher it's been given more attention and should work as expected.
|
|
||||||
|
|
||||||
### Chat
|
|
||||||
As with the last version, the chat functionality remains pretty barebones. This is an area that will get more attention in the future, but it _is_ currently available in the new launcher. It might even work a little better.
|
|
||||||
|
|
||||||
## Server Improvements
|
|
||||||
This release should also be pretty exciting for server admins. With a new launcher with shiny new features brings a set of tools to manage them.
|
|
||||||
|
|
||||||
### LANCommander HQ
|
|
||||||
A new metadata provider has been added: LANCommander HQ. This gives server admins another option for sourcing game metadata and media alongside IGDB and SteamGridDB. In addition, support for external IDs beyond IGDB has been introduced, making it easier to cross-reference games across multiple platforms and services. To get started with the HQ, link your Discord account under "Integrations / HQ" in the server settings. Existing metadata providers such as IGDB and SteamGridDB are still available as well, so no functionality has been lost from previous versions.
|
|
||||||
|
|
||||||
### Preview Tool
|
|
||||||
A new "Preview" editing view has been added to the server for managing game art. Inspired by the launcher's presentation, this tool gives admins a better sense of how their media will look in the launcher before publishing. Screenshots and videos can now be uploaded in bulk, and the media grabber supports selecting multiple assets at once. Animated covers are now supported as well, APNG images grabbed from SteamGridDB are automatically converted to video and should display in the new launcher.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Script Editor Improvements
|
|
||||||
The script editor has received a significant upgrade. Context-aware code completions now suggest built-in PowerShell cmdlets, LANCommander-specific variables, and generated type definitions. Validation has been improved, and script errors are now logged rather than silently swallowed. A new `Set-GameDetails` cmdlet has been added for specifying package details from within scripts.
|
|
||||||
|
|
||||||
### Redistributable Options
|
|
||||||
Redistributables now support configurable options. Options can be defined with a schema editor, given display names, and are preserved across import/export. Assigning redistributables to a game can now be accessed under the "Redistributables" section of the game editor. When selected, a redistributable with options will render as an easy-to-use form and per-game overrides can be defined.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
A new **RunWrapper** script type has been added as well, giving admins more control over how redistributables and games are executed. This should enhance redistributables to cover more use cases such as emulators, launchers, and compatiblity shims like Proton or dgVoodoo.
|
|
||||||
|
|
||||||
### Key Management
|
|
||||||
Key allocation has been improved. The allocation method on keys is now nullable, and a new manual key assignment dialog has been added. The logic for choosing the next available key has also been reworked.
|
|
||||||
|
|
||||||
### Media & Tooling
|
|
||||||
Server settings now include checks for ffmpeg and yt-dlp availability, with automatic installation support in Docker environments. A new streaming endpoint for media has been added, improving video playback in the launcher. Automatic downloads for Steam screenshots have been added as well. YouTube video support has been added to the media grabber, and ffmpeg is now used for video processing tasks such as APNG conversion and thumbnail generation.
|
|
||||||
|
|
||||||
## LANCommander HQ
|
|
||||||
Last but far from least, this release coincides with the launch of [LANCommander HQ](https://hq.lancommander.com), a new metadata provider and community hub for LANCommander users. The HQ aims to provide a centralized platform for game metadata and media across multiple providers, while also normalizing and enhancing that data with a focus on the needs of LANCommander users. There's a bit to cover, so let's dive in!
|
|
||||||
|
|
||||||
### Metadata
|
|
||||||
LANCommander HQ aggregates metadata from multiple sources including IGDB, SteamGridDB, and user contributions. This data is then normalized and enhanced with a focus on the needs of LANCommander users. There are many metadata providers out there, and unfortunately they all have their own unique schemas and data quality issues. The HQ's goal is to provide a single source of truth for game metadata that can be consumed by LANCommander servers and launchers.
|
|
||||||
|
|
||||||
There are a lot of exciting features in the works for the HQ, but for this release the focus is on building out the core infrastructure and integrating with the new launcher. Expect to see more features and improvements in the future as the HQ continues to evolve.
|
|
||||||
|
|
||||||
### Community
|
|
||||||
The main features of the HQ are currently focused on metadata, but there is the potential to expand it into a broader community hub for LANCommander users. This could include an area to share game configurations, scripts, and other resources. Additionally, there are some content moderation tools in place that should allow the HQ to host user-generated content and provide the best possible experience for all users. If you have a knack for curation and want to help out, there will likely be opportunities to get involved in the future!
|
|
||||||
|
|
||||||
### Tiering / Subscriptions
|
|
||||||
The HQ operates on a tiered subscription model. Currently there are only two tiers: Basic (Free) and Premium ($5/month). The Basic tier provides access to the core metadata features of the HQ, while the Premium tier provides access to additional features such as enhanced metadata, relaxed rate limiting, and more. More information will be provided in the near future and will be provided on this site under the [LANCommander HQ](/hq) section. All paid subscriptions on the HQ are handled by Stripe, so every transaction is secure and your personal information is protected.
|
|
||||||
|
|
||||||
This subscription model is primarily in place to help cover the costs of running the HQ while also providing a sustainable path forward for continued development of LANCommander itself. This entire project is developed and maintained by essentially one person with some help from the community here and there. While this is a labor of love, there are real costs associated with running the infrastructure for the HQ and continued development of LANCommander. The subscription model is designed to be as accessible as possible while also providing a way for users to support the project if they find value in it.
|
|
||||||
|
|
||||||
As such, this will probably mean that the Patreon page will be going away in the near future. For existing patrons, it is recommended to switch over to the new subscription model on the HQ as it provides a more direct way to support the project and access the benefits of the HQ _today_.
|
|
||||||
|
|
||||||
## Contributions
|
|
||||||
This release includes contributions from the following community members:
|
|
||||||
|
|
||||||
**@aaronpowell | PR [#395](https://github.com/LANCommander/LANCommander/pull/395): Avalonia Launcher**
|
|
||||||
A substantial 42-commit, 6,000-line PR that bootstrapped the cross-platform Avalonia launcher. Aaron built out the core application structure, service wiring, and async initialization, and then built out the UI with filtered depot browsing and grid layout, a download queue, install/uninstall flows, a settings page, PDF manual viewer, game action bars, and a full CI pipeline for Windows, Linux, and macOS builds. A lot of the foundation that the current launcher sits on came from this PR.
|
|
||||||
|
|
||||||
**@akifreak | PR [#398](https://github.com/LANCommander/LANCommander/pull/398): Fix Game Archive Upload**
|
|
||||||
Discovered that archive uploads through the web UI were silently broken after upgrading to v2.0.2, traced the problem through the JavaScript bundle, and submitted 11 targeted fixes rather than a single bug report. The fixes covered ES module loading, null-guards on DOM elements, a FileMode.Append seek conflict, incorrect archive ID passing, and error propagation throughout the upload pipeline. The uploading process should feel much more stable now!
|
|
||||||
|
|
||||||
**@MasterMNB | PR [#400](https://github.com/LANCommander/LANCommander/pull/400): Avalonia Launcher Back Button**
|
|
||||||
Improved the visibility and styling of the back button in the `GameDetailView`, which was previously hard to distinguish from the background. It's a small change, but it's a real usability improvement that makes navigation feel more intentional.
|
|
||||||
|
|
||||||
## Changelog
|
|
||||||
|
|
||||||
**Launcher**
|
|
||||||
- Added: Brand new launcher built on Avalonia
|
|
||||||
- Added: Screenshots and videos in game detail carousel with lightbox viewer
|
|
||||||
- Added: Redesigned depot with categorization carousels and advanced filtering
|
|
||||||
- Added: Tools support
|
|
||||||
- Added: Download transfer speed graph
|
|
||||||
- Added: OS notifications upon game installation completion
|
|
||||||
- Added: Discord Rich Presence integration
|
|
||||||
- Added: Offline mode for playing games without server connectivity
|
|
||||||
- Added: SSO/OIDC external authentication provider support
|
|
||||||
- Added: Built-in PDF viewer for game manuals
|
|
||||||
- Added: Splash screen on startup
|
|
||||||
- Added: Verify files option in game dropdown
|
|
||||||
- Added: Markdown rendering for game descriptions
|
|
||||||
- Changed: Refactored game/redistributable/tool install process to two-layer queue system
|
|
||||||
- Changed: Imports should be faster and execute in the background without causing major UI hiccups
|
|
||||||
- Changed: Improved memory management with proper disposal of HTTP clients, RPC clients, and cancellation tokens
|
|
||||||
- Fixed: Installing games that already have files on disk will show the verification process during install
|
|
||||||
- Fixed: Logging in and logging out should no longer cause a hung UI
|
|
||||||
- Fixed: Install-uninstall-reinstall cycle no longer locks the game
|
|
||||||
- Fixed: Authentication token race condition causing crashes after login
|
|
||||||
|
|
||||||
**Server**
|
|
||||||
- Added: LANCommander HQ metadata provider support
|
|
||||||
- Added: Support for external IDs beyond IGDB
|
|
||||||
- Added: New launcher-inspired "Preview" tool for managing art
|
|
||||||
- Added: Context-aware script editor with code completions, validation, and PowerShell type definitions
|
|
||||||
- Added: Redistributable options with schema editor and display names
|
|
||||||
- Added: RunWrapper script type
|
|
||||||
- Added: Package versioning for archives
|
|
||||||
- Added: Bulk upload for screenshots and videos
|
|
||||||
- Added: Multiple select support in media grabber
|
|
||||||
- Added: Animated cover support (APNG auto-conversion to video)
|
|
||||||
- Added: Steam screenshot downloads
|
|
||||||
- Added: YouTube video support in media grabber
|
|
||||||
- Added: Media streaming endpoint
|
|
||||||
- Added: ffmpeg/yt-dlp availability checks and auto-install in Docker
|
|
||||||
- Added: Manual key assignment dialog and reworked key allocation
|
|
||||||
- Added: `Set-GameDetails` cmdlet for package scripts
|
|
||||||
- Fixed: Media uploads should now behave as expected
|
|
||||||
- Fixed: Game archive uploads in web UI
|
|
||||||
- Fixed: Orphaned files tool
|
|
||||||
- Fixed: Redistributable archive downloads
|
|
||||||
- Fixed: Script working directory for games
|
|
||||||
- Fixed: SteamCMD login when SteamGuard is enabled
|
|
||||||
- Fixed: Import file cleanup after completion
|
|
||||||
|
|
||||||
**Infrastructure**
|
|
||||||
- Upgraded to .NET 10
|
|
||||||
- Added ARM64 build support
|
|
||||||
- Removed legacy Photino launcher from CI
|
|
||||||
- Added nightly builds for Avalonia launcher
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.0-rc1" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.0.2" to="v2.1.0-rc1" />
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.0-rc2
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ScreenshotCarousel from '@site/src/components/ScreenshotCarousel';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.0 Release Candidate 2 Release Notes
|
|
||||||
|
|
||||||
## Variable Picker Dialog
|
|
||||||
A new variable picker dialog has been added to the action editor and save path editor in the server UI. When editing action arguments, working directories, or save paths, a new button opens a dialog that lets you browse and insert LANCommander variables (`{InstallDir}`, `{DisplayWidth}`, etc.), environment variables (`%APPDATA%`, `%LOCALAPPDATA%`, etc.), and special folder paths (`%MyDocuments%`, `%Desktop%`, etc.) with a single click. No more needing to remember exact variable names or syntax.
|
|
||||||
|
|
||||||
## Redistributable Improvements
|
|
||||||
|
|
||||||
### File Tracking and Cleanup
|
|
||||||
Redistributable files installed into a game's directory are now tracked. When a game is uninstalled, any files that were extracted by redistributables are cleaned up alongside the game's own files. This prevents leftover redistributable artifacts from lingering in the install directory after uninstallation.
|
|
||||||
|
|
||||||
### Detect Install Script Behavior
|
|
||||||
The redistributable install detection logic has been updated. If a redistributable does not have a detect install script defined, the install script will now always run rather than being skipped. This ensures that redistributables without detection scripts are reliably installed every time, which is the expected behavior for most simple redistributable configurations.
|
|
||||||
|
|
||||||
## Package Script Filtering
|
|
||||||
Package scripts are now filtered out of API responses for games, redistributables, and tools. These scripts are used internally during the packaging process and should not be sent to clients. This filtering is applied at both the endpoint and AutoMapper levels, ensuring that package scripts never leak to launchers or other API consumers.
|
|
||||||
|
|
||||||
## Launcher CLI Improvements
|
|
||||||
|
|
||||||
### Full Command Line Verb Support
|
|
||||||
The Avalonia launcher now supports the full set of CLI verbs: `RunScript`, `Install`, `Uninstall`, `Run`, `Sync`, `Import`, `Export`, `Upload`, `Login`, `Logout`, and `ChangeAlias`. Previously only `RunScript` was supported in headless mode. The `--help` and `--version` flags are also now recognized. Console logging has been added for headless execution.
|
|
||||||
|
|
||||||
### CLI Project Removal
|
|
||||||
The standalone `LANCommander.Launcher.CLI` project has been removed. All CLI functionality is now handled directly by the Avalonia launcher's headless mode, consolidating the codebase and eliminating the need for a separate CLI binary.
|
|
||||||
|
|
||||||
## C++ SDK
|
|
||||||
A new C++ SDK (`LANCommander.SDK.Cpp`) has been introduced. Written in C++14, it provides maximum compatibility from Windows 95 through modern platforms. The SDK includes 16 API clients covering authentication, games, library, saves, media, tools, depot, and more. It ships with two HTTP backend implementations (WinINet for Windows and libcurl for cross-platform) and uses vendored cJSON for zero mandatory external dependencies. This SDK is the foundation that powers the legacy launcher.
|
|
||||||
|
|
||||||
## Legacy Launcher
|
|
||||||
|
|
||||||
:::note A Fun Detour
|
|
||||||
The legacy launcher is a fun side project and detour from the main development track. It should not be regarded as a primary concern or a supported production launcher. Think of it as an experiment in seeing just how far back LANCommander's reach can extend.
|
|
||||||
:::
|
|
||||||
|
|
||||||
The legacy launcher is a native Win32 application written in C++ that targets Windows 9x (Windows 95/98/ME) and beyond. Built on Allegro 4 for rendering and GDI+ for image decoding (JPEG cover art, backgrounds, etc.), it provides a surprisingly full-featured LANCommander experience on vintage hardware. GDI+ is a requirement and must be available on the target system. For Windows 9x systems, this means installing the [GDI+ redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=18909).
|
|
||||||
|
|
||||||
Features include:
|
|
||||||
- **Library and Depot browsing** with cover art grid
|
|
||||||
- **Game detail view** with metadata and screenshots
|
|
||||||
- **Download queue** with progress tracking
|
|
||||||
- **Login screen** with server authentication
|
|
||||||
- **Settings screen** with configurable server address
|
|
||||||
- **SQLite-backed local database** for offline game metadata
|
|
||||||
- **Custom window chrome** with a themed UI
|
|
||||||
- **Unicode support** for international character sets
|
|
||||||
|
|
||||||
<ScreenshotCarousel screenshots={[
|
|
||||||
{ src: require('./_Assets/2.1.0-rc2 - Legacy Launcher - Login.png').default, alt: 'Legacy Launcher Login', label: 'Login', caption: 'The login screen running on Windows 98' },
|
|
||||||
{ src: require('./_Assets/2.1.0-rc2 - Legacy Launcher - Library.png').default, alt: 'Legacy Launcher Library', label: 'Library', caption: 'Browsing the game library with cover art' },
|
|
||||||
{ src: require('./_Assets/2.1.0-rc2 - Legacy Launcher - Detail.png').default, alt: 'Legacy Launcher Detail', label: 'Game Detail', caption: 'Game detail view with metadata' },
|
|
||||||
{ src: require('./_Assets/2.1.0-rc2 - Legacy Launcher - Downloads.png').default, alt: 'Legacy Launcher Downloads', label: 'Downloads', caption: 'The download queue in action' },
|
|
||||||
{ src: require('./_Assets/2.1.0-rc2 - Legacy Launcher - Settings.png').default, alt: 'Legacy Launcher Settings', label: 'Settings', caption: 'Configuring server connection settings' },
|
|
||||||
]} />
|
|
||||||
|
|
||||||
## Changelog
|
|
||||||
|
|
||||||
**Server**
|
|
||||||
- Added: Variable picker dialog for action editor and save path editor
|
|
||||||
- Fixed: Package scripts are no longer exposed through API responses
|
|
||||||
- Fixed: Script helper now correctly maps Package and RunWrapper script filenames
|
|
||||||
|
|
||||||
**Launcher**
|
|
||||||
- Added: Full set of CLI verbs (Install, Uninstall, Run, Sync, Import, Export, Upload, Login, Logout, ChangeAlias)
|
|
||||||
- Added: Console logging for headless CLI execution
|
|
||||||
- Changed: Redistributable files are now tracked and cleaned up on uninstall
|
|
||||||
- Changed: Redistributables without detect install scripts now always run the install script
|
|
||||||
- Fixed: Script writing for all script types
|
|
||||||
- Removed: Standalone CLI project (functionality merged into Avalonia launcher)
|
|
||||||
|
|
||||||
**Legacy Launcher**
|
|
||||||
- Added: Complete native Win32 launcher targeting Windows 9x
|
|
||||||
- Added: Library and depot browsing with cover art grid
|
|
||||||
- Added: Game detail view with metadata display
|
|
||||||
- Added: Download queue with SQLite-backed local database
|
|
||||||
- Added: Settings screen with YAML configuration
|
|
||||||
- Added: Custom themed window chrome
|
|
||||||
- Added: Unicode support for Win9x targets
|
|
||||||
- Added: CI workflow for automated builds
|
|
||||||
|
|
||||||
**SDK**
|
|
||||||
- Added: C++ SDK (LANCommander.SDK.Cpp) with C++14 compatibility
|
|
||||||
- Added: WinINet and libcurl HTTP backend implementations
|
|
||||||
- Added: 16 API clients covering full LANCommander API surface
|
|
||||||
- Changed: Game list filtering now shows only standalone mods/expansions and main games
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.0-rc2" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.0-rc1" to="v2.1.0-rc2" />
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.0-rc3
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.0 Release Candidate 3 Release Notes
|
|
||||||
|
|
||||||
## Server Discovery
|
|
||||||
The Avalonia launcher now supports automatic server discovery using the beacon system. When connecting to a server, the launcher can discover LANCommander servers on the local network without needing to manually enter an address. This feature was already present in the legacy Photino launcher and has now been brought forward to the new Avalonia-based launcher.
|
|
||||||
|
|
||||||
## Launcher Improvements
|
|
||||||
|
|
||||||
### List View Rework
|
|
||||||
The list view in the launcher library has been reworked for a cleaner presentation and better usability. It is essentially a reimagination of the library view in the previous launcher.
|
|
||||||
|
|
||||||
### Carousel Fixes
|
|
||||||
Cover art in carousels has received several visual fixes. The shadow overlay on covers now renders correctly, and covers are no longer cut off at the bottom when hovered. These are small polish items that improve the overall look and feel of the depot and library views.
|
|
||||||
|
|
||||||
### Play Button State
|
|
||||||
The play button now correctly reflects the current state of a running game, showing the appropriate playing/stop indicator when a game is actively running.
|
|
||||||
|
|
||||||
### Performance Optimizations
|
|
||||||
General launcher optimizations have been made to improve responsiveness and reduce resource usage.
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
|
|
||||||
### Redistributable and Tool Importing
|
|
||||||
Fixed an issue where importing redistributables and tools from an LCX file was not working correctly.
|
|
||||||
|
|
||||||
### Linux Path Expansion
|
|
||||||
Path variable expansion now correctly preserves the Linux root (`/`) prefix. Previously, expanding variables like `{InstallDir}` on Linux could strip the leading slash, resulting in incorrect paths.
|
|
||||||
|
|
||||||
## Contributions
|
|
||||||
This release includes contributions from the following community members:
|
|
||||||
|
|
||||||
**@akifreak | PR [#403](https://github.com/LANCommander/LANCommander/pull/403): Fix Beacon Discovery**
|
|
||||||
Back for another round of contributions, akifreak tracked down and fixed an issue where server discovery wasn't working reliably. In some cases the launcher was actually finding servers on the network but wasn't surfacing them in the UI. The fix spans the full discovery pipeline; making the probe socket more resilient to bad data, ensuring beacon responses actually reach the client, and refreshing the server list as soon as a new server is found.
|
|
||||||
|
|
||||||
## Changelog
|
|
||||||
|
|
||||||
**Launcher**
|
|
||||||
- Added: Automatic server discovery via beacon system
|
|
||||||
- Added: Play session sync on game import
|
|
||||||
- Added: Additional save handling logging
|
|
||||||
- Changed: Reworked list view layout
|
|
||||||
- Changed: Performance optimizations
|
|
||||||
- Changed: Increased cover art rendering quality
|
|
||||||
- Changed: Action bar layout and behavior adjustments
|
|
||||||
- Fixed: Shadow overlay on covers in carousels
|
|
||||||
- Fixed: Cover art clipping on hover in carousels
|
|
||||||
- Fixed: Play button now shows correct playing/stop state when a game is running
|
|
||||||
- Fixed: Linux path variable expansion now preserves root prefix
|
|
||||||
|
|
||||||
**Server**
|
|
||||||
- Fixed: Redistributable and tool importing
|
|
||||||
- Fixed: Media settings page failing to render
|
|
||||||
|
|
||||||
**SDK**
|
|
||||||
- Fixed: Discovery probe socket resilience against malformed data
|
|
||||||
- Fixed: Broadcast send reliability in DiscoveryProbe
|
|
||||||
- Fixed: Beacon responses now forwarded to BeaconClient event
|
|
||||||
- Fixed: Save client now checks for newer server saves before uploading
|
|
||||||
- Added: Logging in save packaging and upload pipeline
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.0-rc3" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.0-rc2" to="v2.1.0-rc3" />
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.0-rc4
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.0 Release Candidate 4 Release Notes
|
|
||||||
|
|
||||||
## Big Screen Mode
|
|
||||||
The Avalonia launcher now supports a big screen mode designed for use with TVs and handhelds. When enabled, the launcher switches to a fullscreen layout optimized for focused gaming. This pairs with the new gamepad navigation support to make LANCommander usable from the sofa or a handheld without a keyboard or mouse.
|
|
||||||
|
|
||||||
## Gamepad Navigation
|
|
||||||
Full gamepad support has been added to the Avalonia launcher. Controllers are detected and mapped using SDL2, and directional navigation has been implemented across the library views, carousels, game detail pages, and overlay dialogs. Focus management handles moving between UI elements naturally with a d-pad or analog stick, making it possible to browse, install, and launch games entirely with a controller. This feature is still a bit rough around the edges, but should improve in future releases.
|
|
||||||
|
|
||||||
## RunWrapper Scripts for Redistributables
|
|
||||||
RunWrapper scripts were previously defined as a script type but never actually executed. This release adds full execution support during game launch. RunWrapper scripts now run alongside the game process with proper state tracking, cancellation support, and child process cleanup when the game exits.
|
|
||||||
|
|
||||||
## Packaging Dialog
|
|
||||||
The "Package" button has been moved from individual game, redistributable, and tool edit pages to the archive editor. A new packaging dialog provides a consolidated view of the packaging process, making it easier to build and manage archives directly from the archive list.
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
- Fixed scrollbar being overlapped by the titlebar in the launcher
|
|
||||||
- Fixed HQ metadata lookups by updating the HQ SDK dependency
|
|
||||||
- Fixed media downloads failing during game import
|
|
||||||
- Fixed icon downloading
|
|
||||||
- Fixed server save check incorrectly determining newer saves were available
|
|
||||||
|
|
||||||
## Changelog
|
|
||||||
|
|
||||||
**Launcher**
|
|
||||||
- Added: Big screen mode for fullscreen TV/controller use
|
|
||||||
- Added: Gamepad navigation across library, carousels, detail views, and overlays
|
|
||||||
- Fixed: Scrollbar overlapped by titlebar
|
|
||||||
- Fixed: Media download on import
|
|
||||||
- Fixed: Icon downloading
|
|
||||||
|
|
||||||
**Server**
|
|
||||||
- Added: Packaging dialog on archive editor
|
|
||||||
- Added: RunWrapper script type available for redistributable scripts
|
|
||||||
- Changed: Moved "Package" button from edit pages to archive editor
|
|
||||||
- Changed: Updated PowerShell code snippets
|
|
||||||
- Fixed: HQ metadata lookups
|
|
||||||
|
|
||||||
**SDK**
|
|
||||||
- Added: RunWrapper script execution for redistributables with process lifecycle management
|
|
||||||
- Changed: Multi-target framework support
|
|
||||||
- Changed: Source-generated cmdlet registration via new `CmdletRegistrationGenerator`
|
|
||||||
- Fixed: Save client check for newer saves on server
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.0-rc4" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.0-rc3" to="v2.1.0-rc4" />
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.0-rc5
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.0 Release Candidate 5 Release Notes
|
|
||||||
|
|
||||||
## LANCommander Packager
|
|
||||||
A new standalone Avalonia application, LANCommander Packager, has been added for building LCX package files outside of the server. The packager works by monitoring the files and registry entries created by a game's installer. You can then choose which files / registry keys are bundled into the final LCX file.
|
|
||||||
|
|
||||||
## Background Uploading
|
|
||||||
Archive uploads now continue in the background, allowing you to navigate away from the upload page without losing progress. An upload indicator in the sidebar tracks active uploads so you can continue working in other areas of the server while files transfer. This also applies to the import upload dialog.
|
|
||||||
|
|
||||||
## HQ Login in First Time Setup
|
|
||||||
The first time setup wizard now includes a step to log in to LANCommander HQ directly during initial configuration. This streamlines connecting to HQ for metadata and media lookups without needing to visit the settings page after setup is complete.
|
|
||||||
|
|
||||||
## File Manager Improvements
|
|
||||||
The server file manager has received several usability improvements including faster enumeration of large directories, toggleable columns, new Created and Type columns, fixed breadcrumb navigation, and a properly built directory tree with support for cross-platform roots and special folders.
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
- Fixed standalone expansions and mods appearing in nested game lists (#284)
|
|
||||||
- Fixed missing nested game data
|
|
||||||
- Fixed save path matching failing on Windows due to backslash normalization (#266)
|
|
||||||
- Fixed log viewer not working under Settings / Logs (#393)
|
|
||||||
- Fixed user approval menu item not functioning (#405)
|
|
||||||
- Fixed archive processing when using "Use Local File"
|
|
||||||
- Fixed "Use Local File" button being incorrectly disabled
|
|
||||||
|
|
||||||
## Changelog
|
|
||||||
|
|
||||||
**Server**
|
|
||||||
- Added: Background uploading with sidebar progress indicator
|
|
||||||
- Added: HQ login step in first time setup wizard
|
|
||||||
- Added: Button to download current log file
|
|
||||||
- Changed: Improved file manager with faster directory enumeration, toggleable columns, and cross-platform directory tree
|
|
||||||
- Fixed: Log viewer under Settings / Logs (#393)
|
|
||||||
- Fixed: User approval menu item (#405)
|
|
||||||
- Fixed: Archive processing for "Use Local File"
|
|
||||||
- Fixed: "Use Local File" disabled button
|
|
||||||
- Fixed: Standalone expansions/mods shown in nested game lists (#284)
|
|
||||||
- Fixed: Missing nested game data
|
|
||||||
|
|
||||||
**Packager**
|
|
||||||
- Added: New standalone application for building LCX package files
|
|
||||||
- Added: CI workflow for building and releasing the packager
|
|
||||||
- Added: Documentation for packager usage and LCX format
|
|
||||||
|
|
||||||
**SDK**
|
|
||||||
- Fixed: Save path normalization to use forward slashes before regex matching (#266)
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.0-rc5" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.0-rc4" to="v2.1.0-rc5" />
|
|
||||||
|
|
@ -1,678 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.0
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ScreenshotCarousel from '@site/src/components/ScreenshotCarousel';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.0 Release Notes
|
|
||||||
|
|
||||||
:::tip Latest Version
|
|
||||||
This page covers the full LANCommander 2.1 series. The latest patch is **2.1.9** — see [Patch Updates](#patch-updates) below for what's changed since the initial release.
|
|
||||||
:::
|
|
||||||
|
|
||||||
LANCommander 2.1.0 is a landmark release that touches virtually every part of the platform. A brand new launcher built on Avalonia, a standalone packager application, a C++ SDK powering a legacy Win32 launcher, major server improvements, and the launch of LANCommander HQ all come together in what has been the most ambitious update cycle to date.
|
|
||||||
|
|
||||||
## Breaking Changes
|
|
||||||
|
|
||||||
### .NET 10
|
|
||||||
LANCommander has been upgraded from .NET 8 to .NET 10. This should be a seamless transition as all LANCommander binaries are self-contained and include the appropriate .NET runtime. However, if you are running an older version of Windows that does not support .NET 10, you may encounter issues running this version of LANCommander. The minimum supported Windows version is now Windows 10 version 1809.
|
|
||||||
|
|
||||||
## Launching Into the Future
|
|
||||||
To kick things off, LANCommander 2.1.0 introduces a new launcher. As a recap, the previous launcher was built using .NET Blazor and wrapped into a Webview2 chrome using the open source project [Photino](https://www.tryphotino.io/). This decision was originally made in an effort to maintain a somewhat shared codebase with the server web UI.
|
|
||||||
|
|
||||||
Unfortunately, over time limitations of the platform made it apparent that a change had to be made. Community member [aaronpowell](https://github.com/aaronpowell) stepped up and built out a proof of concept for a launcher using Avalonia, an open-source native cross-platform UI framework for .NET. The potential was immediately clear and the decision was made to jump in head first. The following months saw the project refocus on building a new launcher with a major emphasis on performance, reliability, design, and feature parity.
|
|
||||||
|
|
||||||
The result is, well, a project that went off a little off the rails in the best possible fashion:
|
|
||||||
|
|
||||||
<ScreenshotCarousel screenshots={[
|
|
||||||
{ src: require('./_Assets/2.1.0 - Launcher.jpg').default, alt: 'Launcher', label: 'Launcher', caption: 'The brand new Avalonia-based launcher' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Shelf.jpg').default, alt: 'Shelf View', label: 'Shelf View', caption: 'Browse your library in the new shelf layout' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Depot.jpg').default, alt: 'Depot', label: 'Depot', caption: 'The redesigned depot with categorization carousels' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Screenshot.jpg').default, alt: 'Game Details', label: 'Game Details', caption: 'Screenshots and videos displayed right in the detail view' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Downloads.png').default, alt: 'Download Queue', label: 'Download Queue', caption: 'Track every step of the installation process' },
|
|
||||||
]} />
|
|
||||||
|
|
||||||
I think the screenshots speak for themselves. Okay, not quite, there's a lot of fun stuff in this build so let's dive right in!
|
|
||||||
|
|
||||||
### User Library
|
|
||||||
Previous versions of the launcher attempted to bring the art of a game to the forefront. These views are where most players spend their time interacting with the application. However, everyone's tastes are different. As such the library now contains three main views; cover grid, list, and shelf.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Game Details
|
|
||||||
Browsing the user library is great and all, but the detail view is where a game really gets to shine. Metadata has shifted to the right-hand side, descriptions now support more complex formatting with Markdown rendering support, and _finally_ videos and screenshots are displayed in a carousel. A lightbox viewer lets you zoom in on screenshots, watch videos, and even read game manuals right from the detail view thanks to the new built-in PDF viewer.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
This is really just the start of something new. Expect this part of the launcher to be built out more in the future with better publishing tools and metadata expansion.
|
|
||||||
|
|
||||||
### Depot
|
|
||||||
The depot has been overhauled too, probably more than any other part of the launcher. Previous iterations have been _fine_, but with large game sets it was hard to find just what you needed. The new depot puts a focus on categorization while maintaining granular filtering tools to get you exactly where you need to go.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
As you can see, this section more than any other benefits from high quality metadata. We'll get into that later, but first let's talk about game installation.
|
|
||||||
|
|
||||||
### Download Queue
|
|
||||||
Game installation and downloading has been the hardest component to develop in the entire LANCommander platform. And rightly so! Without game installation, all you get is a fancy web UI and a pretty launcher that can't launch any games.
|
|
||||||
|
|
||||||
The LANCommander launcher is essentially a UI wrapper for the LANCommander SDK. The SDK is a .NET library that provides all of the useful bits of communicating with a LANCommander server install. Authentication, script execution, save management, game installation and so much more are provided through this library. In previous iterations, the SDK had a very strict execution plan for installing games. Often times this would lead to deadlocks and outright failures.
|
|
||||||
|
|
||||||
To resolve this in 2.1.0, the game install process has moved to a two-layer queuing system. The first layer of the queue manages what actually enters the download queue. This could be a game, redistributable, tool, or addon. The second layer handles any subprocessing step such as executing the different script types, save downloading, existing file verification, etc. The result is a system that is more transparent and reliable.
|
|
||||||
|
|
||||||
This queuing system has been exposed somewhat in the download queue:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Each entry in the download queue will now report each step of the process during a game installation. In addition to looking a bit less mystical, this should give users an idea of what _exactly_ is happening during a game installation.
|
|
||||||
|
|
||||||
### Big Screen Mode & Gamepad Navigation
|
|
||||||
The launcher now supports a big screen mode designed for use with TVs and handhelds. When enabled, the launcher switches to a fullscreen layout optimized for focused gaming. Gamepad support has been added as well. Controllers are detected and mapped using SDL2, and directional navigation has been implemented across the library views, carousels, game detail pages, and overlay dialogs. Focus management handles moving between UI elements naturally with a d-pad or analog stick, making it possible to browse, install, and launch games with a controller. This feature is pretty barebones for now, but adds a foundation for deeper integration in the future.
|
|
||||||
|
|
||||||
### Discord Rich Presence
|
|
||||||
The launcher now integrates with Discord Rich Presence. When you're playing a game through LANCommander, your Discord status will update to show what you're playing. By default this will show as LANCommander with the game name as the status. If the game is mapped to the correct Discord ID (via external IDs in the server), then the game's official Discord assets will be used for a more polished presentation.
|
|
||||||
|
|
||||||
### Offline Mode
|
|
||||||
Previous attempts at an offline mode in the launcher were pretty clunky and unreliable. In 2.1.0, the launcher now has a proper offline mode that allows you to launch previously installed games even when the server is unreachable.
|
|
||||||
|
|
||||||
### Command Line Interface
|
|
||||||
The Avalonia launcher now handles all CLI functionality directly, replacing the previous standalone CLI project. The full set of CLI verbs is supported: `RunScript`, `Install`, `Uninstall`, `Run`, `Sync`, `Import`, `Export`, `Upload`, `Login`, `Logout`, and `ChangeAlias`. The `--help` and `--version` flags are also recognized, and console logging has been added for headless execution.
|
|
||||||
|
|
||||||
### Single Sign-On
|
|
||||||
SSO was supported in the previous launcher, but it was a bit of an afterthought and not super reliable. In the new launcher it's been given more attention and should work as expected.
|
|
||||||
|
|
||||||
### Chat
|
|
||||||
As with the last version, the chat functionality remains pretty barebones. This is an area that will get more attention in the future, but it _is_ currently available in the new launcher. It might even work a little better.
|
|
||||||
|
|
||||||
## Server Improvements
|
|
||||||
This release should also be pretty exciting for server admins. With a new launcher and shiny new features brings a set of tools to manage them.
|
|
||||||
|
|
||||||
### LANCommander HQ
|
|
||||||
A new metadata provider has been added: LANCommander HQ. This gives server admins another option for sourcing game metadata and media alongside IGDB and SteamGridDB. In addition, support for external IDs beyond IGDB has been introduced, making it easier to cross-reference games across multiple platforms and services. To get started with the HQ, link your Discord account under "Integrations / HQ" in the server settings. The first time setup wizard now includes a step to log in to HQ directly during initial configuration, streamlining the onboarding experience. Existing metadata providers such as IGDB and SteamGridDB are still available as well, so no functionality has been lost from previous versions. We'll cover more about HQ later on in these notes.
|
|
||||||
|
|
||||||
### Preview Tool
|
|
||||||
A new "Preview" editing view has been added to the server for managing game art. Inspired by the launcher's presentation, this tool gives admins a better sense of how their media will look in the launcher before publishing. Screenshots and videos can now be uploaded in bulk, and the media grabber supports selecting multiple assets at once. Animated covers are now supported as well, APNG images grabbed from SteamGridDB are automatically converted to video and should display in the new launcher.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Script Editor Improvements
|
|
||||||
The script editor has received a significant upgrade. Context-aware code completions now suggest built-in PowerShell cmdlets, LANCommander-specific variables, and generated type definitions. Validation has been improved, and script errors are now logged rather than silently swallowed. A new `Set-GameDetails` cmdlet has been added for specifying package details from within scripts.
|
|
||||||
|
|
||||||
### Variable Picker Dialog
|
|
||||||
A new variable picker dialog has been added to the action editor and save path editor. When editing action arguments, working directories, or save paths, a new button opens a dialog that lets you browse and insert LANCommander variables (`{InstallDir}`, `{DisplayWidth}`, etc.), environment variables (`%APPDATA%`, `%LOCALAPPDATA%`, etc.), and special folder paths (`%MyDocuments%`, `%Desktop%`, etc.) with a single click.
|
|
||||||
|
|
||||||
### Redistributable Options
|
|
||||||
Redistributables now support configurable options. Options can be defined with a schema editor, given display names, and are preserved across import/export. Assigning redistributables to a game can now be accessed under the "Redistributables" section of the game editor. When selected, a redistributable with options will render as an easy-to-use form and per-game overrides can be defined.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
A new **RunWrapper** script type has been added as well, giving admins more control over how redistributables and games are executed. RunWrapper scripts now run alongside the game process with proper state tracking, cancellation support, and child process cleanup when the game exits. This should enhance redistributables to cover more use cases such as emulators, launchers, and compatibility shims like Proton or dgVoodoo.
|
|
||||||
|
|
||||||
### Packaging Dialog
|
|
||||||
The "Package" button has been moved from individual game, redistributable, and tool edit pages to the archive editor. A new packaging dialog provides a consolidated view of the packaging process, making it easier to build and manage archives directly from the archive list.
|
|
||||||
|
|
||||||
### Background Uploading
|
|
||||||
Archive uploads now continue in the background, allowing you to navigate away from the upload page without losing progress. An upload indicator in the sidebar tracks active uploads so you can continue working in other areas of the server while files transfer. This also applies to the import upload dialog.
|
|
||||||
|
|
||||||
### File Manager Improvements
|
|
||||||
The server file manager has received several usability improvements including faster enumeration of large directories, toggleable columns, new Created and Type columns, fixed breadcrumb navigation, and a properly built directory tree with support for cross-platform roots and special folders.
|
|
||||||
|
|
||||||
### Key Management
|
|
||||||
Key allocation has been improved. The allocation method on keys is now nullable, and a new manual key assignment dialog has been added. The logic for choosing the next available key has also been reworked.
|
|
||||||
|
|
||||||
### Media & Tooling
|
|
||||||
Server settings now include checks for ffmpeg and yt-dlp availability, with automatic installation support in Docker environments. A new streaming endpoint for media has been added, improving video playback in the launcher. Automatic downloads for Steam screenshots have been added as well. YouTube video support has been added to the media grabber, and ffmpeg is now used for video processing tasks such as APNG conversion and thumbnail generation.
|
|
||||||
|
|
||||||
## LANCommander Packager
|
|
||||||
A new standalone Avalonia application, LANCommander Packager, has been added for building LCX package files outside of the server. The packager works by monitoring the files and registry entries created by a game's installer. You can then choose which files and registry keys are bundled into the final LCX file. If the tool is authenticated to a LANCommander server instance, the game can be directly uploaded to the server as well.
|
|
||||||
|
|
||||||
<ScreenshotCarousel screenshots={[
|
|
||||||
{ src: require('./_Assets/2.1.0 - Packager - Monitor.png').default, alt: 'Packager Monitor', label: 'Monitor', caption: 'The Packager application will monitor the files and registry entries created during installation' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Packager - Select Files.png').default, alt: 'Packager Select Files', label: 'Select Files', caption: 'Files can be individually selected to include in the final import file' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Packager - Registry.png').default, alt: 'Packager Registry Entries', label: 'Registry Entries', caption: 'Registry entries can be individually selected and will be included in install/uninstall scripts' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Packager - Metadata.png').default, alt: 'Packager Metadata', label: 'Metadata', caption: 'Basic metadata can be defined before packaging' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Packager - Metadata Lookup.png').default, alt: 'Packager Metadata Lookup', label: 'Metadata Lookup', caption: 'Metadata can also be pulled in from metadata providers' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Packager - Select Executable.png').default, alt: 'Packager Select Executable', label: 'Select Executable', caption: 'The primary action can be defined before packaging' },
|
|
||||||
{ src: require('./_Assets/2.1.0 - Packager - Generate Package.png').default, alt: 'Packager Generate Package', label: 'Generate Package', caption: 'The final package can be created as an .LCX file or uploaded directly to a server' },
|
|
||||||
]} />
|
|
||||||
|
|
||||||
## C++ SDK & Legacy Launcher
|
|
||||||
|
|
||||||
### C++ SDK
|
|
||||||
A new C++ SDK (`LANCommander.SDK.Cpp`) has been introduced. Written in C++14, it provides maximum compatibility from Windows 95 through modern platforms. The SDK includes 16 API clients covering authentication, games, library, saves, media, tools, depot, and more. It ships with two HTTP backend implementations (WinINet for Windows and libcurl for cross-platform) and uses vendored cJSON for zero mandatory external dependencies. This SDK is the foundation that powers the legacy launcher.
|
|
||||||
|
|
||||||
### Legacy Launcher
|
|
||||||
|
|
||||||
:::note A Fun Detour
|
|
||||||
The legacy launcher is a fun side project and detour from the main development track. It should not be regarded as a primary concern or a supported production launcher. Think of it as an experiment in seeing just how far back LANCommander's reach can extend.
|
|
||||||
:::
|
|
||||||
|
|
||||||
The legacy launcher is a native Win32 application written in C++ that targets Windows 9x (Windows 95/98/ME) and beyond. Built on Allegro 4 for rendering and GDI+ for image decoding (JPEG cover art, backgrounds, etc.), it provides a surprisingly full-featured LANCommander experience on vintage hardware. GDI+ is a requirement and must be available on the target system. For Windows 9x systems, this means installing the [GDI+ redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=18909).
|
|
||||||
|
|
||||||
Features include:
|
|
||||||
- **Library and Depot browsing** with cover art grid
|
|
||||||
- **Game detail view** with metadata and screenshots
|
|
||||||
- **Download queue** with progress tracking
|
|
||||||
- **Login screen** with server authentication
|
|
||||||
- **Settings screen** with configurable server address
|
|
||||||
- **SQLite-backed local database** for offline game metadata
|
|
||||||
- **Custom window chrome** with a themed UI
|
|
||||||
- **Unicode support** for international character sets
|
|
||||||
|
|
||||||
<ScreenshotCarousel screenshots={[
|
|
||||||
{ src: require('./_Assets/2.1.0-rc2 - Legacy Launcher - Login.png').default, alt: 'Legacy Launcher Login', label: 'Login', caption: 'The login screen running on Windows 98' },
|
|
||||||
{ src: require('./_Assets/2.1.0-rc2 - Legacy Launcher - Library.png').default, alt: 'Legacy Launcher Library', label: 'Library', caption: 'Browsing the game library with cover art' },
|
|
||||||
{ src: require('./_Assets/2.1.0-rc2 - Legacy Launcher - Detail.png').default, alt: 'Legacy Launcher Detail', label: 'Game Detail', caption: 'Game detail view with metadata' },
|
|
||||||
{ src: require('./_Assets/2.1.0-rc2 - Legacy Launcher - Downloads.png').default, alt: 'Legacy Launcher Downloads', label: 'Downloads', caption: 'The download queue in action' },
|
|
||||||
{ src: require('./_Assets/2.1.0-rc2 - Legacy Launcher - Settings.png').default, alt: 'Legacy Launcher Settings', label: 'Settings', caption: 'Configuring server connection settings' },
|
|
||||||
]} />
|
|
||||||
|
|
||||||
## LANCommander HQ
|
|
||||||
Last but far from least, this release coincides with the launch of [LANCommander HQ](https://hq.lancommander.com), a new metadata provider and community hub for LANCommander users. The HQ aims to provide a centralized platform for game metadata and media across multiple providers, while also normalizing and enhancing that data with a focus on the needs of LANCommander users. There's a bit to cover, so let's dive in!
|
|
||||||
|
|
||||||
### Metadata
|
|
||||||
LANCommander HQ aggregates metadata from multiple sources including IGDB, SteamGridDB, and user contributions. This data is then normalized and enhanced with a focus on the needs of LANCommander users. There are many metadata providers out there, and unfortunately they all have their own unique schemas and data quality issues. The HQ's goal is to provide a single source of truth for game metadata that can be consumed by LANCommander servers and launchers.
|
|
||||||
|
|
||||||
There are a lot of exciting features in the works for the HQ, but for this release the focus is on building out the core infrastructure and integrating with the new launcher. Expect to see more features and improvements in the future as the HQ continues to evolve.
|
|
||||||
|
|
||||||
### Community
|
|
||||||
The main features of the HQ are currently focused on metadata, but there is the potential to expand it into a broader community hub for LANCommander users. This could include an area to share game configurations, scripts, and other resources. Additionally, there are some content moderation tools in place that should allow the HQ to host user-generated content and provide the best possible experience for all users. If you have a knack for curation and want to help out, there will likely be opportunities to get involved in the future!
|
|
||||||
|
|
||||||
### Tiering / Subscriptions
|
|
||||||
The HQ operates on a tiered subscription model. Currently there are only two tiers: Basic (Free) and Premium ($5/month). The Basic tier provides access to the core metadata features of the HQ, while the Premium tier provides access to additional features such as enhanced metadata, relaxed rate limiting, and more. More information will be provided in the near future and will be provided on this site under the [LANCommander HQ](/hq) section. All paid subscriptions on the HQ are handled by Stripe, so every transaction is secure and your personal information is protected.
|
|
||||||
|
|
||||||
This subscription model is primarily in place to help cover the costs of running the HQ while also providing a sustainable path forward for continued development of LANCommander itself. This entire project is developed and maintained by essentially one person with some help from the community here and there. While this is a labor of love, there are real costs associated with running the infrastructure for the HQ and continued development of LANCommander. The subscription model is designed to be as accessible as possible while also providing a way for users to support the project if they find value in it.
|
|
||||||
|
|
||||||
As such, this will probably mean that the Patreon page will be going away in the near future. For existing patrons, it is recommended to switch over to the new subscription model on the HQ as it provides a more direct way to support the project and access the benefits of the HQ _today_.
|
|
||||||
|
|
||||||
## Contributions
|
|
||||||
This release includes contributions from the following community members:
|
|
||||||
|
|
||||||
**@aaronpowell | PR [#395](https://github.com/LANCommander/LANCommander/pull/395): Avalonia Launcher**
|
|
||||||
A substantial 42-commit, 6,000-line PR that bootstrapped the cross-platform Avalonia launcher. Aaron built out the core application structure, service wiring, and async initialization, and then built out the UI with filtered depot browsing and grid layout, a download queue, install/uninstall flows, a settings page, PDF manual viewer, game action bars, and a full CI pipeline for Windows, Linux, and macOS builds. A lot of the foundation that the current launcher sits on came from this PR.
|
|
||||||
|
|
||||||
**@akifreak | PR [#398](https://github.com/LANCommander/LANCommander/pull/398): Fix Game Archive Upload**
|
|
||||||
Discovered that archive uploads through the web UI were silently broken after upgrading to v2.0.2, traced the problem through the JavaScript bundle, and submitted 11 targeted fixes rather than a single bug report. The fixes covered ES module loading, null-guards on DOM elements, a FileMode.Append seek conflict, incorrect archive ID passing, and error propagation throughout the upload pipeline. The uploading process should feel much more stable now!
|
|
||||||
|
|
||||||
**@akifreak | PR [#403](https://github.com/LANCommander/LANCommander/pull/403): Fix Beacon Discovery**
|
|
||||||
Back for another round of contributions, akifreak tracked down and fixed an issue where server discovery wasn't working reliably. In some cases the launcher was actually finding servers on the network but wasn't surfacing them in the UI. The fix spans the full discovery pipeline; making the probe socket more resilient to bad data, ensuring beacon responses actually reach the client, and refreshing the server list as soon as a new server is found.
|
|
||||||
|
|
||||||
**@MasterMNB | PR [#400](https://github.com/LANCommander/LANCommander/pull/400): Avalonia Launcher Back Button**
|
|
||||||
Improved the visibility and styling of the back button in the `GameDetailView`, which was previously hard to distinguish from the background. It's a small change, but it's a real usability improvement that makes navigation feel more intentional.
|
|
||||||
|
|
||||||
## Changelog
|
|
||||||
|
|
||||||
**Launcher**
|
|
||||||
- Added: Brand new launcher built on Avalonia
|
|
||||||
- Added: Screenshots and videos in game detail carousel with lightbox viewer
|
|
||||||
- Added: Redesigned depot with categorization carousels and advanced filtering
|
|
||||||
- Added: Tools support
|
|
||||||
- Added: Download transfer speed graph
|
|
||||||
- Added: OS notifications upon game installation completion
|
|
||||||
- Added: Discord Rich Presence integration
|
|
||||||
- Added: SSO/OIDC external authentication provider support
|
|
||||||
- Added: Built-in PDF viewer for game manuals
|
|
||||||
- Added: Splash screen on startup
|
|
||||||
- Added: Verify files option in game dropdown
|
|
||||||
- Added: Markdown rendering for game descriptions
|
|
||||||
- Added: Big screen mode for fullscreen TV/controller use
|
|
||||||
- Added: Gamepad navigation across library, carousels, detail views, and overlays
|
|
||||||
- Added: Full set of CLI verbs (Install, Uninstall, Run, Sync, Import, Export, Upload, Login, Logout, ChangeAlias)
|
|
||||||
- Added: Console logging for headless CLI execution
|
|
||||||
- Changed: Refactored game/redistributable/tool install process to two-layer queue system
|
|
||||||
- Changed: Imports should be faster and execute in the background without causing major UI hiccups
|
|
||||||
- Changed: Improved memory management with proper disposal of HTTP clients, RPC clients, and cancellation tokens
|
|
||||||
- Changed: Redistributable files are now tracked and cleaned up on uninstall
|
|
||||||
- Changed: Redistributables without detect install scripts now always run the install script
|
|
||||||
- Fixed: Installing games that already have files on disk will show the verification process during install
|
|
||||||
- Fixed: Linux path variable expansion now preserves root prefix
|
|
||||||
- Fixed: Script writing for all script types
|
|
||||||
- Removed: Standalone CLI project (functionality merged into Avalonia launcher)
|
|
||||||
|
|
||||||
**Server**
|
|
||||||
- Added: LANCommander HQ metadata provider support
|
|
||||||
- Added: Support for external IDs beyond IGDB
|
|
||||||
- Added: New launcher-inspired "Preview" tool for managing art
|
|
||||||
- Added: Context-aware script editor with code completions, validation, and PowerShell type definitions
|
|
||||||
- Added: Redistributable options with schema editor and display names
|
|
||||||
- Added: RunWrapper script type with full execution support
|
|
||||||
- Added: Package versioning for archives
|
|
||||||
- Added: Bulk upload for screenshots and videos
|
|
||||||
- Added: Multiple select support in media grabber
|
|
||||||
- Added: Animated cover support (APNG auto-conversion to video)
|
|
||||||
- Added: Steam screenshot downloads
|
|
||||||
- Added: YouTube video support in media grabber
|
|
||||||
- Added: Media streaming endpoint
|
|
||||||
- Added: ffmpeg/yt-dlp availability checks and auto-install in Docker
|
|
||||||
- Added: Manual key assignment dialog and reworked key allocation
|
|
||||||
- Added: `Set-GameDetails` cmdlet for package scripts
|
|
||||||
- Added: Variable picker dialog for action editor and save path editor
|
|
||||||
- Added: Packaging dialog on archive editor
|
|
||||||
- Added: RunWrapper script type available for redistributable scripts
|
|
||||||
- Added: Background uploading with sidebar progress indicator
|
|
||||||
- Added: HQ login step in first time setup wizard
|
|
||||||
- Added: Button to download current log file
|
|
||||||
- Changed: Moved "Package" button from edit pages to archive editor
|
|
||||||
- Changed: Updated PowerShell code snippets
|
|
||||||
- Changed: Improved file manager with faster directory enumeration, toggleable columns, and cross-platform directory tree
|
|
||||||
- Fixed: Media uploads should now behave as expected
|
|
||||||
- Fixed: Game archive uploads in web UI
|
|
||||||
- Fixed: Orphaned files tool
|
|
||||||
- Fixed: Redistributable archive downloads
|
|
||||||
- Fixed: Script working directory for games
|
|
||||||
- Fixed: SteamCMD login when SteamGuard is enabled
|
|
||||||
- Fixed: Import file cleanup after completion
|
|
||||||
- Fixed: Package scripts are no longer exposed through API responses
|
|
||||||
- Fixed: Script helper now correctly maps Package and RunWrapper script filenames
|
|
||||||
- Fixed: Redistributable and tool importing
|
|
||||||
- Fixed: Media settings page failing to render
|
|
||||||
- Fixed: HQ metadata lookups
|
|
||||||
- Fixed: Log viewer under Settings / Logs (#393)
|
|
||||||
- Fixed: User approval menu item (#405)
|
|
||||||
- Fixed: Archive processing for "Use Local File"
|
|
||||||
- Fixed: "Use Local File" disabled button
|
|
||||||
- Fixed: Standalone expansions/mods shown in nested game lists (#284)
|
|
||||||
- Fixed: Missing nested game data
|
|
||||||
|
|
||||||
**Packager**
|
|
||||||
- Added: New standalone application for building LCX package files
|
|
||||||
- Added: CI workflow for building and releasing the packager
|
|
||||||
|
|
||||||
**Legacy Launcher**
|
|
||||||
- Added: Complete native Win32 launcher targeting Windows 9x
|
|
||||||
- Added: Library and depot browsing with cover art grid
|
|
||||||
- Added: Game detail view with metadata display
|
|
||||||
- Added: Download queue with SQLite-backed local database
|
|
||||||
- Added: Settings screen with YAML configuration
|
|
||||||
- Added: Custom themed window chrome
|
|
||||||
- Added: Unicode support for Win9x targets
|
|
||||||
- Added: CI workflow for automated builds
|
|
||||||
|
|
||||||
**SDK**
|
|
||||||
- Added: C++ SDK (LANCommander.SDK.Cpp) with C++14 compatibility
|
|
||||||
- Added: WinINet and libcurl HTTP backend implementations
|
|
||||||
- Added: 16 API clients covering full LANCommander API surface
|
|
||||||
- Added: RunWrapper script execution for redistributables with process lifecycle management
|
|
||||||
- Added: Logging in save packaging and upload pipeline
|
|
||||||
- Changed: Game list filtering now shows only standalone mods/expansions and main games
|
|
||||||
- Changed: Multi-target framework support
|
|
||||||
- Changed: Source-generated cmdlet registration via new `CmdletRegistrationGenerator`
|
|
||||||
- Fixed: Discovery probe socket resilience against malformed data
|
|
||||||
- Fixed: Broadcast send reliability in DiscoveryProbe
|
|
||||||
- Fixed: Beacon responses now forwarded to BeaconClient event
|
|
||||||
- Fixed: Save client now checks for newer server saves before uploading
|
|
||||||
- Fixed: Save path normalization to use forward slashes before regex matching (#266)
|
|
||||||
|
|
||||||
**Infrastructure**
|
|
||||||
- Upgraded to .NET 10
|
|
||||||
- Added ARM64 build support
|
|
||||||
- Removed legacy Photino launcher from CI
|
|
||||||
- Added nightly builds for Avalonia launcher
|
|
||||||
|
|
||||||
## Patch Updates
|
|
||||||
|
|
||||||
### 2.1.1
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.1 patch notes</summary>
|
|
||||||
|
|
||||||
#### New Features
|
|
||||||
|
|
||||||
##### User Registration in Launcher
|
|
||||||
User registration has been added back into the launcher's login screen. This was a feature from the old launcher that was missed in the port to Avalonia.
|
|
||||||
|
|
||||||
##### Game Update Support
|
|
||||||
The Avalonia launcher's update functionality was only partially-implemented. This has been completed and moved over to the new installation workflow system. Additionally, updates for games can be ignored by clicking the dropdown next to the "Update" button and selecting "Play without updating".
|
|
||||||
|
|
||||||
#### Improvements
|
|
||||||
- Game titles are now dimmed in the library when not installed, making it easier to see what's ready to play at a glance
|
|
||||||
- The games list view and depot now display a helpful message when there are no items, instead of showing a blank screen
|
|
||||||
- The launcher now downloads media on demand if it doesn't exist locally, and gracefully falls back if LibVLC fails to load
|
|
||||||
|
|
||||||
#### Bug Fixes
|
|
||||||
- Fixed bundling of LibVLC on macOS and Windows
|
|
||||||
- Fixed the display of the empty library view
|
|
||||||
- Fixed game updating
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.1" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 2.1.2
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.2 patch notes</summary>
|
|
||||||
|
|
||||||
#### New Features
|
|
||||||
|
|
||||||
##### Redistributable Update Checking
|
|
||||||
The launcher now checks if installed redistributables are up to date and will re-run them when updates are available on the server. This ensures games always have the correct runtime dependencies.
|
|
||||||
|
|
||||||
##### Drag and Drop File Import in Script Editor
|
|
||||||
The script editor now supports drag and drop for `.ps1`, `.reg`, `.ini`, and other text files. PowerShell scripts replace the editor contents, `.reg` files are automatically converted to PowerShell commands, and other text files are inserted as escaped strings.
|
|
||||||
|
|
||||||
##### Manifest and Script Refresh
|
|
||||||
When a game has no update available, the launcher will now refresh the manifest and scripts on disk. This ensures local files stay in sync with server-side changes that don't trigger a full update.
|
|
||||||
|
|
||||||
#### Improvements
|
|
||||||
- Entire row is now clickable in the compact library list view
|
|
||||||
- Items per page selection is now persisted in data tables
|
|
||||||
- Improved process termination handling with fallback for Windows and absolute pathing for `kill` on Linux/macOS
|
|
||||||
|
|
||||||
#### Bug Fixes
|
|
||||||
- Fixed padding in the metadata lookup dialog
|
|
||||||
- Fixed HQ token retrieval on the first-time setup and integrations settings pages
|
|
||||||
- Fixed local server engine tracking (contributed by @Mavyre)
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.2" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 2.1.3
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.3 patch notes</summary>
|
|
||||||
|
|
||||||
#### New Features
|
|
||||||
|
|
||||||
##### Allow Registration Setting
|
|
||||||
Servers now have an "Allow Registration" setting to control whether new users can register accounts. Resolves #408.
|
|
||||||
|
|
||||||
##### Server Autostop Delay
|
|
||||||
Server lifecycle management has been moved to a dedicated `ServerManager`, and servers can now be configured with an autostop delay so they shut down after a period of inactivity. Autostart/autostop for servers should be much more reliable now.
|
|
||||||
|
|
||||||
##### Close to System Tray
|
|
||||||
The launcher can now be closed to the system tray instead of exiting, keeping it running in the background.
|
|
||||||
|
|
||||||
##### Image Optimization Tool
|
|
||||||
A new server-side tool optimizes stored images to reduce disk usage and increase performance when displayed in the launcher.
|
|
||||||
|
|
||||||
##### Play Session Rework
|
|
||||||
Play session tracking has been reworked to be more reliable. Play sessions are now tracked in realtime with the launcher sending keepalives to the server. If a session is detected as stale (e.g. from a crash or improper shutdown), it will be automatically closed and the playtime will be calculated up to that point. This should result in more accurate playtime tracking and prevent issues with sessions that never end.
|
|
||||||
|
|
||||||
If, for some reason, a session is improperly created with a suspiciously long duration, a new server-side tool can be used to clean up these sessions and recalculate playtime under Settings > Tools > **Long Play Session**.
|
|
||||||
|
|
||||||
##### Working Directory from PCGamingWiki
|
|
||||||
Save paths pulled from PCGamingWiki will now attempt to set a working directory automatically.
|
|
||||||
|
|
||||||
#### Breaking Changes
|
|
||||||
##### MySQL/PostgreSQL Database Engine Reinitialization
|
|
||||||
Previous versions of LANCommander had major issues with MySQL/MariaDB and PostgreSQL database engines that would end up softlocking the server when certain operations were performed. This was caused by connections to the database being disposed of prematurely, causing the data access layer to throw exceptions and fail to recover. This has largely been resolved and should result in a much more stable experience using these other database engines.
|
|
||||||
|
|
||||||
However, due to support for MySQL/PostgreSQL falling into neglect, many of the database migrations had become out of sync and would fail to apply correctly. To resolve this, all MySQL/PostgreSQL migrations have been regenerated. This will require deployments using MySQL/PostgreSQL to recreate the database. Normally this type of change would be reserved for a major release, but given the state of the MySQL/PostgreSQL support being completely broken, this change is necessary to provide a stable experience for users of these database engines. If you are using MySQL/PostgreSQL, please make sure to back up your data and be prepared to recreate your database when updating to this version.
|
|
||||||
|
|
||||||
#### Improvements
|
|
||||||
- Performance optimizations for game details were made in the launcher, fixing potentially high CPU usage and RAM allocation with games that have videos or screenshots in the media carousel.
|
|
||||||
- Video players in the media carousel now only play when in view and pause when scrolled out of view or when the window is inactive.
|
|
||||||
- Updated Notify.NET and fixed taskbar progress reporting
|
|
||||||
- Localized remaining time and install progress status
|
|
||||||
- Adjusted styling in the game description
|
|
||||||
- Removed dead code and fixed video/screenshot loading that could block the UI
|
|
||||||
- yt-dlp is now downloaded as a self-contained build removing the dependency on Python for Linux systems.
|
|
||||||
|
|
||||||
#### Bug Fixes
|
|
||||||
- Fixed updating one-to-many relationships on the server. This should resolve various issues with redistributables, tags, genres, and platforms not saving correctly.
|
|
||||||
- Fixed an extra gap on the compact list scrollbar in the launcher
|
|
||||||
- Fixed the missing "Starting" text in the play button when a game is launching
|
|
||||||
- Fixed an exception when adding a game without a SteamGridDB API key configured
|
|
||||||
- Fixed an error thrown during first-time setup when no storage locations exist
|
|
||||||
- Regenerated MySQL/MariaDB and PostgreSQL migrations
|
|
||||||
- Fixed an issue where the identity database context could be disposed of prematurely, causing various issues with user management and authentication when using other database engines
|
|
||||||
- Improved server process termination on Linux by directly calling `kill` via `libc`
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.3" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 2.1.4
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.4 patch notes</summary>
|
|
||||||
|
|
||||||
#### New Features
|
|
||||||
|
|
||||||
##### External Auth Provider Enhancements
|
|
||||||
External authentication providers received a major overhaul. The provider editor now supports auto-discovery of scopes and claim mappings, and claims can be mapped to roles so users are automatically assigned the correct roles when logging in over external auth. Users logging in through an external provider are also auto-provisioned.
|
|
||||||
|
|
||||||
##### Auto Redirect to External Provider
|
|
||||||
A new "Auto Redirect to Provider" setting switches authentication challenges to redirect straight to your external auth provider instead of showing the password login form. If more than one external provider is configured, a minimal provider selection page is shown instead.
|
|
||||||
|
|
||||||
##### Repack Non-Streamable ZIP Archives
|
|
||||||
A new server-side tool in the archive editor can now be used to repack archives that were not created in a streamable format. More information about why this is an issue can be found under the [Archives](/Server/Archives) documentation page.
|
|
||||||
|
|
||||||
##### WebP Media Support
|
|
||||||
Media uploads now support the WebP image format.
|
|
||||||
|
|
||||||
##### Redistributable Uninstall Scripts
|
|
||||||
Redistributables can now define an uninstall script, allowing their runtime dependencies to be cleanly removed.
|
|
||||||
|
|
||||||
##### Single Instance Launcher
|
|
||||||
The launcher now ensures only a single instance can run at a time, preventing conflicts from accidentally opening multiple copies.
|
|
||||||
|
|
||||||
#### Improvements
|
|
||||||
- Local files selected for archive upload can now be moved instead of copied, saving disk space.
|
|
||||||
- Reworked tool installation and action resolution.
|
|
||||||
- Install notifications now only display once the entire install chain is complete.
|
|
||||||
- The "Last Played" text now updates every minute and has been localized.
|
|
||||||
- Added more logging to archive extraction and made the number of install retry attempts configurable.
|
|
||||||
- A message is now shown indicating the server needs to be restarted after changes are made to authentication providers.
|
|
||||||
- Game started/stopped server scripts now run as fire and forget and will not prevent servers from starting.
|
|
||||||
- Adjusted styling for buttons and dropdowns in the launcher.
|
|
||||||
- Updated SharpCompress to 0.49.1.
|
|
||||||
- macOS builds now generate a proper `.app` bundle, and Linux builds now produce an AppImage bundled into the normal workflows.
|
|
||||||
|
|
||||||
#### Bug Fixes
|
|
||||||
- Fixed some situations where saves were not being uploaded/downloaded.
|
|
||||||
- Fixed an error in the launcher when tool actions were not defined.
|
|
||||||
- Fixed server game actions not loading correctly from the server.
|
|
||||||
- Fixed non-standalone addons appearing in the library compact list.
|
|
||||||
- HQ authentication errors are no longer swallowed.
|
|
||||||
- Fixed user promotion / role assignment.
|
|
||||||
- Fixed application icons.
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.4" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 2.1.5
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.5 patch notes</summary>
|
|
||||||
|
|
||||||
#### New Features
|
|
||||||
|
|
||||||
##### Auto Redirect to External Provider in the Launcher
|
|
||||||
The launcher now honors the server's "Auto Redirect to Provider" setting. When enabled, the login screen redirects straight to your external authentication provider, and the standard authentication fields and buttons are hidden based on the server's authentication settings.
|
|
||||||
|
|
||||||
##### Exit Button in Profile Dropdown
|
|
||||||
An "Exit" button is now available under the profile dropdown, making it easier to fully quit the launcher.
|
|
||||||
|
|
||||||
#### Improvements
|
|
||||||
- Consolidated the game flyout into a unified context menu for more consistent actions across the library views.
|
|
||||||
- Tools that have no archive are now hidden from the install overlay.
|
|
||||||
- Automated testing for various aspects of the server UI (thanks [aaronpowell](https://github.com/aaronpowell)!)
|
|
||||||
|
|
||||||
#### Bug Fixes
|
|
||||||
- Fixed removing games from user libraries using the launcher.
|
|
||||||
- Fixed tool installation.
|
|
||||||
- Fixed the clickability of games in the compact library list.
|
|
||||||
- Fixed updating of roles.
|
|
||||||
- Fixed saving of authentication settings.
|
|
||||||
- Fixed admin user creation in first time setup.
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.5" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 2.1.6
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.6 patch notes</summary>
|
|
||||||
|
|
||||||
#### New Features
|
|
||||||
|
|
||||||
##### User and Role Limits
|
|
||||||
Roles and individual users can now be assigned limits for save storage, total user storage, and download speed. This gives admins finer control over resource usage on shared servers. Resolves [#85](https://github.com/LANCommander/LANCommander/issues/85), [#84](https://github.com/LANCommander/LANCommander/issues/84), and [#100](https://github.com/LANCommander/LANCommander/issues/).
|
|
||||||
|
|
||||||
##### PowerShell Modules
|
|
||||||
A new "Scripting" section has been added to the server UI where PowerShell modules can be defined. These act as a library of reusable functions that can be called from any script. Modules are automatically synced to the launcher and imported when scripts are executed.
|
|
||||||
|
|
||||||
##### Per-Game Tool Tracking
|
|
||||||
Tools are now tracked on a per-game basis. Tools can be marked to "Always Install", and any tools installed for a game are automatically uninstalled when that game is uninstalled.
|
|
||||||
|
|
||||||
##### Admin User Creation Dialog
|
|
||||||
Admins can now create new users directly from the server with a new user creation dialog. Fixes [#419](https://github.com/LANCommander/LANCommander/issues/419).
|
|
||||||
|
|
||||||
##### Database Connection Editor
|
|
||||||
The connection string input used in first-time setup and server settings has been refactored into a full database connection component, making it easier to configure database connections. Fixes [#256](https://github.com/LANCommander/LANCommander/issues/256).
|
|
||||||
|
|
||||||
#### Improvements
|
|
||||||
- Added "Select All" and "Load More" buttons to the media grabber. Fixes [#417](https://github.com/LANCommander/LANCommander/issues/417).
|
|
||||||
- Metadata lookups now preserve existing values instead of overwriting them. Fixes [#420](https://github.com/LANCommander/LANCommander/issues/420).
|
|
||||||
- The Library navigation and library/depot switcher are now hidden in both the web UI and launcher when user libraries are disabled.
|
|
||||||
- Action `ServerHost` values now default to the LANCommander server address.
|
|
||||||
|
|
||||||
#### Bug Fixes
|
|
||||||
- Fixed the display of UTC times.
|
|
||||||
- Fixed creation of entities with many-to-many relationships. Ref [#414](https://github.com/LANCommander/LANCommander/issues/414).
|
|
||||||
- Fixed reconciliation of library games based on whether user libraries are enabled or disabled. Ref [#423](https://github.com/LANCommander/LANCommander/issues/423).
|
|
||||||
- The profile cache is now invalidated when logging out. Fixes [#422](https://github.com/LANCommander/LANCommander/issues/422).
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.6" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 2.1.7
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.7 patch notes</summary>
|
|
||||||
|
|
||||||
#### Improvements
|
|
||||||
- The launcher now loads your library from a new `/Library/Games` endpoint and displays it immediately, with images rendered directly from the server. The full import still runs in the background, so offline functionality is preserved while the library becomes usable much sooner.
|
|
||||||
- Depot images are now streamed from a remote image cache instead of being downloaded to disk, reducing UI jank. Fixes [#427](https://github.com/LANCommander/LANCommander/issues/427).
|
|
||||||
- Game installs and uninstalls are now more reliable: installs run in a consistent order (base game, addons, tools, then redistributables), tools are removed before their game is uninstalled, and the game action bar refreshes after a tool is installed. Ref [#414](https://github.com/LANCommander/LANCommander/issues/414).
|
|
||||||
- The modify menu now lists installed addons.
|
|
||||||
- Save upload failures are now logged instead of failing silently.
|
|
||||||
- A running game process is now terminated as a fallback when no spawned window is detected.
|
|
||||||
- View data is now loaded before transitioning, smoothing navigation.
|
|
||||||
|
|
||||||
#### Bug Fixes
|
|
||||||
- Save path changes on a game now take effect immediately instead of requiring a server restart. Games are correctly updated when a save path is added, updated, or deleted.
|
|
||||||
- Fixed installation of games and addons that have no dependent games.
|
|
||||||
- Fixed importing legacy LCX files that have no save paths defined. Fixes [#426](https://github.com/LANCommander/LANCommander/issues/426).
|
|
||||||
- Fixed persisted page sizes in data tables.
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.7" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 2.1.8
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.8 patch notes</summary>
|
|
||||||
|
|
||||||
#### New Features
|
|
||||||
|
|
||||||
##### Runtime Platform Targeting
|
|
||||||
Actions, scripts, and save paths can now be scoped to a specific runtime platform (Windows, Linux, or macOS). This makes it possible to define platform-specific launch actions, install/uninstall scripts, and save paths on a single game without them conflicting across operating systems. A new `Get-Runtime` PowerShell cmdlet is also available for detecting the current platform from within scripts.
|
|
||||||
|
|
||||||
#### Improvements
|
|
||||||
- The offline mode button has been moved to the titlebar for easier access.
|
|
||||||
- The game description editor in the server UI is now a full Markdown editor.
|
|
||||||
- Page functionality has been improved with better menus for adding and deleting pages, and slugs are now generated in PascalCase.
|
|
||||||
- Client/server version mismatches are now detected and logged, making it easier to diagnose connection issues caused by version drift.
|
|
||||||
- Data table sort order is now persisted.
|
|
||||||
|
|
||||||
#### Bug Fixes
|
|
||||||
- Images now load from the local cache when the launcher is in offline mode.
|
|
||||||
- Fixed enumeration of script snippets.
|
|
||||||
- Fixed PowerShell module loading in the launcher. On Windows the execution policy is set to bypass, and module load failures are now trapped and reported as a warning per module instead of failing the entire script.
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.8" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 2.1.9
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.9 patch notes</summary>
|
|
||||||
|
|
||||||
#### Improvements
|
|
||||||
- Path resolution has been unified across the server so that storage paths are resolved consistently everywhere. A migration aligns existing settings storage paths automatically on upgrade.
|
|
||||||
- Depot queries have been optimized for better performance.
|
|
||||||
- Server notifications now use a shorter timeout so a slow or unreachable server no longer holds up the launcher.
|
|
||||||
- Updated SharpCompress to the latest version. This should resolve most extraction issues for games with large archives.
|
|
||||||
|
|
||||||
#### Bug Fixes
|
|
||||||
- Fixed detection of the primary display's resolution on some Linux multi-display configurations.
|
|
||||||
- Fixed application path resolution on the server, correcting how saves, media, archives, and updates are located.
|
|
||||||
- Improved handling of the bypass execution policy for scripts.
|
|
||||||
- Fixed installation of wine32 and winetricks.
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.9" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.9" />
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.8 downloads</summary>
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.8" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.7 downloads</summary>
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.7" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.6 downloads</summary>
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.6" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.5 downloads</summary>
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.5" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.4 downloads</summary>
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.4" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.3 downloads</summary>
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.3" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.2 downloads</summary>
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.2" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.1 downloads</summary>
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.1" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>View 2.1.0 downloads</summary>
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.0" />
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.0.2" to="v2.1.9" />
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.1
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.1 Release Notes
|
|
||||||
|
|
||||||
:::info Full Release Notes
|
|
||||||
This is a patch release for the **2.1 series**. For the complete feature overview and all patch notes, visit the [LANCommander 2.1.0 release notes](./2.1.0).
|
|
||||||
:::
|
|
||||||
|
|
||||||
## New Features
|
|
||||||
|
|
||||||
### User Registration in Launcher
|
|
||||||
User registration has been added back into the launcher's login screen. This was a feature from the old launcher that was missed in the port to Avalonia.
|
|
||||||
|
|
||||||
### Game Update Support
|
|
||||||
The Avalonia launcher's update functionality was only partially-implemented. This has been completed and moved over to the new installation workflow system. Additionally, updates for games can be ignored by clicking the dropdown next to the "Update" button and selecting "Play without updating".
|
|
||||||
|
|
||||||
## Improvements
|
|
||||||
- Game titles are now dimmed in the library when not installed, making it easier to see what's ready to play at a glance
|
|
||||||
- The games list view and depot now display a helpful message when there are no items, instead of showing a blank screen
|
|
||||||
- The launcher now downloads media on demand if it doesn't exist locally, and gracefully falls back if LibVLC fails to load
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
- Fixed bundling of LibVLC on macOS and Windows
|
|
||||||
- Fixed the display of the empty library view
|
|
||||||
- Fixed game updating
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.1" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.0" to="v2.1.1" />
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.2
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.2 Release Notes
|
|
||||||
|
|
||||||
:::info Full Release Notes
|
|
||||||
This is a patch release for the **2.1 series**. For the complete feature overview and all patch notes, visit the [LANCommander 2.1.0 release notes](./2.1.0).
|
|
||||||
:::
|
|
||||||
|
|
||||||
## New Features
|
|
||||||
|
|
||||||
### Redistributable Update Checking
|
|
||||||
The launcher now checks if installed redistributables are up to date and will re-run them when updates are available on the server. This ensures games always have the correct runtime dependencies.
|
|
||||||
|
|
||||||
### Drag and Drop File Import in Script Editor
|
|
||||||
The script editor now supports drag and drop for `.ps1`, `.reg`, `.ini`, and other text files. PowerShell scripts replace the editor contents, `.reg` files are automatically converted to PowerShell commands, and other text files are inserted as escaped strings.
|
|
||||||
|
|
||||||
### Manifest and Script Refresh
|
|
||||||
When a game has no update available, the launcher will now refresh the manifest and scripts on disk. This ensures local files stay in sync with server-side changes that don't trigger a full update.
|
|
||||||
|
|
||||||
## Improvements
|
|
||||||
- Entire row is now clickable in the compact library list view
|
|
||||||
- Items per page selection is now persisted in data tables
|
|
||||||
- Improved process termination handling with fallback for Windows and absolute pathing for `kill` on Linux/macOS
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
- Fixed padding in the metadata lookup dialog
|
|
||||||
- Fixed HQ token retrieval on the first-time setup and integrations settings pages
|
|
||||||
- Fixed local server engine tracking (contributed by @Mavyre)
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.2" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.1" to="v2.1.2" />
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.3
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.3 Release Notes
|
|
||||||
|
|
||||||
:::info Full Release Notes
|
|
||||||
This is a patch release for the **2.1 series**. For the complete feature overview and all patch notes, visit the [LANCommander 2.1.0 release notes](./2.1.0).
|
|
||||||
:::
|
|
||||||
|
|
||||||
## New Features
|
|
||||||
|
|
||||||
### Allow Registration Setting
|
|
||||||
Servers now have an "Allow Registration" setting to control whether new users can register accounts. Resolves #408.
|
|
||||||
|
|
||||||
### Server Autostop Delay
|
|
||||||
Server lifecycle management has been moved to a dedicated `ServerManager`, and servers can now be configured with an autostop delay so they shut down after a period of inactivity. Autostart/autostop for servers should be much more reliable now.
|
|
||||||
|
|
||||||
### Close to System Tray
|
|
||||||
The launcher can now be closed to the system tray instead of exiting, keeping it running in the background.
|
|
||||||
|
|
||||||
### Image Optimization Tool
|
|
||||||
A new server-side tool optimizes stored images to reduce disk usage and increase performance when displayed in the launcher.
|
|
||||||
|
|
||||||
### Play Session Rework
|
|
||||||
Play session tracking has been reworked to be more reliable. Play sessions are now tracked in realtime with the launcher sending keepalives to the server. If a session is detected as stale (e.g. from a crash or improper shutdown), it will be automatically closed and the playtime will be calculated up to that point. This should result in more accurate playtime tracking and prevent issues with sessions that never end.
|
|
||||||
|
|
||||||
If, for some reason, a session is improperly created with a suspiciously long duration, a new server-side tool can be used to clean up these sessions and recalculate playtime under Settings > Tools > **Long Play Session**.
|
|
||||||
|
|
||||||
### Working Directory from PCGamingWiki
|
|
||||||
Save paths pulled from PCGamingWiki will now attempt to set a working directory automatically.
|
|
||||||
|
|
||||||
## Breaking Changes
|
|
||||||
### MySQL/PostgreSQL Database Engine Reinitialization
|
|
||||||
Previous versions of LANCommander had major issues with MySQL/MariaDB and PostgreSQL database engines that would end up softlocking the server when certain operations were performed. This was caused by connections to the database being disposed of prematurely, causing the data access layer to throw exceptions and fail to recover. This has largely been resolved and should result in a much more stable experience using these other database engines.
|
|
||||||
|
|
||||||
However, due to support for MySQL/PostgreSQL falling into neglect, many of the database migrations had become out of sync and would fail to apply correctly. To resolve this, all MySQL/PostgreSQL migrations have been regenerated. This will require deployments using MySQL/PostgreSQL to recreate the database. Normally this type of change would be reserved for a major release, but given the state of the MySQL/PostgreSQL support being completely broken, this change is necessary to provide a stable experience for users of these database engines. If you are using MySQL/PostgreSQL, please make sure to back up your data and be prepared to recreate your database when updating to this version.
|
|
||||||
|
|
||||||
## Improvements
|
|
||||||
- Performance optimizations for game details were made in the launcher, fixing potentially high CPU usage and RAM allocation with games that have videos or screenshots in the media carousel.
|
|
||||||
- Video players in the media carousel now only play when in view and pause when scrolled out of view or when the window is inactive.
|
|
||||||
- Updated Notify.NET and fixed taskbar progress reporting
|
|
||||||
- Localized remaining time and install progress status
|
|
||||||
- Adjusted styling in the game description
|
|
||||||
- Removed dead code and fixed video/screenshot loading that could block the UI
|
|
||||||
- yt-dlp is now downloaded as a self-contained build removing the dependency on Python for Linux systems.
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
- Fixed updating one-to-many relationships on the server. This should resolve various issues with redistributables, tags, genres, and platforms not saving correctly.
|
|
||||||
- Fixed an extra gap on the compact list scrollbar in the launcher
|
|
||||||
- Fixed the missing "Starting" text in the play button when a game is launching
|
|
||||||
- Fixed an exception when adding a game without a SteamGridDB API key configured
|
|
||||||
- Fixed an error thrown during first-time setup when no storage locations exist
|
|
||||||
- Regenerated MySQL/MariaDB and PostgreSQL migrations
|
|
||||||
- Fixed an issue where the identity database context could be disposed of prematurely, causing various issues with user management and authentication when using other database engines
|
|
||||||
- Improved server process termination on Linux by directly calling `kill` via `libc`
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.3" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.2" to="v2.1.3" />
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.4
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.4 Release Notes
|
|
||||||
|
|
||||||
:::info Full Release Notes
|
|
||||||
This is a patch release for the **2.1 series**. For the complete feature overview and all patch notes, visit the [LANCommander 2.1.0 release notes](./2.1.0).
|
|
||||||
:::
|
|
||||||
|
|
||||||
## New Features
|
|
||||||
|
|
||||||
### External Auth Provider Enhancements
|
|
||||||
External authentication providers received a major overhaul. The provider editor now supports auto-discovery of scopes and claim mappings, and claims can be mapped to roles so users are automatically assigned the correct roles when logging in over external auth. Users logging in through an external provider are also auto-provisioned.
|
|
||||||
|
|
||||||
### Auto Redirect to External Provider
|
|
||||||
A new "Auto Redirect to Provider" setting switches authentication challenges to redirect straight to your external auth provider instead of showing the password login form. If more than one external provider is configured, a minimal provider selection page is shown instead.
|
|
||||||
|
|
||||||
### Repack Non-Streamable ZIP Archives
|
|
||||||
A new server-side tool in the archive editor can now be used to repack archives that were not created in a streamable format. More information about why this is an issue can be found under the [Archives](/Server/Archives) documentation page.
|
|
||||||
|
|
||||||
### WebP Media Support
|
|
||||||
Media uploads now support the WebP image format.
|
|
||||||
|
|
||||||
### Redistributable Uninstall Scripts
|
|
||||||
Redistributables can now define an uninstall script, allowing their runtime dependencies to be cleanly removed.
|
|
||||||
|
|
||||||
### Single Instance Launcher
|
|
||||||
The launcher now ensures only a single instance can run at a time, preventing conflicts from accidentally opening multiple copies.
|
|
||||||
|
|
||||||
## Improvements
|
|
||||||
- Local files selected for archive upload can now be moved instead of copied, saving disk space.
|
|
||||||
- Reworked tool installation and action resolution.
|
|
||||||
- Install notifications now only display once the entire install chain is complete.
|
|
||||||
- The "Last Played" text now updates every minute and has been localized.
|
|
||||||
- Added more logging to archive extraction and made the number of install retry attempts configurable.
|
|
||||||
- A message is now shown indicating the server needs to be restarted after changes are made to authentication providers.
|
|
||||||
- Game started/stopped server scripts now run as fire and forget and will not prevent servers from starting.
|
|
||||||
- Adjusted styling for buttons and dropdowns in the launcher.
|
|
||||||
- Updated SharpCompress to 0.49.1.
|
|
||||||
- macOS builds now generate a proper `.app` bundle, and Linux builds now produce an AppImage bundled into the normal workflows.
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
- Fixed some situations where saves were not being uploaded/downloaded.
|
|
||||||
- Fixed an error in the launcher when tool actions were not defined.
|
|
||||||
- Fixed server game actions not loading correctly from the server.
|
|
||||||
- Fixed non-standalone addons appearing in the library compact list.
|
|
||||||
- HQ authentication errors are no longer swallowed.
|
|
||||||
- Fixed user promotion / role assignment.
|
|
||||||
- Fixed application icons.
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.4" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.3" to="v2.1.4" />
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.5
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.5 Release Notes
|
|
||||||
|
|
||||||
:::info Full Release Notes
|
|
||||||
This is a patch release for the **2.1 series**. For the complete feature overview and all patch notes, visit the [LANCommander 2.1.0 release notes](./2.1.0).
|
|
||||||
:::
|
|
||||||
|
|
||||||
## New Features
|
|
||||||
|
|
||||||
### Auto Redirect to External Provider in the Launcher
|
|
||||||
The launcher now honors the server's "Auto Redirect to Provider" setting. When enabled, the login screen redirects straight to your external authentication provider, and the standard authentication fields and buttons are hidden based on the server's authentication settings.
|
|
||||||
|
|
||||||
### Exit Button in Profile Dropdown
|
|
||||||
An "Exit" button is now available under the profile dropdown, making it easier to fully quit the launcher.
|
|
||||||
|
|
||||||
## Improvements
|
|
||||||
- Consolidated the game flyout into a unified context menu for more consistent actions across the library views.
|
|
||||||
- Tools that have no archive are now hidden from the install overlay.
|
|
||||||
- Automated testing for various aspects of the server UI (thanks [aaronpowell](https://github.com/aaronpowell)!)
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
- Fixed removing games from user libraries using the launcher.
|
|
||||||
- Fixed tool installation.
|
|
||||||
- Fixed the clickability of games in the compact library list.
|
|
||||||
- Fixed updating of roles.
|
|
||||||
- Fixed saving of authentication settings.
|
|
||||||
- Fixed admin user creation in first time setup.
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.5" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.4" to="v2.1.5" />
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.6
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.6 Release Notes
|
|
||||||
|
|
||||||
:::info Full Release Notes
|
|
||||||
This is a patch release for the **2.1 series**. For the complete feature overview and all patch notes, visit the [LANCommander 2.1.0 release notes](./2.1.0).
|
|
||||||
:::
|
|
||||||
|
|
||||||
## New Features
|
|
||||||
|
|
||||||
### User and Role Limits
|
|
||||||
Roles and individual users can now be assigned limits for save storage, total user storage, and download speed. This gives admins finer control over resource usage on shared servers. Resolves [#85](https://github.com/LANCommander/LANCommander/issues/85), [#84](https://github.com/LANCommander/LANCommander/issues/84), and [#100](https://github.com/LANCommander/LANCommander/issues/).
|
|
||||||
|
|
||||||
### PowerShell Modules
|
|
||||||
A new "Scripting" section has been added to the server UI where PowerShell modules can be defined. These act as a library of reusable functions that can be called from any script. Modules are automatically synced to the launcher and imported when scripts are executed.
|
|
||||||
|
|
||||||
### Per-Game Tool Tracking
|
|
||||||
Tools are now tracked on a per-game basis. Tools can be marked to "Always Install", and any tools installed for a game are automatically uninstalled when that game is uninstalled.
|
|
||||||
|
|
||||||
### Admin User Creation Dialog
|
|
||||||
Admins can now create new users directly from the server with a new user creation dialog. Fixes [#419](https://github.com/LANCommander/LANCommander/issues/419).
|
|
||||||
|
|
||||||
### Database Connection Editor
|
|
||||||
The connection string input used in first-time setup and server settings has been refactored into a full database connection component, making it easier to configure database connections. Fixes [#256](https://github.com/LANCommander/LANCommander/issues/256).
|
|
||||||
|
|
||||||
## Improvements
|
|
||||||
- Added "Select All" and "Load More" buttons to the media grabber. Fixes [#417](https://github.com/LANCommander/LANCommander/issues/417).
|
|
||||||
- Metadata lookups now preserve existing values instead of overwriting them. Fixes [#420](https://github.com/LANCommander/LANCommander/issues/420).
|
|
||||||
- The Library navigation and library/depot switcher are now hidden in both the web UI and launcher when user libraries are disabled.
|
|
||||||
- Action `ServerHost` values now default to the LANCommander server address.
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
- Fixed the display of UTC times.
|
|
||||||
- Fixed creation of entities with many-to-many relationships. Ref [#414](https://github.com/LANCommander/LANCommander/issues/414).
|
|
||||||
- Fixed reconciliation of library games based on whether user libraries are enabled or disabled. Ref [#423](https://github.com/LANCommander/LANCommander/issues/423).
|
|
||||||
- The profile cache is now invalidated when logging out. Fixes [#422](https://github.com/LANCommander/LANCommander/issues/422).
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.6" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.5" to="v2.1.6" />
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.7
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.7 Release Notes
|
|
||||||
|
|
||||||
:::info Full Release Notes
|
|
||||||
This is a patch release for the **2.1 series**. For the complete feature overview and all patch notes, visit the [LANCommander 2.1.0 release notes](./2.1.0).
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Improvements
|
|
||||||
- The launcher now loads your library from a new `/Library/Games` endpoint and displays it immediately, with images rendered directly from the server. The full import still runs in the background, so offline functionality is preserved while the library becomes usable much sooner.
|
|
||||||
- Depot images are now streamed from a remote image cache instead of being downloaded to disk, reducing UI jank. Fixes [#427](https://github.com/LANCommander/LANCommander/issues/427).
|
|
||||||
- Game installs and uninstalls are now more reliable: installs run in a consistent order (base game, addons, tools, then redistributables), tools are removed before their game is uninstalled, and the game action bar refreshes after a tool is installed. Ref [#414](https://github.com/LANCommander/LANCommander/issues/414).
|
|
||||||
- The modify menu now lists installed addons.
|
|
||||||
- Save upload failures are now logged instead of failing silently.
|
|
||||||
- A running game process is now terminated as a fallback when no spawned window is detected.
|
|
||||||
- View data is now loaded before transitioning, smoothing navigation.
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
- Save path changes on a game now take effect immediately instead of requiring a server restart. Games are correctly updated when a save path is added, updated, or deleted.
|
|
||||||
- Fixed installation of games and addons that have no dependent games.
|
|
||||||
- Fixed importing legacy LCX files that have no save paths defined. Fixes [#426](https://github.com/LANCommander/LANCommander/issues/426).
|
|
||||||
- Fixed persisted page sizes in data tables.
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.7" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.6" to="v2.1.7" />
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.8
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.8 Release Notes
|
|
||||||
|
|
||||||
:::info Full Release Notes
|
|
||||||
This is a patch release for the **2.1 series**. For the complete feature overview and all patch notes, visit the [LANCommander 2.1.0 release notes](./2.1.0).
|
|
||||||
:::
|
|
||||||
|
|
||||||
## New Features
|
|
||||||
|
|
||||||
### Runtime Platform Targeting
|
|
||||||
Actions, scripts, and save paths can now be scoped to a specific runtime platform (Windows, Linux, or macOS). This makes it possible to define platform-specific launch actions, install/uninstall scripts, and save paths on a single game without them conflicting across operating systems. A new `Get-Runtime` PowerShell cmdlet is also available for detecting the current platform from within scripts.
|
|
||||||
|
|
||||||
## Improvements
|
|
||||||
- The offline mode button has been moved to the titlebar for easier access.
|
|
||||||
- The game description editor in the server UI is now a full Markdown editor.
|
|
||||||
- Page functionality has been improved with better menus for adding and deleting pages, and slugs are now generated in PascalCase.
|
|
||||||
- Client/server version mismatches are now detected and logged, making it easier to diagnose connection issues caused by version drift.
|
|
||||||
- Data table sort order is now persisted.
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
- Images now load from the local cache when the launcher is in offline mode.
|
|
||||||
- Fixed enumeration of script snippets.
|
|
||||||
- Fixed PowerShell module loading in the launcher. On Windows the execution policy is set to bypass, and module load failures are now trapped and reported as a warning per module instead of failing the entire script.
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.8" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.7" to="v2.1.8" />
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
---
|
|
||||||
title: 2.1.9
|
|
||||||
---
|
|
||||||
|
|
||||||
import ReleaseDownloads from '@site/src/components/ReleaseDownloads';
|
|
||||||
import ContributorGrid from '@site/src/components/ContributorGrid';
|
|
||||||
|
|
||||||
# LANCommander 2.1.9 Release Notes
|
|
||||||
|
|
||||||
:::info Full Release Notes
|
|
||||||
This is a patch release for the **2.1 series**. For the complete feature overview and all patch notes, visit the [LANCommander 2.1.0 release notes](./2.1.0).
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Improvements
|
|
||||||
- Path resolution has been unified across the server so that storage paths are resolved consistently everywhere. A migration aligns existing settings storage paths automatically on upgrade.
|
|
||||||
- Depot queries have been optimized for better performance.
|
|
||||||
- Server notifications now use a shorter timeout so a slow or unreachable server no longer holds up the launcher.
|
|
||||||
- Updated SharpCompress to the latest version. This should resolve most extraction issues for games with large archives.
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
- Fixed detection of the primary display's resolution on some Linux multi-display configurations.
|
|
||||||
- Fixed application path resolution on the server, correcting how saves, media, archives, and updates are located.
|
|
||||||
- Improved handling of the bypass execution policy for scripts.
|
|
||||||
- Fixed installation of wine32 and winetricks.
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
<ReleaseDownloads release="v2.1.9" />
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<ContributorGrid from="v2.1.8" to="v2.1.9" />
|
|
||||||
|
Before Width: | Height: | Size: 626 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 784 KiB |
|
Before Width: | Height: | Size: 300 KiB |
|
Before Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 411 KiB |
|
Before Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 283 KiB |
|
Before Width: | Height: | Size: 3.2 MiB |
|
Before Width: | Height: | Size: 220 KiB |
|
Before Width: | Height: | Size: 457 KiB |
|
Before Width: | Height: | Size: 829 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 259 KiB |
|
Before Width: | Height: | Size: 921 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
|
@ -1,14 +0,0 @@
|
||||||
## Getting Started
|
|
||||||
The SDK relies on .NET dependency injection in order to expose services to the consuming application. Use of the SDK can be implemented by calling the extension method for registering the services:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
builder.Services.AddLANCommanderClient<Settings>();
|
|
||||||
```
|
|
||||||
|
|
||||||
The generic type parameter (here `Settings`) can be used to allow extension of settings by providing your own class that inherits from `LANCommander.SDK.Settings`.
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
Standard .NET configuration has been implemented in the SDK. By default, `IOptions<Settings>` can be used to retrieve any settings, while `SettingsProvider` is to be used for updating any settings. Any configuration that gets bound to the `Settings` class will be stored in a file called `Settings.yml` on update.
|
|
||||||
|
|
||||||
## Authentication
|
|
||||||
By injecting `LANCommander.SDK.AuthenticationClient`, you can authenticate against a LANCommander server:
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
---
|
|
||||||
sidebar_label: Overview
|
|
||||||
sidebar_position: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
# Overview
|
|
||||||
The LANCommander SDK is a .NET 9 assembly that provides the heart of functionality for the launcher and some parts of the server application. The SDK is currently used for:
|
|
||||||
- Authentication to a LANCommander server
|
|
||||||
- Installation of games / redistributables
|
|
||||||
- Launching of games and play session tracking
|
|
||||||
- Media linking and downloading
|
|
||||||
- Game save syncing, including packing and extraction
|
|
||||||
- PowerShell scripting runtime and execution
|
|
||||||
- Updating a player's profile including alias and custom fields
|
|
||||||
- Submission of issues
|
|
||||||
- Game lobby scanning
|
|
||||||
- Chat client
|
|
||||||
|
|
@ -1,727 +0,0 @@
|
||||||
---
|
|
||||||
title: Cmdlets
|
|
||||||
---
|
|
||||||
|
|
||||||
# Overview
|
|
||||||
Since there is a full PowerShell runtime built into LANCommander, there are a few custom cmdlets that have been added to simplify common tasks that may be needed when installing or configuring a game. This page covers the definition and use of these cmdlets.
|
|
||||||
|
|
||||||
## `Convert-AspectRatio`
|
|
||||||
Calculates a resolution for the desired aspect ratio using an input width and height in pixels.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Convert-AspectRatio
|
|
||||||
-Width <int>
|
|
||||||
-Height <int>
|
|
||||||
-AspectRatio <double>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Convert-AspectRatio` cmdlet is most useful for calculating a resolution for a specific aspect ratio that will fit within a display by either using pillar or letter boxing. For example, some games may only support 4:3 displays and you may want to calculate the correct 4:3 resolution from your 16:9 display. This cmdlet is really useful when paired with `Get-PrimaryDisplay`.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
Convert-AspectRatio -Width 2560 -Height 1440 -AspectRatio (4 / 3)
|
|
||||||
|
|
||||||
# Returns <DisplayResolution>
|
|
||||||
Width : 1920
|
|
||||||
Height : 1440
|
|
||||||
```
|
|
||||||
|
|
||||||
## `ConvertTo-StringBytes`
|
|
||||||
Converts an input string into a byte array.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
ConvertTo-StringBytes
|
|
||||||
-Input <string>
|
|
||||||
-Utf16 <bool>
|
|
||||||
-BigEndian <bool>
|
|
||||||
-MaxLength <int>
|
|
||||||
-MinLength <int>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
`ConvertTo-StringBytes` is extremely useful for patching strings in binary files. It will take any input string and convert it to a byte array. Length can be controlled using the `-MaxLength` and `-MinLength` parameters. Endianness can be set using `-BigEndian`. If the string must be UTF-16 (easily identifiable as characters separated by `0x00`), use `-Utf16`.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
ConvertTo-StringBytes -Input "Hello, world!" -Utf16 1
|
|
||||||
72 0 101 0 108 0 108 0 111 0 44 0 32 0 119 0 111 0 114 0 108 0 100 0 33 0
|
|
||||||
|
|
||||||
ConvertTo-StringBytes -Input "Hello, world!" -MaxLength
|
|
||||||
72 101 108 108 111
|
|
||||||
|
|
||||||
ConvertTo-StringBytes -Input "Hello" -MaxLength 10 -MinLength 10
|
|
||||||
72 101 108 108 111 0 0 0 0 0
|
|
||||||
|
|
||||||
ConvertTo-StringBytes -Input "Hello" -Utf16 1 -BigEndian 1
|
|
||||||
0 72 0 101 0 108 0 108 0 111
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Edit-PatchBinary`
|
|
||||||
Patches binary files at a specified offset.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Edit-PatchBinary
|
|
||||||
-Offset <long>
|
|
||||||
-Data <byte[]>
|
|
||||||
-FilePath <string>
|
|
||||||
-MaxLength <int>
|
|
||||||
-MinLength <int>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
This cmdlet is useful when a binary file has to be patched at a specific offset. It can be extremely useful when paired with `ConvertTo-StringBytes` to update a player name in a binary file.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$bytes = ConvertTo-StringBytes -Input "Master Chief" -Utf16 1 -MaxLength 16 -MinLength 16
|
|
||||||
|
|
||||||
Edit-PatchBinary -FilePath "$($env:LOCALAPPDATA)\Microsoft\Halo 2\Saved Games\S0000000\profile" -Offset 0x08 -Data $bytes
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Get-GameManifest`
|
|
||||||
Parses a game's manifest YAML file from the specified install directory.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-GameManifest
|
|
||||||
-Path <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
Used to deserialize a game's manifest file (`Manifest.yml`) from the specified install directory. Returns the game manifest as an object.
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
```powershell
|
|
||||||
$manifest = Get-GameManifest -Path "C:\Games\Age of Empires II - The Age of Kings"
|
|
||||||
Write-Host $manifest.Title
|
|
||||||
|
|
||||||
Age of Empires II: The Age of Kings
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Get-PrimaryDisplay`
|
|
||||||
Gets the bounds of the machine's current primary display.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-PrimaryDisplay
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Get-PrimaryDisplay` cmdlet takes no parameters and will only return the bounds of the current primary display attached to the machine. This is highly useful in where you might want to automatically set the game's resolution to match the primary display's resolution.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$Display = Get-PrimaryDisplay
|
|
||||||
|
|
||||||
Write-Host "$($Display.Width)x$($Display.Height) @ $($Display.RefreshRate)Hz"
|
|
||||||
|
|
||||||
1920x1080 @ 120Hz
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Update-IniValue`
|
|
||||||
Updates the value of an INI file.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Update-IniValue
|
|
||||||
-Section <string>
|
|
||||||
-Key <string>
|
|
||||||
-Value <string>
|
|
||||||
-FilePath <string>
|
|
||||||
-WrapValueInQuotes <bool> (optional)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
`Update-IniValue` should be used when updating the values of an INI file. These files are typically used for configuring games and may be hard to edit using `Write-ReplaceContentInFile` and regular expressions. INI files are comprised of sections (text surrounded in square brackets, (`[Display]`), and key-value pairs (`Width=1024`).
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
# Change the resolution
|
|
||||||
$Display = Get-PrimaryDisplay
|
|
||||||
Update-IniValue -Section "Display" -Key "Width" -Value "$($Display.Width)" -FilePath "$InstallDirectory\config.ini"
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Write-GameManifest`
|
|
||||||
Serializes a `GameManifest` object and writes it to disk.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Write-GameManifest
|
|
||||||
-Path <string>
|
|
||||||
-Manifest <LANCommander.SDK.GameManifest>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$manifest = Get-GameManifest -Path "C:\Games\Age of Empires II - The Age of Kings"
|
|
||||||
$manifest.SortTitle = "Age of Empires 2"
|
|
||||||
|
|
||||||
Write-GameManifest -Path "C:\Games\Age of Empires II - The Age of Kings\.lancommander\$($manifest.Id)\Manifest.yml"
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Write-ReplaceContentInFile`
|
|
||||||
Find and replace a string in a text file.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Write-ReplaceContentInFile
|
|
||||||
-Pattern <string>
|
|
||||||
-Substitution <string>
|
|
||||||
-FilePath <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
`Write-ReplaceContentInFile` can be used when you want to edit a text file and replace content. The `-Pattern` parameter accepts regular expressions.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
# Changes the player's multiplayer name in Call of Duty (2003)
|
|
||||||
Write-ReplaceContentInFile -Pattern '^seta name (.+)' -Substitution "seta name ""$NewPlayerAlias""" -FilePath "$InstallDirectory\Main\config_mp.cfg"
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Get-UserCustomField`
|
|
||||||
Retrieves the value of a custom field from the user's profile from the server.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-UserCustomField
|
|
||||||
-Name <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
This cmdlet can be useful if you have a game that might require a persistent ID attached to your user. Often times games will assign a unique ID to a player upon creation of a profile, and that ID will be used on a server to keep track of stats, inventory, etc. The list of custom fields added to a user can be viewed under their profile in the server's web UI.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
Get-UserCustomField -Name "SteamId"
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Get-RedistributableOptions`
|
|
||||||
Retrieves the resolved options for a redistributable assigned to a game.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-RedistributableOptions
|
|
||||||
-Path <string>
|
|
||||||
-Id <Guid>
|
|
||||||
-Name <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Get-RedistributableOptions` cmdlet reads the game manifest and returns the resolved option values for the specified redistributable as a nested `PSObject`. Options are resolved in order: schema defaults, then per-game configured values. Nested options in the schema are represented as nested properties on the returned object.
|
|
||||||
|
|
||||||
This cmdlet is useful in [Install](/Scripting/Script Types/Install), [Before Start](/Scripting/Script Types/Before Start), and [Run Wrapper](/Scripting/Script Types/Run Wrapper) scripts where you need to access compatibility shim configuration.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$options = Get-RedistributableOptions -Path $InstallDirectory -Id $GameManifest.Id -Name "umu-launcher"
|
|
||||||
|
|
||||||
# Access nested options
|
|
||||||
Write-Host $options.Game.GAMEID # "umu-default" or admin-configured value
|
|
||||||
Write-Host $options.Proton.PROTONPATH # "GE-Proton" or admin-configured value
|
|
||||||
|
|
||||||
# Use in a script
|
|
||||||
if ($options.Proton.PROTONPATH -eq "GE-Proton") {
|
|
||||||
Write-Host "Using default Proton version"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Update-UserCustomField`
|
|
||||||
Updates the value of a custom field on a users profile.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Update-UserCustomField
|
|
||||||
-Name <string>
|
|
||||||
-Value <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The companion to `Get-UserCustomField`, this cmdlet lets you update or set the value of a custom field on a user's profile directly within your scripts. The most common use case is generating a new user ID on install, writing it to the game's configuration file, and then updating the custom field on the user's profile to store it for subsequent installs.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
Update-UserCustomField -Name "SteamId" -Value "34950494"
|
|
||||||
```
|
|
||||||
|
|
||||||
## `ConvertFrom-SerializedBase64`
|
|
||||||
Deserializes a Base64-encoded YAML string back into an object.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
ConvertFrom-SerializedBase64
|
|
||||||
-Input <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `ConvertFrom-SerializedBase64` cmdlet takes a Base64-encoded string containing YAML-serialized data, decodes it, and deserializes it back into a PowerShell object. This is the companion to `ConvertTo-SerializedBase64` and is useful for reading data that was previously serialized and encoded for storage or transport. Accepts pipeline input.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$data = ConvertFrom-SerializedBase64 -Input "TmFtZTogSGVsbG8="
|
|
||||||
|
|
||||||
# Or via pipeline
|
|
||||||
"TmFtZTogSGVsbG8=" | ConvertFrom-SerializedBase64
|
|
||||||
```
|
|
||||||
|
|
||||||
## `ConvertTo-SerializedBase64`
|
|
||||||
Serializes an object to YAML and encodes it as a Base64 string.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
ConvertTo-SerializedBase64
|
|
||||||
-Input <object>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `ConvertTo-SerializedBase64` cmdlet takes any object, serializes it to YAML, and then encodes the result as a Base64 string. This is useful for storing or transmitting structured data in a compact, text-safe format. Accepts pipeline input.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$obj = @{ Name = "Hello"; Value = 42 }
|
|
||||||
$encoded = ConvertTo-SerializedBase64 -Input $obj
|
|
||||||
|
|
||||||
# Or via pipeline
|
|
||||||
$obj | ConvertTo-SerializedBase64
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Edit-PatchGameSpy`
|
|
||||||
Patches GameSpy master server references in game files to point to a replacement server.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Edit-PatchGameSpy
|
|
||||||
-Path <string>
|
|
||||||
-Hostname <string> (optional, default: "openspy.net")
|
|
||||||
-PublicKey <string> (optional, default: OpenSpy public key)
|
|
||||||
-BinariesToPatch <string[]> (optional, default: "*.dll", "*.exe")
|
|
||||||
-TextFilesToPatch <string[]> (optional, default: "*.ini", "*.cfg", "*.conf")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Edit-PatchGameSpy` cmdlet scans a game's directory for binary and text files that reference GameSpy master servers and patches them to use a replacement server (OpenSpy by default). For binary files, it replaces the `gamespy.com` hostname and public key at the byte level. For text files, it handles Unreal Engine configuration patterns including UT99 and Unreal 2 master server list entries. The replacement hostname must be exactly 12 characters to match the original `gamespy.com` length.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
# Patch all GameSpy references to use OpenSpy (default)
|
|
||||||
Edit-PatchGameSpy -Path "$InstallDirectory"
|
|
||||||
|
|
||||||
# Patch with custom hostname and file patterns
|
|
||||||
Edit-PatchGameSpy -Path "$InstallDirectory" -Hostname "openspy.net" -BinariesToPatch "*.dll","*.exe","*.so"
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Get-HorizontalFov`
|
|
||||||
Calculates a horizontal field of view scaled for the current display's aspect ratio.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-HorizontalFov
|
|
||||||
-Width <int> (optional, defaults to primary display width)
|
|
||||||
-Height <int> (optional, defaults to primary display height)
|
|
||||||
-BaseFov <int> (optional, default: 90)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Get-HorizontalFov` cmdlet calculates a scaled horizontal field of view based on the display's aspect ratio relative to a 4:3 baseline. Many older games use a default 90-degree horizontal FOV designed for 4:3 displays. This cmdlet computes the correct horizontal FOV for wider aspect ratios so that the visible area matches what was intended. If `-Width` and `-Height` are not specified, the primary display's resolution is used automatically.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
# Get FOV for the current display with default 90-degree base
|
|
||||||
$fov = Get-HorizontalFov
|
|
||||||
Write-Host "Horizontal FOV: $fov"
|
|
||||||
|
|
||||||
# Get FOV for a specific resolution with a custom base FOV
|
|
||||||
$fov = Get-HorizontalFov -Width 2560 -Height 1440 -BaseFov 90
|
|
||||||
Write-Host "Horizontal FOV: $fov" # Returns 106
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Get-VerticalFov`
|
|
||||||
Calculates a vertical field of view scaled for the current display's aspect ratio.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-VerticalFov
|
|
||||||
-Width <int> (optional, defaults to primary display width)
|
|
||||||
-Height <int> (optional, defaults to primary display height)
|
|
||||||
-BaseFov <int> (optional, default: 75)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Get-VerticalFov` cmdlet calculates a scaled vertical field of view based on the display's aspect ratio relative to a 4:3 baseline. Some games use vertical FOV for their configuration. This cmdlet computes the correct vertical FOV for wider aspect ratios. If `-Width` and `-Height` are not specified, the primary display's resolution is used automatically.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
# Get vertical FOV for the current display
|
|
||||||
$fov = Get-VerticalFov
|
|
||||||
Write-Host "Vertical FOV: $fov"
|
|
||||||
|
|
||||||
# Get vertical FOV for a specific resolution
|
|
||||||
$fov = Get-VerticalFov -Width 1920 -Height 1080 -BaseFov 75
|
|
||||||
Write-Host "Vertical FOV: $fov" # Returns 59
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Get-SanitizedPath`
|
|
||||||
Removes invalid filename characters from a path string.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-SanitizedPath
|
|
||||||
-Path <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Get-SanitizedPath` cmdlet strips invalid filename characters from the provided path string. This is useful when constructing file paths from user input or game titles that may contain characters not allowed in file names. Accepts pipeline input.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$clean = Get-SanitizedPath -Path "Game: The Sequel?"
|
|
||||||
Write-Host $clean # Returns "Game The Sequel"
|
|
||||||
|
|
||||||
# Or via pipeline
|
|
||||||
"Game: The Sequel?" | Get-SanitizedPath
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Expand-LatestArchive`
|
|
||||||
Downloads and extracts the latest archive for a game, redistributable, or tool.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Expand-LatestArchive
|
|
||||||
-DestinationPath <string> (optional, defaults to current directory)
|
|
||||||
-GameId <Guid> (optional, resolved from $GameManifest or $Game)
|
|
||||||
-RedistributableId <Guid> (optional, resolved from $Redistributable)
|
|
||||||
-ToolId <Guid> (optional, resolved from $Tool)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Expand-LatestArchive` cmdlet extracts the latest archive for a game, redistributable, or tool. When run in a server-side packaging context (where `$LatestArchivePath` is set), it reads directly from the local archive file. When run in a client-side context, it downloads the archive from the LANCommander server via the API. The target ID is automatically resolved from context variables (`$Redistributable`, `$Tool`, `$GameManifest`, or `$Game`) if not explicitly provided. Returns a `DirectoryInfo` object pointing to the extraction destination.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
# Extract to the current directory using the context variable
|
|
||||||
Expand-LatestArchive
|
|
||||||
|
|
||||||
# Extract to a specific directory
|
|
||||||
Expand-LatestArchive -DestinationPath "C:\Games\MyGame"
|
|
||||||
|
|
||||||
# Extract a specific game's archive
|
|
||||||
Expand-LatestArchive -GameId "a1b2c3d4-e5f6-7890-abcd-ef1234567890" -DestinationPath "C:\Staging"
|
|
||||||
|
|
||||||
# Extract a redistributable's archive
|
|
||||||
Expand-LatestArchive -RedistributableId "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
||||||
|
|
||||||
# Extract a tool's archive
|
|
||||||
Expand-LatestArchive -ToolId "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
||||||
```
|
|
||||||
|
|
||||||
## `New-Package`
|
|
||||||
Creates a package result object for the packaging pipeline.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
New-Package
|
|
||||||
-Path <string>
|
|
||||||
-Version <string>
|
|
||||||
-Changelog <string> (optional)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `New-Package` cmdlet creates a `Package` object with the specified path, version, and optional changelog, and sets it as the script's return value. This cmdlet is used in [Package](/Scripting/Script Types/Package) scripts to define the output of the packaging process. The `-Path` parameter should point to the directory containing the package contents to be archived.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
# Create a package from a build output directory
|
|
||||||
New-Package -Path "C:\Build\Output" -Version "1.0.0" -Changelog "Initial release"
|
|
||||||
|
|
||||||
# Minimal usage
|
|
||||||
New-Package -Path "$BuildDirectory" -Version "2.1.0"
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Out-PlayerAvatar`
|
|
||||||
Downloads the current player's avatar from the server.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Out-PlayerAvatar
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Out-PlayerAvatar` cmdlet retrieves the current authenticated player's avatar from the LANCommander server. Returns the avatar file path as a string. This cmdlet takes no parameters and must be run within a LANCommander script context where the player is authenticated.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$avatarPath = Out-PlayerAvatar
|
|
||||||
Write-Host "Avatar saved to: $avatarPath"
|
|
||||||
```
|
|
||||||
|
|
||||||
# Steam-Related Cmdlets
|
|
||||||
|
|
||||||
The following cmdlets provide functionality for interacting with SteamCMD and the Steam Store API. These cmdlets enable you to install Steam games, manage SteamCMD profiles, search for games, and retrieve Steam assets.
|
|
||||||
|
|
||||||
# Connection Management
|
|
||||||
|
|
||||||
## `Connect-SteamCmd`
|
|
||||||
Connects to SteamCMD with the specified username and optional password.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Connect-SteamCmd
|
|
||||||
-Username <string>
|
|
||||||
-Password <SecureString> (optional)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Connect-SteamCmd` cmdlet authenticates with SteamCMD using the provided username and optional password. This is required before installing Steam content that requires authentication. Returns a `SteamCmdStatus` object indicating the connection result.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$securePassword = ConvertTo-SecureString "mypassword" -AsPlainText -Force
|
|
||||||
Connect-SteamCmd -Username "myusername" -Password $securePassword
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Disconnect-SteamCmd`
|
|
||||||
Disconnects from SteamCMD for the specified username.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Disconnect-SteamCmd
|
|
||||||
-Username <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Disconnect-SteamCmd` cmdlet logs out the specified username from SteamCMD. Returns a `SteamCmdStatus` object indicating the logout result.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
Disconnect-SteamCmd -Username "myusername"
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Get-SteamCmdConnectionStatus`
|
|
||||||
Gets the connection status for a SteamCMD username.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-SteamCmdConnectionStatus
|
|
||||||
-Username <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Get-SteamCmdConnectionStatus` cmdlet retrieves the current connection status for the specified username. Returns a `SteamCmdConnectionStatus` object containing information about whether the user is connected and authenticated.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$status = Get-SteamCmdConnectionStatus -Username "myusername"
|
|
||||||
Write-Host "Connected: $($status.IsConnected)"
|
|
||||||
```
|
|
||||||
|
|
||||||
# SteamCMD Configuration
|
|
||||||
|
|
||||||
## `Get-SteamCmdPath`
|
|
||||||
Gets the path to the SteamCMD executable.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-SteamCmdPath
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Get-SteamCmdPath` cmdlet attempts to auto-detect the SteamCMD executable path on the system. Returns the path as a string if found, or nothing if SteamCMD is not detected.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$steamCmdPath = Get-SteamCmdPath
|
|
||||||
if ($steamCmdPath) {
|
|
||||||
Write-Host "SteamCMD found at: $steamCmdPath"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Get-SteamCmdProfile`
|
|
||||||
Gets a SteamCMD profile for the specified username.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-SteamCmdProfile
|
|
||||||
-Username <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Get-SteamCmdProfile` cmdlet retrieves the SteamCMD profile configuration for the specified username. Returns a `SteamCmdProfile` object containing the username and install directory, or nothing if the profile doesn't exist.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$profile = Get-SteamCmdProfile -Username "myusername"
|
|
||||||
if ($profile) {
|
|
||||||
Write-Host "Install Directory: $($profile.InstallDirectory)"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Get-SteamCmdProfiles`
|
|
||||||
Gets all SteamCMD profiles.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-SteamCmdProfiles
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Get-SteamCmdProfiles` cmdlet retrieves all configured SteamCMD profiles. Returns a collection of `SteamCmdProfile` objects.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$profiles = Get-SteamCmdProfiles
|
|
||||||
foreach ($profile in $profiles) {
|
|
||||||
Write-Host "$($profile.Username): $($profile.InstallDirectory)"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Set-SteamCmdProfile`
|
|
||||||
Creates or updates a SteamCMD profile.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Set-SteamCmdProfile
|
|
||||||
-Username <string>
|
|
||||||
-InstallDirectory <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Set-SteamCmdProfile` cmdlet creates or updates a SteamCMD profile with the specified username and install directory. This profile is used to store SteamCMD configuration settings.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
Set-SteamCmdProfile -Username "myusername" -InstallDirectory "C:\Steam\Content"
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Remove-SteamCmdProfile`
|
|
||||||
Removes a SteamCMD profile.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Remove-SteamCmdProfile
|
|
||||||
-Username <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Remove-SteamCmdProfile` cmdlet deletes the SteamCMD profile for the specified username.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
Remove-SteamCmdProfile -Username "myusername"
|
|
||||||
```
|
|
||||||
|
|
||||||
# Steam Content Installation
|
|
||||||
|
|
||||||
## `Install-SteamContent`
|
|
||||||
Installs Steam content (game, DLC, etc.) using SteamCMD.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Install-SteamContent
|
|
||||||
-AppId <uint>
|
|
||||||
-InstallDirectory <string>
|
|
||||||
-Username <string> (optional)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Install-SteamContent` cmdlet queues an installation job to download and install Steam content using SteamCMD. The `AppId` parameter specifies the Steam App ID to install, and `InstallDirectory` is where the content will be installed. If `Username` is provided, it will use that profile's authentication. Returns a `SteamCmdInstallJob` object that can be used to track the installation progress.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$job = Install-SteamContent -AppId 730 -InstallDirectory "C:\Games\Counter-Strike 2" -Username "myusername"
|
|
||||||
Write-Host "Installation job started: $($job.Id)"
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Remove-SteamContent`
|
|
||||||
Removes Steam content from the specified install directory.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Remove-SteamContent
|
|
||||||
-InstallDirectory <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Remove-SteamContent` cmdlet removes Steam content from the specified installation directory. Returns a `SteamCmdStatus` object indicating the result of the operation.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
Remove-SteamContent -InstallDirectory "C:\Games\Counter-Strike 2"
|
|
||||||
```
|
|
||||||
|
|
||||||
# Steam Store
|
|
||||||
|
|
||||||
## `Search-SteamGames`
|
|
||||||
Searches for games on the Steam Store.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Search-SteamGames
|
|
||||||
-Keyword <string>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Search-SteamGames` cmdlet searches the Steam Store for games matching the specified keyword. Returns a collection of `GameSearchResult` objects containing the game name and App ID.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$results = Search-SteamGames -Keyword "Counter-Strike"
|
|
||||||
foreach ($result in $results) {
|
|
||||||
Write-Host "$($result.Name) - App ID: $($result.AppId)"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Get-SteamWebAssetUri`
|
|
||||||
Gets the URI for a Steam web asset (logo, header, etc.).
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-SteamWebAssetUri
|
|
||||||
-AppId <int>
|
|
||||||
-WebAssetType <WebAssetType>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Get-SteamWebAssetUri` cmdlet returns the URI for a specific web asset type for the given Steam App ID. The `WebAssetType` parameter accepts one of the following values:
|
|
||||||
- `Capsule` - Small capsule image (231x87)
|
|
||||||
- `CapsuleLarge` - Large capsule image (616x353)
|
|
||||||
- `Header` - Header image
|
|
||||||
- `HeroCapsule` - Hero capsule image
|
|
||||||
- `LibraryCover` - Library cover image (600x900)
|
|
||||||
- `LibraryHeader` - Library header image
|
|
||||||
- `LibraryHero` - Library hero image
|
|
||||||
- `Logo` - Game logo (PNG)
|
|
||||||
|
|
||||||
Returns a `Uri` object.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$logoUri = Get-SteamWebAssetUri -AppId 730 -WebAssetType Logo
|
|
||||||
Write-Host "Logo URL: $logoUri"
|
|
||||||
```
|
|
||||||
|
|
||||||
## `Get-SteamAppInfo`
|
|
||||||
Gets app details from the Steam Store (no API key required) and the **changenumber** (build ID) and last updated time from Steam via SteamKit2 (PICS).
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
```powershell
|
|
||||||
Get-SteamAppInfo
|
|
||||||
-AppId <uint>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Description
|
|
||||||
The `Get-SteamAppInfo` cmdlet returns a `SteamAppInfo` object with name, short description, release date, developers, publishers, and store URL from the public Steam Store `appdetails` endpoint. It also connects to Steam via SteamKit2 (PICS) to fill **LastChangenumber** and **LastUpdated** for the public branch—no Web API key required. If SteamKit2 cannot connect or the app cannot be queried, those two properties are null.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```powershell
|
|
||||||
$info = Get-SteamAppInfo -AppId 413150
|
|
||||||
if ($info) {
|
|
||||||
Write-Host "Name: $($info.Name)"
|
|
||||||
Write-Host "Description: $($info.Description)"
|
|
||||||
Write-Host "Release date: $($info.ReleaseDate)"
|
|
||||||
Write-Host "Developer: $($info.Developer)"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
sidebar_label: Overview
|
|
||||||
sidebar_position: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
# Scripting
|
|
||||||
LANCommander includes a full PowerShell runtime that enables powerful automation for game installation, configuration, and management. Scripts are attached to games and executed by the launcher at key points in the game's lifecycle.
|
|
||||||
|
|
||||||
Scripts have access to a set of custom cmdlets that simplify common tasks such as patching binary files, reading display information, updating INI files, and syncing player profile data with the server.
|
|
||||||
|
|
||||||
import DocCardList from '@theme/DocCardList';
|
|
||||||
|
|
||||||
<DocCardList />
|
|
||||||