#!/bin/sh
# AppRun — ProvenanceEF2 (Star Trek: Voyager — Elite Force II; native Linux port)
#
# The AppImage runtime executes this once it has mounted the image at $APPDIR.
# It does four things:
#
#   1. puts the bundled libraries on LD_LIBRARY_PATH, and with them the two game
#      modules the engine dlopen()s by bare name (game.so, cgame.so);
#   2. picks the Vulkan loader (the host's when there is one, the bundled
#      fallback copy otherwise) through SDL's SDL_VULKAN_LIBRARY;
#   3. on a first boot -- no installation remembered, none on the command line
#      -- asks for the retail installation with a directory dialog and
#      remembers the answer; it is referenced in place, never copied;
#   4. execs the engine, passing the user's arguments through untouched.
#
# Everything else is the engine's own code, and this script implements none of
# it: no retail discovery, no validation, no copying, and no fs_basepath or
# fs_homepath of its own.  The engine reads its game data from the search paths
# it already has (code/qcommon/files.cpp: FS_InitPathVars) and writes its
# configs and saves to the home paths it already derives from XDG
# (code/sys/sys_unix.c: Sys_HomeDataPath).  Nothing is ever written into the
# AppImage, which is a read-only squashfs.
#
# Environment:
#   PROVENANCEEF2_BUNDLED_VULKAN=1  force the bundled libvulkan.so.1 even if the host has one
#
# Engine flags (passed through, handled by the engine):
#   +set fs_basepath <path>   where the retail base/ directory is
#   +set fs_homepath <path>   where configs and saves go
#   +set cl_renderer vulkan   the renderer module to load (renderer_vulkan.so)

set -u

APPDIR="${APPDIR:-$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)}"
export APPDIR
VERSION="__PROVENANCEEF2_VERSION__"
BIN="$APPDIR/usr/bin/provenanceef2"
BUNDLED_VULKAN="$APPDIR/usr/lib/vulkan/libvulkan.so.1"
DATA_ROOT="${XDG_DATA_HOME:-$HOME/.local/share}/provenanceef2"

say() { printf 'provenanceef2: %s\n' "$*" >&2; }
die() { printf 'provenanceef2: error: %s\n' "$*" >&2; exit "${2:-1}"; }

usage() {
    cat <<EOF
ProvenanceEF2 $VERSION — Star Trek: Voyager — Elite Force II (native Linux)

  ProvenanceEF2-*.AppImage [engine arguments]

The retail game data is not included. On a first run without game data a window
asks for your retail installation and remembers the answer (never copied, only
referenced; PROVENANCEEF2_SKIP_PICKER=1 disables the question). You can also
point the game at your own retail installation yourself:

  ProvenanceEF2-*.AppImage +set fs_basepath /path/to/elite-force-ii

or put the retail base/ directory (pak0.pk3 ... and the rest) where the engine
looks for it on its own:

  $DATA_ROOT/base/

Configs and saves land in the same tree, under the engine's own home paths.
Set XDG_DATA_HOME before launching to move that root somewhere else.

Everything after this text is passed to the engine unchanged, including:
  +set <cvar> <value>  (engine console commands)
  e.g. +set r_mode -1 +set r_customwidth 1920 +set r_customheight 1080
       +set s_initsound 0

AppImage runtime options:
  --appimage-extract-and-run  run without FUSE (slower; extracts to \$TMPDIR)
  --appimage-extract          unpack the AppDir under ./squashfs-root
  --appimage-version          print the runtime version
  --apprun-version            print the ProvenanceEF2 version
  --apprun-help               this text
EOF
}

case "${1:-}" in
    --apprun-help)    usage; exit 0 ;;
    --apprun-version) printf 'ProvenanceEF2 %s\n' "$VERSION"; exit 0 ;;
esac

[ -x "$BIN" ] || die "the engine binary is missing from the image ($BIN) — the AppImage is broken" 3
[ -f "$APPDIR/usr/bin/renderer_vulkan.so" ] \
    || die "renderer_vulkan.so is missing from the image — the engine cannot start without it" 3

# --------------------------------------------------------------- 1. bundled libs
# usr/lib holds the third-party closure (SDL and whatever it drags in that is
# not desktop-owned).  usr/bin holds the engine and the three modules it loads:
# renderer_vulkan.so by path (Sys_LoadDll is called with useSystemLib=qfalse, so
# the bare-name lookup is skipped and Sys_BinaryPath() is tried instead --
# code/client/cl_main.cpp and code/sys/sys_main.c:601) and game.so / cgame.so by
# bare dlopen (Sys_LoadGameDll, code/sys/sys_main.c:689), which LD_LIBRARY_PATH
# resolves.  usr/lib goes first so the bundled SDL wins over the host's.
LD_LIBRARY_PATH="$APPDIR/usr/lib:$APPDIR/usr/bin${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
export LD_LIBRARY_PATH

