If you're new to setting up Wine Bottles in ROCKNIX, then you should read qcs-wine-bottles.md first.
This guide is intended for people who wish to share their functional wine bottles with others, for easier consumption. The system used in this guide is extremely similar to PortMaster and the system used for packaging ports. There are three simple terms used throughout:
.winecellar: This is a user-created folder that ideally lives inroms/windows. It is meant to store shared custom binaries to help with running wine bottles (such astools/splash) and custom wine builds.bottle.json: This json file is similar toport.jsonin that it holds identifying information about the game it's bundled with. Launch scripts will use jquery to parse this file to correctly configure wine for the game.winecask.json: This json file is a merged combination of allbottle.jsonfiles in a GitHub repository. It is only needed if you plan on distributing your wine bottles with Pharos.
Parsing bottle.json files with jquery to fill out environment variables and download dependencies is much easier to maintain than several custom launch scripts. Launch scripts must still be modified anyway to point to the game directory, executable, and add any additional launch options, but using jquery parsing avoids launch scripts having hundreds of lines to sift through.
What follows is a basic bottle.json file.
{
// This section is used by Pharos to install the package.
"version": 1,
"name": "bottledir.zip",
"items": [
"Bottle Name.sh",
"bottledir"
],
"runner": "default", // The runner defines which binary to use to run the game.
"deps": [
// This is an array of dependencies required for wine to run the game.
],
"env": {
"WINEDEBUG": "-all", // This environment variable defines log level output.
"WINEARCH": "win64" // This environment variable defines which architecture the wine prefix uses.
},
"configdir": [
// This is an array of the config/save directories used by the game. These are usually documented on pcgamingwiki.
],
// This section is used by Pharos to display the package in the gui.
"attr": {
"title": "",
"desc": "",
"inst": "Add your game files to the data folder",
"genres": [
],
"availability": "paid"
}
}The entries are then used in launch scripts, for example:
# ================================================
# WINE RUNNER CONFIG
# ================================================
# Function to find the latest runner version
find_runner_dir() {
# Find any folder under ../.winecellar that matches $1 (case-insensitive)
# Sorts by version and takes the latest one (tail -n1)
find "../.winecellar" -maxdepth 1 -type d -iname "*$1*" | sort -V | tail -n1
}
# Runner selection
RUNNER=$(jq -r '.runner // "default"' "$GAMEDIR/bottle.json")
WINEARCH=$(jq -r '.env.WINEARCH // "win64"' "$GAMEDIR/bottle.json")
case "$RUNNER" in
default)
# Use PATH wine/box64 with standard .wine prefix
WINEPREFIX="$HOME/.wine"
WINE="wine"
;;
proton)
RUNNER_DIR=$(find_runner_dir "proton")
WINEPREFIX="$HOME/.proton"
WINE="$(readlink -f "$RUNNER_DIR/bin/wine")"
;;
wine-wow64)
RUNNER_DIR=$(find_runner_dir "wine-wow64")
WINEPREFIX="$HOME/.wine"
WINE="$(readlink -f "$RUNNER_DIR/bin/wine")"
;;
*)
echo "Error: Unknown runner '$RUNNER' specified in bottle.json"
exit 1
;;
esac
# Append 32 to prefix if win32 architecture is required
[ "$WINEARCH" = "win32" ] && WINEPREFIX="${WINEPREFIX}32"
# Set BOX based on architecture
BOX=$([ "$WINEARCH" = "win32" ] && echo "box86" || echo "box64")
# Error checking for non-default runners and PATH setup
if [ "$RUNNER" != "default" ]; then
if [ -z "$RUNNER_DIR" ] || [ ! -x "$WINE" ]; then
echo "Error: Required runner '$RUNNER' not found or is not executable."
exit 1
fi
export PATH="$(dirname "$WINE"):$PATH"
fi
echo "[LAUNCHER]: Using runner '$RUNNER' with WINEPREFIX='$WINEPREFIX' BOX='$BOX' WINE='$WINE'"
# Mapping of dependencies to a file that indicates installation
declare -A DEP_DLL_MAP=(
[vcrun2022]="drive_c/windows/system32/vcruntime140_1.dll"
[dxvk]="drive_c/windows/system32/dxgi.dll"
[vkd3d-proton]="drive_c/windows/system32/d3d12.dll"
[vcrun2019]="drive_c/windows/system32/vcruntime140.dll"
[dotnet48]="drive_c/windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll"
)
# Install dependencies from bottle.json
if jq -e '.deps' "$GAMEDIR/bottle.json" >/dev/null 2>&1; then
echo "[LAUNCHER]: Installing dependencies from bottle.json..."
jq -r '.deps[]?' "$GAMEDIR/bottle.json" | while read -r dep; do
marker="${DEP_DLL_MAP[$dep]}"
if [ -n "$marker" ] && [ -f "$WINEPREFIX/$marker" ]; then
echo "[LAUNCHER]: $dep already installed (found $marker)"
else
echo "[LAUNCHER]: Installing $dep..."
WINEPREFIX="$WINEPREFIX" winetricks -q "$dep" || {
echo "[ERROR]: Failed to install $dep"
exit 1
}
fi
done
fi
# If proton then install dxvk and vkd3d-proton
if [ "$RUNNER" = "proton" ]; then
if ! WINEPREFIX="$WINEPREFIX" winetricks list-installed | grep -q '^dxvk$'; then
echo "[LAUNCHER]: Installing DXVK into Proton prefix..."
WINEPREFIX="$WINEPREFIX" winetricks -q dxvk
fi
if ! WINEPREFIX="$WINEPREFIX" winetricks list-installed | grep -q '^vkd3d-proton$'; then
echo "[LAUNCHER]: Installing vkd3d-proton into Proton prefix..."
WINEPREFIX="$WINEPREFIX" winetricks -q vkd3d-proton
fi
fi
# Load bottle env
if command -v jq >/dev/null; then
while IFS="=" read -r k v; do
export "$k=$v"
done < <(jq -r '.env | to_entries | .[] | "\(.key)=\(.value)"' "$GAMEDIR/bottle.json")
else
echo "Error: jq not found"
exit 1
fi
# Config Setup
CONFIGDIRS=$(jq -r '.configdir[]?' "$GAMEDIR/bottle.json")
if [ -n "$CONFIGDIRS" ] && [ -n "$WINEPREFIX" ]; then
mkdir -p "$GAMEDIR/config"
while IFS= read -r dir; do
SRC="$WINEPREFIX/$dir"
if [ -d "$SRC" ]; then
echo "[CONFIG]: Binding $SRC -> $GAMEDIR/config"
bind_directories "$SRC" "$GAMEDIR/config"
else
echo "[CONFIG]: Warning: $SRC does not exist, skipping."
fi
done <<< "$CONFIGDIRS"
fiLaunch scripts have not changed much otherwise. It's still advised to use the PortMaster Preamble to make use of its functions and environment variables (like bind_directories and $directory). Local variables come after:
# ================================================
# LOCAL VARIABLES
# ================================================
GAMEDIR="/$directory/windows/bottledir"
EXEC="$GAMEDIR/data/EXECNAME"
BASE=$(basename "$EXEC")
SPLASH="/$directory/windows/.winecellar/tools/splash"
LOG="$GAMEDIR/log.txt"
cd "$GAMEDIR"
> "$LOG" && exec > >(tee "$LOG") 2>&1
# Splash
chmod 777 "$SPLASH"
"$SPLASH" "$GAMEDIR/splash.png" 50000 &Notice how .winecellar is used here to reference the splash binary, which is then used to display a splash image while the bottle is loading. A full example can be seen with Windswept. In short, the only things that should require modifying in the launch script are:
- The GAMEDIR
- EXECNAME
- The GPTK file used (near the bottom of the script)