Files
omarchy-sc/citizenctl
T
2026-08-31 18:17:56 +02:00

911 lines
30 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -u
PLUGIN_ID="local.omarchy-citizen"
PLUGIN_VERSION="0.8.0"
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/starcitizen-lug"
DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}"
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/omarchy-citizen"
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy-citizen"
UPDATE_CACHE="$CACHE_DIR/lug-update-status"
LOG_FILE="$STATE_DIR/omarchy-citizen.log"
WINE_CONF="$CONFIG_DIR/winedir.conf"
GAME_CONF="$CONFIG_DIR/gamedir.conf"
SELF="$(readlink -f "${BASH_SOURCE[0]}")"
PLUGIN_DIR="$(cd -- "$(dirname -- "$SELF")" && pwd)"
SANITIZER="$PLUGIN_DIR/support-sanitize.py"
BACKEND_EXTERNAL="$HOME/.local/lib/omarchy-citizen/omarchy-citizen-backend"
BACKEND_BUNDLED="$PLUGIN_DIR/backend/bin/omarchy-citizen-backend"
MANAGED_LUG="$DATA_DIR/omarchy-citizen/vendor/lug-helper/lug-helper.appimage"
MANAGED_WINE="$DATA_DIR/omarchy-citizen/vendor/wine/current"
GUI_PACKAGES=(zenity polkit cabextract unzip)
mkdir -p "$CACHE_DIR" "$STATE_DIR"
rotate_log() {
local max_bytes=$((4 * 1024 * 1024))
local keep_bytes=$((2 * 1024 * 1024))
if [[ -f "$LOG_FILE" ]] && (( $(stat -c '%s' "$LOG_FILE" 2>/dev/null || echo 0) > max_bytes )); then
tail -c "$keep_bytes" "$LOG_FILE" > "$LOG_FILE.tmp" 2>/dev/null || true
mv -f "$LOG_FILE.tmp" "$LOG_FILE" 2>/dev/null || true
fi
}
rotate_log
ACTION="${1:-primary}"
log_line() {
local message="$*"
printf '%s [%s] %s\n' "$(date '+%Y-%m-%dT%H:%M:%S%z')" "$$" "$message" >> "$LOG_FILE" 2>/dev/null || true
}
log_line "action=$ACTION version=$PLUGIN_VERSION"
find_backend() {
if [[ -x "$BACKEND_EXTERNAL" ]]; then
printf '%s\n' "$BACKEND_EXTERNAL"
return 0
fi
if [[ -x "$BACKEND_BUNDLED" ]]; then
printf '%s\n' "$BACKEND_BUNDLED"
return 0
fi
return 1
}
backend_status() {
local game_output="" plugin_output="" health="setup" prefix_state="missing" launcher_state="missing" game_state="missing"
local wine_version="" dxvk_version="" lug_version="" hardware="unknown" hardware_reason="" gpu="" vulkan="unknown"
if game_output="$(backend_game_status 2>/dev/null)"; then
health="$(printf '%s\n' "$game_output" | sed -n 's/^health=//p' | head -n1)"
prefix_state="$(printf '%s\n' "$game_output" | sed -n 's/^prefix_state=//p' | head -n1)"
launcher_state="$(printf '%s\n' "$game_output" | sed -n 's/^launcher_state=//p' | head -n1)"
game_state="$(printf '%s\n' "$game_output" | sed -n 's/^game_state=//p' | head -n1)"
wine_version="$(printf '%s\n' "$game_output" | sed -n 's/^wine_version=//p' | head -n1)"
dxvk_version="$(printf '%s\n' "$game_output" | sed -n 's/^dxvk_version=//p' | head -n1)"
lug_version="$(printf '%s\n' "$game_output" | sed -n 's/^lug_version=//p' | head -n1)"
hardware="$(printf '%s\n' "$game_output" | sed -n 's/^hardware=//p' | head -n1)"
hardware_reason="$(printf '%s\n' "$game_output" | sed -n 's/^hardware_reason=//p' | head -n1)"
gpu="$(printf '%s\n' "$game_output" | sed -n 's/^gpu=//p' | head -n1)"
vulkan="$(printf '%s\n' "$game_output" | sed -n 's/^vulkan=//p' | head -n1)"
fi
printf 'plugin_version=%s\n' "$PLUGIN_VERSION"
printf 'health=%s\n' "${health:-setup}"
printf 'deps=ready\n'
printf 'deps_missing=\n'
printf 'helper=%s\n' "$([[ -n "$lug_version" ]] && echo ready || echo missing)"
printf 'helper_managed=autopilot\n'
printf 'helper_version=%s\n' "$lug_version"
printf 'update=unknown\n'
printf 'update_version=\n'
printf 'prefix=%s\n' "${prefix_state:-missing}"
if [[ "$prefix_state" == "partial" ]]; then printf 'prefix_detail=unvollständig\n'; else printf 'prefix_detail=\n'; fi
printf 'launcher=%s\n' "${launcher_state:-missing}"
printf 'game=%s\n' "${game_state:-missing}"
printf 'hardware=%s\n' "$hardware"
printf 'hardware_reason=%s\n' "$hardware_reason"
printf 'hardware_gpu=%s\n' "$gpu"
printf 'hardware_vulkan=%s\n' "$vulkan"
if plugin_output="$(backend_status 2>/dev/null)"; then
printf 'backend=ready\n'
else
printf 'backend=missing\n'
fi
printf 'backend_version=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^backend_version=//p' | head -n1)"
printf 'plugin_managed=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^managed=//p' | head -n1)"
printf 'plugin_auto=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^auto_apply=//p' | head -n1)"
printf 'plugin_update=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^update=//p' | head -n1)"
printf 'plugin_local_commit=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^local_commit=//p' | head -n1)"
printf 'plugin_remote_commit=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^remote_commit=//p' | head -n1)"
printf 'autopilot=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^auto_maintain=//p' | head -n1)"
printf 'managed_lug_version=%s\n' "${lug_version}"
printf 'managed_wine_version=%s\n' "${wine_version}"
printf 'managed_dxvk_version=%s\n' "${dxvk_version}"
printf 'maintenance_result=%s\n' "$(printf '%s\n' "$plugin_output" | sed -n 's/^maintenance_result=//p' | head -n1)"
}
hardware_info() {
local out reason gpu vulkan
out="$(backend_game_status 2>/dev/null || true)"
reason="$(printf '%s\n' "$out" | sed -n 's/^hardware_reason=//p')"
gpu="$(printf '%s\n' "$out" | sed -n 's/^gpu=//p')"
vulkan="$(printf '%s\n' "$out" | sed -n 's/^vulkan=//p')"
if command -v zenity >/dev/null 2>&1; then
zenity --warning --width=600 --title="Omarchy Citizen – Hardware" --text="<b>Star Citizen ist auf diesem System noch nicht spielbereit.</b>\n\nGPU:\n${gpu:-nicht erkannt}\n\nVulkan: ${vulkan:-unbekannt}\n\n${reason:-Hardware-Prüfung fehlgeschlagen.}" >/dev/null 2>&1 || true
else
printf '%s\n' "$reason"
fi
}
probe_detached_start() {
local label="$1"
shift
"$@" >>"$LOG_FILE" 2>&1 &
local pid=$!
sleep 0.45
if ! kill -0 "$pid" 2>/dev/null; then
local rc=0
wait "$pid" || rc=$?
if (( rc != 0 )); then
log_line "$label failed rc=$rc"
return "$rc"
fi
else
disown "$pid" 2>/dev/null || true
fi
log_line "$label accepted"
return 0
}
launch_terminal_action() {
local action="$1"
log_line "launch-terminal action=$action"
# Prefer direct argv-safe terminal launching. This avoids the presentation
# wrapper joining arguments into one shell command string.
if command -v uwsm-app >/dev/null 2>&1 && command -v xdg-terminal-exec >/dev/null 2>&1; then
if probe_detached_start "uwsm-xdg-terminal" \
setsid uwsm-app -- xdg-terminal-exec \
--app-id=org.omarchy.terminal \
--title="Omarchy Citizen Setup" \
-e bash "$SELF" "$action"; then
printf 'terminal=opened\n'
return 0
fi
fi
if command -v xdg-terminal-exec >/dev/null 2>&1; then
if probe_detached_start "xdg-terminal" \
xdg-terminal-exec \
--title="Omarchy Citizen Setup" \
-e bash "$SELF" "$action"; then
printf 'terminal=opened\n'
return 0
fi
fi
# Final compatibility fallback for older/current Omarchy installations.
if command -v omarchy-launch-floating-terminal-with-presentation >/dev/null 2>&1; then
if probe_detached_start "omarchy-floating-terminal" \
omarchy-launch-floating-terminal-with-presentation bash "$SELF" "$action"; then
printf 'terminal=opened\n'
return 0
fi
fi
echo "Das Setup-Terminal konnte nicht geöffnet werden." >&2
notify_error "Das Setup-Terminal konnte nicht geöffnet werden.
Bitte klicke auf „Support-Paket erstellen“. Der fehlgeschlagene Startversuch ist dort protokolliert."
return 1
}
backup_lug_target_configs() {
local stamp="$1"
local f
mkdir -p "$CONFIG_DIR"
for f in "$WINE_CONF" "$GAME_CONF"; do
if [[ -f "$f" ]]; then
mv -- "$f" "${f}.incomplete-${stamp}"
log_line "backed up LUG config $(basename "$f") -> $(basename "${f}.incomplete-${stamp}")"
fi
done
}
stop_prefix_wineserver() {
local prefix="$1"
local wineserver=""
# Kill only a wineserver associated with the runner inside this target prefix.
# Do not kill unrelated Wine applications globally.
wineserver="$(find "$prefix/runners" -type f -path '*/bin/wineserver' -perm -u+x -print -quit 2>/dev/null || true)"
if [[ -n "$wineserver" ]]; then
WINEPREFIX="$prefix" "$wineserver" -k >>"$LOG_FILE" 2>&1 || true
sleep 0.5
fi
}
recover_incomplete_prefix_terminal() {
set -Ee
exec > >(tee -a "$LOG_FILE") 2>&1
local prefix stamp backup datap4k=""
recovery_failed() {
local rc=$?
trap - ERR
echo
echo "=================================================="
echo " REPARATUR KONNTE NICHT ABGESCHLOSSEN WERDEN"
echo "=================================================="
echo
echo "Fehlercode: $rc"
echo
echo "Dein vorheriger Ordner wurde nicht gelöscht."
echo "Im SC-Panel kannst du jetzt „Support-Paket erstellen“ wählen."
echo
log_line "recover-prefix-terminal failed rc=$rc"
notify "Omarchy Citizen" "Setup-Reparatur fehlgeschlagen. Bitte erstelle ein Support-Paket."
if [[ -t 0 ]]; then
read -r -p "Drücke Enter, um dieses Fenster zu schließen … " _ || true
else
sleep 10
fi
exit "$rc"
}
trap recovery_failed ERR
prefix="$(find_incomplete_prefix 2>/dev/null)" || {
echo "Es wurde kein unvollständiger Wine-Prefix mehr gefunden."
echo "Starte stattdessen die normale Einrichtung."
log_line "recover-prefix-terminal no incomplete prefix found"
trap - ERR
return 0
}
datap4k="$prefix/drive_c/Program Files/Roberts Space Industries/StarCitizen/LIVE/Data.p4k"
echo
echo "=================================================="
echo " Omarchy Citizen – Setup sicher reparieren"
echo "=================================================="
echo
echo "Unvollständiger Wine-Prefix:"
echo " $prefix"
echo
# Never move real game data ourselves.
if [[ -f "$datap4k" ]]; then
echo "Vorhandene Star-Citizen-Spieldaten wurden erkannt."
echo "Omarchy Citizen verschiebt diese Daten nicht selbst."
echo "Die Reparatur wird an den LUG Helper übergeben."
echo
log_line "recover-prefix-terminal Data.p4k present; delegate to LUG"
run_helper_visible --install
trap - ERR
return 0
fi
stamp="$(date '+%Y%m%d-%H%M%S')"
backup="${prefix}-incomplete-${stamp}"
echo "Der halbfertige Ordner wird NICHT gelöscht."
echo "Er wird gesichert als:"
echo " $backup"
echo
echo "Danach wird der offizielle LUG-Installer sauber neu gestartet."
echo
log_line "recover-prefix-terminal prefix=$prefix backup=$backup"
stop_prefix_wineserver "$prefix"
mv -- "$prefix" "$backup"
backup_lug_target_configs "$stamp"
echo "✓ Backup erstellt."
echo
echo "Starte frische LUG-Einrichtung …"
echo
run_helper_visible --install
echo
echo "Prüfe den neu angelegten Wine-Prefix …"
if read_prefix >/dev/null 2>&1; then
echo "✓ Wine-Prefix ist vollständig initialisiert."
log_line "recover-prefix-terminal succeeded"
trap - ERR
notify "Omarchy Citizen" "Wine-Prefix wurde erfolgreich neu erstellt."
echo
echo "Reparatur abgeschlossen. Du kannst dieses Fenster schließen."
return 0
fi
echo
echo "Der LUG-Installer wurde beendet, aber drive_c/system.reg/user.reg"
echo "sind weiterhin nicht vollständig vorhanden."
echo
log_line "recover-prefix-terminal LUG returned but prefix still incomplete"
return 1
}
recover_incomplete_prefix() {
launch_terminal_action recover-prefix-terminal
}
guided_setup_interactive() {
log_line "guided-setup begin"
if ! find_helper >/dev/null 2>&1; then
launch_terminal_action install-stack-terminal
return 0
fi
if find_incomplete_prefix >/dev/null 2>&1; then
log_line "guided setup found incomplete prefix; opening visible recovery terminal"
launch_terminal_action recover-prefix-terminal
return $?
fi
run_helper_sync --preflight-check || true
if ! read_prefix >/dev/null 2>&1; then
run_helper_sync --install || true
elif ! prefix="$(read_prefix 2>/dev/null)" || [[ ! -f "$prefix/sc-launch.sh" ]]; then
run_helper_sync --update-launch-script || true
fi
prefix="$(read_prefix 2>/dev/null || true)"
if [[ -n "$prefix" && -f "$prefix/sc-launch.sh" ]]; then
game_dir="$(read_game_dir 2>/dev/null || true)"
if [[ -z "$game_dir" || ! -f "$game_dir/LIVE/Bin64/StarCitizen.exe" ]]; then
log_line "guided-setup opening RSI Launcher for game installation"
nohup bash "$prefix/sc-launch.sh" >>"$LOG_FILE" 2>&1 &
fi
fi
notify "Omarchy Citizen" "Einrichtung abgeschlossen. Falls Star Citizen noch fehlt, ist der RSI Launcher für die Installation geöffnet."
log_line "guided-setup end"
}
guided_setup() {
launch_terminal_action install-stack-terminal
}
install_stack_terminal() {
set -Ee
exec > >(tee -a "$LOG_FILE") 2>&1
setup_failed() {
local rc=$?
trap - ERR
echo
echo "=================================================="
echo " SETUP KONNTE NICHT ABGESCHLOSSEN WERDEN"
echo "=================================================="
echo
echo "Fehlercode: $rc"
echo "Im SC-Panel kannst du mit einem Klick ein Support-Paket erstellen."
log_line "owned-stack setup failed rc=$rc"
notify "Omarchy Citizen" "Setup fehlgeschlagen. Bitte Support-Paket erstellen."
if [[ -t 0 ]]; then read -r -p "Drücke Enter zum Schließen … " _ || true; fi
exit "$rc"
}
trap setup_failed ERR
echo
echo "=================================================="
echo " Omarchy Citizen – Spielbereit machen"
echo "=================================================="
echo
echo "Omarchy Citizen verwaltet den kritischen Gaming-Stack jetzt selbst."
echo "Der LUG Helper entscheidet nicht mehr, welche Wine-Version installiert wird."
echo
local hw
hw="$(backend_game_status)"
if [[ "$(printf '%s\n' "$hw" | sed -n 's/^health=//p')" == "hardware-blocked" ]]; then
echo "Hardware-Prüfung nicht bestanden:"
printf '%s\n' "$hw" | grep -E '^(hardware_reason|gpu|vulkan)='
trap - ERR
return 2
fi
echo "1/4 Autopilot aktivieren und Quellen synchronisieren …"
autopilot_enable
echo
echo "2/4 Kompatiblen Wine-Runner prüfen …"
wine_doctor
echo
echo "3/4 Wine-Prefix, Komponenten und RSI Launcher installieren/reparieren …"
backend_game_install
echo
echo "4/4 Gaming-Stack abschließend synchronisieren …"
autopilot_maintain || true
trap - ERR
echo
echo "=================================================="
echo " SOFTWARE-STACK BEREIT"
echo "=================================================="
echo
echo "Der RSI Launcher kann jetzt gestartet werden."
echo "Anmeldung und der eigentliche Spieldownload erfolgen im offiziellen RSI Launcher."
notify "Omarchy Citizen" "Software-Stack ist bereit. RSI Launcher kann gestartet werden."
}
update_helper_terminal() {
set -Ee
exec > >(tee -a "$LOG_FILE") 2>&1
echo "Synchronisiere LUG Helper, Wine Runner und DXVK über Autopilot …"
autopilot_maintain
echo "✓ Gaming-Stack ist aktuell."
}
system_update_terminal() {
set -e
log_line "omarchy update begin"
omarchy update
rm -f "$UPDATE_CACHE"
log_line "omarchy update end rc=0"
}
launch_game() {
log_line "launch via owned backend"
if ! backend_game_launch >>"$LOG_FILE" 2>&1; then
notify_error "Star Citizen konnte nicht gestartet werden. Nutze „Problem beheben“ oder erstelle ein Support-Paket."
return 1
fi
}
primary_action() {
local st health backend
backend="$(find_backend 2>/dev/null || true)"
[[ -n "$backend" ]] && systemctl --user start omarchy-citizen-update.service >/dev/null 2>&1 || true
st="$(status)"
health="$(printf '%s\n' "$st" | sed -n 's/^health=//p' | head -n1)"
case "$health" in
ready|install-game)
launch_game
;;
hardware-blocked)
hardware_info
;;
*)
launch_terminal_action install-stack-terminal
;;
esac
}
repair_stack_terminal() {
set -Ee
exec > >(tee -a "$LOG_FILE") 2>&1
echo "Omarchy Citizen prüft und repariert den gesamten Star-Citizen-Stack …"
autopilot_maintain || true
backend_game_repair
echo "Reparatur abgeschlossen."
}
repair_assistant_interactive() {
local st health
st="$(status)"
health="$(printf '%s\n' "$st" | sed -n 's/^health=//p' | head -n1)"
if [[ "$health" == "hardware-blocked" ]]; then hardware_info; return; fi
launch_terminal_action repair-stack-terminal
}
repair_assistant() { repair_assistant_interactive; }
sanitize_to() {
local source="$1"
local target="$2"
if [[ ! -f "$source" ]]; then
return 0
fi
if command -v python3 >/dev/null 2>&1 && [[ -f "$SANITIZER" ]]; then
python3 "$SANITIZER" < "$source" > "$target"
else
sed \
-e "s#${HOME//\#/\\#}#~#g" \
-e 's/[A-Za-z0-9._%+-]\+@[A-Za-z0-9.-]\+\.[A-Za-z]\{2,\}/<email>/g' \
"$source" > "$target"
fi
}
capture_sanitized() {
local target="$1"
shift
local tmp="$CACHE_DIR/capture-$$-$RANDOM.txt"
{
"$@"
} >"$tmp" 2>&1 || true
sanitize_to "$tmp" "$target"
rm -f "$tmp"
}
support_build() {
local stamp support_id work downloads archive prefix="" game_dir=""
stamp="$(date '+%Y%m%d-%H%M%S')"
support_id="OC-${stamp}-$(printf '%s-%s-%s' "$stamp" "$$" "$RANDOM" | sha256sum | cut -c1-6)"
work="$CACHE_DIR/support-$support_id"
if command -v xdg-user-dir >/dev/null 2>&1; then
downloads="$(xdg-user-dir DOWNLOAD 2>/dev/null || true)"
else
downloads=""
fi
[[ -n "$downloads" && -d "$downloads" ]] || downloads="$HOME/Downloads"
mkdir -p "$downloads" "$work"
log_line "support build id=$support_id"
cat > "$work/README_SUPPORT.txt" <<EOF
Omarchy Citizen Support-Paket
Support-ID: $support_id
Plugin-Version: $PLUGIN_VERSION
Erstellt: $(date '+%Y-%m-%d %H:%M:%S %z')
Dieses Paket wurde automatisch erstellt, um Support ohne Linux-Kenntnisse zu ermöglichen.
Datenschutz:
- Home-Pfad, Benutzername und Hostname werden beim Export maskiert.
- E-Mail-Adressen, IP-/MAC-Adressen und typische Token-/Session-Werte werden maskiert.
- Es werden keine Browserdaten, SSH-Schlüssel oder Passwortdateien gesammelt.
- Star-Citizen-Game.log/EAC-Vollprotokolle sind im Standardpaket NICHT enthalten.
- Die Maskierung ist eine Best-Effort-Funktion. Nutzer können das Archiv vor dem Senden prüfen.
Bitte bei Support-Anfragen die Support-ID mit angeben.
EOF
{
echo "support_id=$support_id"
echo "plugin_id=$PLUGIN_ID"
echo "plugin_version=$PLUGIN_VERSION"
echo "created=$(date --iso-8601=seconds)"
"$SELF" status
} > "$work/citizen-status.txt"
if backend="$(find_backend 2>/dev/null)"; then
capture_sanitized "$work/updater-status.json" "$backend" status --json
fi
if [[ -f "$STATE_DIR/updater.log" ]]; then
tail -n 1200 "$STATE_DIR/updater.log" > "$CACHE_DIR/updater-log-$$.txt"
sanitize_to "$CACHE_DIR/updater-log-$$.txt" "$work/updater.log"
rm -f "$CACHE_DIR/updater-log-$$.txt"
fi
capture_sanitized "$work/omarchy-debug.txt" omarchy debug --no-sudo --print
if backend="$(find_backend 2>/dev/null)"; then
capture_sanitized "$work/autopilot-status.txt" "$backend" status
capture_sanitized "$work/game-status.txt" "$backend" game-status
capture_sanitized "$work/wine-doctor.txt" "$backend" doctor
fi
{
echo "=== Kernel / Desktop ==="
uname -rmo 2>/dev/null || true
printf 'XDG_SESSION_TYPE=%s\n' "${XDG_SESSION_TYPE:-unknown}"
printf 'XDG_CURRENT_DESKTOP=%s\n' "${XDG_CURRENT_DESKTOP:-unknown}"
printf 'WAYLAND_DISPLAY=%s\n' "${WAYLAND_DISPLAY:-unknown}"
echo
echo "=== Memory ==="
free -h 2>/dev/null || true
echo
echo "=== Filesystems ==="
df -hT / "$HOME" 2>/dev/null || true
echo
echo "=== Block devices ==="
lsblk -o NAME,SIZE,FSTYPE,FSAVAIL,MOUNTPOINTS 2>/dev/null || true
echo
echo "=== GPU ==="
lspci -nnk 2>/dev/null | grep -A4 -Ei 'VGA|3D|Display' || true
echo
echo "=== Vulkan ==="
if command -v vulkaninfo >/dev/null 2>&1; then
vulkaninfo --summary 2>/dev/null || true
else
echo "vulkaninfo not installed"
fi
echo
echo "=== Star Citizen kernel limits ==="
sysctl vm.max_map_count 2>/dev/null || true
printf 'hard_open_files=%s\n' "$(ulimit -Hn 2>/dev/null || true)"
} > "$CACHE_DIR/system-$$.txt"
sanitize_to "$CACHE_DIR/system-$$.txt" "$work/system.txt"
rm -f "$CACHE_DIR/system-$$.txt"
{
echo "=== Relevant packages ==="
pacman -Q omarchy omarchy-dev lug-helper zenity polkit cabextract unzip 2>/dev/null || true
echo
echo "=== AUR helper ==="
yay --version 2>/dev/null | head -n 4 || true
echo
echo "=== Commands ==="
for cmd in omarchy lug-helper yay zenity wine winetricks gamescope gamemoderun; do
if command -v "$cmd" >/dev/null 2>&1; then
printf '%s=present\n' "$cmd"
else
printf '%s=missing\n' "$cmd"
fi
done
} > "$work/packages.txt"
if command -v omarchy >/dev/null 2>&1; then
capture_sanitized "$work/plugin-validation.txt" omarchy plugin validate "$PLUGIN_DIR"
fi
if [[ -f "$LOG_FILE" ]]; then
tail -n 1500 "$LOG_FILE" > "$CACHE_DIR/plugin-log-$$.txt"
sanitize_to "$CACHE_DIR/plugin-log-$$.txt" "$work/omarchy-citizen.log"
rm -f "$CACHE_DIR/plugin-log-$$.txt"
fi
if [[ -f /tmp/omarchy-update.log ]]; then
tail -n 500 /tmp/omarchy-update.log > "$CACHE_DIR/update-log-$$.txt"
sanitize_to "$CACHE_DIR/update-log-$$.txt" "$work/omarchy-update-tail.log"
rm -f "$CACHE_DIR/update-log-$$.txt"
fi
# LUG Helper writes the detailed Wine-prefix installation output here.
# This is the most useful file when winetricks/Wine prefix creation fails.
latest_lug_install_log="$(find /tmp -maxdepth 1 -type f -name 'lughelper-install-*.log' -printf '%T@ %p\n' 2>/dev/null \
| sort -nr | head -n1 | cut -d' ' -f2- || true)"
if [[ -n "$latest_lug_install_log" && -f "$latest_lug_install_log" ]]; then
tail -n 1200 "$latest_lug_install_log" > "$CACHE_DIR/lug-install-$$.txt"
sanitize_to "$CACHE_DIR/lug-install-$$.txt" "$work/lug-helper-install-tail.log"
rm -f "$CACHE_DIR/lug-install-$$.txt"
fi
configured="$(configured_prefix 2>/dev/null || true)"
if [[ -n "$configured" ]]; then
{
printf 'configured_prefix=%s\n' "$configured"
printf 'directory_exists=%s\n' "$([[ -d "$configured" ]] && echo yes || echo no)"
printf 'drive_c=%s\n' "$([[ -d "$configured/drive_c" ]] && echo present || echo missing)"
printf 'system_reg=%s\n' "$([[ -f "$configured/system.reg" ]] && echo present || echo missing)"
printf 'user_reg=%s\n' "$([[ -f "$configured/user.reg" ]] && echo present || echo missing)"
printf 'runner_dirs=%s\n' "$(find "$configured/runners" -mindepth 1 -maxdepth 1 -type d -printf '%f ' 2>/dev/null || true)"
} > "$CACHE_DIR/prefix-health-$$.txt"
sanitize_to "$CACHE_DIR/prefix-health-$$.txt" "$work/wine-prefix-health.txt"
rm -f "$CACHE_DIR/prefix-health-$$.txt"
fi
prefix="$(read_prefix 2>/dev/null || true)"
game_dir="$(read_game_dir 2>/dev/null || true)"
{
printf 'wine_prefix=%s\n' "${prefix:-not-configured}"
printf 'game_dir=%s\n' "${game_dir:-not-configured}"
printf 'launch_script=%s\n' "$([[ -n "$prefix" && -f "$prefix/sc-launch.sh" ]] && echo present || echo missing)"
printf 'game_binary=%s\n' "$([[ -n "$game_dir" && -f "$game_dir/LIVE/Bin64/StarCitizen.exe" ]] && echo present || echo missing)"
} > "$CACHE_DIR/paths-$$.txt"
sanitize_to "$CACHE_DIR/paths-$$.txt" "$work/star-citizen-path-status.txt"
rm -f "$CACHE_DIR/paths-$$.txt"
if [[ -n "$prefix" && -f "$prefix/sc-launch.log" ]]; then
tail -n 600 "$prefix/sc-launch.log" > "$CACHE_DIR/sc-launch-$$.txt"
sanitize_to "$CACHE_DIR/sc-launch-$$.txt" "$work/sc-launch-tail.log"
rm -f "$CACHE_DIR/sc-launch-$$.txt"
fi
if [[ -n "$prefix" && -f "$prefix/sc-launch.sh" ]]; then
head -n 350 "$prefix/sc-launch.sh" > "$CACHE_DIR/sc-script-$$.txt"
sanitize_to "$CACHE_DIR/sc-script-$$.txt" "$work/sc-launch-script-sanitized.txt"
rm -f "$CACHE_DIR/sc-script-$$.txt"
fi
archive="$downloads/Omarchy-Citizen-Support-$support_id.tar.gz"
tar -C "$work" -czf "$archive" .
rm -rf "$work"
log_line "support archive=$archive"
if command -v wl-copy >/dev/null 2>&1; then
printf '%s' "$archive" | wl-copy
fi
if command -v zenity >/dev/null 2>&1; then
zenity --info --width=580 \
--title="Support-Paket erstellt" \
--text="Support-ID:
<b>$support_id</b>
Das bereinigte Support-Paket wurde in deinem Downloads-Ordner erstellt:
$(basename "$archive")
Der Dateipfad wurde – falls die Zwischenablage verfügbar ist – kopiert.
Schicke dieses Archiv zusammen mit der Support-ID an den Plugin-Support." \
>/dev/null 2>&1 || true
else
notify "Omarchy Citizen" "Support-Paket erstellt: $(basename "$archive")"
fi
if command -v xdg-open >/dev/null 2>&1; then
xdg-open "$downloads" >/dev/null 2>&1 &
fi
printf '%s\n' "$archive"
}
support_start() {
support_build
}
open_debug_log() {
if [[ ! -f "$LOG_FILE" ]]; then
notify_error "Noch kein Debug-Log vorhanden."
return 1
fi
xdg-open "$LOG_FILE" >/dev/null 2>&1 &
}
open_log() {
local prefix log
prefix="$(read_prefix 2>/dev/null)" || {
notify_error "Noch kein Star-Citizen-Wine-Prefix gefunden."
return 1
}
log="$prefix/sc-launch.log"
if [[ ! -f "$log" ]]; then
notify_error "Noch kein Start-Log gefunden.
Starte den RSI Launcher mindestens einmal."
return 1
fi
xdg-open "$log" >/dev/null 2>&1 &
}
open_wiki() {
xdg-open "https://wiki.starcitizen-lug.org" >/dev/null 2>&1 &
}
open_ngl_page() {
xdg-open "https://www.nglproject.com/de#downloads" >/dev/null 2>&1 &
}
ngl_info() {
local msg
msg="NGL ist ein optionaler Community-Mod für den Windows-RSI-Launcher.
Omarchy Citizen behandelt NGL als EXPERIMENTELL und installiert es nie ohne deine Auswahl und Bestätigung.
Der Mod läuft im selben Wine-Prefix wie dein RSI Launcher."
if command -v zenity >/dev/null 2>&1; then
zenity --info --width=520 --title="Omarchy Citizen – NGL" --text="$msg" >/dev/null 2>&1 &
else
notify "Omarchy Citizen – NGL" "$msg"
fi
}
ngl_install_interactive() {
local prefix script selected workdir exe
if ! command -v zenity >/dev/null 2>&1; then
notify_error "Die NGL-Installation benötigt die grafische Dateiauswahl. Bitte zuerst das normale Setup ausführen."
return 1
fi
prefix="$(read_prefix 2>/dev/null)" || {
notify_error "Star Citizen muss zuerst eingerichtet werden."
return 1
}
script="$prefix/sc-launch.sh"
[[ -f "$script" ]] || {
notify_error "Das Star-Citizen-Start-Script fehlt. Nutze zuerst „Problem beheben“."
return 1
}
selected="$(zenity \
--file-selection \
--title="NGL Installer auswählen" \
--filename="$HOME/Downloads/" \
--file-filter="NGL Installer | *.zip *.ZIP *.exe *.EXE" \
--file-filter="Alle Dateien | *" 2>/dev/null)" || return 0
[[ -f "$selected" ]] || return 1
workdir="$CACHE_DIR/ngl-installer"
rm -rf -- "$workdir"
mkdir -p "$workdir"
case "${selected,,}" in
*.zip)
unzip -q "$selected" -d "$workdir" || {
notify_error "Der NGL-Installer konnte nicht entpackt werden."
return 1
}
exe="$(find "$workdir" -type f \( -iname '*ngl*.exe' -o -iname '*installer*.exe' -o -iname '*setup*.exe' -o -iname '*.exe' \) \
-printf '%p\n' | head -n 1)"
;;
*.exe)
exe="$selected"
;;
*)
notify_error "Bitte eine NGL-ZIP- oder EXE-Datei auswählen."
return 1
;;
esac
[[ -n "${exe:-}" && -f "$exe" ]] || {
notify_error "Kein Windows-Installer in der ausgewählten Datei gefunden."
return 1
}
if ! zenity --question --width=560 \
--title="NGL experimentell installieren?" \
--ok-label="Installer starten" \
--cancel-label="Abbrechen" \
--text="NGL ist Community-Code und läuft im selben Wine-Prefix wie dein RSI Launcher.
Bitte nutze ausschließlich Downloads von nglproject.com.
Fortfahren?" 2>/dev/null; then
return 0
fi
log_line "NGL installer confirmed by user"
{
printf 'wine '
printf '%q' "$exe"
printf '\nexit\n'
} | bash "$script" shell >>"$LOG_FILE" 2>&1
}
ngl_install() {
ngl_install_interactive
}
case "$ACTION" in
status) status ;;
hardware-info) hardware_info ;;
autopilot-enable) autopilot_enable ;;
autopilot-maintain) autopilot_maintain ;;
wine-doctor) wine_doctor ;;
primary) primary_action ;;
setup) guided_setup ;;
recover-prefix) recover_incomplete_prefix ;;
recover-prefix-terminal) recover_incomplete_prefix_terminal ;;
guided-setup-interactive) guided_setup_interactive ;;
repair) repair_assistant ;;
repair-interactive) repair_assistant_interactive ;;
repair-stack-terminal) repair_stack_terminal ;;
support) support_start ;;
support-build) support_build ;;
debug-log) open_debug_log ;;
plugin-update-check) plugin_update_check ;;
plugin-update-now) plugin_update_now ;;
plugin-auto-enable) plugin_auto_enable ;;
plugin-auto-disable) plugin_auto_disable ;;
updater-log) open_updater_log ;;
check-update) check_update ;;
install-stack) launch_terminal_action install-stack-terminal ;;
install-stack-terminal) install_stack_terminal ;;
update-helper) launch_terminal_action update-helper-terminal ;;
update-helper-terminal) update_helper_terminal ;;
system-update) launch_terminal_action system-update-terminal ;;
system-update-terminal) system_update_terminal ;;
launch) launch_game ;;
helper) run_helper_gui ;;
install) run_helper_gui --install ;;
preflight) run_helper_gui --preflight-check ;;
runners) run_helper_gui --manage-runners ;;
dxvk) run_helper_gui --manage-dxvk ;;
repair-launch) run_helper_gui --update-launch-script ;;
repair-rsi) run_helper_gui --update-rsi-launcher ;;
dirs) run_helper_gui --show-directories ;;
log) open_log ;;
wiki) open_wiki ;;
ngl-page) open_ngl_page ;;
ngl-info) ngl_info ;;
ngl-install) ngl_install ;;
ngl-install-interactive) ngl_install_interactive ;;
*)
notify_error "Unbekannte Omarchy-Citizen-Aktion: $ACTION"
exit 2
;;
esac