255 lines
9.4 KiB
Bash
255 lines
9.4 KiB
Bash
#!/bin/bash
|
|
# Monocoque Distrobox Installer
|
|
# For immutable Linux distributions (Bazzite, Silverblue, etc.)
|
|
# where native package managers are unavailable.
|
|
#
|
|
# Installs monocoque and dependencies inside an Arch Linux distrobox container,
|
|
# with wrapper scripts on the host for transparent access.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_VERSION="1.0.0"
|
|
CONTAINER="simracing"
|
|
INSTALL_DIR="$HOME/.local/share/simracing"
|
|
BIN_DIR="$HOME/.local/bin"
|
|
CONFIG_DIR="$HOME/.config/monocoque"
|
|
|
|
# Color output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
}
|
|
|
|
log_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
print_header() {
|
|
echo ""
|
|
echo "╔══════════════════════════════════════════════════════════════════╗"
|
|
echo "║ Monocoque Distrobox Installer v${SCRIPT_VERSION} ║"
|
|
echo "╚══════════════════════════════════════════════════════════════════╝"
|
|
echo ""
|
|
}
|
|
|
|
# --- Main ---
|
|
|
|
print_header
|
|
|
|
# Check ~/.local/bin is in PATH
|
|
if [[ ":$PATH:" != *":$BIN_DIR:"* ]]; then
|
|
log_error "$BIN_DIR is not in your PATH."
|
|
log_info "Add this to your shell config:"
|
|
echo " export PATH=\"\$HOME/.local/bin:\$PATH\""
|
|
exit 1
|
|
fi
|
|
|
|
# Check distrobox is available
|
|
if ! command -v distrobox &>/dev/null; then
|
|
log_error "distrobox is not installed."
|
|
log_info "Install distrobox first: https://distrobox.it/#installation"
|
|
exit 1
|
|
fi
|
|
|
|
# Ensure dialout group exists and user is a member
|
|
log_info "Checking serial device access (dialout group)..."
|
|
if ! grep -q '^dialout:' /etc/group 2>/dev/null; then
|
|
if grep -q '^dialout:' /usr/lib/group 2>/dev/null; then
|
|
log_info "Adding dialout group to /etc/group (Fedora Atomic fix)..."
|
|
grep -E '^dialout:' /usr/lib/group | sudo tee -a /etc/group >/dev/null
|
|
else
|
|
log_info "Creating dialout group..."
|
|
sudo groupadd dialout
|
|
fi
|
|
fi
|
|
if ! groups | grep -qw dialout; then
|
|
log_info "Adding $USER to the dialout group for serial device access..."
|
|
sudo usermod -aG dialout "$USER"
|
|
log_warn "You will need to REBOOT after setup completes for serial access to work."
|
|
echo ""
|
|
fi
|
|
|
|
# Prevent ModemManager from grabbing Moza serial devices
|
|
UDEV_RULE="/etc/udev/rules.d/99-moza-serial.rules"
|
|
if [ ! -f "$UDEV_RULE" ]; then
|
|
if systemctl is-active --quiet ModemManager 2>/dev/null; then
|
|
echo ""
|
|
log_warn "ModemManager is running on your system."
|
|
echo " Moza wheel bases use USB serial devices that ModemManager may claim,"
|
|
echo " preventing monocoque from communicating with the wheel."
|
|
echo ""
|
|
echo " A udev rule can tell ModemManager to ignore Moza devices (vendor 346e)."
|
|
echo " This only affects Moza USB devices — other modems will work normally."
|
|
echo ""
|
|
read -rp "Install udev rule to prevent ModemManager from grabbing Moza devices? [Y/n]: " mm_confirm
|
|
if [[ "$mm_confirm" =~ ^[Nn]$ ]]; then
|
|
echo ""
|
|
log_info "Skipped udev rule. If monocoque can't talk to your wheel, run:"
|
|
echo " sudo tee $UDEV_RULE <<< 'ACTION==\"add|change\", SUBSYSTEM==\"usb\", ATTR{idVendor}==\"346e\", ENV{ID_MM_DEVICE_IGNORE}=\"1\"'"
|
|
echo " sudo udevadm control --reload-rules && sudo udevadm trigger"
|
|
echo ""
|
|
else
|
|
log_info "Installing udev rule..."
|
|
echo 'ACTION=="add|change", SUBSYSTEM=="usb", ATTR{idVendor}=="346e", ENV{ID_MM_DEVICE_IGNORE}="1"' | sudo tee "$UDEV_RULE" >/dev/null
|
|
sudo udevadm control --reload-rules
|
|
sudo udevadm trigger
|
|
log_success "ModemManager udev rule installed"
|
|
fi
|
|
else
|
|
# ModemManager not running — install the rule silently
|
|
echo 'ACTION=="add|change", SUBSYSTEM=="usb", ATTR{idVendor}=="346e", ENV{ID_MM_DEVICE_IGNORE}="1"' | sudo tee "$UDEV_RULE" >/dev/null
|
|
sudo udevadm control --reload-rules
|
|
sudo udevadm trigger
|
|
fi
|
|
fi
|
|
|
|
# Create the Arch Linux distrobox container
|
|
if ! distrobox list 2>/dev/null | grep -q "$CONTAINER"; then
|
|
log_info "Creating Arch Linux container '$CONTAINER'..."
|
|
distrobox create \
|
|
--image docker.io/library/archlinux:latest \
|
|
--name "$CONTAINER" \
|
|
--pre-init-hooks "sed -i 's/^SigLevel.*/SigLevel = Never/' /etc/pacman.conf && pacman -Sy --noconfirm archlinux-keyring && pacman-key --init && pacman-key --populate archlinux && sed -i 's/^SigLevel.*/SigLevel = Required DatabaseOptional/' /etc/pacman.conf"
|
|
log_success "Container '$CONTAINER' created"
|
|
else
|
|
log_info "Container '$CONTAINER' already exists, skipping creation."
|
|
fi
|
|
|
|
# Install packages inside the container
|
|
log_info "Installing packages inside container (this may take a few minutes)..."
|
|
distrobox enter "$CONTAINER" -- bash -c '
|
|
set -euo pipefail
|
|
|
|
# Install build dependencies
|
|
echo "Installing build dependencies..."
|
|
sudo pacman -Syu --needed --noconfirm base-devel git mingw-w64-gcc
|
|
|
|
# Install yay (AUR helper) if not present
|
|
if ! command -v yay &>/dev/null; then
|
|
echo "Installing yay AUR helper..."
|
|
TMPDIR=$(mktemp -d)
|
|
git clone https://aur.archlinux.org/yay-bin.git "$TMPDIR/yay-bin"
|
|
cd "$TMPDIR/yay-bin"
|
|
makepkg -si --noconfirm
|
|
cd /
|
|
rm -rf "$TMPDIR"
|
|
fi
|
|
|
|
# Install AUR packages sequentially (simd depends on simapi, monocoque depends on both)
|
|
echo "Installing AUR packages..."
|
|
yay -S --needed --noconfirm simapi-git
|
|
yay -S --needed --noconfirm simd-git
|
|
yay -S --needed --noconfirm monocoque-git
|
|
|
|
# Build simshmbridge (not on AUR)
|
|
INSTALL_DIR="$HOME/.local/share/simracing"
|
|
mkdir -p "$INSTALL_DIR"
|
|
cd "$INSTALL_DIR"
|
|
if [ ! -d "simshmbridge" ]; then
|
|
echo "Cloning simshmbridge..."
|
|
git clone --recurse-submodules "https://github.com/Spacefreak18/simshmbridge.git"
|
|
else
|
|
echo "simshmbridge already cloned, pulling latest..."
|
|
cd simshmbridge && git pull && git submodule update --init --recursive && cd ..
|
|
fi
|
|
echo "Building simshmbridge..."
|
|
cd "$INSTALL_DIR/simshmbridge"
|
|
git submodule update --init --recursive
|
|
make clean 2>/dev/null || true
|
|
make -j$(nproc)
|
|
|
|
echo ""
|
|
echo "All components built successfully inside container."
|
|
'
|
|
|
|
# Install wrapper scripts to ~/.local/bin
|
|
log_info "Installing wrapper scripts..."
|
|
mkdir -p "$BIN_DIR"
|
|
|
|
cat > "$BIN_DIR/start-simd" << 'EOF'
|
|
#!/usr/bin/env bash
|
|
exec distrobox enter simracing -- simd "$@"
|
|
EOF
|
|
chmod +x "$BIN_DIR/start-simd"
|
|
|
|
cat > "$BIN_DIR/start-monocoque" << 'EOF'
|
|
#!/usr/bin/env bash
|
|
exec distrobox enter simracing -- monocoque play "$@"
|
|
EOF
|
|
chmod +x "$BIN_DIR/start-monocoque"
|
|
|
|
cat > "$BIN_DIR/test-monocoque" << 'EOF'
|
|
#!/usr/bin/env bash
|
|
exec distrobox enter simracing -- monocoque test -vv "$@"
|
|
EOF
|
|
chmod +x "$BIN_DIR/test-monocoque"
|
|
|
|
log_success "Wrapper scripts installed"
|
|
|
|
# Setup monocoque config
|
|
mkdir -p "$CONFIG_DIR"
|
|
if [ ! -f "$CONFIG_DIR/monocoque.config" ]; then
|
|
log_info "Creating monocoque config template..."
|
|
cat > "$CONFIG_DIR/monocoque.config" << 'EOF'
|
|
configs = (
|
|
{
|
|
sim = "default";
|
|
car = "default";
|
|
devices = (
|
|
{
|
|
device = "Serial";
|
|
type = "Wheel";
|
|
subtype = "MozaNew";
|
|
devpath = "/dev/serial/by-id/CHANGE_ME_TO_YOUR_MOZA_BASE";
|
|
baud = 115200;
|
|
});
|
|
}
|
|
);
|
|
EOF
|
|
log_success "Config created at $CONFIG_DIR/monocoque.config"
|
|
else
|
|
log_info "Config already exists, skipping"
|
|
fi
|
|
|
|
# Done
|
|
echo ""
|
|
echo "╔══════════════════════════════════════════════════════════════════╗"
|
|
echo "║ Installation Complete! ║"
|
|
echo "╚══════════════════════════════════════════════════════════════════╝"
|
|
echo ""
|
|
log_success "Monocoque (distrobox) installed!"
|
|
echo ""
|
|
echo " Installed:"
|
|
echo " AUR packages: simapi-git, simd-git, monocoque-git (in '$CONTAINER' container)"
|
|
echo " Bridge: $INSTALL_DIR/simshmbridge/"
|
|
echo " Config: $CONFIG_DIR/monocoque.config"
|
|
echo " Commands: start-simd, start-monocoque, test-monocoque"
|
|
echo ""
|
|
echo " Next steps:"
|
|
echo " 1. Set your device path in $CONFIG_DIR/monocoque.config"
|
|
echo " (replace CHANGE_ME_TO_YOUR_MOZA_BASE with your device from /dev/serial/by-id/)"
|
|
echo " 2. Test with: test-monocoque"
|
|
echo " 3. Set Steam launch options for your games to start the telemetry stack automatically:"
|
|
echo " In Steam > Game Properties > Launch Options, add:"
|
|
echo " start-simd & start-monocoque & <bridge_path> %command%"
|
|
echo " For example, for Assetto Corsa:"
|
|
echo " start-simd & start-monocoque & $INSTALL_DIR/simshmbridge/assets/acbridge.exe %command%"
|
|
echo ""
|
|
echo " For tools that automate steps 1 and 3 (Moza auto-detection, Steam launch"
|
|
echo " option configuration, unified game launcher), visit:"
|
|
echo " https://github.com/cescofry/simracing-utilities"
|
|
echo ""
|