# ------------------------------------------------------------ 2. Vulkan loader
# Neither the client nor renderer_vulkan.so links Vulkan: NEEDED carries only
# libm/libc/libstdc++/libgcc_s/libSDL2, and the client calls
# SDL_Vulkan_CreateSurface, so *SDL* dlopens libvulkan.so.1 at run time.  That
# is the loader, not the driver: it reads the host's /usr/share/vulkan/icd.d and
# loads the host GPU driver, none of which can be shipped here.  Loader and
# driver ship from the same stack, so the host's loader is the right one
# whenever it exists; the copy under usr/lib/vulkan is only for a host that has
# a driver but no loader package.  SDL_VULKAN_LIBRARY is SDL's hook for it.
if [ -n "${PROVENANCEEF2_BUNDLED_VULKAN:-}" ] && [ -f "$BUNDLED_VULKAN" ]; then
    SDL_VULKAN_LIBRARY="$BUNDLED_VULKAN"
    export SDL_VULKAN_LIBRARY
elif ! ldconfig -p 2>/dev/null | grep -q 'libvulkan\.so\.1'; then
    if [ -f "$BUNDLED_VULKAN" ]; then
        say "no system libvulkan.so.1 — using the bundled loader"
        SDL_VULKAN_LIBRARY="$BUNDLED_VULKAN"
        export SDL_VULKAN_LIBRARY
    else
        say "warning: no Vulkan loader found; the renderer will fail to initialise"
    fi
fi

# ------------------------------------------------- 3. first-boot install picker
# The Android build asks for the retail files in a first-run import; the Linux
# release selects the installation instead, and references it in place -- this
# script never copies anything.  The choice persists in basepath.conf under the
# engine's data root; a +set fs_basepath on the command line overrides all of
# it, and PROVENANCEEF2_SKIP_PICKER=1 turns the dialog off for headless runs.
have_basepath_arg=0
_prev=""
for _a in "$@"; do
    [ "$_prev" = "+set" ] && [ "$_a" = "fs_basepath" ] && have_basepath_arg=1
    _prev="$_a"
done

# an EF2 installation root carries EF2.exe and a base/ directory holding paks;
# a base/ directory handed over directly is accepted as its parent
valid_root() {
    [ -f "$1/EF2.exe" ] && ls "$1/base/"*.pk3 >/dev/null 2>&1
}

if [ "$have_basepath_arg" = 0 ]; then
    _root=""
    _conf="$DATA_ROOT/basepath.conf"
    if [ -f "$_conf" ]; then
        _root="$(head -n 1 "$_conf")"
        valid_root "$_root" || { say "the remembered installation ($_root) is gone — asking again"; _root=""; }
    fi
    if [ -z "$_root" ] && [ -z "${PROVENANCEEF2_SKIP_PICKER:-}" ] \
        && [ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]; then
        _tries=0
        while [ -z "$_root" ] && [ "$_tries" -lt 3 ]; do
            _tries=$((_tries + 1))
            if command -v zenity >/dev/null 2>&1; then
                _pick="$(zenity --file-selection --directory \
                    --title="Select your Star Trek: Elite Force II installation" \
                    --text="Pick the folder that holds EF2.exe and its base/ directory." \
                    2>/dev/null)"
            elif command -v kdialog >/dev/null 2>&1; then
                _pick="$(kdialog --getexistingdirectory "$HOME" \
                    --title "Select your Star Trek: Elite Force II installation" 2>/dev/null)"
            else
                say "no directory picker available (zenity/kdialog) — install one, or pass +set fs_basepath <path>"
                break
            fi
            [ -z "$_pick" ] && break
            if valid_root "$_pick"; then
                _root="$_pick"
            elif [ -f "$_pick/pak0.pk3" ]; then
                _root="$(dirname -- "$_pick")"
            else
                zenity --error --text="That folder does not look like an Elite Force II installation (no EF2.exe with a base/ directory of paks)." 2>/dev/null \
                    || say "not an Elite Force II installation: $_pick"
            fi
        done
        if [ -n "$_root" ]; then
            mkdir -p "$DATA_ROOT"
            printf '%s\n' "$_root" > "$_conf"
            say "using the installation at $_root (remembered in basepath.conf)"
        fi
    fi
    if [ -n "$_root" ]; then
        set -- "$@" +set fs_basepath "$_root"
    fi
fi

# --------------------------------------------------------------- 4. hand over
# Arguments are forwarded verbatim: the engine owns every flag, including
# +set fs_basepath, and the working directory is left alone so relative paths
# given on the command line keep working.
exec "$BIN" "$@"
