This commit is contained in:
mord0d 2024-01-11 22:55:42 +05:00
commit c281b94d6a
No known key found for this signature in database
6 changed files with 1321 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
_drafts
run
TODO

22
LICENSE Normal file
View file

@ -0,0 +1,22 @@
Copyright (c) 2019-2021, mord0d and their slaves
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

123
README.md Normal file
View file

@ -0,0 +1,123 @@
gamelib
=======
`gamelib` is a shell script for gaming on [FreeBSD](https://www.freebsd.org).
## Supported emulators:
- amd64
- dolphin
- dosbox
- gzdoom
- pcsxr
- renpy
- wine
- wine32 (lib32 required)
- i386 **\[UNTESTED\]**
- dolphin
- dosbox
- gzdoom
- pcsxr
- renpy
- wine
## Pre-requirements:
- Running X11.
- `pkg` (any version with `fetch` subcommand but **not** 1.13.1, it's broken!)
installed;
- Binary repo(s) with supported emulators/engines enabled;
- No need to install any packages (except `pkg` itself), they'll never be used;
- **\[OPTIONAL\]** amd64 with lib32 support (used by `i386-wine`);
## Setup games:
### The structure of the directory with games:
- `$GAMELIB_GAMES_DIR`
- `gamename/` (without spaces)
- `gamelib.conf` (see below)
- `game/` (place here game files)
- `prefix/` (do **not** create it manually!)
### The structure of `gamelib.conf`:
| Function | Description |
| :---: | --- |
| `prerun()` | Function that triggered any time before game run |
| `prerun_first()` | Function that triggered after prefix was created |
These functions available for all supported emulators/engines, even if
`gamelib.conf` does not required.
#### dolphin
| Variable | Description |
| :---: | --- |
| `dolphin_file=` | GameCube/Wii disk image file (relative from the `game/`, see above) |
#### dosbox
| Variable | Description |
| :---: | --- |
| `dosbox_file=` | MS-DOS executable (relative from the `game/`, see above) |
#### gzdoom
| Variable | Description |
| :---: | --- |
| `gzdoom_file=` | WAD file (relative from the `game/`, see above) |
#### pcsxr
| Variable | Description |
| :---: | --- |
| `pcsxr_file=` | Sony PlayStation (PSX) image file (relative from the `game/`, see above) |
| `pcsxr_plugins_dir=` | Absolute path to the directory with plugins, they will be symlinked to the prefix |
| `pcsxr_bios_dir=` | Absolute path to the directory with bios, they will be symlinked to the prefix |
#### renpy
No `gamelib.conf` required.
#### wine (any arch)
| Variable | Description |
| :---: | --- |
| `wine_file=` | Microsoft Windows executable (PE32/PE32+) (relative from the `game/`, see above) |
| `wine_args=` | Additional arguments for the executable |
| `wine_dlls=` | Space-separated dlls that will be installed by winetricks |
| `wine_settings=` | Space-separated settings that will be configured by winetricks |
## Pre-run:
```
export GAMELIB_GAMES_DIR="${HOME}/games"
```
Optional, you can set `GAMELIB_DEBUG` to enable stdout/stderr (in any case,
everything will be logged to `$GAMELIB_GAMES_DIR/.gamelib/gamelib.log`):
```
export GAMELIB_DEBUG=1
```
Then run gamelib:
```
/path/to/gamelib/gamelib help
```
## License:
This project is licensed under the terms of [2-Clause BSD](./LICENSE).

975
gamelib Executable file
View file

@ -0,0 +1,975 @@
#!/bin/sh
#
# Copyright (c) 2019-2021, mord0d and their slaves
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
VERSION="0.5.3"
PROGNAME="gamelib"
arch="$(uname -m)"
euid="$(id -u)"
uid="$(id -ur)"
user="$(id -urn)"
group="$(id -grn)"
orig_HOME="${HOME}"
orig_XDG_CONFIG_HOME="${XDG_CONFIG_HOME}"
orig_XDG_CACHE_HOME="${XDG_CACHE_HOME}"
orig_XDG_DATA_HOME="${XDG_DATA_HOME}"
orig_PATH="${PATH}"
orig_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}"
orig_LD_32_LIBRARY_PATH_RPATH="${LD_32_LIBRARY_PATH_RPATH}"
orig_LD_32_LIBRARY_PATH="${LD_32_LIBRARY_PATH}"
orig_PYTHONPATH="${PYTHONPATH}"
MY_LOCKFILE="${TMPDIR:-/tmp}/.${PROGNAME}-$uid.lock"
MY_DATEFORMAT="${GAMELIB_DATE_FORMAT:-%Y-%m-%d %H:%M:%S}"
MY_DEBUG="${GAMELIB_DEBUG:-0}"
MY_TEMPDIR="${TMPDIR:-/tmp}/.${PROGNAME}}"
# cmd:iscmd {{{
cmd:iscmd() {
command -v "${1}" >/dev/null 2>&1
}
# }}}
# cmd:ls {{{
cmd:ls() {
ls --color=never -1 "${@}" 2>/dev/null
}
# }}}
# cmd:ln {{{
cmd:ln() {
ln -s "${1}" "${2}" >/dev/null 2>&1
return ${?}
}
# }}}
# cmd:mkdir {{{
cmd:mkdir() {
mkdir -p "${1}" >/dev/null 2>&1
return ${?}
}
# }}}
# hlpr:startup {{{
hlpr:startup() {
export MY_GAMESDIR="${GAMELIB_GAMES_DIR}"
if [ -n "${MY_GAMESDIR}" -a -d "${MY_GAMESDIR}" -a -r "${MY_GAMESDIR}" -a -w "${MY_GAMESDIR}" -a -x "${MY_GAMESDIR}" ]; then
export MY_DIR="${MY_GAMESDIR}/.gamelib"
else
hlpr:die "\$GAMELIB_GAMES_DIR is not set or it is not a directory or have wrong permissions"
fi
cmd:mkdir "${MY_DIR}"
[ -n "${MY_DIR}" -a -d "${MY_DIR}" -a -r "${MY_DIR}" -a -w "${MY_DIR}" -a -x "${MY_DIR}" ] || hlpr:die "\$GAMELIB_GAMES_DIR has wrong permissions"
export MY_LIBDIR="${MY_DIR}/lib"
export MY_BINDIR="${MY_DIR}/bin"
export MY_TEMPDIR="${MY_DIR}/tmp"
export MY_LOGFILE="${MY_DIR}/gamelib.log"
for dir in "${MY_LIBDIR}" "${MY_BINDIR}"; do
cmd:mkdir "${dir}"
done
}
# }}}
# hlpr:shutdown {{{
hlpr:shutdown() {
if cmd:iscmd "xrandr"; then
for out in $(xrandr -q | awk '/ connected /{print $1}'); do
xrandr --output "${out}" --auto --gamma 1.0
done
fi
unset LIBGL_DRIVERS_PATH LC_ALL TZ
unset bin path
if [ -n "${orig_PATH}" ]; then
export PATH="${orig_PATH}"
else
unset PATH
fi
if [ -n "${orig_HOME}" ]; then
export HOME="${orig_HOME}"
else
unset HOME
fi
if [ -n "${orig_XDG_CONFIG_HOME}" ]; then
export XDG_CONFIG_HOME="${orig_XDG_CONFIG_HOME}"
else
unset XDG_CONFIG_HOME
fi
if [ -n "${orig_XDG_CACHE_HOME}" ]; then
export XDG_CACHE_HOME="${orig_XDG_CACHE_HOME}"
else
unset XDG_CACHE_HOME
fi
if [ -n "${orig_XDG_DATA_HOME}" ]; then
export XDG_DATA_HOME="${orig_XDG_DATA_HOME}"
else
unset XDG_DATA_HOME
fi
if [ -n "${orig_LD_LIBRARY_PATH}" ]; then
export LD_LIBRARY_PATH="${orig_LD_LIBRARY_PATH}"
else
unset LD_LIBRARY_PATH
fi
if [ -n "${orig_LD_32_LIBRARY_PATH}" ]; then
export LD_32_LIBRARY_PATH="${orig_LD_32_LIBRARY_PATH}"
else
unset LD_32_LIBRARY_PATH
fi
if [ -n "${orig_LD_32_LIBRARY_PATH_RPATH}" ]; then
export LD_32_LIBRARY_PATH_RPATH="${orig_LD_32_LIBRARY_PATH_RPATH}"
else
unset LD_32_LIBRARY_PATH_RPATH
fi
if [ -n "${orig_PYTHONPATH}" ]; then
export PYTHONPATH="${orig_PYTHONPATH}"
else
unset PYTHONPATH
fi
rm -R "${MY_TEMPDIR}" >/dev/null 2>&1
rm "${MY_LOCKFILE}" >/dev/null 2>&1
}
# }}}
# hlpr:msg_log {{{
hlpr:msg_log() {
c_reset="\033[0m"
c_bold="\033[1m"
c_black="\033[30m"
c_red="\033[31m"
c_green="\033[32m"
c_yellow="\033[33m"
c_blue="\033[34m"
c_magenta="\033[35m"
c_cyan="\033[36m"
b_black="\033[30;1m"
b_red="\033[31;1m"
b_green="\033[32;1m"
b_yellow="\033[33;1m"
b_blue="\033[34;1m"
b_magenta="\033[35;1m"
b_cyan="\033[36;1m"
d="$(date "+${MY_DATEFORMAT}")"
lvl="${1}"
shift
case "${lvl}" in
(INF) clr="${b_green}" ;;
(WRN) clr="${b_yellow}" ;;
(ERR) clr="${b_red}" ;;
(FTL) clr="${b_red}" ;;
esac
if [ -z "${MY_LOGFILE}" -o "${MY_DEBUG}" != "0" ]; then
echo -e "[${clr}${lvl}${c_reset}] ${c_cyan}${d}${c_reset} ${c_bold}${*}${c_reset}" >&2
fi
echo "[${lvl}:${$}] ${d} ${*}" >>"${MY_LOGFILE:-/dev/null}"
}
# }}}
# hlpr:err {{{
hlpr:err() {
hlpr:msg_log "ERR" "${@}"
}
# }}}
# hlpr:wrn {{{
hlpr:wrn() {
hlpr:msg_log "WRN" "${@}"
}
# }}}
# hlpr:inf {{{
hlpr:inf() {
hlpr:msg_log "INF" "${@}"
}
# }}}
# hlpr:die {{{
hlpr:die() {
hlpr:msg_log "FTL" "${@}"
exit 1
}
# }}}
# hlpr:ask {{{
hlpr:ask() {
while true; do
read -p "${1}? [y/n] " answer
case "${answer}" in
([Yy]) return 0 ;;
([Nn]) return 1 ;;
(*) MY_DEBUG=1 hlpr:err "incorrect input; only \"y\" or \"n\"" ;;
esac
done
}
# }}}
# hlpr:pkgline {{{
hlpr:pkgline() {
case "${1}" in
(dolphin) pkg_line="^dolphin-emu-[0-9]" ;;
(dosbox) pkg_line="^dosbox-[0-9]" ;;
(gzdoom) pkg_line="^gzdoom-[0-9]" ;;
(pcsxr) pkg_line="^pcsxr-[0-9]" ;;
(renpy) pkg_line="^renpy-[0-9]" ;;
(renpy6) pkg_line="^renpy[0-9]-[0-9]" ;;
(wine) pkg_line="^wine-devel-[0-9]" ;; # TODO:BROKEN
# (wine) pkg_line="^wine-[0-9]" ;;
(wine32) pkg_line="^i386-wine-devel-[0-9]" ;;
(*) return 1 ;;
esac
echo "${pkg_line}"
}
# }}}
# get:pkgname {{{
get:pkgname() {
pkg search "$(hlpr:pkgline "${1}")" 2>/dev/null | awk '{print $1}' | sort -V | tail -n1
return ${?}
}
# }}}
# get:gametype {{{
get:gametype() {
unset wine_file wine_args wine_dlls wine_settings
unset -f prerun prerun_first
unset dolphin_file
unset gzdoom_file
unset dosbox_file
unset ft sv pv
if [ -d "${MY_GAMESDIR}/${1}/game" ]; then
if [ -f "${MY_GAMESDIR}/${1}/gamelib.conf" ]; then
. "${MY_GAMESDIR}/${1}/gamelib.conf"
if [ -n "${dolphin_file}" -a -f "${MY_GAMESDIR}/${1}/game/${dolphin_file}" ]; then
ft="$(file -Lbr "${MY_GAMESDIR}/${1}/game/${dolphin_file}")"
if echo "${ft}" | grep -qE '^Nintendo (Wii|GameCube) disc image \(GCZ format\)$'; then
echo "dolphin"
else
hlpr:err "\"${dolphin_file}\" is not a dolphin image file"
return 1
fi
elif [ -n "${dosbox_file}" -a -f "${MY_GAMESDIR}/${1}/game/${dosbox_file}" ]; then
ft="$(file -Lbr "${MY_GAMESDIR}/${1}/game/${dosbox_file}")"
# MS-DOS executable, LE executable for MS-DOS, DOS4GW DOS extender
# MS-DOS executable
if echo "${ft}" | grep -qE '^MS-DOS executable.*$'; then
echo "dosbox"
else
hlpr:err "\"${dosbox_file}\" is not a dosbox executable file"
return 1
fi
elif [ -n "${gzdoom_file}" -a -f "${MY_GAMESDIR}/${1}/game/${gzdoom_file}" ]; then
ft="$(file -Lbr "${MY_GAMESDIR}/${1}/game/${gzdoom_file}")"
if echo "${ft}" | grep -qE '^doom main IWAD data containing [0-9]+ lumps$'; then
echo "gzdoom"
else
hlpr:err "\"${gzdoom_file}\" is not a gzdoom WAD file"
return 1
fi
elif [ -n "${pcsxr_file}" -a -f "${MY_GAMESDIR}/${1}/game/${pcsxr_file}" ]; then
if run:pcsxr:disktype "${MY_GAMESDIR}/${1}/game/${pcsxr_file}" | grep -q '^ Application "PLAYSTATION"$'; then
echo "pcsxr"
else
hlpr:err "\"${pcsxr_file}\" is not a PlayStation (PSX) disk image"
return 1
fi
elif [ -n "${wine_file}" -a -f "${MY_GAMESDIR}/${1}/game/${wine_file}" ]; then
ft="$(file -Lbr "${MY_GAMESDIR}/${1}/game/${wine_file}" 2>/dev/null)"
# PE32 executable (GUI) Intel 80386, for MS Windows
# PE32 executable (GUI) Intel 80386 (stripped to external PDB), for MS Windows
# PE32 executable (GUI) Intel 80386, for MS Windows, Nullsoft Installer self-extracting archive
# PE32+ executable (GUI) x86-64, for MS Windows
# PE32+ executable (GUI) x86-64 (stripped to external PDB), for MS Windows
# MS-DOS executable PE32 executable (GUI) Intel 80386, for MS Windows, MZ for MS-DOS
if echo "${ft}" | grep -qE '^PE32 executable.*Intel 80386.*for MS Windows' \
|| echo "${ft}" | grep -qE '^MS-DOS executable.*Intel 80386.*for MS Windows'; then
if [ "${arch}" = "amd64" ]; then
if [ -f "/libexec/ld-elf32.so.1" ]; then
echo "wine32"
else
hlpr:err "you can not run win32 executables on ${arch} without lib32 support"
return 1
fi
elif [ "${arch}" = "i386" ]; then
echo "wine"
fi
elif echo "${ft}" | grep -qE '^PE32\+ executable.*x86-64.*for MS Windows$'; then
if [ "${arch}" = "amd64" ]; then
echo "wine"
else
hlpr:err "you can not run win64 executables on ${arch}"
return 1
fi
fi
else
hlpr:err "\"${1}\": unknown game type"
return 1
fi
else
if [ -f "${MY_GAMESDIR}/${1}/game/archive.rpa" ]; then
sv="$(grep -o '[0-9]' "${MY_GAMESDIR}/${1}/game/script_version.txt" 2>/dev/null | head -n1)"
pv="$(pkg rquery '%v' 'renpy' 2>/dev/null | sed 's/\..*//')"
if [ -n "${sv}" -a -n "${pv}" -a "${sv}" = "${pv}" ]; then
echo "renpy"
else
hlpr:wrn "old versions of RenPy not supported (yet)"
echo "renpy6"
fi
else
hlpr:err "\"${1}\": unknown game type"
return 1
fi
fi
else
return 1
fi
}
# }}}
# prnt:license {{{
prnt:license() {
sed -n 's/^# //; s/^#$//; 4,25p' "${0}"
}
# }}}
# prnt:version {{{
prnt:version() {
echo "${PROGNAME} ${VERSION}"
}
# }}}
# prnt:usage {{{
prnt:usage() {
cat <<-__EOF__ | column -ts'|'
run <game> [args]|run game
clean|available in: renpy
cfg, cmd, reg|available in: wine
reinit|available in: dosbox, wine
gui|available in: dolphin, pcsxr
list|show games list
help|show this help
version|print ${PROGNAME} version
upgrade|upgrade existing libs (emulators)
license|print license
__EOF__
}
# }}}
# prnt:list {{{
prnt:list() {
orig_MY_DEBUG="${MY_DEBUG}"
MY_DEBUG=0
for i in $(cmd:ls "${MY_GAMESDIR}"); do
gametype="$(get:gametype "${i}")"
if [ -n "${gametype}" ]; then
echo "${i}|${gametype}"
fi
done | column -ts'|'
MY_DEBUG="${orig_MY_DEBUG}"
}
# }}}
# prnt:list_libs {{{
prnt:list_libs() {
for lib in $(cmd:ls "${MY_LIBDIR}"); do
gameline="$(hlpr:pkgline "${lib#*.}")"
if [ ${?} -eq 0 ]; then
ver="$(grep "${gameline}" "${MY_LIBDIR}/${lib}/.packages.${PROGNAME}" | grep -oE '\-[0-9].*' | sed 's/^-//')"
echo -n "${lib#*.}|${ver}"
if [ -d "${MY_LIBDIR}/${lib}.old" ]; then
oldver="$(grep "${gameline}" "${MY_LIBDIR}/${lib}.old/.packages.${PROGNAME}" | grep -oE '\-[0-9].*' | sed 's/^-//')"
echo "|${oldver}"
else
echo ""
fi
fi
done | column -ts'|'
}
# }}}
# gamelib:add {{{
gamelib:add() {
pkg="$(get:pkgname "${1}")"
pkg_tmp="${MY_TEMPDIR}/.${PROGNAME}-${uid}-${1}"
pkg_unpack="${pkg_tmp}/Unpack"
pkg_workdir="${pkg_tmp}/Workdir"
cmd:mkdir "${pkg_tmp}"
cmd:mkdir "${pkg_unpack}"
# cmd:mkdir "${pkg_workdir}"
if ! pkg fetch -q -U -d -o "${pkg_tmp}" -y "${pkg}" >/dev/null 2>&1; then
cd "${MY_DIR}"
rm -fR "${pkg_tmp}" >/dev/null 2>&1
hlpr:die "fetch packages for \"${1}\" failed"
fi
for p in $(find "${pkg_tmp}/All" -type f -print 2>/dev/null); do
if ! tar -x -C "${pkg_unpack}" -f "${p}" >/dev/null 2>&1; then
cd "${MY_DIR}"
rm -fR "${pkg_tmp}" >/dev/null 2>&1
hlpr:die "cannot unpack \"${p##*/}\" for \"${1}\""
fi
done
chflags -R 0 "${pkg_unpack}" >/dev/null 2>&1
chown -R ${user}:${group} "${pkg_unpack}" >/dev/null 2>&1
chmod -R u+rw,go-w "${pkg_unpack}" >/dev/null 2>&1
mv "${pkg_unpack}/usr/local" "${pkg_workdir}" >/dev/null 2>&1
rm -R "${pkg_unpack}" >/dev/null 2>&1
cd "${pkg_workdir}"
for i in "include" "libdata/pkgconfig" "man" "var" "share/aclocal" \
"share/applications" "share/certs" "share/cmake" "share/bash-completion" \
"share/doc" "share/emacs" "share/examples" "share/ffmpeg/examples" \
"share/gtk-doc" "share/info" "share/licenses" "share/locale" "share/pciids" \
"share/readline"; do
[ -d "${pkg_workdir}/${i}" ] && rm -R "${pkg_workdir}/${i}" >/dev/null 2>&1
done
cmd:ls "${pkg_tmp}/All" | sed 's/\.[a-z]*$//' > "${pkg_workdir}/.packages.${PROGNAME}"
mv "${pkg_workdir}" "${MY_LIBDIR}/${arch}.${1}" >/dev/null 2>&1
rm -R "${pkg_tmp}" >/dev/null 2>&1
return ${?}
}
# }}}
# gamelib:upgrade {{{
gamelib:upgrade() {
for lib in $(cmd:ls "${MY_LIBDIR}"); do
gameline="$(hlpr:pkgline "${lib#*.}")"
if [ ${?} -eq 0 ]; then
i="$(grep "${gameline}" "${MY_LIBDIR}/${lib}/.packages.${PROGNAME}")"
p="$(get:pkgname "${lib#*.}")"
if [ "${i}" != "${p}" ]; then
if hlpr:ask "upgrade ${lib#*.}"; then
hlpr:inf "upgrade ${lib}..."
if [ -d "${MY_LIBDIR}/${lib}.old" ]; then
rm -R "${MY_LIBDIR}/${lib}.old"
fi
mv "${MY_LIBDIR}/${lib}" "${MY_LIBDIR}/${lib}.old"
gamelib:add "${lib#*.}"
fi
fi
fi
done
return ${?}
}
# }}}
# gamelib:rollback {{{
gamelib:rollback() {
if [ -d "${MY_LIBDIR}/${arch}.${1}.old" ]; then
if [ -d "${MY_LIBDIR}/${arch}.${1}" ]; then
rm -R "${MY_LIBDIR}/${arch}.${1}" >/dev/null 2>&1
fi
mv "${MY_LIBDIR}/${arch}.${1}.old" "${MY_LIBDIR}/${arch}.${1}"
else
hlpr:die "\"${1}\" can't be rolled back"
fi
}
# }}}
# run:gamelib:configure {{{
run:gamelib:configure() {
# export LC_ALL="C"
# export LC_ALL="ru_RU.UTF-8"
export TZ="UTC"
export HOME="${MY_GAMESDIR}/${1}/prefix"
export XDG_CONFIG_HOME="${HOME}/.config"
export XDG_CACHE_HOME="${HOME}/.cache"
export XDG_DATA_HOME="${HOME}/.local/share"
for dir in "${XDG_CONFIG_HOME}" "${XDG_CACHE_HOME}" "${XDG_DATA_HOME}"; do
cmd:mkdir "${dir}" || hlpr:die "can't create \"${dir}\""
done
}
# }}}
# run:dolphin {{{
run:dolphin() {
export path="${MY_LIBDIR}/${arch}.dolphin"
export bin="${path}/bin/dolphin-emu"
export PATH="${path}/bin:${PATH}"
export LD_LIBRARY_PATH="${path}/lib:${path}/lib/pulseaudio:${LD_LIBRARY_PATH}"
cmd:mkdir "${PREFIX_DIR}"
run:gamelib:configure "${1}"
cd "${GAME_DIR}"
. ../gamelib.conf
[ -f "${GAME_DIR}/${dolphin_file}" ] || hlpr:die "\"${dolphin_file}\" not found"
case "${2}" in
(gui) "${bin}" >>"${PREFIX_DIR}/gamelib.log" 2>&1; return ;;
('') ;;
(*) hlpr:wrn "unknown argument \"${2}\""; return ;;
esac
if [ -f "${HOME}/.config/dolphin-emu/Dolphin.ini" ]; then
"${bin}-nogui" "${dolphin_file}" >>"${PREFIX_DIR}/gamelib.log" 2>&1
else
"${bin}" >>"${PREFIX_DIR}/gamelib.log" 2>&1
fi
return ${?}
}
# }}}
# run:dosbox:configure {{{
run:dosbox:configure() {
cat > "${GAME_DIR}/dosbox.conf" <<-__EOF__
[sdl]
fullscreen=false
fulldouble=false
fullresolution=desktop
windowresolution=original
output=opengl
autolock=true
sensitivity=100
waitonerror=true
priority=higher,normal
mapperfile=mapper-0.74-3.map
usescancodes=false
[dosbox]
language=
machine=vesa_nolfb
captures=capture
memsize=64
[render]
frameskip=0
aspect=true
scaler=none
[cpu]
core=auto
cputype=auto
cycles=auto
cycleup=10
cycledown=20
[mixer]
nosound=false
rate=44100
blocksize=1024
prebuffer=512
[midi]
mpu401=intelligent
mididevice=default
midiconfig=
[sblaster]
sbtype=sb16
sbbase=220
irq=7
dma=1
hdma=5
sbmixer=true
oplmode=auto
oplemu=default
oplrate=44100
[gus]
gus=false
gusrate=44100
gusbase=240
gusirq=5
gusdma=3
ultradir=C:\ULTRASND
[speaker]
pcspeaker=true
pcrate=44100
tandy=auto
tandyrate=44100
disney=false
[joystick]
joysticktype=auto
timed=false
autofire=false
swap34=false
buttonwrap=false
[serial]
serial1=dummy
serial2=disabled
serial3=disabled
serial4=disabled
[dos]
xms=true
ems=true
umb=true
keyboardlayout=none
[ipx]
ipx=false
[autoexec]
echo off
cls
MOUNT C: ${1}
C:
${2}
EXIT
__EOF__
return ${?}
}
# }}}
# run:dosbox {{{
run:dosbox() {
export path="${MY_LIBDIR}/${arch}.dosbox"
export bin="${path}/bin/dosbox"
export PATH="${path}/bin:${PATH}"
export LD_LIBRARY_PATH="${path}/lib:${LD_LIBRARY_PATH}"
cmd:mkdir "${PREFIX_DIR}"
run:gamelib:configure "${1}"
cd "${GAME_DIR}"
. ../gamelib.conf
[ -f "${GAME_DIR}/${dosbox_file}" ] || hlpr:die "\"${dosbox_file}\" not found"
if [ ! -f "${GAME_DIR}/dosbox.conf" ]; then
run:dosbox:configure "$(pwd)" "${dosbox_file}"
fi
case "${2}" in
(reinit) run:dosbox:configure "$(pwd)" "${dosbox_file}"; return ;;
('') ;;
(*) hlpr:wrn "unknown argument \"${2}\""; return ;;
esac
${bin} "${GAME_DIR}/${dosbox_file}" >>"${PREFIX_DIR}/gamelib.log" 2>&1
return ${?}
}
# }}}
# run:gzdoom {{{
run:gzdoom() {
export path="${MY_LIBDIR}/${arch}.gzdoom"
export bin="${path}/bin/gzdoom"
export PATH="${path}/bin:${PATH}"
export LD_LIBRARY_PATH="${path}/lib:${LD_LIBRARY_PATH}"
cmd:mkdir "${PREFIX_DIR}"
run:gamelib:configure "${1}"
cd "${GAME_DIR}"
. ../gamelib.conf
[ -f "${GAME_DIR}/${gzdoom_file}" ] || hlpr:die "\"${gzdoom_file}\" not found"
if [ ! -f "${XDG_CONFIG_HOME}/gzdoom/gzdoom.pk3" ]; then
${bin} -iwad "/dev/null" >/dev/null 2>&1
cmd:mkdir "${XDG_CONFIG_HOME}/gzdoom"
cmd:ln "${path}/share/doom/gzdoom/gzdoom.pk3" "${XDG_CONFIG_HOME}/gzdoom/gzdoom.pk3"
fi
${bin} -iwad "${GAME_DIR}/${gzdoom_file}" >>"${PREFIX_DIR}/gamelib.log" 2>&1
return ${?}
}
# }}}
# run:pcsxr:disktype {{{
run:pcsxr:disktype() {
if [ ! -x "${MY_BINDIR}/disktype.${arch}" ]; then
pkg_tmp="${MY_TEMPDIR}/.${PROGNAME}-${uid}-disktype"
pkg fetch -q -U -d -o "${pkg_tmp}" -y "disktype" >/dev/null 2>&1
cd "${pkg_tmp}" \
tar -x -C "${pkg_tmp}" -f "${pkg_tmp}"/All/disktype* >/dev/null 2>&1
chflags -R 0 "${pkg_tmp}" >/dev/null 2>&1
chown -R ${user}:${group} "${pkg_tmp}" >/dev/null 2>&1
chmod -R u+rw,go-w "${pkg_tmp}" >/dev/null 2>&1
mv "${pkg_tmp}/usr/local/bin/disktype" "${MY_BINDIR}/disktype.${arch}" >/dev/null 2>&1
cd "${MY_DIR}"
rm -R "${pkg_tmp}" >/dev/null 2>&1
fi
"${MY_BINDIR}/disktype.${arch}" "${1}" 2>/dev/null
return ${?}
}
# }}}
# run:pcsxr:configure {{{
run:pcsxr:configure() {
cmd:mkdir "${HOME}/.pcsxr/bios"
cmd:mkdir "${HOME}/.pcsxr/plugins"
for plugin in $(cmd:ls "${path}/lib/pcsxr"); do
if [ ! -f "${HOME}/.pcsxr/plugins/${plugin}" ]; then
cmd:ln "${path}/lib/pcsxr/${plugin}" "${HOME}/.pcsxr/plugins/${plugin}"
fi
done
return ${?}
}
# }}}
# run:pcsxr {{{
run:pcsxr() {
local first=0
export path="${MY_LIBDIR}/${arch}.pcsxr"
export bin="${path}/bin/pcsxr"
export PATH="${path}/bin:${PATH}"
export LD_LIBRARY_PATH="${path}/lib:${LD_LIBRARY_PATH}"
cmd:mkdir "${PREFIX_DIR}"
run:gamelib:configure "${1}"
if [ ! -d "${HOME}/.pcsxr" ]; then
run:pcsxr:configure
first=1
fi
cd "${GAME_DIR}"
. ../gamelib.conf
if [ -n "${pcsxr_plugins_dir}" -a -d "${pcsxr_plugins_dir}" ]; then
cmd:mkdir "${HOME}/.pcsxr/plugins"
IFS=$'\n'
for plugin in $(cmd:ls "${pcsxr_plugins_dir}"); do
if [ ! -f "${HOME}/.pcsxr/plugins/${plugin}" ]; then
cmd:ln "${pcsxr_plugins_dir}/${plugin}" "${HOME}/.pcsxr/plugins/${plugin}"
fi
done
fi
if [ -n "${pcsxr_bios_dir}" -a -d "${pcsxr_bios_dir}" ]; then
cmd:mkdir "${HOME}/.pcsxr/bios"
IFS=$'\n'
for bios in $(cmd:ls "${pcsxr_bios_dir}"); do
if [ ! -f "${HOME}/.pcsxr/plugins/${bios}" ]; then
cmd:ln "${pcsxr_bios_dir}/${bios}" "${HOME}/.pcsxr/bios/${bios}"
fi
done
fi
case "${2}" in
(gui) ${bin} >>"${PREFIX_DIR}/gamelib.log" 2>&1; return ;;
(reinit) run:pcsxr:configure; return ;;
('') ;;
(*) hlpr:wrn "unknown argument \"${2}\""; return ;;
esac
if [ ${first} -eq 1 ]; then
prerun_first >/dev/null 2>&1
else
prerun >/dev/null 2>&1
fi
if [ -f "${HOME}/.pcsxr/pcsxr.cfg" ]; then
${bin} -nogui -cdfile "${GAME_DIR}/${pcsxr_file}" >>"${PREFIX_DIR}/gamelib.log" 2>&1
else
${bin} >>"${PREFIX_DIR}/gamelib.log" 2>&1
fi
return ${?}
}
# }}}
# run:renpy:common {{{
run:renpy:common() {
# if [ "x${path}" != "x" ]; then
# return 1
# fi
export bin="${path}/bin/renpy"
export PATH="${path}/bin:${PATH}"
export LD_LIBRARY_PATH="${path}/lib:${LD_LIBRARY_PATH}"
if head -n1 "${bin}" | grep -q '^#!/usr/local/bin'; then
sed -i '' 's,^#!/usr/local/bin/,#!/usr/bin/env ,' "$(readlink -f -- "${bin}")"
fi
p="$(head -n1 "${bin}" | awk '{print $2}')"
export PYTHONPATH="${path}/lib:${path}/lib/${p}/site-packages:${PYTHONPATH}"
cmd:mkdir "${PREFIX_DIR}"
run:gamelib:configure "${1}"
cd "${GAME_DIR}"
case "${2}" in
(clean)
read -p "Are you REALLY sure? (type \"yes\" if so) " answer
if [ "${answer}" = "yes" ]; then
[ -f "${GAME_DIR}/traceback.txt" ] && rm "${GAME_DIR}/traceback.txt" >/dev/null 2>&1
[ -f "${GAME_DIR}/log.txt" ] && rm "${GAME_DIR}/log.txt" >/dev/null 2>&1
[ -d "${GAME_DIR}/cache" ] && rm -R "${GAME_DIR}/cache" >/dev/null 2>&1
# [ -d "${GAME_DIR}/saves" ] && rm -R "${GAME_DIR}/saves" >/dev/null 2>&1
fi
return
;;
('') ;;
(*) hlpr:wrn "unknown argument \"${2}\""; return ;;
esac
${bin} "${GAME_DIR}" >>"${PREFIX_DIR}/gamelib.log" 2>&1
return ${?}
}
# }}}
run:renpy() {
export path="${MY_LIBDIR}/${arch}.renpy"
run:renpy:common "${@}"
}
run:renpy6() {
export path="${MY_LIBDIR}/${arch}.renpy6"
run:renpy:common "${@}"
}
# run:wine:winetricks {{{
run:wine:winetricks() {
if [ ! -x "${MY_BINDIR}/winetricks" ]; then
url="https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks"
fetch -qo "${MY_BINDIR}/winetricks" "${url}" >/dev/null 2>&1
chmod ug+x go-w "${MY_BINDIR}/winetricks" >/dev/null 2>&1
else
"${MY_BINDIR}/winetricks" --self-update
fi
export WINE="${bin}"
"${MY_BINDIR}/winetricks" ${@} >>"${PREFIX_DIR}/gamelib.log" 2>&1
return ${?}
}
# }}}
# run:wine:configure {{{
run:wine:configure() {
${bin} wineboot.exe -i >/dev/null 2>&1
if [ ! -h "${HOME}/.wine/dosdevices/e:" -a ! -d "${HOME}/.wine/dosdevices/e:" ]; then
cmd:ln "${GAME_DIR}" "${HOME}/.wine/dosdevices/e:"
fi
run:wine:winetricks settings \
"autostart_winedbg=disabled" "csmt=on" "fontfix" "fontsmooth=gray" \
"glsl=enabled" "grabfullscreen=y" "hidewineexports=enable" "isolate_home" \
"mimeassoc=off" "multisampling=enabled" "nocrashdialog" "remove_mono" \
"sandbox" "sound=oss" "vd=off" "videomemorysize=default" "win7" \
"windowmanagerdecorated=y" "windowmanagermanaged=y" >/dev/null 2>&1
run:wine:winetricks corefonts
for i in $(cmd:ls "${HOME}/.wine/dosdevices/"); do
if [ "${i}" != "c:" -a "${i}" != "e:" ]; then
rm "${HOME}/.wine/dosdevices/${i}" >/dev/null 2>&1
fi
done
${bin} winecfg.exe >/dev/null 2>&1
return ${?}
}
# }}}
# run:wine:common {{{
run:wine:common() {
local first=0
export PATH="${MY_BINDIR}:${PATH}"
run:gamelib:configure "${1}"
cmd:mkdir "${PREFIX_DIR}"
if [ ! -d "${HOME}/.wine" ]; then
run:wine:configure "${1}"
first=1
fi
cd "${GAME_DIR}"
. ../gamelib.conf
[ -f "${GAME_DIR}/${wine_file}" ] || hlpr:die "\"${wine_file}\" not found"
if [ -n "${wine_dlls}" ]; then
# run:wine:winetricks dlls ${wine_dlls} >>"${PREFIX_DIR}/gamelib.log" 2>&1
run:wine:winetricks ${wine_dlls} >>"${PREFIX_DIR}/gamelib.log" 2>&1
fi
if [ -n "${wine_settings}" ]; then
run:wine:winetricks settings ${wine_settings} >>"${PREFIX_DIR}/gamelib.log" 2>&1
fi
case "${2}" in
(cfg) ${bin} winecfg.exe >>"${PREFIX_DIR}/gamelib.log" 2>&1; return ;;
(cmd) ${bin} cmd.exe >>"${PREFIX_DIR}/gamelib.log" 2>&1; return ;;
(reg) ${bin} regedit.exe >>"${PREFIX_DIR}/gamelib.log" 2>&1; return ;;
(reinit)
run:wine:configure "${1}"
prerun_first >/dev/null 2>&1
return
;;
(sh) sh; return ;;
('') ;;
(*) hlpr:wrn "unknown argument \"${2}\""; return ;;
esac
if [ ${first} -eq 1 ]; then
prerun_first >/dev/null 2>&1
else
prerun >/dev/null 2>&1
fi
${bin} "${GAME_DIR}/${wine_file}" ${wine_args} >>"${PREFIX_DIR}/gamelib.log" 2>&1
return ${?}
}
# }}}
# run:wine32 {{{
run:wine32() {
export path="${MY_LIBDIR}/${arch}.wine32"
export bin="${path}/bin32/wine"
# export bin="${path}/bin32/wine"
export PATH="${path}/bin:${path}/bin32:${PATH}"
export LIBGL_DRIVERS_PATH="${path}/lib32/.libGL/dri"
# export LD_32_LIBRARY_PATH="${path}/lib32:${path}/lib32/wine:${path}/lib32/.libGL:${path}/lib32/.libGL/dri/:${LD_32_LIBRARY_PATH}"
export LD_32_LIBRARY_PATH="${path}/lib32:${path}/lib32/wine/i386-unix:${path}/lib32/wine/i386-windows:${path}/lib32/.libGL:${path}/lib32/.libGL/dri/:${LD_32_LIBRARY_PATH}"
export LD_32_LIBRARY_PATH_RPATH=y
run:wine:common "${@}"
return ${?}
}
# }}}
# run:wine {{{
run:wine() {
export path="${MY_LIBDIR}/${arch}.wine"
[ "${arch}" = "amd64" ] && suf="64"
export bin="${path}/bin/wine${suf}"
export PATH="${path}/bin:${PATH}"
export LD_LIBRARY_PATH="${path}/lib:${path}/lib/wine:${path}/lib32/wine/i386-unix:${path}/lib32/wine/i386-windows:${LD_LIBRARY_PATH}"
run:wine:common "${@}"
return ${?}
}
# }}}
# run:gamelib {{{
run:gamelib() {
[ -n "${DISPLAY}" ] || hlpr:die "graphical session needed"
gamelib="$(get:gametype "${1}")"
[ ${?} -eq 0 ] || return 1
if [ -f "${MY_LOCKFILE}" ]; then
trap '' EXIT INT ABRT TERM
hlpr:die "another instance of ${PROGNAME} is running with PID $(cat "${MY_LOCKFILE}")"
else
trap hlpr:shutdown EXIT INT ABRT TERM
echo ${$} > "${MY_LOCKFILE}"
fi
if [ ! -d "${MY_LIBDIR}/${arch}.${gamelib}" ]; then
hlpr:inf "prepare ${gamelib}..."
gamelib:add "${gamelib}"
fi
export GAME_DIR="${MY_GAMESDIR}/${1}/game"
export PREFIX_DIR="${MY_GAMESDIR}/${1}/prefix"
run:${gamelib} "${@}"
return ${?}
}
# }}}
[ ${euid} -ne 0 ] || hlpr:die "do not run this program as root!"
[ ${euid} -eq ${uid} ] || hlpr:die "EUID and UID does not match"
case "${arch}" in
(amd64) ;;
(i386) hlpr:wrn "\"${arch}\" is not tested" ;;
(*) hlpr:die "unsupported architecture \"${arch}\"" ;;
esac
hlpr:startup
case "${1}" in
(run) shift; run:gamelib "${@}" ;;
(list) prnt:list ;;
(help) prnt:usage ;;
(version) prnt:version ;;
(license) prnt:license ;;
(list-libs) prnt:list_libs ;;
(upgrade) gamelib:upgrade ;;
(rollback) shift; gamelib:rollback "${@}" ;;
(*) MY_DEBUG=1 hlpr:die "unknown action \"${1}\", try \"help\"" ;;
esac
exit ${?}
# vim: foldlevel=0

70
gamelib.gui Executable file
View file

@ -0,0 +1,70 @@
#!/bin/sh
VERSION="0.2"
PROGNAME="gamelib.gui"
GAMELIB="$(dirname -- "$(readlink -f -- "${0}")")/gamelib"
hlpr:die() {
echo "${@}" >&2
exit 1
}
[ $(${GAMELIB} list | wc -l) -ne 0 ] || hlpr:die "you have no games"
orig_IFS="${IFS}"
IFS=$'\n'
for game in $(${GAMELIB} list); do
img="${GAMELIB_GAMES_DIR}/${game%% *}/gamelib_gui.png"
if [ -r "${img}" ]; then
image="${img}"
else
image="applications-games"
fi
conf="${GAMELIB_GAMES_DIR}/${game%% *}/gamelib_gui.conf"
if [ -f "${conf}" ]; then
. "${conf}"
[ -n "${name}" ] || name="$(echo "${game%% *}" | sed 's/-/ /g')"
[ -n "${description}" ] || description="${game##* }"
else
name="$(echo "${game%% *}" | sed 's/-/ /g')"
description="${game##* }"
fi
games="${games}
${game%% *} ${game##* } '${image}' '${name}' ' ${description} '"
done
games="$(echo "${games}" | sed '/^$/d')"
gnum="$(echo "${games}" | wc -l | sed 's/^[[:space:]]*//')"
# game: 96×32
game="$(eval yad \
--width 600 --height 600 --center \
--class "'${PROGNAME%.*}'" \
--title "'${PROGNAME}'" \
--text "'$(${GAMELIB} version) (gui: ${VERSION})\n${gnum} games found:'" \
--image "'applications-games'" --image-on-top \
--buttons-layout "'center'" \
--button "'_cancel:1'" \
--button "'_run:0'" \
--list --no-headers \
--print-column 1 \
--search-column 0 \
--expand-column 4 \
--tooltip-column 5 \
--ellipsize-cols 4,5 \
--separator "''" \
--column game:HD --column type:HD --column icon:IMG --column name:TEXT --column description:HD \
${games})"
exitcode=${?}
case ${exitcode} in
(0) ${GAMELIB} run "${game}" ;;
(1) echo "${PROGNAME}: canceled" >&2 ;;
(252) echo "${PROGNAME}: escaped" >&2 ;;
(*) echo "${PROGNAME}: exited with ${exitcode}" >&2 ;;
esac
exit ${exitcode}

128
gamelib.new Executable file
View file

@ -0,0 +1,128 @@
#!/bin/sh
#
# Copyright (c) 2019-2021, mord0d and their slaves
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
VERSION="0.6"
PROGNAME="gamelib"
arch="$(uname -m)"
uid="$(id -u)"
gid="$(id -g)"
: ${TMPDIR:=/tmp}
: ${GAMELIB_DEBUG:=0}
LOCKFILE="${TMPDIR}/.${PROGNAME}-${uid}.lock"
TEMPDIR="${TMPDIR}/.${PROGNAME}-${uid}"
# gl_log {{{
gl_log() {
local lvl="${1}"
shift
if [ "${lvl}" = "FTL" ] || [ "${GAMELIB_DEBUG}" -ne 0 ] || [ -z "${LOGFILE}" -o ! -w "${LOGFILE}" ]; then
echo "[${lvl}] ${*}" >&2
fi
echo "[${lvl}:${$}] $(date -j '+%Y-%m-%d %H:%M:%S') ${*}" >> "${LOGFILE:=/dev/null}"
}
# }}}
gl_run() {
}
gl_edit() {
}
gl_upgrade() {
}
gl_rollback() {
}
gl_usage() {
}
# gl_version {{{
gl_version() {
echo "${PROGNAME} ${VERSION}"
}
# }}}
# gl_license {{{
gl_license() {
sed -n 's/^# //; s/^#$//; 4,25p' "${0}"
}
# }}}
gl_list() {
}
game=''
subcommands=''
upgrade=0
rollback=0
edit=0
while :; do
case "${1}" in
('') break ;;
(-h|--help) gl_usage; exit 0 ;;
(-V|--version) gl_version; exit 0 ;;
(-L|--license) gl_license; exit 0 ;;
(-l|--list) gl_list; exit 0 ;;
(-v|--verbose) GAMELIB_DEBUG=1; shift ;;
(-u|--upgrade) upgrade=1; rollback=0; shift ;;
(-b|--rollback) rollback=1; upgrade=0; shift ;;
(-r|--run) shift; subcommands="${subcommands} ${1}"; shift ;;
(-e|--edit) edit=1; shift ;;
(-w|--workdir) shift; GAMELIB_GAMES_DIR="${1}"; shift ;;
(-*) gl_log ERR "Unknown option \"${1}\"!"; exit 1 ;;
(*) game="${1}"; shift ;;
esac
done
if [ -z "${GAMELIB_GAMES_DIR}" ]; then
gl_log FTL "\"\$GAMELIB_GAMES_DIR\" is not defined!"
exit 1
fi
if [ ! -d "${GAMELIB_GAMES_DIR}" ]; then
gl_log FTL "\"\$GAMELIB_GAMES_DIR\" is not a directory"
exit 1
fi
if [ -z "${game}" ]; then
gl_log FTL "No game specified!"
gl_list
exit 1
fi
if [ ${edit} -eq 1 ]; then
gl_edit "${game}"
exit ${?}
fi
if [ ${upgrade} -eq 1 ]; then
gl_upgrade "${game}"
elif [ ${rollback} -eq 1 ]; then
gl_rollback "${game}"
else
gl_run "${game}" "${subcommands}"
fi